diff --git a/WMass/python/plotter/.gitignore b/WMass/python/plotter/.gitignore index 9320c7bae3c4..a1da37bc5337 100644 --- a/WMass/python/plotter/.gitignore +++ b/WMass/python/plotter/.gitignore @@ -3,6 +3,7 @@ *_cc.so *.pcm mdunser.cc +mciprian.cc # local folders my_old_wmass_lep/ diff --git a/WMass/python/plotter/cropNegativeTemplateBins.py b/WMass/python/plotter/cropNegativeTemplateBins.py new file mode 100644 index 000000000000..b69e4de6c245 --- /dev/null +++ b/WMass/python/plotter/cropNegativeTemplateBins.py @@ -0,0 +1,121 @@ +#!/usr/bin/env python + +#from shutil import copyfile +import re, sys, os, os.path, ROOT, copy, math +from array import array +#import numpy as np +import root_numpy + +# in the fit, bins with 0 content in the nominal are ignored. +# so, after we made the shape files, we can just set to 0 the negative content of bins in the +# nominal templates (no need to touch the alternate as well) +# note that, by default, this function modify the original input file + +def cropNegativeContent(h, silent=True, cropError=False): + + dim = h.GetDimension() + nbins = 0 + if dim == 1: nbins = h.GetNbinsX() + 2 + elif dim == 2: nbins = (h.GetNbinsX() + 2) * (h.GetNbinsY() + 2) + elif dim == 3: nbins = (h.GetNbinsX() + 2) * (h.GetNbinsY() + 2) * (h.GetNbinsZ() + 2) + + integral = h.Integral() + for i in range(nbins): + nom = h.GetBinContent(i) + if nom<0.0: + h.SetBinContent(i, 0) + if cropError: + h.SetBinError(i, 0) + integralNonNeg = h.Integral() + if not silent: + print "{n}: original integral = {i} changed by {r}".format(n=h.GetName(), + i=str(integral), + r=str(integralNonNeg/integral)) + + +if __name__ == "__main__": + + from optparse import OptionParser + parser = OptionParser(usage="%prog [options]") + #parser.add_option("-i", "--indir", dest="indir", type="string", default="", help="Input folder"); + parser.add_option("-f", "--infile", dest="infile", type="string", default="", help="Input file name"); + parser.add_option("-o", "--outdir", dest="outdir", type="string", default="./", help="Output folder (current one as default)"); + parser.add_option("-p", "--processes", dest="processes", type="string", default="x_Z|x_W.*|x_Top.*|.*DiBosons.*|x_data_fakes.*", help="Regular expression for histograms to be affected"); + parser.add_option("-a", "--all", dest="allHists", action="store_true", default=False, help="Crop all templates, not just those for systematics"); + parser.add_option("-s", "--silent", dest="silent", action="store_true", default=False, help="Print info when acting on histograms"); + (options, args) = parser.parse_args() + + # if not len(options.indir): + # print "Warning: you must specify a folder with signal root files with option --indir" + # quit() + if not len(options.infile): + print "Warning: you must specify an input file name with option --infile" + quit() + + # manage output folder + outdir = options.outdir + if not outdir.endswith('/'): outdir += "/" + if outdir != "./": + if not os.path.exists(outdir): + print "Creating folder", outdir + os.system("mkdir -p " + outdir) + + basenameFile = os.path.basename(options.infile) + + charge = "" + flavour = "" + if not any(ch in basenameFile for ch in ["plus", "minus"]): + print "Warning: I could not understand charge plus|minus from file name. Abort" + quit() + else: + charge = "plus" if "plus" in basenameFile else "minus" + + if not any(fl in basenameFile for fl in ["el_", "mu_"]): + print "Warning: I could not understand flavour el|mu from file name. Abort" + quit() + else: + flavour = "mu" if "mu_" in basenameFile else "el" + + isMu = True if flavour == "mu" else False + + infileCopy = outdir + basenameFile.replace(".root","_ORIGINAL.root") + print "Copying original file with shapes into a backup" + cpcmd = "cp {f} {fnew}".format(f=options.infile,fnew=infileCopy) + print cpcmd + os.system(cpcmd) + outfile = outdir + basenameFile + if os.path.abspath(outfile) != os.path.abspath(options.infile): + print "Copying original file with shapes again in output folder" + cpcmd = "cp {f} {fnew}".format(f=options.infile,fnew=outfile) + print cpcmd + os.system(cpcmd) + else: + print "Output folder is the same as the input file. I will update the input file" + + tfno = ROOT.TFile(options.infileCopy,'READ') + if not tfno or not tfno.IsOpen(): + raise RuntimeError('Unable to open file {fn}'.format(fn=options.infile)) + of = ROOT.TFile(outfile,'UPDATE') + if not of or not of.IsOpen(): + raise RuntimeError('Unable to open file {fn}'.format(fn=outfile)) + nKeys = tfno.GetNkeys() + nCopiedKeys = 0 + for ikey,e in enumerate(tfno.GetListOfKeys()): + name = e.GetName() + if not re.match(options.processes,name): continue + if not options.allHists and re.match(".*(Up|Down)",name): continue + obj = e.ReadObj() + if not obj: + raise RuntimeError('Unable to read object {n}'.format(n=name)) + cropNegativeContent(obj, silent=options.silent) + obj.Write(name,ROOT.TObject.kOverwrite) + nCopiedKeys += 1 + if (ikey+1) % 100 == 0: + sys.stdout.write('Key {0:.2%} \r'.format(float(ikey+1)/nKeys)) + sys.stdout.flush() + + print "Overwrote {n}/{tot} from {fn}".format(n=str(nCopiedKeys),tot=str(nKeys),fn=options.infile) + print "Updated file saved in {of}".format(of=outfile) + of.Close() + tfno.Close() + diff --git a/WMass/python/plotter/fakeRate.cc b/WMass/python/plotter/fakeRate.cc index 66c12dd5d82b..2506708f14ae 100644 --- a/WMass/python/plotter/fakeRate.cc +++ b/WMass/python/plotter/fakeRate.cc @@ -56,14 +56,13 @@ TH2 * PRi_mu[30] = {0}; TH2 * PR_el = 0; TH2 * PRi_el[20] = {0}; -TH2 * FRcorrection = 0; -TH2 * FRcorrection_i[5]; +// test, idea is to have nominal fake/promp rate with all variations in the same histogram, to facilitate their loading and usage (eta-pt vs variation index) +// first bin (i=1) corresponds to nominal +TH3 * FR3D_mu = 0; +TH3 * PR3D_mu = 0; +TH3 * FR3D_el = 0; +TH3 * PR3D_el = 0; -// following few lines are obsolete -TH2 * FRnormSyst_el = 0; // normalization systematics for FR asaf pt and eta (equivalent to lnN nuisance parameter for each template bin) -TH2 * FRnormSyst_el_i[3] = {0}; // will only have up and down, but let's use 3 to include a nominal variation -TH2 * FRnormSyst_mu = 0; // normalization systematics for FR asaf pt and eta (equivalent to lnN nuisance parameter for each template bin) -TH2 * FRnormSyst_mu_i[3] = {0}; bool loadFRHisto(const std::string &histoName, const std::string file, const char *name) { @@ -94,12 +93,6 @@ bool loadFRHisto(const std::string &histoName, const std::string file, const cha else if (TString(histoName).Contains("angular_7")) { histo = & angular_7; } else if (TString(histoName).BeginsWith("PR_mu_i")) {histo = & PR_temp; hptr2 = & PRi_mu[TString(histoName).ReplaceAll("PR_mu_i","").Atoi()];} else if (TString(histoName).BeginsWith("PR_el_i")) {histo = & PR_temp; hptr2 = & PRi_el[TString(histoName).ReplaceAll("PR_el_i","").Atoi()];} - else if (histoName == "FRnormSyst_el") { histo = & FRnormSyst_el; hptr2 = & FRnormSyst_el_i[0];} - else if (histoName == "FRnormSyst_mu") { histo = & FRnormSyst_mu; hptr2 = & FRnormSyst_mu_i[0];} - else if (TString(histoName).BeginsWith("FRnormSyst_el_i")) {histo = & FR_normSyst_temp; hptr2 = & FRnormSyst_el_i[TString(histoName).ReplaceAll("FRnormSyst_el_i","").Atoi()];} - else if (TString(histoName).BeginsWith("FRnormSyst_mu_i")) {histo = & FR_normSyst_temp; hptr2 = & FRnormSyst_mu_i[TString(histoName).ReplaceAll("FRnormSyst_mu_i","").Atoi()];} - else if (histoName == "FR_correction") { histo = & FRcorrection; hptr2 = & FRcorrection_i[0]; } - else if (TString(histoName).BeginsWith("FR_correction_i")) {histo = & FRcorr_temp; hptr2 = & FRcorrection_i[TString(histoName).ReplaceAll("FRcorrection_i","").Atoi()];} if (histo == 0) { std::cerr << "ERROR: histogram " << histoName << " is not defined in fakeRate.cc." << std::endl; return 0; @@ -147,6 +140,10 @@ bool loadFRHisto3D(const std::string &histoName, const std::string file, const c if (TString(histoName).Contains("helicityFractions_0")) { histo = & helicityFractions_0; } else if (TString(histoName).Contains("helicityFractions_L")) { histo = & helicityFractions_L; } else if (TString(histoName).Contains("helicityFractions_R")) { histo = & helicityFractions_R; } + else if (TString(histoName).Contains("muonFakeRate3D")) { histo = & FR3D_mu; } + else if (TString(histoName).Contains("muonPromptRate3D")) { histo = & PR3D_mu; } + else if (TString(histoName).Contains("electronFakeRate3D")) { histo = & FR3D_el; } + else if (TString(histoName).Contains("electronPromptRate3D")) { histo = & PR3D_el; } if (histo == 0) { std::cerr << "ERROR: histogram " << histoName << " is not defined in fakeRate.cc." << std::endl; return 0; @@ -189,37 +186,6 @@ bool loadFRHisto3D(const std::string &histoName, const std::string file, const c } -//=============================================================== - -float getFakeRatenormWeight(float lpt, float leta, int lpdgId, int ivar = 0) { - - if (!ivar) return 1.0; // this is a special case: the "nominal" FRnormSyst TH1 was never created (it would be FR_el or FR_mu) - // only the variations are considered here - // ivar == 1: up variation - // ivar == 2: down variation - - if (FRnormSyst_el_i[ivar] == 0 && FRnormSyst_mu_i[ivar] == 0) { - std::cout << "Error in getFakeRatenormWeight(): both histograms are 0. Returning 0" << std::endl; - return 0; - } - - int fid = abs(lpdgId); - TH2 *hist = (fid == 11 ? FRnormSyst_el_i[ivar] : FRnormSyst_mu_i[ivar]); - if (hist == 0) { - std::cout << "Error in getFakeRatenormWeight(): hist == 0. Returning 0" << std::endl; - return 0; - } - - // do we need a weight just as a function of eta or pt as well? - float absleta = std::abs(leta); - int etabin = std::max(1, std::min(hist->GetNbinsX(), hist->GetXaxis()->FindBin(absleta))); - int ptbin = std::max(1, std::min(hist->GetNbinsX(), hist->GetYaxis()->FindBin(lpt))); - - // TH1 content is a fraction, like 30%, so we return 1 +/- var - float var = hist->GetBinContent(etabin, ptbin); - return (ivar == 1) ? (1 + var) : (1 - var); - -} //=============================================================== @@ -449,6 +415,86 @@ float* _getFakeRateWmass(float lpt, float leta, int lpdgId, int iFR=0, int iPR= //====================== +float* _getFakeRate3DWmass(float lpt, float leta, int lpdgId, int iFR=1, int iPR=1) { + + // this function reads the FR/PR from a histogram, it does not derive it reading the parameters of a + // functional form used to interpolate FR/PR + // + // WARNING: THE HISTOGRAM HAS PT ON X AXIS AND ETA ON Y AXIS + // + + double feta = std::fabs(leta); + int fid = abs(lpdgId); + + TH3 *hist_fr = (fid == 11 ? FR3D_mu : FR3D_el); + TH3 *hist_pr = (fid == 11 ? PR3D_mu : PR3D_el); + if (hist_fr == 0 || hist_pr == 0) { + // this is the case where you expect electrons but get a muon, or viceversa + // Indeed, selection is evaluated as 1 or 0 multiplying the event weight in TTree::Draw(...), so you potentially have all flavours here + // do not issue warning messages here, unless it is for testing + //std::cout << "Error in _getFakeRateWmass: hist_fr == 0 || hist_pr == 0. It seems the flavour is not what you expect. Returning 0" << std::endl; + return 0; + } + + Bool_t hasNegativeEta = (hist_fr->GetYaxis()->GetBinLowEdge(1) < 0) ? true : false; + + // FR and PR histogram should have same binning, but let's make it general + // + // First FR + int etabin = std::max(1, std::min(hist_fr->GetNbinsY(), hist_fr->GetYaxis()->FindBin(hasNegativeEta ? leta : feta))); + int ptbin = std::max(1, std::min(hist_fr->GetNbinsX(), hist_fr->GetXaxis()->FindBin(lpt))); + float fr = hist_fr->GetBinContent(ptbin, etabin, iFR); + // and now PR + etabin = std::max(1, std::min(hist_pr->GetNbinsY(), hist_pr->GetYaxis()->FindBin(hasNegativeEta ? leta : feta))); + ptbin = std::max(1, std::min(hist_pr->GetNbinsX(), hist_pr->GetXaxis()->FindBin(lpt))); + float pr = hist_pr->GetBinContent(ptbin, etabin, iPR); + + // safety checks + if (fr >= pr) return 0; + if (pr > 1.0) pr = 1.0; // just in case + + + static float rates[2]; + rates[0] = pr; + rates[1] = fr; + return rates; +} + + + +//====================== + +float fakeRateWeight_1lep(float lpt, float leta, int lpdgId, bool passWP, int iFR=1, int iPR=1) { + + float* rates = _getFakeRate3DWmass(lpt,leta,lpdgId,iFR,iPR); + float pr = rates[0]; + float fr = rates[1]; + + float weight; + + // safety thing + if (pr <= fr) { + // std::cout << "### Error in weight: FR >= PR. Please check!" << std::endl; + // std::cout << " pt: " << lpt << " eta:" << leta << " pdgid: " << lpdgId << std::endl; + return 0; + } + + if (passWP) { + // tight + // returning a negative weight + weight = fr*(pr-1)/(pr-fr); // pr=1 --> return 0 + } else { + // not tight (but still loose) + weight = fr*pr/(pr-fr); // pr=1 --> return fr/(1-fr) + } + + // std::cout << "passWP = " << passWP << "\t Weight for data_fakes = " << weight << std::endl; + return weight; + +} + +//-------------------------------- + float fakeRateWeight_promptRateCorr_1l_i_smoothed(float lpt, float leta, int lpdgId, bool passWP, int iFR=0, int iPR=0) { float* rates = _getFakeRate(lpt,leta,lpdgId,iFR,iPR); @@ -606,92 +652,6 @@ float fakeRateWeight_promptRateCorr_2l_i_smoothed(float lpt1, float leta1, int l //============================== -float fakeRateWeight_1l_i_smoothed(float lpt, float leta, int lpdgId, bool passWP, int iFR=0) { //, int expected_pdgId=11) { - if (!passWP) { - double fpt = lpt; double feta = std::fabs(leta); int fid = abs(lpdgId); - // int fAbsExpected_pdgId = abs(expected_pdgId); - // if (fid != fAbsExpected_pdgId) { - // return 0; - // } - if (FRi_el[iFR] == 0 and FRi_mu[iFR] == 0) { - // this is the case where the histogram was not loaded correctly (one is 0 because you use the other flavour) - std::cout << "Error in fakeRateWeight_1l_i_smoothed: hist == 0. Returning 0" << std::endl; - return 0; - } - TH2 *hist = (fid == 11 ? FRi_el[iFR] : FRi_mu[iFR]); - if (hist == 0) { - // this is the case where you expect electrons but get a muon, or viceversa - // Indeed, selection is evaluated as 1 or 0 multiplying the event weight in TTree::Draw(...), so you potentially have all flavours here - // do not issue warnign mewssages here, unless it is for testing - //std::cout << "Error in fakeRateWeight_1l_i_smoothed: hist == 0. Returning 0" << std::endl; - //std::cout << "pdg ID = " << lpdgId << std::endl; - return 0; - } - Bool_t hasNegativeEta = (hist->GetXaxis()->GetBinLowEdge(1) < 0); - int etabin = std::max(1, std::min(hist->GetNbinsX(), hist->GetXaxis()->FindBin(hasNegativeEta ? leta : feta))); - float p0 = hist->GetBinContent(etabin, 1); - float p1 = hist->GetBinContent(etabin, 2); - if (iFR==1) p0 += hist->GetBinError(etabin, 1); - else if (iFR==2) p0 -= hist->GetBinError(etabin, 1); - else if (iFR==3) p1 += hist->GetBinError(etabin, 2); - else if (iFR==4) p1 -= hist->GetBinError(etabin, 2); - float fr = p0 + p1*lpt; - return fr/(1-fr); - - } else return 0; -} - - -float fakeRateWeight_1l_i_smoothed_FRcorr(float lpt, float leta, int lpdgId, bool passWP, int iFR=0, float var=-999, int iFRcorr=0) { //, int expected_pdgId=11) { - if (!passWP) { - double fpt = lpt; double feta = std::fabs(leta); int fid = abs(lpdgId); - // int fAbsExpected_pdgId = abs(expected_pdgId); - // if (fid != fAbsExpected_pdgId) { - // return 0; - // } - if (FRi_el[iFR] == 0 and FRi_mu[iFR] == 0) { - // this is the case where the histogram was not loaded correctly (one is 0 because you use the other flavour) - std::cout << "Error in fakeRateWeight_1l_i_smoothed: hist == 0. Returning 0" << std::endl; - return 0; - } - TH2 *hist = (fid == 11 ? FRi_el[iFR] : FRi_mu[iFR]); - if (hist == 0) { - // this is the case where you expect electrons but get a muon, or viceversa - // Indeed, selection is evaluated as 1 or 0 multiplying the event weight in TTree::Draw(...), so you potentially have all flavours here - // do not issue warnign mewssages here, unless it is for testing - //std::cout << "Error in fakeRateWeight_1l_i_smoothed: hist == 0. Returning 0" << std::endl; - //std::cout << "pdg ID = " << lpdgId << std::endl; - return 0; - } - int etabin = std::max(1, std::min(hist->GetNbinsX(), hist->GetXaxis()->FindBin(feta))); - float p0 = hist->GetBinContent(etabin, 1); - float p1 = hist->GetBinContent(etabin, 2); - if (iFR==1) p0 += hist->GetBinError(etabin, 1); - else if (iFR==2) p0 -= hist->GetBinError(etabin, 1); - else if (iFR==3) p1 += hist->GetBinError(etabin, 2); - else if (iFR==4) p1 -= hist->GetBinError(etabin, 2); - float fr = p0 + p1*lpt; - - // FR correction (iFRcorr > 0 not supported yet, could be used for variations) - float FRcorrection = 1; - TH2 *hist_FRcorr = 0; - if (var > -999) { - hist_FRcorr = FRcorrection_i[iFRcorr]; - if (hist_FRcorr == 0) { - std::cout << "Error in fakeRateWeight_1l_i_smoothed_FRcorr: hist_FRcorr == 0. Applying no correction (i.e. 1)" << std::endl; - //return 0; - } else { - int varbin = std::max(1, std::min(hist_FRcorr->GetNbinsX(), hist_FRcorr->GetXaxis()->FindBin(var))); - etabin = std::max(1, std::min(hist_FRcorr->GetNbinsY(), hist_FRcorr->GetYaxis()->FindBin(leta))); - FRcorrection = hist_FRcorr->GetBinContent(varbin,etabin); - } - } - - return FRcorrection * fr/(1-fr); - - } else return 0; -} - float fakeRateWeight_1l_i(float lpt, float leta, int lpdgId, bool passWP, int iFR) { if (!passWP) { diff --git a/WMass/python/plotter/makeHistogramsWMass.py b/WMass/python/plotter/makeHistogramsWMass.py index fd5218014dda..431da2dd7098 100644 --- a/WMass/python/plotter/makeHistogramsWMass.py +++ b/WMass/python/plotter/makeHistogramsWMass.py @@ -6,6 +6,8 @@ import re, sys, os, os.path import math +from cropNegativeTemplateBins import cropNegativeContent + def mirrorShape(nominal,alternate,mirror): # assumes any regularization (e.g. cropping negative bin content to make it 0) already happened outside # same for normalization @@ -72,10 +74,11 @@ def unroll2Dto1D(h): parser.add_option("-o", "--out", dest="outname", type="string", default=None, help="output name") parser.add_option("--od", "--outdir", dest="outdir", type="string", default=None, help="output name") parser.add_option("-v", "--verbose", dest="verbose", default=0, type="int", help="Verbosity level (0 = quiet, 1 = verbose, 2+ = more)") -parser.add_option("--asimov", dest="asimov", action="store_true", help="Asimov") +parser.add_option("--asimov", dest="asimov", action="store_true", default=False, help="Asimov") parser.add_option("--2d-binning-function",dest="binfunction", type="string", default=None, help="Function used to bin the 2D histogram: for now can be None or unroll2Dto1D") parser.add_option("--infile",dest="infile", type="string", default=None, help="File to read histos from (to reuse the one made with --savefile)") parser.add_option("--savefile",dest="savefile", type="string", default=None, help="File to save histos to (this has only those produced by getPlotsRaw() )") +parser.add_option("--crop-negative-bin", dest="cropNegativeBin", action="store_true", default=False, help="Set negative bins to 0") (options, args) = parser.parse_args() @@ -120,6 +123,10 @@ def unroll2Dto1D(h): else: report['data_obs'] = report['data'].Clone("x_data_obs") +if options.cropNegativeBin: + for p,h in report.iteritems(): + cropNegativeContent(h,silent=False) + allyields = dict([(p,h.Integral()) for p,h in report.iteritems()]) procs = [] for i,s in enumerate(mca.listSignals()): @@ -276,4 +283,15 @@ def unroll2Dto1D(h): workspace.Close() print "Wrote to ",myout+binname+".input.root" - +# now check goodness of file, if bad returns an exit code different from 0 +f = ROOT.TFile.Open(myout+binname+".input.root", "READ") +if f.IsZombie(): + print 'file is probably corrupted' + sys.exit(100) +if f.TestBit(ROOT.TFile.kRecovered): + print 'file is in fishy state, was recovered' + sys.exit(101) +if f.GetListOfKeys().GetSize()==0: + print 'file is bad, has no keys' + sys.exit(102) +print "File is in good state :)" diff --git a/WMass/python/plotter/mcAnalysis.py b/WMass/python/plotter/mcAnalysis.py index 87ed1540c5ae..ff7af8fc251f 100755 --- a/WMass/python/plotter/mcAnalysis.py +++ b/WMass/python/plotter/mcAnalysis.py @@ -50,6 +50,60 @@ def __init__(self,samples,options): self._premap.append((re.compile(k.strip()+"$"), to)) self.readMca(samples,options) + + def getSumGenWeightMCfromHisto(self, pname, rootfile, verbose=False): + + maxGenWgt = None + sumGenWeights = 1.0 + nUnweightedEvents = 1.0 + + ROOT.gEnv.SetValue("TFile.AsyncReading", 1); + #tmp_rootfile = ROOT.TXNetFile(rootfile+"?readaheadsz=65535") + tmp_rootfile = ROOT.TFile(rootfile+"?readaheadsz=65535") + + if self._options.weight and len(self._options.maxGenWeightProc): + # get sum of weights from histograms, filtering some events with large weights + for procRegExp,tmp_maxGenWgt in self._options.maxGenWeightProc: + if re.match(procRegExp,pname): + #tmp_maxGenWgt is a string, convert to float + maxGenWgt = fabs(float(tmp_maxGenWgt)) + log10_maxGenWgt = math.log10(maxGenWgt) + histo_sumgenweight = tmp_rootfile.Get('hGenWeights') + if not histo_sumgenweight: + raise RuntimeError, "Can't get histogram hGenWeights from %s.\nMake sure it is available when using option --max-genWeight-procs" % rootfile + minBin = histo_sumgenweight.GetXaxis().FindFixBin(-log10_maxGenWgt) + maxBin = histo_sumgenweight.GetXaxis().FindFixBin(log10_maxGenWgt) + sumGenWeights = histo_sumgenweight.Integral(minBin,maxBin) + if self._options.clipGenWeightToMax: + # then the other histogram, whose integral is the number of events before any cut + histo_numweight = tmp_rootfile.Get('hNumWeights') + if not histo_numweight: + raise RuntimeError, "Can't get histogram hNumWeights from %s.\nMake sure it is available when using option --max-genWeight-procs and --clip-genWeight-toMax" % rootfile + # get actual upper threshold based on the bin edge + maxGenWgt = math.pow(10.0,histo_sumgenweight.GetXaxis().GetBinUpEdge(maxBin)) + if verbose: + print "INFO >>> Process %s -> actual genWeight threshold set to %s" % (pname,str(maxGenWgt)) + nLargeWeight = histo_numweight.Integral(0,max(0,minBin-1)) + histo_numweight.Integral(min(histo_numweight.GetNbinsX()+1,maxBin+1), histo_numweight.GetNbinsX()+1) + sumGenWeights += (nLargeWeight*maxGenWgt) + nUnweightedEvents = histo_numweight.Integral(0,histo_numweight.GetNbinsX()+1) + else: + # get sum of weights from Runs tree (faster, but only works if not cutting away large genWeight) + tmp_tree = tmp_rootfile.Get('Runs') + if not tmp_tree or tmp_tree == None: + raise RuntimeError, "Can't get tree Runs from %s.\n" % rootfile + tmp_hist = ROOT.TH1D("sumweights","",1,0,10) + tmp_hist2 = ROOT.TH1D("sumcount","",1,0,10) + tmp_tree.Draw("1>>sumweights", "genEventSumw") + tmp_hist = ROOT.gROOT.FindObject("sumweights") + sumGenWeights = tmp_hist.Integral() + tmp_tree.Draw("1>>sumcount", "genEventCount") + tmp_hist2 = ROOT.gROOT.FindObject("sumcount") + nUnweightedEvents = tmp_hist2.Integral() + + tmp_rootfile.Close() + return (maxGenWgt, sumGenWeights, nUnweightedEvents) + + def readMca(self,samples,options,addExtras={},field0_addExtras=""): # when called with not empty addExtras, issue a warning in case you are overwriting settings @@ -141,9 +195,17 @@ def readMca(self,samples,options,addExtras={},field0_addExtras=""): if re.match(p+"$", field[1]): skipMe = True if skipMe: continue cnamesWithPath = [] - + + #print ">>> printing line" + #print line + #print ">>>" if options.nanoaodTree: field1_regexp = re.compile(field[1]) + if len(options.filterProcessFiles): + for procRegexp,filterRegExp in options.filterProcessFiles: + if re.match(procRegexp,field[0]): + field1_regexp = re.compile(filterRegExp) + subpath = extra['SubPath'] if 'SubPath' in extra else ".*" subPath_regexp = re.compile(subpath) pathsToSearch = options.path @@ -181,6 +243,7 @@ def readMca(self,samples,options,addExtras={},field0_addExtras=""): cnamesWithPath += (list(glob.iglob("%s/%s*" % (treepath,match.group(0))))) cnames = [os.path.basename(cname) for cname in cnamesWithPath] else: cnames = [ x.strip() for x in field[1].split("+") ] + total_w = 0.; to_norm = False; ttys = []; is_w = -1 pname0 = pname @@ -193,8 +256,12 @@ def readMca(self,samples,options,addExtras={},field0_addExtras=""): else: print "INFO >>> Process %s -> rejecting events with genWeight > %s" % (pname,tmp_maxGenWgt) - #for cname in cnames: - for cnameWithPath in (cnamesWithPath if len(cnamesWithPath) else cnames): + ### CHECKPOINT + allFiles = cnamesWithPath if len(cnamesWithPath) else cnames + nAllFiles = len(allFiles) + + iFile = 0 + for cnameWithPath in allFiles: cname = os.path.basename(cnameWithPath) if options.useCnames: pname = pname0+"."+cname for (ffrom, fto) in options.filesToSwap: @@ -249,6 +316,14 @@ def readMca(self,samples,options,addExtras={},field0_addExtras=""): #print "cname = %s" % cname #print "rootfile: %s" % rootfile #print "objname : %s" % objname + # + prepath = '' + if not 'root:/' in rootfile: + if '/eos/user/' in rootfile: + prepath = 'root://eosuser.cern.ch//' + elif '/eos/cms/store/' in rootfile: + prepath = 'root://eoscms.cern.ch//' + rootfile = prepath+rootfile else: if options.remotePath: rootfile = "root:%s/%s/%s_tree.root" % (options.remotePath, cname, treename) @@ -270,7 +345,9 @@ def readMca(self,samples,options,addExtras={},field0_addExtras=""): ## needed temporarily pckfile = basepath+"/%s/skimAnalyzerCount/SkimReport.pck" % cname - tty = TreeToYield(rootfile, options, settings=extra, name=pname, cname=cname, objname=objname, frienddir=friendDir); ttys.append(tty) + tty = TreeToYield(rootfile, options, settings=extra, name=pname, cname=cname, objname=objname, frienddir=friendDir); + ttys.append(tty) + if signal: self._signals.append(tty) self._isSignal[pname] = True @@ -295,66 +372,21 @@ def readMca(self,samples,options,addExtras={},field0_addExtras=""): is_w = 0 elif options.nanoaodTree: - maxGenWgt = None - sumGenWeights = 1.0 - nUnweightedEvents = 1.0 - if options.weight and len(options.maxGenWeightProc): - # get sum of weights from Events tree, filtering some events with large weights - # this assumes the trees are unskimmed to correctly compute the sum!! - for procRegExp,tmp_maxGenWgt in options.maxGenWeightProc: - if re.match(procRegExp,pname): - #tmp_maxGenWgt is a string, convert to float - maxGenWgt = abs(float(tmp_maxGenWgt)) - ROOT.gEnv.SetValue("TFile.AsyncReading", 1); - #tmp_rootfile = ROOT.TXNetFile(rootfile+"?readaheadsz=65535") - tmp_rootfile = ROOT.TFile(rootfile+"?readaheadsz=65535") - tmp_tree = tmp_rootfile.Get('Events') - if not tmp_tree or tmp_tree == None: - raise RuntimeError, "Can't get tree Events from %s.\n" % rootfile - # check the tree was not skimmed - nEvents = tmp_tree.GetEntries() - tmp_tree_runs = tmp_rootfile.Get('Runs') - if not tmp_tree_runs or tmp_tree_runs == None: - raise RuntimeError, "Can't get tree Runs from %s.\n" % rootfile - for i,event in enumerate(tmp_tree_runs): - nGenEvents = event.genEventCount - if i: break - if nEvents != nGenEvents: - print "nEvents = %d nGenEvents = %f" % (nEvents,nGenEvents) - raise RuntimeError, "You are trying to remove or clip large gen weights, so I am recomputing the sum of gen weights excluding them.\nHowever, it seems the file\n%s\n you are using contains a skimmed tree.\nIn this way the sum of gen weights will be wrong" % rootfile - ## check was ok - if options.clipGenWeightToMax: - # set weight to max - # TMath::Sign(a,b) returns a with the sign of b - nUnweightedEvents = tmp_tree.Draw("1>>sumweights", "TMath::Sign(TMath::Min(abs(genWeight),%s),genWeight)" % str(maxGenWgt)) - else: - # reject event with weight > max - nUnweightedEvents = tmp_tree.Draw("1>>sumweights", "genWeight*(abs(genWeight) < %s)" % str(maxGenWgt)) - tmp_hist = ROOT.gROOT.FindObject("sumweights") - sumGenWeights = tmp_hist.Integral() - tmp_rootfile.Close() - else: - # get sum of weights from Runs tree (faster, but only works if not cutting away large genWeight) - ROOT.gEnv.SetValue("TFile.AsyncReading", 1); - #tmp_rootfile = ROOT.TXNetFile(rootfile+"?readaheadsz=65535") - tmp_rootfile = ROOT.TFile(rootfile+"?readaheadsz=65535") - tmp_tree = tmp_rootfile.Get('Runs') - if not tmp_tree or tmp_tree == None: - raise RuntimeError, "Can't get tree Runs from %s.\n" % rootfile - tmp_tree.Draw("1>>sumweights", "genEventSumw") - tmp_hist = ROOT.gROOT.FindObject("sumweights") - sumGenWeights = tmp_hist.Integral() - tmp_tree.Draw("1>>sumcount", "genEventCount") - tmp_hist2 = ROOT.gROOT.FindObject("sumcount") - nUnweightedEvents = tmp_hist2.Integral() - tmp_rootfile.Close() + (maxGenWgt, sumGenWeights, nUnweightedEvents) = self.getSumGenWeightMCfromHisto(pname, rootfile, verbose=(iFile==0)) + sys.stdout.write('INFO >>> preparing files {0:.2%} \r'.format(float(iFile+1)/nAllFiles)) + sys.stdout.flush() + + if options.weight and True: # True for now, later on this could explicitly require using the actual genWeights as opposed to using sum of unweighted events for MC (see the case for cmgtools below) if (is_w==0): raise RuntimeError, "Can't put together a weighted and an unweighted component (%s)" % cnames is_w = 1; total_w += sumGenWeights if maxGenWgt != None: - scale = "genWeight*(%s)*(abs(genWeight)<%s)" % (field[2],str(maxGenWgt)) + if options.clipGenWeightToMax: + scale = "(%s)*TMath::Sign(TMath::Min(abs(genWeight),%s),genWeight)" % (field[2],str(maxGenWgt)) + else: + scale = "genWeight*(%s)*(abs(genWeight)<%s)" % (field[2],str(maxGenWgt)) else: scale = "genWeight*(%s)" % field[2] elif not options.weight: @@ -449,7 +481,10 @@ def readMca(self,samples,options,addExtras={},field0_addExtras=""): for p in p0.split(","): if re.match(p+"$", pname): tty.setOption('NormSystematic', float(p1)) if pname not in self._rank: self._rank[pname] = len(self._rank) + iFile += 1 + ### END CHECKPOINT if to_norm: + print ">>> Total sumgenweights = %s (process = %s)" % (str(total_w),pname) for tty in ttys: if options.weight: tty.setScaleFactor("%s*%g" % (scale, 1000.0/total_w)) @@ -827,7 +862,7 @@ def addMCAnalysisOptions(parser,addTreeToYieldOnesToo=True): parser.add_option("-P", "--path", dest="path", action="append", type="string", default=[], help="Path to directory with input trees and pickle files. Can supply multiple paths which will be searched in order. (default: ./") parser.add_option("--RP", "--remote-path", dest="remotePath", type="string", default=None, help="path to remote directory with trees, but not other metadata (default: same as path)") parser.add_option("-p", "--process", dest="processes", type="string", default=[], action="append", help="Processes to print (comma-separated list of regexp, can specify multiple ones)"); - parser.add_option("--pg", "--pgroup", dest="premap", type="string", default=[], action="append", help="Group proceses into one. Syntax is ' := (comma-separated list of regexp)', can specify multiple times. Note tahat it is applied _before_ -p, --sp and --xp"); + parser.add_option("--pg", "--pgroup", dest="premap", type="string", default=[], action="append", help="Group proceses into one. Syntax is ' := (comma-separated list of regexp)', can specify multiple times. Note that it is applied _before_ -p, --sp and --xp"); parser.add_option("--xf", "--exclude-files", dest="filesToExclude", type="string", default=[], action="append", help="Files to exclude (comma-separated list of regexp, can specify multiple ones)"); parser.add_option("--xp", "--exclude-process", dest="processesToExclude", type="string", default=[], action="append", help="Processes to exclude (comma-separated list of regexp, can specify multiple ones)"); parser.add_option("--sf", "--swap-files", dest="filesToSwap", type="string", default=[], nargs=2, action="append", help="--swap-files X Y uses file Y instead of X in the MCA"); @@ -848,8 +883,8 @@ def addMCAnalysisOptions(parser,addTreeToYieldOnesToo=True): parser.add_option("--clip-genWeight-toMax", dest="clipGenWeightToMax", action="store_true", default=False, help="It only works with --nanoaod-tree when using --max-genWeight-procs, setting large weights to the max instead of rejecting the event"); parser.add_option("--no-heppy-tree", dest="noHeppyTree", action="store_true", default=False, help="Set to true to read root files when they were not made with Heppy (different convention for path names, might need to be adapted)"); parser.add_option("--nanoaod-tree", dest="nanoaodTree", action="store_true", default=False, help="Set to true to read root files from nanoAOD"); - - + parser.add_option("--filter-proc-files", dest="filterProcessFiles", type="string", nargs=2, action="append", default=[], help="Can use this option to override second field on each process line in MCA file, so to select few files without modifying the MCA file (e.g. for tests). E.g. --filter-proc-files 'W.*' '.*_12_.*' to only use files with _12_ in their name. Only works with option --nanoaod-tree"); + if __name__ == "__main__": from optparse import OptionParser parser = OptionParser(usage="%prog [options] tree.root cuts.txt") diff --git a/WMass/python/plotter/mcPlots.py b/WMass/python/plotter/mcPlots.py index b402d3ce86be..bffecc43a12a 100755 --- a/WMass/python/plotter/mcPlots.py +++ b/WMass/python/plotter/mcPlots.py @@ -415,7 +415,7 @@ def doNormFit(pspec,pmap,mca,saveScales=False): ROOT.RooMsgService.instance().setGlobalKillBelow(gKill) -def doRatioHists(pspec,pmap,total,totalSyst,maxRange,fixRange=False,fitRatio=None,errorsOnRef=True,ratioNums="signal",ratioDen="background",ylabel="Data/pred.",doWide=False,showStatTotLegend=False,errorBarsOnRatio=True,ratioYLabelSize=0.06,ratioNumsWithData=""): +def doRatioHists(pspec,pmap,total,totalSyst,maxRange,fixRange=False,fitRatio=None,errorsOnRef=True,onlyStatErrorsOnRef=False,ratioNums="signal",ratioDen="background",ylabel="Data/pred.",doWide=False,showStatTotLegend=False,errorBarsOnRatio=True,ratioYLabelSize=0.06,ratioNumsWithData=""): numkeys = [ "data" ] if len(ratioNumsWithData): for p in pmap.iterkeys(): @@ -483,7 +483,10 @@ def doRatioHists(pspec,pmap,total,totalSyst,maxRange,fixRange=False,fitRatio=Non unity.SetBinContent(b, 1 if n > 0 else 0) unity0.SetBinContent(b, 1 if n > 0 else 0) if errorsOnRef: - unity.SetBinError(b, e/n if n > 0 else 0) + if onlyStatErrorsOnRef: + unity.SetBinError(b, 0) + else: + unity.SetBinError(b, e/n if n > 0 else 0) unity0.SetBinError(b, e0/n if n > 0 else 0) else: unity.SetBinError(b, 0) @@ -513,7 +516,7 @@ def doRatioHists(pspec,pmap,total,totalSyst,maxRange,fixRange=False,fitRatio=Non unity0.SetMarkerStyle(1); unity0.SetMarkerColor(ROOT.kBlue-7); ROOT.gStyle.SetErrorX(0.5); - if errorsOnRef: + if errorsOnRef and not onlyStatErrorsOnRef: unity.Draw("E2"); else: unity.Draw("AXIS"); @@ -523,10 +526,10 @@ def doRatioHists(pspec,pmap,total,totalSyst,maxRange,fixRange=False,fitRatio=Non unity.SetFillStyle(3013); unity0.SetFillStyle(3013); if errorsOnRef: - unity.Draw("AXIS SAME"); + if not onlyStatErrorsOnRef: unity.Draw("AXIS SAME"); unity0.Draw("E2 SAME"); else: - if total != totalSyst and errorsOnRef: + if (total != totalSyst or onlyStatErrorsOnRef) and errorsOnRef: unity0.Draw("E2 SAME"); rmin = float(pspec.getOption("RMin",rmin)) rmax = float(pspec.getOption("RMax",rmax)) @@ -550,7 +553,7 @@ def doRatioHists(pspec,pmap,total,totalSyst,maxRange,fixRange=False,fitRatio=Non unity.GetYaxis().SetTitle(ylabel) total.GetXaxis().SetLabelOffset(999) ## send them away total.GetXaxis().SetTitleOffset(999) ## in outer space - total.GetYaxis().SetTitleSize(ratioYLabelSize) + total.GetYaxis().SetTitleSize(0.065) total.GetYaxis().SetTitleOffset(0.75 if doWide else 1.48) if options.setTitleYoffset > 0: total.GetYaxis().SetTitleOffset(options.setTitleYoffset) total.GetYaxis().SetLabelSize(0.05) @@ -591,7 +594,7 @@ def doRatioHists(pspec,pmap,total,totalSyst,maxRange,fixRange=False,fitRatio=Non leg1.SetTextFont(42) leg1.SetTextSize(0.035*0.7/0.3) leg1.AddEntry(unity, "total bkg. unc.", "F") - if showStatTotLegend: leg1.Draw() + if showStatTotLegend and not onlyStatErrorsOnRef: leg1.Draw() global legendratio0_, legendratio1_ legendratio0_ = leg0 legendratio1_ = leg1 @@ -1167,7 +1170,7 @@ def printOnePlot(self,mca,pspec,pmap,makeCanvas=True,outputDir=None,printDir=Non if doRatio: p2.cd(); rdata,rnorm,rnorm2,rline = doRatioHists(pspec,pmap,total,totalSyst, maxRange=options.maxRatioRange, fixRange=options.fixRatioRange, - fitRatio=options.fitRatio, errorsOnRef=options.errorBandOnRatio, + fitRatio=options.fitRatio, errorsOnRef=options.errorBandOnRatio, onlyStatErrorsOnRef=options.onlyStatErrorOnRatio, ratioNums=options.ratioNums, ratioDen=options.ratioDen, ylabel=options.ratioYLabel, doWide=doWide, showStatTotLegend=(False if options.noLegendRatioPlot else True), errorBarsOnRatio = options.errorBarsOnRatio, @@ -1355,6 +1358,7 @@ def addPlotMakerOptions(parser, addAlsoMCAnalysis=True): parser.add_option("--ratioNums", dest="ratioNums", type="string", default="signal", help="Numerator(s) of the ratio, when comparing MCs (comma separated list of regexps)") parser.add_option("--ratioYLabel", dest="ratioYLabel", type="string", default="Data/pred.", help="Y axis label of the ratio histogram.") parser.add_option("--noErrorBandOnRatio", dest="errorBandOnRatio", action="store_false", default=True, help="Do not show the error band on the reference in the ratio plots") + parser.add_option("--onlyStatErrorOnRatio", dest="onlyStatErrorOnRatio", action="store_true", default=False, help="Show only stat error on reference in ratio plots (when --noErrorBandOnRatio is False)") parser.add_option("--noErrorBarsOnRatio", dest="errorBarsOnRatio", action="store_false", default=True, help="Do not show the error bars on the ratio plots (affect each numerator, unlike --noErrorBandOnRatio") parser.add_option("--fitRatio", dest="fitRatio", type="int", default=None, help="Fit the ratio with a polynomial of the specified order") parser.add_option("--scaleSigToData", dest="scaleSignalToData", action="store_true", default=False, help="Scale all signal processes so that the overall event yield matches the observed one") @@ -1407,13 +1411,13 @@ def addPlotMakerOptions(parser, addAlsoMCAnalysis=True): parser.add_option("--allProcInLegend", dest="allProcInLegend", action="store_true", default=False, help="Put all processes in legend, regardless their integral.") parser.add_option("--forceFillColorNostackMode", dest="forceFillColorNostackMode", type="string", default="", help="Use fill color and style defined in MCA file when using --plotmode nostack|norm (comma separated list of regexps, by default only lines are used).") parser.add_option("--drawStatBox", dest="drawStatBox", action="store_true", default=False, help="Draw stat box"); + parser.add_option("-o", "--out", dest="out", default=None, help="Output file name. by default equal to plots -'.txt' +'.root'"); if __name__ == "__main__": from optparse import OptionParser parser = OptionParser(usage="%prog [options] mc.txt cuts.txt plots.txt") addPlotMakerOptions(parser) - parser.add_option("-o", "--out", dest="out", default=None, help="Output file name. by default equal to plots -'.txt' +'.root'"); (options, args) = parser.parse_args() mca = MCAnalysis(args[0],options) cuts = CutsFile(args[1],options) diff --git a/WMass/python/plotter/mciprian.cc b/WMass/python/plotter/mciprian.cc deleted file mode 100644 index c9fd44a4797a..000000000000 Binary files a/WMass/python/plotter/mciprian.cc and /dev/null differ diff --git a/WMass/python/plotter/plotUtils/utility.py b/WMass/python/plotter/plotUtils/utility.py index 7725dbef5111..4505dbd62ef5 100644 --- a/WMass/python/plotter/plotUtils/utility.py +++ b/WMass/python/plotter/plotUtils/utility.py @@ -3250,3 +3250,100 @@ def dressed2D(h1d,binning,name,title=''): h2_1 = ROOT.TH2F(name, title, n1, min1, max1, n2, min2, max2) h2_backrolled_1 = roll1Dto2D(h1d, h2_1 ) return h2_backrolled_1 + +#============================== + +def drawGraphCMS(grList, + xAxisNameTmp = "xAxis", + yAxisNameTmp = "yAxis", + canvasName = "default", + outputDIR = "./", + leg_roc = None, # text for legend + legendCoords = "0.5,0.15,0.9,0.35;2", # number after ; sets the number of columns + lumi = None, + vecMCcolors = [ROOT.kBlack, ROOT.kRed, ROOT.kGreen+2, ROOT.kBlue, ROOT.kOrange+1, ROOT.kCyan+2, ROOT.kGray+2], + etabinText = "", + canvasSize="800,800", + passCanvas=None, + ): + + + adjustSettings_CMS_lumi() + xAxisName = "" + xmin = 0 + xmax = 0 + xAxisName,setXAxisRangeFromUser,xmin,xmax = getAxisRangeFromUser(xAxisNameTmp) + # + yAxisName = "" + ymin = 0 + ymax = 0 + yAxisName,setYAxisRangeFromUser,ymin,ymax = getAxisRangeFromUser(yAxisNameTmp) + + nGraphs = len(grList) + + cw,ch = canvasSize.split(',') + canvas = passCanvas if passCanvas != None else ROOT.TCanvas("canvas","",int(cw),int(ch)) + canvas.SetTickx(1) + canvas.SetTicky(1) + canvas.cd() + canvas.SetFillColor(0) + canvas.SetGrid() + canvas.SetLeftMargin(0.14) + canvas.SetRightMargin(0.06) + canvas.cd() + + nColumnsLeg = 1 + if ";" in legendCoords: + nColumnsLeg = int(legendCoords.split(";")[1]) + legcoords = [float(x) for x in (legendCoords.split(";")[0]).split(',')] + lx1,ly1,lx2,ly2 = legcoords[0],legcoords[1],legcoords[2],legcoords[3] + leg = ROOT.TLegend(lx1,ly1,lx2,ly2) + leg.SetFillColor(0) + leg.SetFillStyle(0) + leg.SetBorderSize(0) + leg.SetNColumns(nColumnsLeg) + + for ig in range(0,nGraphs): + grList[ig].SetMarkerStyle(20); + grList[ig].SetMarkerColor(vecMCcolors[ig]); + grList[ig].SetLineColor(vecMCcolors[ig]); + grList[ig].SetLineWidth(2); + grList[ig].SetFillColor(vecMCcolors[ig]); + if ig == 0: + grList[ig].Draw("ap") + else: + grList[ig].Draw("p same"); + leg.AddEntry(grList[ig],leg_roc[ig],"LF"); + + leg.Draw("same") + canvas.RedrawAxis("sameaxis") + + grList[0].GetXaxis().SetTitleSize(0.05); + grList[0].GetXaxis().SetLabelSize(0.04); + grList[0].GetYaxis().SetTitleOffset(1.3); + grList[0].GetYaxis().SetTitleSize(0.05); + grList[0].GetYaxis().SetLabelSize(0.04); + grList[0].GetXaxis().SetTitle(xAxisName.c_str()); + grList[0].GetYaxis().SetTitle(yAxisName.c_str()); + if setXAxisRangeFromUser: + grList[0].GetXaxis().SetRangeUser(xmin,xmax); + if setYAxisRangeFromUser: + grList[0].GetYaxis().SetRangeUser(ymin,ymax); + + setTDRStyle() # check if it doesn't screw things up + if lumi != None: + CMS_lumi(canvas,lumi,True,False) + else: + CMS_lumi(canvas,"",True,False) + + etabin = ROOT.TLatex() + etabin.SetNDC(); # not sure it is needed + etabin.SetTextSize(0.05); + etabin.SetTextFont(42); + etabin.SetTextColor(ROOT.kBlack); + etabin.DrawLatex(0.15,0.15,etabinText); + + canvas.RedrawAxis("sameaxis"); + + for ext in [".png",".pdf"]: + canvas.SaveAs(outputDIR+canvasName+ext) diff --git a/WMass/python/plotter/runVertexStudy.py b/WMass/python/plotter/runVertexStudy.py index 22c5d22abe3c..4822530132ae 100644 --- a/WMass/python/plotter/runVertexStudy.py +++ b/WMass/python/plotter/runVertexStudy.py @@ -4,16 +4,17 @@ import ROOT #workingPoints = ["alwaystrue", "genEtaPt", "vertexPresel", "muonInAccept", "muMediumId", "muTightIso", "mtl1pf40", "trigger"] -workingPoints = ["alwaystrue", "genMuNoEtaPt", "vertexPresel", "muonInAccept", "muMediumId", "muTightIso", "mtl1pf40", "trigger"] - +workingPoints = ["alwaystrue", "onemuon", "trigger", "muonID", "pfRelIso04", "mtl1pf40", "vertex"] path = "{cmssw}/src/CMGTools/WMass/python/plotter/".format(cmssw=os.environ['CMSSW_BASE']) -mcafile = path + "w-mass-13TeV/wmass_mu/mca_wmu_forTest.txt" -cutfile = path + "w-mass-13TeV/wmass_mu/cuts_wmu_VertexStudy.txt" -plotfile = path + "w-mass-13TeV/wmass_mu/plots_forTest.txt" -proc = "QCD" # Wnopt +mcafile = path + "w-mass-13TeV/testingNano/cfg/test/mca_vertexStudy.txt" +cutfile = path + "w-mass-13TeV/testingNano/cfg/test/cuts_vertexStudy.txt" +plotfile = path + "w-mass-13TeV/testingNano/cfg/plots_test.txt" +#proc = "Wmunu_minus,Wmunu_plus" # +proc = "Zmumu" # # -plots = "dzVertex_gen_primary__Wpt,dzVertex_gen_primary__dressedLepPt" +plots = "dzVertex_gen_primary__Wpt,dzVertex_gen_primary__dressedLepPt" # we actually use the preFSR lepton, but name didn't change +# for Z events in 2-lepton phase space, dressedLepPt is always the pt of one of the lepton with the same charge (don't remember which one) # this script is meant to run the study on vertex using W MC or other MC @@ -25,10 +26,18 @@ parser.add_option("-o", "--outdir", dest="outdir", type="string", default=None, help="Output folder for all plots (each one will be in a specific subfolder)"); parser.add_option("-n", "--job-name", dest="jobName", type="string", default="vertexStudy", help="Name assigned to jobs"); parser.add_option("--ntuples-path", dest="ntuplesPath", type="string", default="/eos/cms/store/cmst3/group/wmass/mciprian/heppyNtuples/TREES_W_VERTEXSTUDY_94X_V2/", help="Path to ntuples") + # /eos/cms/store/cmst3/group/wmass/w-mass-13TeV/postNANO/dec2020/ + parser.add_option( '--doZ', dest="doZ", action="store_true", default=False, help="Run on Z events with 2-lepton phase space") (options, args) = parser.parse_args() ntuplesPath = options.ntuplesPath + if options.doZ: + workingPoints[1] = "twomuon" + cutfile = cutfile.replace("cuts_vertexStudy.txt","cuts_vertexStudy_2lep.txt") + proc = "Zmumu" + + ## constructing the command and arguments to run in condor submit file runner = "%s/src/CMGTools/WMass/python/postprocessing/lxbatch_runner.sh" % os.environ['CMSSW_BASE'] @@ -61,7 +70,7 @@ Error = {ld}/$(ProcId).error getenv = True request_memory = 2000 -+MaxRuntime = 7200 ++MaxRuntime = 43200 +JobBatchName = "{name}"\n '''.format(runner=runner,ld=options.logdir,name=options.jobName)) if os.environ['USER'] in ['mdunser', 'psilva']: @@ -74,11 +83,12 @@ for wp in workingPoints: cmd = "python mcPlots.py " cmd += " {mca} {cut} {plot}".format(mca=mcafile,cut=cutfile,plot=plotfile) - cmd += " -f -l 35.9 --s2v --tree treeProducerWMass --obj tree --noCms -j 8 " + cmd += " -f -l 35.9 --s2v --obj Events --noCms -j 8 " cmd += " --legendFontSize 0.05 --setLegendCoordinates 0.2,0.77,0.9,0.92 --allProcInLegend --noLegendRatioPlot --n-column-legend 2 " cmd += " --sP {plots} ".format(plots=plots) - cmd += " -P {ntp} -F Friends {ntp}friends/tree_Friend_{{cname}}.root ".format(ntp=ntuplesPath) - cmd += " -p {proc} -W 1.0 -U {wp} --pdir {o}/{wp}/ ".format(proc=proc,o=outdir,wp=wp) + cmd += " -P {ntp} ".format(ntp=ntuplesPath) + cmd += " -p {proc} -W (1/35.9)*puWeight*PrefireWeight -U {wp} --pdir {o}/{wp}/ ".format(proc=proc,o=outdir,wp=wp) + cmd += " --nanoaod-tree --max-genWeight-procs W|Z 50000.0 --clip-genWeight-toMax " cmdargs = [x.strip() for x in cmd.split()] strargs='' for a in cmdargs: # join do not preserve " or ' diff --git a/WMass/python/plotter/runfakerate.sh b/WMass/python/plotter/runfakerate.sh new file mode 100644 index 000000000000..634762653e3f --- /dev/null +++ b/WMass/python/plotter/runfakerate.sh @@ -0,0 +1,93 @@ +#! /bin/bash +# this script is a wrapper for the commands used to compute and pack the fake rate +# +plotterPath="${CMSSW_BASE}/src/CMGTools/WMass/python/plotter" +treePath="/eos/cms/store/cmst3/group/wmass/w-mass-13TeV/postNANO/dec2020/" +dataPeriod="all" # all, preVFP, postVFP +# +###################### +# options to set +###################### +#-------------------------- +dryRun="n" +reweightZpt="n" # use W and Z with reweighted pt +useSignedEta="y" # distinguish bins of positive and negative rapidity (if passing binning with just positive values below, it will just skip the negative, so you are actually using half statistics) +charge="" # "p", "n", or "" for positive, negative or both leptons +useLeptonScaleFactors="y" # to use weight for lepton scale factors (since they are obtained in a different phase space, one should do it with and without and compare) +#-------------------------- +ptDefinition="pt" # pt variable in w-mass-13TeV/make_fake_rates_xvars.txt +#------------------------- +#today=`date +"%d_%m_%Y"` +#outdir="fr_${today}_eta_${ptDefinition}_mT40_${lumi/./p}fb_signedEta_jetPt30" +outdir="fr_eta_${ptDefinition}_${dataPeriod}" +lumi="35.9" +if [[ "${dataPeriod}" == "preVFP" ]]; then + lumi="19.3" +elif [[ "${dataPeriod}" == "postVFP" ]]; then + lumi="16.6" +else: + lumi="35.9" +fi +###################### +###################### +# additional options to be passed to w-mass-13TeV/make_fake_rates_data.py +# can pass a new cut as you would do with mcPlots.py +# for now passing options to run on nanoAOD (as implemented in mcAnalysis.py) +#addOption=" -A alwaystrue pfmet 'MET_T1_pt<30' " +addOption=" --nanoaod-tree --max-genWeight-procs 'W.*|Z.*' '50000.0' --clip-genWeight-toMax " + +if [[ "${useLeptonScaleFactors}" != "y" ]]; then + outdir="${outdir}_noLepSF" +fi + +chargeCmd="" +if [[ "${charge}" == "p" ]]; then + chargeCmd=" --charge \"p\" " + outdir="${outdir}_plus" +elif [[ "${charge}" == "n" ]]; then + chargeCmd=" --charge \"n\" " + outdir="${outdir}_minus" +fi + +outdir="${plotterPath}/plots/fake-rate/wmassUL2016/${outdir}/" +echo "Creating ${outdir}" +mkdir -p ${outdir} + +cmdComputeFR="python ${plotterPath}/w-mass-13TeV/make_fake_rates_data.py --qcdmc --pt ${ptDefinition} --lumi ${lumi} --tree-path ${treePath} --outdir ${outdir} ${chargeCmd} " + +if [[ "${useLeptonScaleFactors}" != "y" ]]; then + cmdComputeFR="${cmdComputeFR} --no-scaleFactors" +fi + +if [[ "${useSignedEta}" == "y" ]]; then + cmdComputeFR="${cmdComputeFR} --useSignedEta " +fi + +if [[ "${reweightZpt}" == "y" ]]; then + cmdComputeFR="${cmdComputeFR} --reweightZpt " +fi + +if [[ "X${addOption}" != "X" ]]; then + cmdComputeFR="${cmdComputeFR} --addOpts \"${addOption}\" " +fi + +if [[ "${dryRun}" == "y" ]]; then + cmdComputeFR="${cmdComputeFR} --dry-run " + echo "Running this command:" + echo "" + echo "${cmdComputeFR} > commands4fakeRate.sh" + echo "" + echo "${cmdComputeFR} > commands4fakeRate.sh" | bash + echo "The commands used for fake-rate are stored in commands4fakeRate.sh" + echo "Use the following command to really run things" + echo "" + echo "cat commands4fakeRate.sh | bash" # here we really run the commands saved in commands4fakeRate.sh + echo "" +else + echo "Running this command:" + echo "" + echo "${cmdComputeFR}" + echo "" + echo "${cmdComputeFR}" | bash +fi + diff --git a/WMass/python/plotter/testMuonSF/allSFs.root b/WMass/python/plotter/testMuonSF/allSFs.root new file mode 100644 index 000000000000..25c96b7e08ef Binary files /dev/null and b/WMass/python/plotter/testMuonSF/allSFs.root differ diff --git a/WMass/python/plotter/tree2yield.py b/WMass/python/plotter/tree2yield.py index 850f51cded00..a50776b7c248 100644 --- a/WMass/python/plotter/tree2yield.py +++ b/WMass/python/plotter/tree2yield.py @@ -17,8 +17,8 @@ from CMGTools.WMass.plotter.cutsFile import * from CMGTools.WMass.plotter.fakeRate import * -from CMGTools.TTHAnalysis.plotter.mcCorrections import * -#from CMGTools.WMass.plotter.mcCorrections import * +#from CMGTools.TTHAnalysis.plotter.mcCorrections import * +from CMGTools.WMass.plotter.mcCorrections import * if "/functions_cc.so" not in ROOT.gSystem.GetLibraries(): compileMacro("src/CMGTools/WMass/python/plotter/functions.cc") @@ -293,7 +293,7 @@ def getEntries(self,useEList=True,closeFileAfterwards=True): tfile = ROOT.TFile.Open(self._fname) if not tfile: raise RuntimeError, "Cannot open %s\n" % self._fname t = tfile.Get(self._objname) - if not t: raise RuntimeError, "Cannot find tree %s in file %s\n" % (self._objname, self._fname) + if not t: raise RuntimeError, "Cannot find tree %s in file %s\n" % (self._objname, self._fname) self._entries = t.GetEntries() else: self._entries = self.getTree().GetEntries() diff --git a/WMass/python/plotter/utilityMacros/interface/utility.h b/WMass/python/plotter/utilityMacros/interface/utility.h index 3f7fdf11a641..7da2c1a55e3c 100644 --- a/WMass/python/plotter/utilityMacros/interface/utility.h +++ b/WMass/python/plotter/utilityMacros/interface/utility.h @@ -930,7 +930,7 @@ TObject* getObjectCloneFromFile(TFile* inputFile = NULL, const string& hvarName if (sampleDir == "") hvar = (TObject*) inputFile->Get((hvarName).c_str()); else hvar = (TObject*) inputFile->Get((sampleDir + "/" + hvarName).c_str()); if (!hvar || hvar == NULL) { - cout << "Error in getObjectCloneFromFile(): object '" << hvarName << "' not found in file (directory is " << sampleDir << "). End of programme." << endl; + cout << "Error in getObjectCloneFromFile(): object '" << hvarName << "' not found in file '" << inputFile->GetName() << "' (directory is '" << sampleDir << "'). End of programme." << endl; exit(EXIT_FAILURE); } diff --git a/WMass/python/plotter/utilityMacros/src/makeFakeRateGraphPlotsAndSmoothing.C b/WMass/python/plotter/utilityMacros/src/makeFakeRateGraphPlotsAndSmoothing.C index ca239744d3a7..bc0a9fc3a8ee 100644 --- a/WMass/python/plotter/utilityMacros/src/makeFakeRateGraphPlotsAndSmoothing.C +++ b/WMass/python/plotter/utilityMacros/src/makeFakeRateGraphPlotsAndSmoothing.C @@ -7,7 +7,7 @@ const static int smoothPolinDegree = 2; const static Double_t xMaxFitFakeRateData = (smoothPolinDegree == 1) ? 48 : 65; // for muons, can set it to at least 55 const static Bool_t drawPol1NarrowRange = (smoothPolinDegree == 1 and xMaxFitFakeRateData > 48) ? true : false; // set first argument as false not to draw the fit in narrow range (only for pol1) const static Bool_t smoothPromptRateAlwaysPol1 = false; // false if you want to use pol1 -static const Double_t ptMin_fitRangeData = (smoothPolinDegree == 2) ? 30 : 30; // can use 32 for pol1 // for muons, the value is hardcoded to always be 26 +static const Double_t ptMin_fitRangeData = (smoothPolinDegree == 2) ? 26 : 30; // can use 32 for pol1 // for muons, the value is hardcoded to always be 26 const static Bool_t excludePoints_Data = false; static const Double_t ptMin_excludeRangeData = 37; // used only if excludePoints_Data = true static const Double_t ptMax_excludeRangeData = 50; // used only if excludePoints_Data = true @@ -722,16 +722,16 @@ void doFakeRateGraphPlots(const string& inputFileName = "", TGraphAsymmErrors* fr_data_subEWKMC = nullptr; TGraphAsymmErrors* fr_data_subScaledUpEWKMC = nullptr; TGraphAsymmErrors* fr_data_subScaledDownEWKMC = nullptr; - TGraphAsymmErrors* fr_w = nullptr; - TGraphAsymmErrors* fr_z = nullptr; - TGraphAsymmErrors* fr_wpt = nullptr; // reweighted zpt - TGraphAsymmErrors* fr_zpt = nullptr; // reweighted zpt + TGraphAsymmErrors* fr_wlnu = nullptr; + TGraphAsymmErrors* fr_zll = nullptr; + //TGraphAsymmErrors* fr_wtaunu = nullptr; // don't need it for now + //TGraphAsymmErrors* fr_ztautau = nullptr; // don't need it for now TGraphAsymmErrors* fr_vv = nullptr; TGraphAsymmErrors* fr_top = nullptr; TGraphAsymmErrors* fr_qcd = nullptr; - TGraphAsymmErrors* fr_ewk = nullptr; // all EWK + TGraphAsymmErrors* fr_ewk = nullptr; // all EWK (W,Z, to leptons or taus, Top and Dibosons) TGraphAsymmErrors* fr_top_vv = nullptr; // Top+DiBosons - TGraphAsymmErrors* fr_wz = nullptr; // W+Z + TGraphAsymmErrors* fr_wz = nullptr; // W+Z (to leptons or taus) string detId = isEB ? "EB" : "EE"; string yrange = isEB ? "0.25,1.4" : "0,1.4"; // range for plotting all graphs @@ -744,10 +744,12 @@ void doFakeRateGraphPlots(const string& inputFileName = "", createPlotDirAndCopyPhp(outDir); adjustSettings_CMS_lumi(outDir); - vector processes = {"data", "data_sub", "QCD", - hasReweightedWZpt ? "Wpt" : "W", - hasReweightedWZpt ? "Zpt" : "Z", - "DiBosons", "Top"}; + vector processes = {"data", "data_sub", //"QCD", + hasReweightedWZpt ? "Wpt" : "Wmunu", + hasReweightedWZpt ? "Zpt" : "Zmumu", + hasReweightedWZpt ? "Wpt" : "Wtaunu", + hasReweightedWZpt ? "Zpt" : "Ztautau"}; + //"DiBosons", "Top"}; vector hpass; vector hntot; @@ -1024,7 +1026,7 @@ void doFakeRateGraphPlots(const string& inputFileName = "", if (processes[j] == "QCD") { hpass.back() = hpass.back()->Rebin(nBinsQCD,"",ptBinBoundariesQCD.data()); hntot.back() = hntot.back()->Rebin(nBinsQCD,"",ptBinBoundariesQCD.data()); - } else if (processes[j] == "W" || processes[j] == "Z" || processes[j] == "Wpt" || processes[j] == "Zpt") { + } else if (processes[j].find("W") != std::string::npos || processes[j].find("Z") != std::string::npos) { hpass_ewk_scaledUp->Add(hpass.back(), 1.+ subtrEWK_nSigma*scaleFactor[processes[j]]); hntot_ewk_scaledUp->Add(hntot.back(), 1.+ subtrEWK_nSigma*scaleFactor[processes[j]]); hpass_ewk_scaledDown->Add(hpass.back(), 1. - subtrEWK_nSigma*scaleFactor[processes[j]]); @@ -1058,21 +1060,29 @@ void doFakeRateGraphPlots(const string& inputFileName = "", } - if (processes[j] == "W") { + if (processes[j] == "Wmunu") { - fr_w = new TGraphAsymmErrors(hpass.back(), hntot.back(), "cl=0.683 b(1,1) mode"); + fr_wlnu = new TGraphAsymmErrors(hpass.back(), hntot.back(), "cl=0.683 b(1,1) mode"); } else if (processes[j] == "Wpt") { - fr_w = new TGraphAsymmErrors(hpass.back(), hntot.back(), "cl=0.683 b(1,1) mode"); + fr_wlnu = new TGraphAsymmErrors(hpass.back(), hntot.back(), "cl=0.683 b(1,1) mode"); - } else if (processes[j] == "Z") { + } else if (processes[j] == "Zmumu") { - fr_z = new TGraphAsymmErrors(hpass.back(), hntot.back(), "cl=0.683 b(1,1) mode"); + fr_zll = new TGraphAsymmErrors(hpass.back(), hntot.back(), "cl=0.683 b(1,1) mode"); + + // } else if (processes[j] == "Wtaunu") { + + // fr_wtaunu = new TGraphAsymmErrors(hpass.back(), hntot.back(), "cl=0.683 b(1,1) mode"); + + // } else if (processes[j] == "Ztautau") { + + // fr_ztautau = new TGraphAsymmErrors(hpass.back(), hntot.back(), "cl=0.683 b(1,1) mode"); } else if (processes[j] == "Zpt") { - fr_z = new TGraphAsymmErrors(hpass.back(), hntot.back(), "cl=0.683 b(1,1) mode"); + fr_zll = new TGraphAsymmErrors(hpass.back(), hntot.back(), "cl=0.683 b(1,1) mode"); } else if (processes[j] == "DiBosons") { @@ -1161,8 +1171,8 @@ void doFakeRateGraphPlots(const string& inputFileName = "", colorList.push_back(kBlue); legendEntries.push_back("W,Z MC (prompt rate)"); } else { - gr.push_back(fr_w); - gr.push_back(fr_z); + gr.push_back(fr_wlnu); + gr.push_back(fr_zll); colorList.push_back(kBlue); colorList.push_back(kAzure+2); legendEntries.push_back("W MC (prompt rate)"); @@ -1272,7 +1282,7 @@ void doFakeRateGraphPlots(const string& inputFileName = "", } else { - ptr_w = fitGraph(fr_w, isEB, Form("%s::%f,%f",ptXaxisName.c_str(),ptMin,ptMax), Form("Prompt Rate::%s",yrange_w.c_str()), Form("fr_w_%s_%s",detId.c_str(),plotPostFix.c_str()), outDirFits+"w/", "W MC (prompt rate)", legCoordFit,inputLuminosity,false, true, 1.0, false, nullptr, false, -1, -1, isMuon, etaLow,etaHigh); + ptr_w = fitGraph(fr_wlnu, isEB, Form("%s::%f,%f",ptXaxisName.c_str(),ptMin,ptMax), Form("Prompt Rate::%s",yrange_w.c_str()), Form("fr_wlnu_%s_%s",detId.c_str(),plotPostFix.c_str()), outDirFits+"w/", "W MC (prompt rate)", legCoordFit,inputLuminosity,false, true, 1.0, false, nullptr, false, -1, -1, isMuon, etaLow,etaHigh); // fit is Y=a*X+b // bin n.1 is for b (first parameter of pol1), bin n.2 is for a for (UInt_t ipar = 0; ipar < ptr_w->NPar(); ++ipar) { @@ -1280,7 +1290,7 @@ void doFakeRateGraphPlots(const string& inputFileName = "", frSmoothParameter_w->SetBinError(etaBinTH1,ipar+1,ptr_w->ParError(ipar)); } - ptr_z = fitGraph(fr_z, isEB, Form("%s::%f,%f",ptXaxisName.c_str(),ptMin,ptMax), Form("Prompt Rate::%s",yrange_z.c_str()), Form("fr_z_%s_%s",detId.c_str(),plotPostFix.c_str()), outDirFits+"z/", "Z MC (prompt rate)", legCoordFit,inputLuminosity,false, true, 1.0, false, nullptr, false, -1, -1, isMuon, etaLow,etaHigh); + ptr_z = fitGraph(fr_zll, isEB, Form("%s::%f,%f",ptXaxisName.c_str(),ptMin,ptMax), Form("Prompt Rate::%s",yrange_z.c_str()), Form("fr_zll_%s_%s",detId.c_str(),plotPostFix.c_str()), outDirFits+"z/", "Z MC (prompt rate)", legCoordFit,inputLuminosity,false, true, 1.0, false, nullptr, false, -1, -1, isMuon, etaLow,etaHigh); // fit is Y=a*X+b // bin n.1 is for b (first parameter of pol1), bin n.2 is for a for (UInt_t ipar = 0; ipar < ptr_z->NPar(); ++ipar) { @@ -1403,8 +1413,10 @@ void makeFakeRateGraphPlotsAndSmoothing(const string& inputFilePath = "www/wmass // use cross section uncertainty // might want to use an eta-dependent factor for W - scaleFactor["W"] = 0.038; - scaleFactor["Z"] = 0.04; + scaleFactor["Wmunu"] = 0.038; + scaleFactor["Zmumu"] = 0.04; + scaleFactor["Wtaunu"] = 0.038; + scaleFactor["Ztautau"] = 0.04; scaleFactor["Wpt"] = 0.038; scaleFactor["Zpt"] = 0.04; scaleFactor["Top"] = 0.09; diff --git a/WMass/python/plotter/utilityMacros/src/makeFakeRateGraphPlotsAndSmoothing.py b/WMass/python/plotter/utilityMacros/src/makeFakeRateGraphPlotsAndSmoothing.py index e4a991cba8ee..fba6564b3f4f 100644 --- a/WMass/python/plotter/utilityMacros/src/makeFakeRateGraphPlotsAndSmoothing.py +++ b/WMass/python/plotter/utilityMacros/src/makeFakeRateGraphPlotsAndSmoothing.py @@ -5,19 +5,19 @@ dryrun = 0 doMuons = 1 -hasReweightedWZpt = 1 +hasReweightedWZpt = 0 if doMuons: - inputFolder = "fr_27_03_2020_eta_pt_finer_mT40_35p9fb_signedEta_subtrAllMC_L1prefire_jetPt30_nativeMCatNLOxsec_reweightWZpt_dxy200micron" - inputFullPath = "www/wmass/13TeV/fake-rate/test_mu/testFR_wmass/" + inputFolder + "/mu/comb/" - outputFolder = "www/wmass/13TeV/fake-rate/muon/FR_graphs_tests/muonFRandPR_fitFRpol2PRerf_xFit26to65_nativeMCatNLOxsec_reweightWZpt_dxy200micron/" - outfileTag = outputFolder.split('/')[-2] - histPrefix = "fakeRateNumerator_mu_vs_etal1mu_pt_finer" + inputFolder = "fr_eta_pt_all" + inputFullPath = "www/wmass/13TeV/fake-rate/wmassUL2016/" + inputFolder + "/" + outputFolder = inputFullPath + "FRandPR_graphs/" + outfileTag = "muonFRandPR_nanoAODv8" + histPrefix = "fakeRateNumerator_vs_eta_pt" isMuon = "true" showMergedEWK = "true" saveToFile = "false" - noDrawQCD = "false" + noDrawQCD = "true" etaBinBoundariesList = "-2.4,-2.3,-2.2,-2.1,-2.0,-1.9,-1.8,-1.7,-1.6,-1.5,-1.4,-1.3,-1.2,-1.1,-1.0,-0.9,-0.8,-0.7,-0.6,-0.5,-0.4,-0.3,-0.2,-0.1,0.0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0,1.1,1.2,1.3,1.4,1.5,1.6,1.7,1.8,1.9,2.0,2.1,2.2,2.3,2.4" #etaBinBoundariesList = "-2.4,-2.2,-2.05,-1.9,-1.75,-1.6,-1.45,-1.3,-1.15,-1.0,-0.9,-0.8,-0.7,-0.6,-0.5,-0.4,-0.3,-0.2,-0.1,0.0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0,1.15,1.3,1.45,1.6,1.75,1.9,2.05,2.2,2.4" @@ -38,8 +38,7 @@ # work in progress options = '"{i}","{o}","{f}",'.format(i=inputFullPath, o=outputFolder, f=outfileTag) -options += '"{h}",{ism}, {smewk}, {save}, "{etabin}", {qcd}, {zwpt}'.format(h=histPrefix, ism=isMuon, smewk=showMergedEWK, - save=saveToFile, etabin=etaBinBoundariesList, qcd=noDrawQCD, zwpt="true" if hasReweightedWZpt else "false") +options += '"{h}",{ism}, {smewk}, {save}, "{etabin}", {qcd}, {zwpt}'.format(h=histPrefix, ism=isMuon, smewk=showMergedEWK,save=saveToFile, etabin=etaBinBoundariesList, qcd=noDrawQCD, zwpt="true" if hasReweightedWZpt else "false") cmd = "root -l -b -q 'makeFakeRateGraphPlotsAndSmoothing.C++({opt})' ".format(opt=options) print "-"*30 diff --git a/WMass/python/plotter/w-mass-13TeV/cardMaker.py b/WMass/python/plotter/w-mass-13TeV/cardMaker.py index ed5b9ce391ed..f282d78f3257 100755 --- a/WMass/python/plotter/w-mass-13TeV/cardMaker.py +++ b/WMass/python/plotter/w-mass-13TeV/cardMaker.py @@ -5,48 +5,80 @@ import makeSystematicMultipliers as ms import utilities utilities = utilities.util() +def isExcludedNuisance(excludeNuisances=[], name="", keepNuisances=[]): + if len(excludeNuisances) and any(re.match(x,name) for x in excludeNuisances): + if len(keepNuisances) and any(re.match(x,name) for x in keepNuisances): + return False + else: + print ">>>>> Excluding nuisance: ", name + return True + else: + return False class CardMaker: def __init__(self,options,charge,flavor): self._options = options self.charge = charge self.flavor = flavor - + self.data_eras = ["B", "C", "D", "E", "F", "F_postVFP", "G", "H"] + self.excludeNuisances = [] + self.keepNuisances = [] + if len(options.excludeNuisances): + self.excludeNuisances = options.excludeNuisances.split(",") + if len(options.keepNuisances): + self.keepNuisances = options.keepNuisances.split(",") + ### import the right dictionary process - systematic list depending on wmass/wlike #pathToImport = os.environ['CMSSW_BASE']+'/src/CMGTools/WMass/python/plotter/w-mass-13TeV/' pathToImport = os.path.dirname(sys.argv[0])+'/' if self._options.wmass: pathToImport += 'wmass_'+flavor - self.boson = 'W' + self.boson = 'W{fl}nu'.format(fl=self.flavor) else: pathToImport += 'wlike_'+flavor - self.boson = 'Z' + self.boson = 'Z{fl}{fl}'.format(fl=self.flavor) self.systematics = self.getSystList() self.centralfiles = self.getCentralProcesses() - self.shapesfile = os.path.join(self._options.inputdir,self.flavor+'_{ch}_shapes.root'.format(ch=charge)) - self.cardfile = os.path.join(self._options.inputdir,self.flavor+'_{ch}_card.txt' .format(ch=charge)) + self.shapesfile = os.path.join(self._options.inputdir,self.boson+'_{ch}_shapes.root'.format(ch=charge)) + self.cardfile = os.path.join(self._options.inputdir,self.boson+'_{ch}_card.txt' .format(ch=charge)) self.systFile = pathToImport+'/systsFit.txt' - - def getCentralProcesses(self): - acoeffs = ['ac']+['a{ic}'.format(ic=i) for i in range(8)] - sig_proc = ['{boson}{charge}_{ic}_{flav}'.format(charge=self.charge,ic=coeff,flav=self.flavor,boson=self.boson) for coeff in acoeffs] - other_boson_procs = ['{otherboson}_{flav}_{charge}'.format(flav=self.flavor,charge=self.charge,otherboson='Z' if self._options.wmass else 'W')] - otherprocs = ['bkg_and_data_{flav}_{charge}'.format(flav=self.flavor,charge=self.charge)] + # self.centralHistograms = self.getCentralHistograms() # to implement + + + def getCentralProcesses(self): + #acoeffs = ['ac']+['a{ic}'.format(ic=i) for i in range(8)] + acoeffs = [''] + # signal + sig_proc = ['{boson}_{charge}{ic}'.format(charge=self.charge,ic=("_"+coeff) if len(coeff) else "",boson=self.boson) for coeff in acoeffs] + # antisignal + other_boson_procs = ['{otherboson}_{charge}'.format(charge=self.charge,otherboson='Zmumu' if self._options.wmass else 'Wmunu')] + # other stuff (for data use then global one (not split by era, it is created afterwards) + other_files = ["Wtaunu","Ztautau","otherBkgHisto", "dataHisto"] + otherprocs = ["{op}_{charge}".format(op=otherproc,charge=self.charge) for otherproc in other_files] return sig_proc + other_boson_procs + otherprocs def getSystList(self): - ### systematics that are applied to both W and Z - baseSysts = ['pdf{i}'.format(i=ipdf) for ipdf in range(1,61)] - baseSysts += ['{qcdpar}{idir}'.format(qcdpar=par,idir=idir) for par in ['alphaS','muR','muF','muRmuF'] for idir in ['Up','Dn']] - baseSysts += ['kalPtErr{i}{idir}'.format(i=istat,idir=idir) for istat in range(133) for idir in ['Up','Dn']] - baseSysts += ['kalPtClosureErr{idir}'.format(idir=idir) for idir in ['Up','Dn']] + ### systematics that are applied to both W and Z, for mu and tau decays + NPDFSYSTS=2 + baseSysts = ['pdf{i}'.format(i=ipdf) for ipdf in range(1,1+NPDFSYSTS)] + baseSysts += ['alphaS{idir}'.format(idir=idir) for idir in ['Up','Dn']] + # FIXME: need a better way to decide if and how these are binned, depending on what was done in make_wmass_cards.py + qcdSystsUnbin = ['{qcdpar}{idir}'.format(qcdpar=par,idir=idir) for par in ['muR','muF','muRmuF'] for idir in ['Up','Dn']] + NVPTBINS = 2 + qcdSystsPtChargebin = ['{qcdpar}{ipt}{ch}{idir}'.format(qcdpar=par,ipt=ipt,ch=self.charge,idir=idir) for par in ['muR','muF','muRmuF'] for ipt in range(1,1+NVPTBINS) for idir in ['Up','Dn']] + #baseSysts += ['kalPtErr{i}{idir}'.format(i=istat,idir=idir) for istat in range(133) for idir in ['Up','Dn']] + #baseSysts += ['kalPtClosureErr{idir}'.format(idir=idir) for idir in ['Up','Dn']] ### W/Z mass points - massPoints = ['mWmass_0']+['mWmass_{sgn}{i}'.format(sgn=sgn,i=imass) for sgn in['m','p'] for imass in range(1,21)] + MASSVARIATIONS = [10* i for i in range(1,3)] + massPoints = ['massShift{v}MeV{d}".format(v=mvar,d=idir)' for mvar in MASSVARIATIONS for idir in ['Up','Down']] ### other systematics - otherSysts = ['fsr'] + # otherSysts = ['fsr'] + otherSysts = [] ### build the systematic dictionary for the root files - systsCards = {self.boson: baseSysts + massPoints + otherSysts, - 'Z' if self._options.wmass else 'W': baseSysts} + systsCards = {self.boson: baseSysts + qcdSystsPtChargebin + massPoints + otherSysts, + 'Zmumu' if self._options.wmass else 'Wmunu': baseSysts + qcdSystsUnbin, + 'Wtaunu': baseSysts + qcdSystsPtChargebin + massPoints, + 'Ztautau': baseSysts + qcdSystsUnbin} return systsCards def applySystematics(self, dictWithCentrals, systEnv): #process, syst_regexp, syst_file, outfile_name): @@ -73,12 +105,13 @@ def applySystematics(self, dictWithCentrals, systEnv): #process, syst_regexp, sy if ('plus' in proc and 'minus' in systName) or ('minus' in proc and 'plus' in systName): continue if re.match(proc_regexp,proc): + #print "hname = %s systname = %s" % (proc_hist.GetName(),systName) tmp_var = copy.deepcopy(proc_hist.Clone(proc_hist.GetName()+'_'+systName)) tmp_var.Multiply(tmp_syst) allVars.append(tmp_var) dictProcSyst[(proc, systName)] = None - outfile = ROOT.TFile(options.inputdir+'/{f}_{ch}_shapes.root.multiplierSystematics'.format(f=self.flavor,ch=self.charge), 'RECREATE') + outfile = ROOT.TFile(options.inputdir+'/{f}_{ch}_shapes.root.multiplierSystematics'.format(f=self.boson,ch=self.charge), 'RECREATE') for v in allVars: v.Write() @@ -112,26 +145,37 @@ def mirrorShape(self,nominal,alternate,newname,alternateShapeOnly=False,use2xNom mirror.Scale(nominal.Integral()/mirror.Integral()) return (alternate,mirror) - def mergeChunks(self): + def mergeChunks(self, dryRun=False): ## prepare the relevant files. only the datacards and the correct charge allfiles = [os.path.join(dp, f) for dp, dn, fn in os.walk(self._options.inputdir,followlinks=True) for f in fn if f.endswith('.input.root')] + datafiles = [f for f in allfiles if any('dataHisto_{e}_{ch}.input.root'.format(e=era,ch=self.charge) in f for era in self.data_eras)] + datafolder = os.path.dirname(os.path.abspath(datafiles[0]))+"/" + # start merging data (contains data and fakes) + outf = "dataHisto_{ch}.input.root".format(ch=self.charge) + haddcmd = "hadd -f -k {df}{of} {i}".format(df=datafolder,of=outf,i=" ".join(datafiles)) + print "Merging files with data and fakes" + print haddcmd + if not dryRun: os.system(haddcmd) + ## get only the central processes files = [f for f in allfiles if any(os.path.basename(f)==centralfile+'.input.root' for centralfile in self.centralfiles)] files = sorted(files) #, key = lambda x: int(x.rstrip('.input.root').split('_')[1])) - acoeffs = [self.charge+'_ac']+['{charge}_a{ic}'.format(charge=self.charge,ic=i) for i in range(8)] + #acoeffs = [self.charge+'_ac']+['{charge}_a{ic}'.format(charge=self.charge,ic=i) for i in range(8)] tmpfiles = [] for proc in self.centralfiles: - boson = proc[0] + print 'processing process: ',proc + boson = proc.split("_")[0] bosonSysts = self.systematics[boson] if boson in self.systematics else [] - ### this should be probably removed from make_wmass_cards.py, but now it is there and should use it - suffix = {'W': 'sig', 'Z': 'dy'} ## the input ROOT file is not built from the inputdir since it may come from different partX subdir central_input = [f for f in files if os.path.basename(f)==proc+'.input.root'][0] - syst_inputs = sorted([f for f in allfiles if any(os.path.basename(f)=='{proc}_{sfx}_{syst}.input.root'.format(proc=proc,sfx=suffix[boson],syst=syst) for syst in bosonSysts)]) - print 'processing process: ',proc + if len(bosonSysts): + syst_inputs = sorted([f for f in allfiles if any(os.path.basename(f)=='{proc}_{syst}.input.root'.format(proc=proc,syst=syst) for syst in bosonSysts)]) + else: + syst_inputs = [] + nominals = {} for irf,rf in enumerate([central_input]+syst_inputs): print '\twith nominal/systematic file: ',rf @@ -144,47 +188,40 @@ def mergeChunks(self): for e in tf.GetListOfKeys() : name=e.GetName() obj=e.ReadObj() + # x_data must be removed, it was already copied as x_data_obs, which is what we need + if name == "x_data" and 'data' in proc: + continue # exclude the asimov data_obs which is in any single card, apart the file with the real data - if name.endswith('data_obs') and 'data' not in proc: continue - - name = name.replace('Dn','Down') - ### remove the _dy_ / _sig_ from the process name which is present only in the mWmass "systematic" variations - cleanName = name.replace('_sig_','_').replace('_dy_','_') - + if name.endswith('data_obs') and 'data' not in proc: + continue + if name.endswith("Dn"): + name = name.replace('Dn','Down') ### bkg_and_data is in central_input, with no systs. All the systematics (Up/Down) are just copied into the target file if irf==0: if name not in plots: - plots[name] = obj.Clone(cleanName) - nominals[name] = obj.Clone(cleanName+"0") + plots[name] = obj.Clone(name+"_clone") + nominals[name] = obj.Clone(name+"0") nominals[name].SetDirectory(None) #print 'replacing old %s with %s' % (name,name) - plots[name].Write() + plots[name].Write(name) else: if any(sysname in name for sysname in ['pdf','fsr']): # these changes by default shape and normalization. Each variation should be symmetrized wrt nominal - pfx = '_'.join(name.split("_")[:-2]) + pfx = '_'.join(name.split("_")[:-1]) # was -2, but names changed if 'pdf' in name: - patt = re.compile('(pdf)(\d+)') - tokens = patt.findall(name) - sysname = tokens[0][0]; isys = int(tokens[0][1]) - cleanName = "{pfx}_{sysname}{isys}".format(pfx=pfx,sysname=sysname,isys=isys) - (alternate,mirror) = self.mirrorShape(nominals[pfx],obj,cleanName,self._options.pdfShapeOnly) + (alternate,mirror) = self.mirrorShape(nominals[pfx],obj,name,alternateShapeOnly=self._options.pdfShapeOnly) else: - tokens = name.split("_"); pfx = '_'.join(tokens[:-2]); syst = tokens[-1] - cleanName = "{pfx}_{syst}".format(pfx=pfx,syst=syst) - (alternate,mirror) = self.mirrorShape(nominals[pfx],obj,cleanName,alternateShapeOnly=True) + (alternate,mirror) = self.mirrorShape(nominals[pfx],obj,name,alternateShapeOnly=True) for alt in [alternate,mirror]: if alt.GetName() not in plots: - plots[alt.GetName()] = alt.Clone() - plots[alt.GetName()].Write() - elif re.match('.*mWmass.*',name): # this is a special "syst". No need to have Up/Down - plots[name] = obj.Clone(cleanName) - plots[name].Write() + plots[alt.GetName()] = alt.Clone(alt.GetName()+"_clone") + plots[alt.GetName()].Write(alt.GetName()) + elif re.match('.*massShift.*',name): + plots[name] = obj.Clone(name+"_clone") + plots[name].Write(name) else: - tokens = name.split("_"); pfx = '_'.join(tokens[:-2]); syst = tokens[-1].replace('Dn','Down') - cleanName = "{pfx}_{syst}".format(pfx=pfx,syst=syst) if name not in plots: - plots[name] = obj.Clone(cleanName) - plots[name].Write() + plots[name] = obj.Clone(name+"_clone") + plots[name].Write(name) of.Close() if self._options.mergeRoot: @@ -192,7 +229,7 @@ def mergeChunks(self): os.system(haddcmd) os.system('rm {indir}/tmp_*.root'.format(indir=self._options.inputdir)) - print "DONE adding input chunks." + print "DONE adding input chunks." def activateSystMatrix(self,systFile): @@ -226,13 +263,15 @@ def writeDatacard(self,systFile=''): obj=e.ReadObj() syst = name.split('_')[-1] if not any(idir in syst for idir in ['Up','Down']): - if re.match('((m|p)\d+|0)',syst): + if re.match('((m|p)\d+|0)',syst): # this was probably for some obsolete systs (proc,syst) = ('_'.join(name.split('_')[1:-2]),'_'.join(name.split('_')[-2:])) histo = None else: + #print "hname = %s" % name (proc,syst) = ('_'.join(name.split('_')[1:]),'central') - histo = obj.Clone() + histo = obj.Clone() # this changes the name adding _clone! resetting name below histo.SetDirectory(None) + histo.SetName(name) else: (proc,syst) = ('_'.join(name.split('_')[1:-1]),name.split('_')[-1]) histo = None @@ -240,7 +279,7 @@ def writeDatacard(self,systFile=''): tf.Close() processes = [proc for (proc,syst) in procAndHistos if (syst=='central' and proc!='data' and proc!='data_obs')] - signalprocs = sorted([p for p in filter(lambda x: x.startswith('{boson}{charge}'.format(boson=self.boson,charge=self.charge)),processes)]) + signalprocs = sorted([p for p in filter(lambda x: x.startswith('{boson}_{charge}'.format(boson=self.boson,charge=self.charge)),processes)]) signalProcAndInd = [(p,-1*i) for i,p in enumerate(signalprocs)] otherprocs = [p for p in filter(lambda x: x not in signalprocs, processes)] otherProcAndInd = [(p,i+1) for i,p in enumerate(otherprocs)] @@ -268,7 +307,7 @@ def writeDatacard(self,systFile=''): ### skip the central histograms if syst=='central': continue ### the mW steps need to be implemented when we know how it is implemented ion combinetf - if 'mWmass' in syst: + if 'massShift' in syst: pass ### for each syst, there is Up/Down, just write the line once if any([syst.endswith('Up'),syst.endswith('Down')]): @@ -279,15 +318,17 @@ def writeDatacard(self,systFile=''): if sytPatt.match(systName) and procPatt.match(proc): process_index = procindices[proc] appliedSystMatrix[systName][process_index] = str(scaling) - if group not in systGroups: systGroups[group] = [systName] + if group not in systGroups: + systGroups[group] = [systName] else: - if systName not in systGroups[group]: systGroups[group].append(systName) + if systName not in systGroups[group]: + systGroups[group].append(systName) if options.mergeRoot or options.remakeMultipliers: os.system('hadd -f {of} {of}.baseSystematics {of}.multiplierSystematics'.format(of=self.shapesfile)) ### now write the datacard - channel = '{boson}{charge}'.format(boson='W' if self._options.wmass else 'Z',charge=self.charge) + channel = '{boson}_{charge}'.format(boson='Wmunu' if self._options.wmass else 'Zmumu',charge=self.charge) datacard = open(self.cardfile,'w') ### -- header -- datacard.write("imax 1\n") @@ -308,7 +349,11 @@ def writeDatacard(self,systFile=''): datacard.write('##----------------------------------\n') ### -- single systematics -- - for systName,values in appliedSystMatrix.iteritems(): + excludedSysts = [] + for systName,values in sorted(appliedSystMatrix.iteritems()): + if isExcludedNuisance(self.excludeNuisances, systName, self.keepNuisances): + excludedSysts.append(systName) + continue ### do not write systematic lines if it is not applied to any process if any([v!='-' for v in values]): datacard.write( '%-15s shape %s\n' % (systName," ".join([kpatt % v for v in values]))) @@ -316,37 +361,127 @@ def writeDatacard(self,systFile=''): ### -- groups -- datacard.write('\n\n') for group,systs in systGroups.iteritems(): - datacard.write( '%-15s group = %s\n' % (group," ".join(sorted(systs))) ) + sortedsysts = [x for x in systs if x not in excludedSysts] + sortedsysts = sorted(sortedsysts) + datacard.write( '%-15s group = %s\n' % (group," ".join(sortedsysts)) ) datacard.close() print "Done. Datacard in ",self.cardfile -def combineCharges(options): + +def prepareChargeFit(options, charges=["plus"]): + + suffix = 'card' if options.freezePOIs else 'card_withXsecMask' + if options.fitSingleCharge: + # this makes sense only when a single datacard for a given charge is different from those that would be used + # for the combination (e.g. because to facilitate the combination some lines that require both charges are + # added to the datacard for a specific charge) + suffix += "_singleCharge{ch}".format(ch=charges[0]) + + datacards=[]; + channels=[] + binname = "Wmunu" if options.wmass else "Zmumu" + for charge in charges: + datacards.append(os.path.abspath(options.inputdir)+"/{b}_{ch}_card.txt".format(b=binname,ch=charge)) + channels.append('{b}_{ch}'.format(b=binname,ch=charge)) + maskedChannels = ['InAcc'] + #if something_happens: + # maskedChannels.append('OutAcc') + if not options.freezePOIs: + for mc in maskedChannels: + datacards.append(os.path.abspath(options.inputdir)+"/{b}_{ch}_xsec_{maskchan}_card.txt".format(b=binname,ch=charge,maskchan=mc)) + channels.append('{b}_{ch}_xsec_{maskchan}'.format(b=binname,ch=charge,maskchan=mc)) + + print "="*20 + print "Looking for these cards" + print "-"*20 + for d in datacards: + print d + print "="*20 + ### prepare the combineCards and txt2hdf5 commands - charges = ['plus','minus'] - singleChargeCards = ['{idir}/{flav}_{charge}_card.txt'.format(idir=options.inputdir,flav=options.flavor,charge=ch) for ch in charges] - if any([not os.path.exists(card) for card in singleChargeCards]): - raise RuntimeError, "At least one between %s does not exist. Cannot combine." % " ".join(singleChargeCards) - print "Cards for + and - ready. Combining them now..." - combinedCard = '{idir}/{flav}_card.txt'.format(idir=options.inputdir,flav=options.flavor) - cards = {} - for ch in charges: - cards[ch] = '{idir}/{flav}_{charge}_card.txt'.format(idir=os.path.abspath(options.inputdir),flav=options.flavor,charge=ch) - ccCmd = 'combineCards.py --noDirPrefix '+' '.join(['{ch}={dcfile}'.format(ch=ch,dcfile=card) for ch,card in cards.iteritems()])+' > '+combinedCard - txt2hdf5Cmd = 'text2hdf5.py {cf} --clipSystVariations {varmax} {pfx}'.format(cf=combinedCard,varmax=1.3,pfx='--postfix '+ options.postfix if len(options.postfix) else '') - - ## run the commands: need cmsenv in the combinetf release - print ccCmd - os.system(ccCmd) - print "Combined card in ",combinedCard - print txt2hdf5Cmd - os.system(txt2hdf5Cmd) - hdf5name=combinedCard.replace('.txt','.hdf5') - print "hdf5 file in ",hdf5name - - if len(options.postfix): - hdf5name = hdf5name.replace('.hdf5','_%s.hdf5' % options.postfix) - combineCmd = 'combinetf.py -t -1 --binByBinStat {hdf5file}'.format(hdf5file=hdf5name) + if True: #sum([os.path.exists(card) for card in datacards])==len(datacards): + if options.fitSingleCharge: + print "I am going to run fit for single charge {ch}".format(ch=charges[0]) + else: + print "Cards for W+ and W- done. Combining them now..." + + combinedCard = os.path.abspath(options.inputdir)+"/"+binname+'_'+suffix+'.txt' + ccCmd = 'combineCards.py --noDirPrefix '+' '.join(['{ch}={dcfile}'.format(ch=channels[i],dcfile=card) for i,card in enumerate(datacards)])+' > '+combinedCard + + txt2hdf5Cmd = 'text2hdf5.py {cf} '.format(cf=combinedCard) + + ## here making the TF meta file + if not options.freezePOIs: + # actually it seems this would work also for frozen POIs, to be checked + maskchan = [' --maskedChan {b}_{charge}_xsec_{maskchan}'.format(b=binname,charge=ch,maskchan=mc) for ch in charges for mc in maskedChannels] + txt2hdf5Cmd += ' {maskch} --X-allow-no-background'.format(maskch=' '.join(maskchan)) + + if not options.doSystematics: + txt2hdf5Cmd = txt2hdf5Cmd + " -S 0 " + if len(options.postfix): + txt2hdf5Cmd = txt2hdf5Cmd + " --postfix " + options.postfix + if options.clipSystVariations > 0.0: + txt2hdf5Cmd = txt2hdf5Cmd + " --clipSystVariations " + str(options.clipSystVariations) + if options.clipSystVariationsSignal > 0.0: + txt2hdf5Cmd = txt2hdf5Cmd + " --clipSystVariationsSignal " + str(options.clipSystVariationsSignal) + + ## run the commands: need cmsenv in the combinetf release + print + print ccCmd + print + if not options.justFit: + os.system(ccCmd) + print "Combined card in ",combinedCard + print + print txt2hdf5Cmd + print + if not options.skip_text2hdf5: + print "Running text2hdf5.py, it might take time ..." + os.system(txt2hdf5Cmd) + + metafilename = combinedCard.replace('.txt','.hdf5') + if len(options.postfix): + metafilename = metafilename.replace('.hdf5','_%s.hdf5' % options.postfix) + + bbboptions = " --binByBinStat " + if not options.noCorrelateXsecStat: bbboptions += "--correlateXsecStat " + combineCmd = 'combinetf.py -t -1 {bbb} {metafile} --saveHists --computeHistErrors --doh5Output '.format(metafile=metafilename, bbb="" if options.noBBB else bbboptions) + if options.freezePOIs: + combineCmd += " --POIMode none" + if options.doImpactsOnMW: + combineCmd += " --doImpacts " + else: + if options.doSystematics: + combineCmd += " --doImpacts " + + fitdir_data = "{od}/fit/data/".format(od=os.path.abspath(options.inputdir)) + fitdir_Asimov = "{od}/fit/hessian/".format(od=os.path.abspath(options.inputdir)) + if not os.path.exists(fitdir_data): + print "Creating folder", fitdir_data + os.system("mkdir -p " + fitdir_data) + if not os.path.exists(fitdir_Asimov): + print "Creating folder", fitdir_Asimov + os.system("mkdir -p " + fitdir_Asimov) + print "" + fitPostfix = "" if not len(options.postfix) else ("_"+options.postfix) + + print "Use the following command to run combine (add --seed to specify the seed, if needed). See other options in combinetf.py" + print + combineCmd_data = combineCmd.replace("-t -1 ","-t 0 ") + combineCmd_data = combineCmd_data + " --postfix Data{pf}_bbb{b} --outputDir {od} ".format(pf=fitPostfix, od=fitdir_data, b="0" if options.noBBB else "1_cxs0" if options.noCorrelateXsecStat else "1_cxs1") + combineCmd_Asimov = combineCmd + " --postfix Asimov{pf}_bbb{b} --outputDir {od} ".format(pf=fitPostfix, od=fitdir_Asimov, b="0" if options.noBBB else "1_cxs0" if options.noCorrelateXsecStat else "1_cxs1") + print combineCmd_data + if not options.skip_combinetf and not options.skipFitData: + os.system(combineCmd_data) + print "" + print combineCmd_Asimov + if not options.skip_combinetf and not options.skipFitAsimov: + os.system(combineCmd_Asimov) + + +def combineCharges(options): + prepareChargeFit(options, charges=['plus','minus']) def makeAllSystematicMultipliers(indir): @@ -388,7 +523,7 @@ def makeAllSystematicMultipliers(indir): if __name__ == "__main__": from optparse import OptionParser - parser = OptionParser(usage='%prog [self._options] cards/card*.txt') + parser = OptionParser(usage='%prog [self._options]') parser.add_option('-m','--merge-root', dest='mergeRoot', default=False, action='store_true', help='Merge the root files with the inputs also') parser.add_option('-i','--input', dest='inputdir', default='', type='string', help='input directory with all the cards inside') parser.add_option('-f','--flavor', dest='flavor', default='mu', type='string', help='lepton flavor (mu,el)') @@ -398,11 +533,36 @@ def makeAllSystematicMultipliers(indir): parser.add_option( '--comb' , dest='combineCharges' , default=False, action='store_true', help='Combine W+ and W-, if single cards are done') parser.add_option( '--postfix', dest='postfix', type="string", default="", help="Postfix for .hdf5 file created with text2hdf5.py when combining charges"); parser.add_option('--wmass', dest='wmass', action="store_true", default=False, help="Make cards for the wmass analysis. Default is wlike"); - + # options for card maker and fit + parser.add_option("-S", "--doSystematics", type=int, default=1, help="enable systematics when running text2hdf5.py (-S 0 to disable them)") + parser.add_option( "--exclude-nuisances", dest="excludeNuisances", default="", type="string", help="Pass comma-separated list of regular expressions to exclude some systematics") + parser.add_option( "--keep-nuisances", dest="keepNuisances", default="", type="string", help="Pass comma-separated list of regular expressions to keep some systematics, overriding --exclude-nuisances. Can be used to keep only 1 syst while excluding all the others") + parser.add_option("", "--clipSystVariations", type=float, default=-1., help="Clipping of syst variations, passed to text2hdf5.py") + parser.add_option("", "--clipSystVariationsSignal", type=float, default=-1., help="Clipping of signal syst variations, passed to text2hdf5.py") + parser.add_option('--fp','--freezePOIs' , dest='freezePOIs' , default=False, action='store_true', help='run tensorflow with --freezePOIs (for the pdf only fit)') + parser.add_option( '--no-bbb' , dest='noBBB', default=False, action='store_true', help='Do not use bin-by-bin uncertainties') + parser.add_option( '--no-correlate-xsec-stat' , dest='noCorrelateXsecStat', default=False, action='store_true', help='Do not use option --correlateXsecStat when using bin-by-bin uncertainties ') + parser.add_option( '--no-text2hdf5' , dest='skip_text2hdf5', default=False, action='store_true', help='skip running text2hdf5.py at the end, only prints command (useful if hdf5 file already exists, or for tests)') + parser.add_option( '--no-combinetf' , dest='skip_combinetf', default=False, action='store_true', help='skip running combinetf.py at the end, just print command (useful for tests)') + parser.add_option( '--just-fit', dest='justFit' , default=False, action='store_true', help='Go directly to fit part (can also skip text2hdf5 with --no-text2hdf5)') + parser.add_option( '--skip-fit-data', dest='skipFitData' , default=False, action='store_true', help='If True, fit only Asimov') + parser.add_option( '--skip-fit-asimov', dest='skipFitAsimov' , default=False, action='store_true', help='If True, fit only data') + parser.add_option( '--fit-single-charge', dest='fitSingleCharge', default=False, action='store_true', help='Prepare datacard for single-charge fit (groups with other charge are skipped') + + # --impacts-mW might not be needed or might not work, to be checked + parser.add_option( '--impacts-mW', dest='doImpactsOnMW', default=False, action='store_true', help='Set up cards to make impacts of nuisances on mW') (options, args) = parser.parse_args() charges = options.charge.split(',') + if options.combineCharges: + if options.fitSingleCharge: + print "Error: options --fit-single-charge and --comb are incompatible. Abort" + quit() + if len(charges) != 2: + print "Error: --comb requires two charges, use -C 'plus,minus' and try again" + quit() + if options.remakeMultipliers: print 'making all the systematic multipliers' makeAllSystematicMultipliers(options.inputdir) @@ -410,10 +570,19 @@ def makeAllSystematicMultipliers(indir): for charge in charges: - cm = CardMaker(options,charge,options.flavor) - if options.mergeRoot: - cm.mergeChunks() - cm.writeDatacard() - + if not options.justFit: + cm = CardMaker(options,charge,options.flavor) + if options.mergeRoot: + cm.mergeChunks() + cm.writeDatacard() + if options.fitSingleCharge: + prepareChargeFit(options, charges=[charge]) + print "-"*30 + print "Done fitting charge {ch}".format(ch=charge) + print "="*30 + if options.combineCharges and len(charges)==2: - combineCharges(options) + combineCharges(options) + print "-"*30 + print "Done fitting charge combination" + print "="*30 diff --git a/WMass/python/plotter/w-mass-13TeV/dataFakeRateLite.py b/WMass/python/plotter/w-mass-13TeV/dataFakeRateLite.py new file mode 100644 index 000000000000..cf6b8a34181d --- /dev/null +++ b/WMass/python/plotter/w-mass-13TeV/dataFakeRateLite.py @@ -0,0 +1,127 @@ +#!/usr/bin/env python +#from mcAnalysis import * +#from CMGTools.WMass.plotter.mcEfficiencies import * +from CMGTools.WMass.plotter.mcPlots import * +import itertools + +if "/fakeRate_cc.so" not in ROOT.gSystem.GetLibraries(): + compileMacro("src/CMGTools/WMass/python/plotter/fakeRate.cc") + +def makeDataSub(report,mca): + data_sub = report['data'].Clone(report['data'].GetName()+'_sub') + data_sub_syst = report['data'].Clone(report['data'].GetName()+'_sub_syst') + for p in mca.listBackgrounds(): + if p not in report: continue + b = report[p] + data_sub.Add(b, -1.0) + data_sub_syst.Add(b, -1.0) + syst = mca.getProcessOption(p,'NormSystematic',0.) + #print "subtracting background %s from data with systematic %r" % (p,syst) + if syst <= 0: continue + if "TH1" in b.ClassName(): + for bx in xrange(1,b.GetNbinsX()+1): + data_sub_syst.SetBinError(bx, hypot(data_sub_syst.GetBinError(bx), syst * b.GetBinContent(bx))) + elif "TH2" in b.ClassName(): + for (bx,by) in itertools.product(range(1,b.GetNbinsX()+1), range(1,b.GetNbinsY()+1)): + data_sub_syst.SetBinError(bx, by, hypot(data_sub_syst.GetBinError(bx, by), syst * b.GetBinContent(bx, by))) + elif "TH3" in b.ClassName(): + for (bx,by,bz) in itertools.product(range(1,b.GetNbinsX()+1), range(1,b.GetNbinsY()+1), range(1,b.GetNbinsZ()+1)): + data_sub_syst.SetBinError(bx, by, bz, hypot(data_sub_syst.GetBinError(bx, by, bz), syst * b.GetBinContent(bx, by, bz))) + report['data_sub'] = data_sub + report['data_sub_syst'] = data_sub_syst + +def makeEff(mca,cut,idplot,xvarplot,mainOptions=None): + import copy + is2D = (":" in xvarplot.expr.replace("::","--")) + options = copy.copy(idplot.opts) + options.update(xvarplot.opts) + mybins = copy.copy(xvarplot.bins) + if xvarplot.bins[0] == "[": + mybins += "*[-0.5,0.5,1.5]" + else: + mybins += ",2,-0.5,1.5" + print "making eff for idplot = ",idplot.name," ", idplot.expr, " vs ",xvarplot.expr + pspec = PlotSpec("%s_vs_%s" % (idplot.name, xvarplot.name), + "%s:%s" % (idplot.expr,xvarplot.expr), + mybins, + options) + report = mca.getPlots(pspec,cut,makeSummary=True) + if 'signal' in report and 'background' in report: + report['total'] = mergePlots(pspec.name+"_total", [ report[s] for s in ('signal','background') ] ) + if 'data' in report and 'background' in report: + makeDataSub(report, mca) + return report + + +if __name__ == "__main__": + from optparse import OptionParser + parser = OptionParser(usage="%prog [options] mc.txt cuts.txt ids.txt xvars.txt") + parser.add_option("--fitVar", dest="fitVar", default="", type="string", help="Variable to fit (used to be mT, now it is usually eta)") + addPlotMakerOptions(parser, addAlsoMCAnalysis=True) + (options, args) = parser.parse_args() + + mca = MCAnalysis(args[0],options) + procs = mca.listProcesses() + cut = CutsFile(args[1],options).allCuts() + ids = PlotFile(args[2],options).plots() + xvars = PlotFile(args[3],options).plots() + fitvarname = options.fitVar + + print "Processes = ",procs + + outname = options.out if options.out else (args[2].replace(".txt","")+".root") + if os.path.dirname(outname) != "": + dirname = os.path.dirname(outname) + options.printDir = dirname + if not os.path.exists(dirname): + os.system("mkdir -p "+dirname) + if os.path.exists("/afs/cern.ch"): os.system("cp /afs/cern.ch/user/m/mciprian/public/index.php "+dirname) + # copy mca and cut file to output folder + os.system("cp %s %s " % (args[0], dirname)) + os.system("cp %s %s " % (args[1], dirname)) + + + outfile = ROOT.TFile(outname,"RECREATE") + plotter = PlotMaker(outfile, options) + + vars2d = [] + print "xvars: %s" % " ".join(x.name for x in xvars) + for xspec in xvars: + if xspec.name == fitvarname: continue + for fspec in xvars: + if fspec.name != fitvarname: continue + if xspec.bins[0] == "[": + if fspec.bins[0] == "[": + fbins = fspec.bins + else: + (nbins,fmin,fmax) = map(float, fspec.bins.split(',')) + fbins = "[" + ",".join(map(str, [fmin+i*(fmax-fmin)/nbins for i in xrange(0,int(nbins+1))])) + "]" + bins2d = xspec.bins + "*" + fbins + elif fspec.bins[0] == "[": + (nbins,xmin,xmax) = map(float, xspec.bins.split(',')) + xbins = "[" + ",".join(map(str, [xmin+i*(xmax-xmin)/nbins for i in xrange(0,int(nbins+1))])) + "]" + bins2d = xbins + "*" + fspec.bins + else: + bins2d = xspec.bins + "," + fspec.bins + print "Doing %s_%s: %s" % (fspec.name, xspec.name, bins2d) + pspec = PlotSpec("%s_%s" % (fspec.name, xspec.name), "%s:%s" % (fspec.expr, xspec.expr), bins2d, xspec.opts) + pspec.xvar = xspec + pspec.fvar = fspec + vars2d.append(pspec) + + backup = options.globalRebin; + options.globalRebin = 1 + hists = [ (y,x2.xvar,x2.fvar,x2,makeEff(mca,cut,y,x2,mainOptions=options)) for y in ids for x2 in vars2d ] + print "N(hists) = %d" % len(hists) + options.globalRebin = backup + + for (yspec,xspec,fspec,x2d,report) in hists: + for k,v in report.iteritems(): + print "{n}: {i}".format(n=v.GetName(),i=v.Integral()) + outfile.WriteTObject(v) + outfile.ls() + outfile.Close() + print "Output saved to %s. exiting." % outname + exit() + + diff --git a/WMass/python/plotter/w-mass-13TeV/functionsWMass.cc b/WMass/python/plotter/w-mass-13TeV/functionsWMass.cc index 0563bb5778f0..8aa5ad57724a 100644 --- a/WMass/python/plotter/w-mass-13TeV/functionsWMass.cc +++ b/WMass/python/plotter/w-mass-13TeV/functionsWMass.cc @@ -7,6 +7,7 @@ #include "TH3.h" #include "TF1.h" #include "TH2Poly.h" +#include "TRandom.h" #include "TSpline.h" #include "TCanvas.h" #include "TGraphAsymmErrors.h" @@ -46,6 +47,30 @@ string getEnvironmentVariable(const string& env_var_name = "CMSSW_BASE") { } +float getValFromTH2(TH2*h = NULL, float x = 0.0, float y = 0.0) { + + if (!h) { + cout << "Error in getValFromTH2(): uninitialized histogram. Abort" << endl; + exit(EXIT_FAILURE); + } + int xbin = std::max(1, std::min(h->GetNbinsX(), h->GetXaxis()->FindFixBin(x))); + int ybin = std::max(1, std::min(h->GetNbinsY(), h->GetYaxis()->FindFixBin(y))); + return h->GetBinContent(xbin,ybin); + +} + +bool isOddEvent(ULong64_t evt) { + + return (evt%2) ? 1 : 0; + +} + +bool isEvenEvent(ULong64_t evt) { + + return (evt%2) ? 0 : 1; + +} + float returnChargeVal(float val1, int ch1, float val2, int ch2, ULong64_t evt){ float retVal = -999.; @@ -57,6 +82,7 @@ float returnChargeVal(float val1, int ch1, float val2, int ch2, ULong64_t evt){ } + float returnPlusVal(float val1, int ch1, float val2, int ch2){ // return value of the lepton with desired charge, without looking at event parity @@ -85,6 +111,7 @@ float returnChargeValAllEvt(int desiredCharge, float val1, int ch1, float val2, } +// FIXME: better not to use this function, using the average is a bias float mt_wlike_samesign(float pt1, float phi1, float pt2, float phi2, float met, float phimet) { // compute mt with both cases, and return average @@ -141,12 +168,39 @@ float mt_wlike_samesign_random(float pt1, float phi1, float pt2, float phi2, flo float mt_wlike(float pt1, float phi1, int ch1, float pt2, float phi2, int ch2, float met, float phimet, ULong64_t evt) { //if (ch1 == ch2) return mt_wlike_samesign(pt1,phi1,pt2,phi2,met,phimet); + float ptL = 0.0; + float phiL = 0.0; - float ptL = returnChargeVal(pt1,ch1,pt2,ch2,evt); - float phiL = returnChargeVal(phi1,ch1,phi2,ch2,evt); + float ptl = 0.0; + float phil = 0.0; + + // positive (negative) leptons on odd (even) events + if (isOddEvent(evt)) { + if (ch1 > 0) { + ptL = pt1; + phiL = phi1; + ptl = pt2; + phil = phi2; + } else { + ptL = pt2; + phiL = phi2; + ptl = pt1; + phil = phi1; + } + } else { + if (ch1 < 0) { + ptL = pt1; + phiL = phi1; + ptl = pt2; + phil = phi2; + } else { + ptL = pt2; + phiL = phi2; + ptl = pt1; + phil = phi1; + } + } - float ptl = returnChargeVal(pt1,ch2,pt2,ch1,evt); - float phil = returnChargeVal(phi1,ch2,phi2,ch1,evt); TVector2 pl = TVector2(); pl.SetMagPhi(ptl,phil); @@ -202,23 +256,6 @@ float helicityWeightSimple(float yw, float ptw, float costheta, int pol) } -float wpt_slope_weight(float wpt, float offset, float slope){ - if(wpt > 20.) return 1.; - float weight = offset + slope*wpt; - return weight; -} - - -float prefireJetsWeight(float eta){ - float feta = fabs(eta); - if (feta < 2.0) return 0.9986; - if (feta < 2.2) return 0.9880; - if (feta < 2.3) return 0.9875; - if (feta < 2.4) return 0.9871; - if (feta < 2.5) return 0.9865; - return 1.; -} - TFile* _file_prefireMapJets = NULL; TH2F* prefireMapJets = NULL; @@ -236,130 +273,6 @@ float mydeltaR(float eta1, float phi1, float eta2, float phi2) { return std::sqrt(deta*deta + dphi*dphi); } -double prefireJetsScaleFactor(int njet_tmp, - float jet1_pt = 0.0, float jet1_eta = 0.0, - float jet2_pt = 0.0, float jet2_eta = 0.0, - float jet3_pt = 0.0, float jet3_eta = 0.0) { - - - double ret1 = 1.0; - // return 1.0; for tests - if (njet_tmp == 0) { - //std::cout << "njet = " << njet_tmp << std::endl; - return ret1; - } - - std::vector jet_eta; - std::vector jet_pt; - jet_eta.clear(); - jet_pt.clear(); - float maxEta_prefireMap = 3.5; // map arrives up to 3.5, but prefire in bin 3.0-3.5 is lower than in 2.5-3.0 - - // check how many jets can prefire, this part is ugly because this function could not accept a pointer to jets - // because it need to be passed to TTree::Draw and it doesn't accept pointers - if (njet_tmp == 1) { - if (fabs(jet1_eta) < maxEta_prefireMap && fabs(jet1_eta) > 2.0 && jet1_pt > 30.0) { - jet_eta.push_back(jet1_eta); - jet_pt.push_back(jet1_pt); - } - } else if (njet_tmp == 2) { - if (fabs(jet1_eta) < maxEta_prefireMap && fabs(jet1_eta) > 2.0 && jet1_pt > 30.0) { - jet_eta.push_back(jet1_eta); - jet_pt.push_back(jet1_pt); - } - if (fabs(jet2_eta) < maxEta_prefireMap && fabs(jet2_eta) > 2.0 && jet2_pt > 30.0) { - jet_eta.push_back(jet2_eta); - jet_pt.push_back(jet2_pt); - } - } else if (njet_tmp >= 3) { - if (fabs(jet1_eta) < maxEta_prefireMap && fabs(jet1_eta) > 2.0 && jet1_pt > 30.0) { - jet_eta.push_back(jet1_eta); - jet_pt.push_back(jet1_pt); - } - if (fabs(jet2_eta) < maxEta_prefireMap && fabs(jet2_eta) > 2.0 && jet2_pt > 30.0) { - jet_eta.push_back(jet2_eta); - jet_pt.push_back(jet2_pt); - } - if (fabs(jet3_eta) < maxEta_prefireMap && fabs(jet3_eta) > 2.0 && jet3_pt > 30.0) { - jet_eta.push_back(jet3_eta); - jet_pt.push_back(jet3_pt); - } - } - - unsigned int njet = jet_eta.size(); - // std::cout << "array size == " << njet << std::endl; - if (njet == 0) return ret1; - - // for (UInt_t ij = 0; ij < njet; ij++) { - // std::cout << ij << ") jet pt/eta = " << jet_pt[ij] << " / " << jet_eta[ij] << std::endl; - // } - - // must pass collection of cleaned jet - // abs(eta) on X axis, pt on Y axis - if (not prefireMapJets) { - _file_prefireMapJets = new TFile("/afs/cern.ch/work/m/mdunser/public/cmssw/w-helicity-13TeV/CMSSW_8_0_25/src/CMGTools/WMass/data/scaleFactors/muons/Map_Jet_L1FinOReff_bxm1_looseJet_SingleMuon_Run2016B-H.root"); - prefireMapJets = (TH2F*) ((TEfficiency*)_file_prefireMapJets->Get("prefireEfficiencyMap"))->CreateHistogram(); - } - - // this function allows for up to 2 jets to prefire - // probability that a third jet prefires is really negligible (even with 2 of them but ok) - int etabin = 0; - int ptbin = 0; - int maxXbins = prefireMapJets->GetNbinsX(); - int maxYbins = prefireMapJets->GetNbinsY(); - float effPrefireJet1 = 0.0; - float effPrefireJet2 = 0.0; - - if (njet > 0) { - etabin = std::max(1, std::min( maxXbins, prefireMapJets->GetXaxis()->FindFixBin(fabs(jet_eta[0])) ) ); - ptbin = std::max(1, std::min( maxYbins, prefireMapJets->GetYaxis()->FindFixBin(jet_pt[0]) ) ); - effPrefireJet1 = prefireMapJets->GetBinContent(etabin,ptbin); - if (njet > 1) { - etabin = std::max(1, std::min( maxXbins, prefireMapJets->GetXaxis()->FindFixBin(fabs(jet_eta[1])) ) ); - ptbin = std::max(1, std::min( maxYbins, prefireMapJets->GetYaxis()->FindFixBin(jet_pt[1]) ) ); - effPrefireJet2 = prefireMapJets->GetBinContent(etabin,ptbin); - } - } else { - return ret1; - } - - double sf = 1.0; - if (njet == 1) { - sf = (1. - effPrefireJet1); - // if (sf < 0.9) { - // std::cout << "njet = " << njet << "\t SF(1) = " << sf - // << " \t jet pt/eta = " << jet_pt[0] << " / " << jet_eta[0] << std::endl; - // } - return ret1; - return sf; - } else if (njet >= 2) { - sf = (1. - (effPrefireJet1 + effPrefireJet2 - effPrefireJet1 * effPrefireJet2)); - // if (sf < 0.9) { - // std::cout << "njet = " << njet << "\t SF(2) = " << sf - // << " \t jet1 pt/eta = " << jet_pt[0] << " / " << jet_eta[0] - // << " \t jet2 pt/eta = " << jet_pt[1] << " / " << jet_eta[1] << std::endl; - // } - return ret1; - return sf; - } else { - // std::cout << "njet = " << njet << std::endl; - return ret1; // should never arrive here but let's be safe - } -} - - -float prefireJetsWeight_2l(float eta1, float eta2) { - - // fixing older implementation with 1-xx - // prefireJetsWeight returns the SF to be applied to MC, not the prefiring probability (which is basically 1-SF) - // the probability that at least one lepton induces prefiring is pTot = p1 + p2 - p1*p2 - // so the SF to be used becomes 1 - pTot - float pf1 = 1. - prefireJetsWeight(eta1); - float pf2 = 1. - prefireJetsWeight(eta2); - return 1. - (pf1 + pf2 - pf1*pf2); - -} - //------------------- @@ -368,6 +281,7 @@ TH2D * ratio_FSRoverNoFSR_etaPt_mu = NULL; TFile *_file_ratio_FSRoverNoFSR_etaPt_el = NULL; TH2D * ratio_FSRoverNoFSR_etaPt_el = NULL; +// old function, should not be needed this time float FSRscaleFactorEtaPt(int pdgId, float dresspt, float dresseta) { // these histograms are the gen-level xsec before any cut (except the gen_decayId) @@ -601,365 +515,9 @@ float postfitQCDWeight(float pt2l, int pol, int charge, int flav=0) { return hist_scales->GetBinContent(ptbin); } -TFile *_file_recoToMedium_leptonSF_el = NULL; -TH2F *_histo_recoToMedium_leptonSF_el = NULL; -TFile *_file_recoToLoose_leptonSF_el = NULL; -TH2F *_histo_recoToLoose_leptonSF_el = NULL; -TFile *_file_elereco_leptonSF_gsf = NULL; -TH2F *_histo_elereco_leptonSF_gsf = NULL; - -float _get_electronSF_recoToCustomTight(int pdgid, float pt, float eta, float var) { - - if (_cmssw_base_ == "") { - cout << "Setting _cmssw_base_ to environment variable CMSSW_BASE" << endl; - _cmssw_base_ = getEnvironmentVariable("CMSSW_BASE"); - } - - if (!_histo_elereco_leptonSF_gsf) { - _file_elereco_leptonSF_gsf = new TFile(Form("%s/src/CMGTools/WMass/python/postprocessing/data/leptonSF/EGM2D_eleGSF.root",_cmssw_base_.c_str()),"read"); - _histo_elereco_leptonSF_gsf = (TH2F*)(_file_elereco_leptonSF_gsf->Get("EGamma_SF2D")); - _histo_elereco_leptonSF_gsf->Smooth(1,"k3a"); - } - - if (!_histo_recoToMedium_leptonSF_el) { - _file_recoToMedium_leptonSF_el = new TFile(Form("%s/src/CMGTools/WMass/python/postprocessing/data/leptonSF/EGM2D_eleCutBasedMediumWP.root",_cmssw_base_.c_str()),"read"); - _histo_recoToMedium_leptonSF_el = (TH2F*)(_file_recoToMedium_leptonSF_el->Get("EGamma_SF2D")); - _histo_recoToMedium_leptonSF_el->Smooth(1,"k3a"); - } - - if (!_histo_recoToLoose_leptonSF_el) { - _file_recoToLoose_leptonSF_el = new TFile(Form("%s/src/CMGTools/WMass/python/postprocessing/data/leptonSF/EGM2D_eleCutBasedLooseWP.root",_cmssw_base_.c_str()),"read"); - _histo_recoToLoose_leptonSF_el = (TH2F*)(_file_recoToLoose_leptonSF_el->Get("EGamma_SF2D")); - _histo_recoToLoose_leptonSF_el->Smooth(1,"k3a"); - } - - if(abs(pdgid)==11) { - TH2F *histMedium = _histo_recoToMedium_leptonSF_el; - TH2F *histLoose = _histo_recoToLoose_leptonSF_el; - int etabin = std::max(1, std::min(histMedium->GetNbinsX(), histMedium->GetXaxis()->FindFixBin(eta))); - int ptbin = std::max(1, std::min(histMedium->GetNbinsY(), histMedium->GetYaxis()->FindFixBin(pt))); - float out = 0; - if(fabs(eta)<1.479) out = histLoose->GetBinContent(etabin,ptbin)+var*histLoose->GetBinError(etabin,ptbin); - else out = histMedium->GetBinContent(etabin,ptbin)+var*histMedium->GetBinError(etabin,ptbin); - - TH2F *hist = _histo_elereco_leptonSF_gsf; - etabin = std::max(1, std::min(hist->GetNbinsX(), hist->GetXaxis()->FindFixBin(eta))); - ptbin = std::max(1, std::min(hist->GetNbinsY(), hist->GetYaxis()->FindFixBin(pt))); - out *= (hist->GetBinContent(etabin,ptbin)+var*(hist->GetBinError(etabin,ptbin) + 0.01*((pt<20) || (pt>80)))); - - return out; - } - - return 0; - -} - -TFile *_file_trigger_wmass_leptonEff_el = NULL; -TH2F *_histo_trigger_wmass_leptonEff_DATA_el = NULL; -TH2F *_histo_trigger_wmass_leptonEff_MC_el = NULL; - -float _get_electronEff_HLT(float pt, float eta, bool isData) { - if (!_histo_trigger_wmass_leptonEff_DATA_el || !_histo_trigger_wmass_leptonEff_MC_el) { - _file_trigger_wmass_leptonEff_el = new TFile(Form("%s/src/CMGTools/WMass/python/postprocessing/data/leptonSF/new2016_madeSummer2018/electrons_trigger_pt30to55.root",_cmssw_base_.c_str()),"read"); - _histo_trigger_wmass_leptonEff_DATA_el = (TH2F*)(_file_trigger_wmass_leptonEff_el->Get("EGamma_EffData2D")); - _histo_trigger_wmass_leptonEff_MC_el = (TH2F*)(_file_trigger_wmass_leptonEff_el->Get("EGamma_EffMC2D")) ; - //_histo_trigger_wmass_leptonEff_DATA_el->Smooth(1,"k3a"); - //_histo_trigger_wmass_leptonEff_MC_el->Smooth(1,"k3a"); - } - TH2F *hist = isData ? _histo_trigger_wmass_leptonEff_DATA_el : _histo_trigger_wmass_leptonEff_MC_el; - int etabin = std::max(1, std::min(hist->GetNbinsX(), hist->GetXaxis()->FindFixBin(eta))); - int ptbin = std::max(1, std::min(hist->GetNbinsY(), hist->GetYaxis()->FindFixBin(pt))); - float out = hist->GetBinContent(etabin,ptbin); - return out; -} - - -TFile *_file_trigger_wmass_leptonSF_el = NULL; -TH2F *_histo_trigger_wmass_leptonSF_el = NULL; -TFile *_file_trigger_ee0p1_wmass_leptonSF_el = NULL; -TH2F *_histo_trigger_ee0p1_wmass_leptonSF_el = NULL; -TFile *_file_reco_wmass_leptonSF_el = NULL; -TH2F *_histo_reco_wmass_leptonSF_el = NULL; -TFile *_file_fullid_wmass_leptonSF_el = NULL; -TH2F *_histo_fullid_wmass_leptonSF_el = NULL; -TFile *_file_fullid_ee0p1_wmass_leptonSF_el = NULL; -TH2F *_histo_fullid_ee0p1_wmass_leptonSF_el = NULL; -TFile *_file_cluster_wmass_leptonSF_el = NULL; -TH2F *_histo_cluster_wmass_leptonSF_el = NULL; - -float _get_electronSF_anyStep(float pt, float eta, int step, bool geterr=false) { - if (_cmssw_base_ == "") { - cout << "Setting _cmssw_base_ to environment variable CMSSW_BASE" << endl; - _cmssw_base_ = getEnvironmentVariable("CMSSW_BASE"); - } - - if (!_histo_trigger_wmass_leptonSF_el) { - _file_trigger_wmass_leptonSF_el = new TFile(Form("%s/src/CMGTools/WMass/python/postprocessing/data/leptonSF/new2016_madeSummer2018/etaptSmooth_electrons_trigger_30_55_onlyErf.root",_cmssw_base_.c_str()),"read"); - _histo_trigger_wmass_leptonSF_el = (TH2F*)(_file_trigger_wmass_leptonSF_el->Get("scaleFactor")); - } - if (!_histo_trigger_ee0p1_wmass_leptonSF_el) { - _file_trigger_ee0p1_wmass_leptonSF_el = new TFile(Form("%s/src/CMGTools/WMass/python/postprocessing/data/leptonSF/new2016_madeSummer2018/electrons_trigger_endcap0p1.root",_cmssw_base_.c_str()),"read"); - _histo_trigger_ee0p1_wmass_leptonSF_el = (TH2F*)(_file_trigger_ee0p1_wmass_leptonSF_el->Get("scaleFactor")); - } - if (!_histo_reco_wmass_leptonSF_el) { - _file_reco_wmass_leptonSF_el = new TFile(Form("%s/src/CMGTools/WMass/python/postprocessing/data/leptonSF/new2016_madeSummer2018/electrons_reco_pt30to45.root",_cmssw_base_.c_str()),"read"); - _histo_reco_wmass_leptonSF_el = (TH2F*)(_file_reco_wmass_leptonSF_el->Get("EGamma_SF2D")); - } - if (!_histo_fullid_wmass_leptonSF_el) { - _file_fullid_wmass_leptonSF_el = new TFile(Form("%s/src/CMGTools/WMass/python/postprocessing/data/leptonSF/new2016_madeSummer2018/etaptSmooth_electrons_fullID_V2_pt25to55.root",_cmssw_base_.c_str()),"read"); - _histo_fullid_wmass_leptonSF_el = (TH2F*)(_file_fullid_wmass_leptonSF_el->Get("Graph2D_from_scaleFactor_smoothedByGraph")); - } - if (!_histo_fullid_ee0p1_wmass_leptonSF_el) { - _file_fullid_ee0p1_wmass_leptonSF_el = new TFile(Form("%s/src/CMGTools/WMass/python/postprocessing/data/leptonSF/new2016_madeSummer2018/electrons_fullID_V2_endcap0p1.root",_cmssw_base_.c_str()),"read"); - _histo_fullid_ee0p1_wmass_leptonSF_el = (TH2F*)(_file_fullid_ee0p1_wmass_leptonSF_el->Get("EGamma_SF2D")); - } - if (!_histo_cluster_wmass_leptonSF_el) { - _file_cluster_wmass_leptonSF_el = new TFile(Form("%s/src/CMGTools/WMass/python/postprocessing/data/leptonSF/new2016_madeSummer2018/l1EG_eff.root",_cmssw_base_.c_str()),"read"); - _histo_cluster_wmass_leptonSF_el = (TH2F*)(_file_cluster_wmass_leptonSF_el->Get("l1EG_eff")); - } - - TH2F *hist = 0; - if (step==1) { - hist = fabs(eta)<1.566 ? _histo_trigger_wmass_leptonSF_el : _histo_trigger_ee0p1_wmass_leptonSF_el; - } - else if (step==2) hist = _histo_reco_wmass_leptonSF_el; - else if (step==3) { - hist = fabs(eta)<1.566 ? _histo_fullid_wmass_leptonSF_el : _histo_fullid_ee0p1_wmass_leptonSF_el; - } - else if (step==4) hist = _histo_cluster_wmass_leptonSF_el; - else { - std::cout << "Step " << step << " of the efficiency corrections not foreseen. Returning 0" << std::endl; - return 0.; - } - - int etabin = std::max(1, std::min(hist->GetNbinsX(), hist->GetXaxis()->FindFixBin(eta))); - int ptbin = std::max(1, std::min(hist->GetNbinsY(), hist->GetYaxis()->FindFixBin(pt))); - float out = geterr ? hist->GetBinError(etabin,ptbin) : hist->GetBinContent(etabin,ptbin); - return out; -} - -float eleSF_HLT(float pt, float eta) { - return _get_electronSF_anyStep(pt,eta,1); -} - -float eleSF_HLT_2lfriends(float matchpt1, float sf1, float matchpt2, float sf2) { - if (matchpt1>-1 && matchpt2>-1) { - return 0.5*(sf1+sf2); - } else if (matchpt1>-1) - return sf1; - else - return sf2; -} - -float eleSF_HLT_2l(float matchpt1, float pt1, float eta1, float matchpt2, float pt2, float eta2) { - if (matchpt1>-1 && matchpt2>-1) { - float sf1 = _get_electronSF_anyStep(pt1,eta1,1); - float sf2 = _get_electronSF_anyStep(pt2,eta2,1); - return 0.5*(sf1+sf2); - } else if (matchpt1>-1) - return _get_electronSF_anyStep(pt1,eta1,1); - else - return _get_electronSF_anyStep(pt2,eta2,1); -} - -float eleSF_HLT_2lAvg(float matchpt1, float pt1, float eta1, float matchpt2, float pt2, float eta2) { - if (matchpt1>-1 && matchpt2>-1) { - double eff1_DATA = _get_electronEff_HLT(pt1,eta1,true); - double eff2_DATA = _get_electronEff_HLT(pt2,eta2,true); - float sf1 = _get_electronSF_anyStep(pt1,eta1,1); - float sf2 = _get_electronSF_anyStep(pt2,eta2,1); - return (eff1_DATA*sf1 + eff2_DATA*sf2) / (eff1_DATA+eff2_DATA); - } else if (matchpt1>-1) { - return _get_electronSF_anyStep(pt1,eta1,1); - } - else { - return _get_electronSF_anyStep(pt2,eta2,1); - } -} - -float eleEff_HLT_2l_DATA(float pt1, float eta1, float pt2, float eta2) { - float eff1 = _get_electronEff_HLT(pt1,eta1,true); - float eff2 = _get_electronEff_HLT(pt2,eta2,true); - return eff1 + eff2 - eff1*eff2; -} - -float eleSF_HLT_2lComb(float matchpt1, float pt1, float eta1, float matchpt2, float pt2, float eta2) { - double eff1_DATA = _get_electronEff_HLT(pt1,eta1,true); - double eff2_DATA = _get_electronEff_HLT(pt2,eta2,true); - double eff1_MC = _get_electronEff_HLT(pt1,eta1,false); - double eff2_MC = _get_electronEff_HLT(pt2,eta2,false); - double eff_DATA,eff_MC; - if (matchpt1>-1 && matchpt2>-1) { - eff_DATA = std::min(1., eff1_DATA + eff2_DATA - eff1_DATA*eff2_DATA); - eff_MC = std::min(1., eff1_MC + eff2_MC - eff1_MC*eff2_MC); - } else if (matchpt1>-1) { - eff_DATA = eff1_DATA * (1-eff2_DATA); - eff_MC = eff1_MC * (1-eff2_MC); - // return _get_electronSF_anyStep(pt1,eta1,1); - } else { - eff_DATA = eff2_DATA * (1-eff1_DATA); - eff_MC = eff2_MC * (1-eff1_MC); - // return _get_electronSF_anyStep(pt2,eta2,1); - } - if (eff_DATA>1 || eff_MC>1) - std::cout << pt1 << " "<< eta1 << " 2 = " << pt2 << " " << eta2 << " eff = " << eff_DATA << " " << eff_MC << std::endl; - return eff_DATA / eff_MC; -} - - -float eleSF_GSFReco(float pt, float eta) { - return _get_electronSF_anyStep(pt,eta,2); -} - -float eleSF_FullID(float pt, float eta) { - return _get_electronSF_anyStep(std::min(pt,float(45.)),eta,3); -} - -float eleSF_Clustering(float pt, float eta) { - return _get_electronSF_anyStep(pt,eta,4); -} - -float eleSF_L1Eff(float pt, float eta, bool geterr=false) { - float sf; - if (fabs(eta)<1.479 || pt<35) { - //if (fabs(eta)<1.479) { - sf = geterr ? 0.0 : 1.0; - } - else sf = _get_electronSF_anyStep(pt,eta,4,geterr); - return sf; -} - -float eleSF_L1Eff_2l(float pt1, float eta1, float pt2, float eta2) { - float eta,pt; - if (fabs(eta1) > fabs(eta2)) { - eta = eta1; - pt = pt1; - } else { - eta = eta2; - pt = pt2; - } - if (fabs(eta)<1.479 || pt<35) return 1.; - return _get_electronSF_anyStep(pt,eta,4); -} - - -float _lepSF(int pdgId, float pt, float eta, float sf1, float sf2, float sf3, int nSigma=0) { - float abseta = fabs(eta); - float syst=0; - float sf4=1.0; float sf4_err=0.0; - if (abs(pdgId)==11) { - sf4 = eleSF_L1Eff(pt,eta); - sf4_err = eleSF_L1Eff(pt,eta,true); - if (abseta<1) syst = 0.006; - else if (abseta<1.479) syst = 0.008; - else if (abseta<2) syst = 0.013; - else syst = 0.016; - if (abseta>1.479) syst = hypot(syst,sf4_err); - } else if (abs(pdgId)==13) { - if (abseta<1) syst = 0.002; - else if (abseta<1.5) syst = 0.004; - else syst = 0.014; - } - double ret = sf1*sf2*sf3*sf4 + nSigma*syst; - if (ret <= 0.0) { - // cout << "Error: returning bad SF: " << ret << " Please check! Returning 1" << endl; - // cout << ">>> pdgId, pt, eta, sf1, sf2, sf3, nsigma --> " << pdgId << ", " << pt << ", " << eta << ", " << sf1 << ", " << sf2 << ", " << sf3 << ", " << nSigma << endl; - return 1; - } else { - return ret; - } - -} - -float lepSF(int pdgId, float pt, float eta, float sf1, float sf2, float sf3) { - return _lepSF(pdgId,pt,eta,sf1,sf2,sf3,0); -} -float lepSFRelUp(int pdgId, float pt, float eta, float sf1, float sf2, float sf3) { - return _lepSF(pdgId,pt,eta,sf1,sf2,sf3, 1)/_lepSF(pdgId,pt,eta,sf1,sf2,sf3,0); -} -float lepSFRelDn(int pdgId, float pt, float eta, float sf1, float sf2, float sf3) { - return _lepSF(pdgId,pt,eta,sf1,sf2,sf3, -1)/_lepSF(pdgId,pt,eta,sf1,sf2,sf3,0); -} - -#include "TRandom.h" -TRandom3 *rng = NULL; -EnergyScaleCorrection_class *calibrator = NULL; - -float ptCorr(float pt, float eta, float phi, float r9, int run, int isData, ULong64_t eventNumber) { - - if(!calibrator) calibrator = new EnergyScaleCorrection_class("CMGTools/WMass/python/postprocessing/data/leptonScale/el/Legacy2016_07Aug2017_FineEtaR9_ele",0); - - if(!isData) { - if(!rng) rng = new TRandom3(); - // use eventNumber as seed, otherwise each time the function is called for the same event, the smearer produce a different pt values - // the better solution would be to have the corrected pt in the friend trees - rng->SetSeed(eventNumber); // make it really random across different jobs - } - - if (isData) return pt * calibrator->ScaleCorrection(run,fabs(eta)<1.479,r9,fabs(eta),pt); - else { - float smear = calibrator->getSmearingSigma(run,fabs(eta)<1.479,r9,fabs(eta),pt,0,0); - return pt * ( 1.0 + smear * rng->Gaus()); - } -} - -TFile *_file_residualcorr_scale = NULL; -TH2D *_histo_residualcorr_scale = NULL; - -float residualScale(float pt, float eta, int isData, const char *fileCorr="../postprocessing/data/leptonScale/el/plot_dm_diff.root") { - if(!isData) return 1.; - - if(!_histo_residualcorr_scale) { - _file_residualcorr_scale = new TFile(fileCorr); - _histo_residualcorr_scale = (TH2D*)(_file_residualcorr_scale->Get("histSmooth")); - } - - TH2D *hist = _histo_residualcorr_scale; - int etabin = std::max(1, std::min(hist->GetNbinsX(), hist->GetXaxis()->FindFixBin(fabs(eta)))); - int ptbin = std::max(1, std::min(hist->GetNbinsY(), hist->GetYaxis()->FindFixBin(pt))); - - const float MZ0 = 91.1876; - float scale = 1. - hist->GetBinContent(etabin,ptbin)/MZ0/sqrt(2.); - if (scale < 0) { - cout << "WARNING in residualScale() function: scale < 0 --> returning 0." << endl; - return 0; - } else { - return scale; - } - -} - -float ptElFull(float pt, float eta, int nSigma=0) { - - if (nSigma == 0) return pt; - - // THE FOLLOWING USES STD EGAMMA SYSTEMATICS (W/O RESIDUAL CORRECTIONS, INTEGRATED IN ETA/PT) - /* - float relSyst=0.; - if(fabs(eta)<1.0) relSyst = 0.0015; - else if(fabs(eta)<1.479) relSyst = 0.005; - else relSyst = 0.01; - return (1.+nSigma*relSyst) * pt; - */ - // the following uses private residual corrections of AN-17-340 - if (_cmssw_base_ == "") { - cout << "Setting _cmssw_base_ to environment variable CMSSW_BASE" << endl; - _cmssw_base_ = getEnvironmentVariable("CMSSW_BASE"); - } - float syst = 1-residualScale(pt,eta,1,Form("%s/src/CMGTools/WMass/python/postprocessing/data/leptonScale/el/plot_dm_diff_closure_smoothWithSpline.root",_cmssw_base_.c_str())); - return (1. + nSigma*syst) * pt; - -} - -float ptElFullUp(float pt, float eta) { - return ptElFull(pt,eta,1); -} - -float ptElFullDn(float pt, float eta) { - return ptElFull(pt,eta,-1); -} +//// ALL THE FOLLOWING PART UNTIL "//// XXXX" IS OBSOLETE, CAN BE REMOVED AT SOME POINT // ================== // full muon pT with scale variations @@ -1046,67 +604,13 @@ float ptMuScaleUncorr1Dn(float pt, float eta) { return ptScaleUncorr(pt, eta, 13, 1, false); } -//------------------- -// electrons -float ptEleScaleUncorr0Up(float pt, float eta) { - return ptScaleUncorr(pt, eta, 11, 0, true); -} - -float ptEleScaleUncorr0Dn(float pt, float eta) { - return ptScaleUncorr(pt, eta, 11, 0, false); -} - -float ptEleScaleUncorr1Up(float pt, float eta) { - return ptScaleUncorr(pt, eta, 11, 1, true); -} - -float ptEleScaleUncorr1Dn(float pt, float eta) { - return ptScaleUncorr(pt, eta, 11, 1, false); -} - -float ptEleScaleUncorr2Up(float pt, float eta) { - return ptScaleUncorr(pt, eta, 11, 2, true); -} - -float ptEleScaleUncorr2Dn(float pt, float eta) { - return ptScaleUncorr(pt, eta, 11, 2, false); -} - -float ptEleScaleUncorr3Up(float pt, float eta) { - return ptScaleUncorr(pt, eta, 11, 3, true); -} - -float ptEleScaleUncorr3Dn(float pt, float eta) { - return ptScaleUncorr(pt, eta, 11, 3, false); -} +//// XXXX (PART ABOVE IS OBSOLETE) //=============================================== -float ptMuFull(float pt, float eta, int nSigma=0) { - - if (nSigma == 0) return pt; - - // THE FOLLOWING USES THE DERIVED MUON NON-CLOSURE - if (_cmssw_base_ == "") { - cout << "Setting _cmssw_base_ to environment variable CMSSW_BASE" << endl; - _cmssw_base_ = getEnvironmentVariable("CMSSW_BASE"); - } - float syst = 1-residualScaleMu(pt,eta,1,Form("%s/src/CMGTools/WMass/data/muonscale/scale_correction_nonclosure_mu.root",_cmssw_base_.c_str())); - //float syst = 0.004; // test - return (1. + nSigma*syst) * pt; - -} - -float ptMuFullUp(float pt, float eta) { - return ptMuFull(pt,eta,1); -} - -float ptMuFullDn(float pt, float eta) { - return ptMuFull(pt,eta,-1); -} - //================================================== +TRandom3 *rng = NULL; float getSmearedVar(float var, float smear, ULong64_t eventNumber, int isData, bool smearOnlyMC=false) { @@ -1119,6 +623,7 @@ float getSmearedVar(float var, float smear, ULong64_t eventNumber, int isData, b } +// old function, can probably be removed float triggerSF_2l(float l11pass, float l12pass, float l21pass, float l22pass, float l1sf, float l2sf, int randomize=0){ float weight = -999.; @@ -1275,9 +780,33 @@ TH2F *_histo_selection_leptonSF_fast_mu_minus = NULL; float _get_muonSF_fast_wlike(float pt1, float eta1, int charge1, float pt2, float eta2, int charge2, ULong64_t event) { // to be improved, still experimental - float pt = returnChargeVal(pt1,charge1,pt2,charge2,event); - float eta = returnChargeVal(eta1,charge1,eta2,charge2,event); - int charge = returnChargeVal(charge1,charge1,charge2,charge2,event); + float pt = 0.0; + float eta = 0.0; + int charge = 0.0; + + // positive (negative) leptons on odd (even) events + if (isOddEvent(event)) { + if (charge1 > 0) { + pt = pt1; + eta = eta1; + charge = charge1; + } else { + pt = pt2; + eta = eta2; + charge = charge2; + } + } else { + if (charge1 < 0) { + pt = pt1; + eta = eta1; + charge = charge1; + } else { + pt = pt2; + eta = eta2; + charge = charge2; + } + } + if (_cmssw_base_ == "") { cout << "Setting _cmssw_base_ to environment variable CMSSW_BASE" << endl; @@ -1340,6 +869,105 @@ float _get_muonSF_fast_wlike(float pt1, float eta1, int charge1, float pt2, floa } + +TFile *_file_allSF = NULL; +// 3 elements, depending on what dataset period one is using for the scale factors +TH2F *_histo_trigger_minus[3] = {NULL, NULL, NULL}; +TH2F *_histo_trigger_plus[3] = {NULL, NULL, NULL}; +TH2F *_histo_iso[3] = {NULL, NULL, NULL}; +TH2F *_histo_isonotrig[3] = {NULL, NULL, NULL}; +TH2F *_histo_idip[3] = {NULL, NULL, NULL}; +TH2F *_histo_tracking[3] = {NULL, NULL, NULL}; + +// I think the function cannot have more than 8 arguments, let's see +float _get_AllMuonSF_fast_wlike(float pt1, float eta1, int charge1, int trigMatch1, float pt2, float eta2, int charge2, int trigMatch2, ULong64_t event, int era = 0) { + + // era = 0 to pick SF for all year, 1 for BtoF and 2 for GtoH + string dataEraForSF = "BtoH"; + if (era == 1) + dataEraForSF = "BtoF"; + else if (era == 2 ) + dataEraForSF = "GtoH"; + + // to be improved, still experimental + float pt = 0.0; + float eta = 0.0; + int charge = 0.0; + // positive (negative) leptons on odd (even) events + if (isOddEvent(event)) { + if (charge1 > 0) { + pt = pt1; + eta = eta1; + charge = charge1; + } else { + pt = pt2; + eta = eta2; + charge = charge2; + } + } else { + if (charge1 < 0) { + pt = pt1; + eta = eta1; + charge = charge1; + } else { + pt = pt2; + eta = eta2; + charge = charge2; + } + } + + + if (_cmssw_base_ == "") { + cout << "Setting _cmssw_base_ to environment variable CMSSW_BASE" << endl; + _cmssw_base_ = getEnvironmentVariable("CMSSW_BASE"); + } + + // open the single file we have + if (!_file_allSF) { + _file_allSF = new TFile(Form("%s/src/CMGTools/WMass/python/plotter/testMuonSF/allSFs.root",_cmssw_base_.c_str()),"read"); + } + + // trigger + if (!_histo_trigger_plus[era]) { + _histo_trigger_plus[era] = (TH2F*)(_file_allSF->Get(Form("SF2D_trigger_%s_plus",dataEraForSF.c_str()))); + } + if (!_histo_trigger_minus[era]) { + _histo_trigger_minus[era] = (TH2F*)(_file_allSF->Get(Form("SF2D_trigger_%s_minus",dataEraForSF.c_str()))); + } + // ID + ip (interaction point, i.e. dz and dxy) + if (!_histo_idip[era]) { + _histo_idip[era] = (TH2F*)(_file_allSF->Get(Form("SF2D_idip_%s_both",dataEraForSF.c_str()))); + } + if (!_histo_tracking[era]) { + _histo_tracking[era] = (TH2F*)(_file_allSF->Get(Form("SF2D_tracking_%s_both",dataEraForSF.c_str()))); + } + if (!_histo_iso[era]) { + _histo_iso[era] = (TH2F*)(_file_allSF->Get(Form("SF2D_iso_%s_both",dataEraForSF.c_str()))); + } + if (!_histo_isonotrig[era]) { + _histo_isonotrig[era] = (TH2F*)(_file_allSF->Get(Form("SF2D_isonotrig_%s_both",dataEraForSF.c_str()))); + } + + + TH2F *histTrigger = ( charge > 0 ? _histo_trigger_plus[era] : _histo_trigger_minus[era] ); + float sf = getValFromTH2(histTrigger,eta,pt); + sf *= getValFromTH2(_histo_idip[era],eta1,pt1) * getValFromTH2(_histo_idip[era],eta2,pt2); + sf *= getValFromTH2(_histo_tracking[era],eta1,pt1) * getValFromTH2(_histo_tracking[era],eta2,pt2); + // sf *= getValFromTH2(_histo_iso[era],eta1,pt1) * getValFromTH2(_histo_iso[era],eta2,pt2); + // for SF validation the SF for iso should be applied on the second lepton only if it had passed the trigger + // so we should not apply this SF, but then also not applying thr isolation cut on that leg, but only on the + // selected one + // sf *= getValFromTH2(_histo_iso[era],eta,pt); + TH2F *histIso1 = (trigMatch1 ? _histo_iso[era] : _histo_isonotrig[era]); + TH2F *histIso2 = (trigMatch2 ? _histo_iso[era] : _histo_isonotrig[era]); + sf *= getValFromTH2(histIso1,eta1,pt1) * getValFromTH2(histIso2,eta2,pt2); + // cout << " sf = " << sf << endl; + + return sf; + +} + + // details like histograms and location might be updated float _get_muonSF_fast_wmass(float pt, float eta, int charge) { @@ -1386,118 +1014,6 @@ float _get_muonSF_fast_wmass(float pt, float eta, int charge) { //============================ -TFile *_file_eleTrigger_EBeta0p1 = NULL; -TH2F *_histo_eleTrigger_EBeta0p1 = NULL; -TFile *_file_eleTrigger_EEeta0p1 = NULL; -TH2F *_histo_eleTrigger_EEeta0p1 = NULL; -TFile *_file_eleID_EBeta0p1 = NULL; -TH2F *_histo_eleID_EBeta0p1 = NULL; -TFile *_file_eleID_EEeta0p1 = NULL; -TH2F *_histo_eleID_EEeta0p1 = NULL; - -float _get_electronSF_TriggerAndID(int pdgid, float pt, float eta) { - - if (_cmssw_base_ == "") { - cout << "Setting _cmssw_base_ to environment variable CMSSW_BASE" << endl; - _cmssw_base_ = getEnvironmentVariable("CMSSW_BASE"); - } - - // get all histograms - if (!_histo_eleTrigger_EBeta0p1) { - _file_eleTrigger_EBeta0p1 = new TFile(Form("%s/src/CMGTools/WMass/python/postprocessing/data/leptonSF/new2016_madeSummer2018/etaptSmooth_electrons_trigger_30_55_onlyErf.root",_cmssw_base_.c_str()),"read"); - _histo_eleTrigger_EBeta0p1 = (TH2F*)(_file_eleTrigger_EBeta0p1->Get("scaleFactor")); - } - - if (!_histo_eleTrigger_EEeta0p1) { - _file_eleTrigger_EEeta0p1 = new TFile(Form("%s/src/CMGTools/WMass/python/postprocessing/data/leptonSF/new2016_madeSummer2018/electrons_trigger_endcap0p1.root",_cmssw_base_.c_str()),"read"); - _histo_eleTrigger_EEeta0p1 = (TH2F*)(_file_eleTrigger_EEeta0p1->Get("scaleFactor")); - } - - if (!_histo_eleID_EBeta0p1) { - _file_eleID_EBeta0p1 = new TFile(Form("%s/src/CMGTools/WMass/python/postprocessing/data/leptonSF/new2016_madeSummer2018/TnPstuff/electron/elFullID_V2_granular/smoothEfficiency_electrons_fullID_V2_granular.root",_cmssw_base_.c_str()),"read"); - _histo_eleID_EBeta0p1 = (TH2F*)(_file_eleID_EBeta0p1->Get("scaleFactor")); - } - - if (!_histo_eleID_EEeta0p1) { - _file_eleID_EEeta0p1 = new TFile(Form("%s/src/CMGTools/WMass/python/postprocessing/data/leptonSF/new2016_madeSummer2018/TnPstuff/electron/elFullID_V2_endcap0p1/smoothEfficiency_electrons_fulID_V2_endcap0p1.root",_cmssw_base_.c_str()),"read"); - _histo_eleID_EEeta0p1 = (TH2F*)(_file_eleID_EEeta0p1->Get("scaleFactor")); - } - - int etabinTrigger = 0; - int etabinID = 0; - int ptbinTrigger = 0; - int ptbinID = 0; - TH2F *histTrigger = NULL; - TH2F *histID = NULL; - - if (fabs(pdgid) == 11) { - if (fabs(eta) >= 1.566) { - histTrigger = _histo_eleTrigger_EEeta0p1; - histID = _histo_eleID_EEeta0p1; - } else { - histTrigger = _histo_eleTrigger_EBeta0p1; - histID = _histo_eleID_EBeta0p1; - } - int etabinTrigger = std::max(1, std::min(histTrigger->GetNbinsX(), histTrigger->GetXaxis()->FindFixBin(eta))); - int ptbinTrigger = std::max(1, std::min(histTrigger->GetNbinsY(), histTrigger->GetYaxis()->FindFixBin(pt))); - int etabinID = std::max(1, std::min(histID->GetNbinsX(), histID->GetXaxis()->FindFixBin(eta))); - int ptbinID = std::max(1, std::min(histID->GetNbinsY(), histID->GetYaxis()->FindFixBin(pt))); - return histTrigger->GetBinContent(etabinTrigger,ptbinTrigger) * histID->GetBinContent(etabinID,ptbinID); - } - - return 0; - -} - -//float triggerSF_2l_histo(float l1pt, float l1eta, float l11pass, float l12pass, float l2pt, float l2eta, float l21pass, float l22pass){ -// float weight = -999.; -// -// bool l1pass = (l11pass > -1. || l12pass > -1.); -// bool l2pass = (l21pass > -1. || l22pass > -1.); -// -// float l1sf = _get_muonSF_selectionToTrigger(13,l1pt,l1eta); -// float l2sf = _get_muonSF_selectionToTrigger(13,l2pt,l2eta); -// -// int randomize = 0; -// -// if ( l1pass && !l2pass) weight = l1sf; -// else if (!l1pass && l2pass) weight = l2sf; -// else if ( l1pass && l2pass) { -// if (!randomize) weight = (l1sf+l2sf)/2.; -// else { -// if(!rng) rng = new TRandom3(); -// float randy = rng->Uniform(-1.,1.); -// if (randy < 0.) weight = l1sf; -// else weight = l2sf; -// } -// } -// -// //else return -999.; // this should never happen -// -// return weight; -//} - -//float triggerSF_2l_byCharge(float l1pt, float l1eta, float l11pass, float l12pass, float l1charge, int charge){ -// float weight = -999.; -// -// bool l1pass = (l11pass > -1. || l12pass > -1.); -// -// float l1sf = 1.; -// if (l1pass) l1sf = _get_muonSF_selectionToTrigger(13,l1pt,l1eta); -// -// if (l1charge*charge > 0) weight = l1sf; -// else weight = 1.; -// -// return weight; -//} -// -//float triggerSF_1l_histo(float l1pt, float l1eta){ -// -// float l1sf = _get_muonSF_selectionToTrigger(13,l1pt,l1eta); -// -// return l1sf; -//} - int unroll2DTo1D_ptSlices(int pdgid, float pt, float eta){ float ptmin = 0; float etaMax = 0; @@ -1611,338 +1127,304 @@ float effSystEtaBins(int inuisance, int pdgId, float eta, float pt, float etamin return ret; } -float lepSFRmuUp(int pdgId, float pt, float eta, int charge, float sf2) { - - // in this function SF1 is obtained inside here, while SF3 (reco SF, which would generally be 1) is treated as prefiring SF - // at this level we can have electrons, because the cuts are applied afterwards, and this would return bad numbers - if (fabs(pdgId) != 13) return 0; - double trigSF = _get_muonSF_selectionToTrigger(pdgId,pt,eta,charge); - double prefireSF = prefireJetsWeight(eta); - return _lepSF(pdgId,pt,eta,trigSF,sf2,prefireSF, 1)/_lepSF(pdgId,pt,eta,trigSF,sf2,prefireSF,0); -} - -float lepSFRmuDn(int pdgId, float pt, float eta, int charge, float sf2) { - - // in this function SF1 is obtained inside here, while SF3 (reco SF, which would generally be 1) is treated as prefiring SF - // at this level we can have electrons, because the cuts are applied afterwards, and this would return bad numbers - if (fabs(pdgId) != 13) return 0; - double trigSF = _get_muonSF_selectionToTrigger(pdgId,pt,eta,charge); - double prefireSF = prefireJetsWeight(eta); - return _lepSF(pdgId,pt,eta,trigSF,sf2,prefireSF, -1)/_lepSF(pdgId,pt,eta,trigSF,sf2,prefireSF,0); - -} - - -float _muonTriggerSF_2l_trigMatch(int requiredCharge, // pass positive or negative number, depending on what you want - float matchedTrgObjMuPt_l1, float matchedTrgObjMuPt_l2, - int pdgId1, int pdgId2, // used to decide which lepton has the required charge - float pt1, float pt2, - float eta1, float eta2 - ) { - - int pdgId = 0; - float pt = 0.0; - float eta = 0.0; - // muon (negative charge) has positive pdgId, antimuon (postive charge) has negative pdgId - // so, product of charge and pdgId_n must be negative to use pdgId_n and not the pther pdgId_n' - if (requiredCharge * pdgId1 < 0) { - // use lep 1 - pdgId = pdgId1; - pt = pt1; - eta = eta1; - if (matchedTrgObjMuPt_l1 < 0.0) return 0; // if no match to trigger, discard events - } else { - // use lep 2 - pdgId = pdgId2; - pt = pt2; - eta = eta2; - if (matchedTrgObjMuPt_l2 < 0.0) return 0; // if no match to trigger, discard events - } - - return _get_muonSF_selectionToTrigger(pdgId, pt, eta, requiredCharge); - -} - - -bool triggerMatch(int requiredCharge, // pass positive or negative number, depending on what you want - float matchedTrgObjMuPt_l1, float matchedTrgObjMuPt_l2, - int pdgId1, int pdgId2 // used to decide which lepton has the required charge - ) { - - int pdgId = 0; - // muon (negative charge) has positive pdgId, antimuon (postive charge) has negative pdgId - // so, product of charge and pdgId_n must be negative to use pdgId_n and not the pther pdgId_n' - if (requiredCharge * pdgId1 < 0) { - // use lep 1 - if (matchedTrgObjMuPt_l1 < 0.0) return 0; // if no match to trigger, discard events - else return 1; - } else { - // use lep 2 - pdgId = pdgId2; - if (matchedTrgObjMuPt_l2 < 0.0) return 0; // if no match to trigger, discard events - else return 1; - } - -} - - - -float triggerSFforChargedLepton(int requiredCharge, // pass positive or negative number, depending on what you want - int pdgid1, int pdgid2, // used to decide which lepton has the required charge - float pt1, float pt2, - float eta1, float eta2 - ) { - - int pdgId = 0; - float pt = 0.0; - float eta = 0.0; +// float _muonTriggerSF_2l_trigMatch(int requiredCharge, // pass positive or negative number, depending on what you want +// float matchedTrgObjMuPt_l1, float matchedTrgObjMuPt_l2, +// int pdgId1, int pdgId2, // used to decide which lepton has the required charge +// float pt1, float pt2, +// float eta1, float eta2 +// ) { + +// int pdgId = 0; +// float pt = 0.0; +// float eta = 0.0; +// // muon (negative charge) has positive pdgId, antimuon (postive charge) has negative pdgId +// // so, product of charge and pdgId_n must be negative to use pdgId_n and not the pther pdgId_n' +// if (requiredCharge * pdgId1 < 0) { +// // use lep 1 +// pdgId = pdgId1; +// pt = pt1; +// eta = eta1; +// if (matchedTrgObjMuPt_l1 < 0.0) return 0; // if no match to trigger, discard events +// } else { +// // use lep 2 +// pdgId = pdgId2; +// pt = pt2; +// eta = eta2; +// if (matchedTrgObjMuPt_l2 < 0.0) return 0; // if no match to trigger, discard events +// } + +// return _get_muonSF_selectionToTrigger(pdgId, pt, eta, requiredCharge); + +// } + + +// bool triggerMatch(int requiredCharge, // pass positive or negative number, depending on what you want +// float matchedTrgObjMuPt_l1, float matchedTrgObjMuPt_l2, +// int pdgId1, int pdgId2 // used to decide which lepton has the required charge +// ) { + +// int pdgId = 0; +// // muon (negative charge) has positive pdgId, antimuon (postive charge) has negative pdgId +// // so, product of charge and pdgId_n must be negative to use pdgId_n and not the pther pdgId_n' +// if (requiredCharge * pdgId1 < 0) { +// // use lep 1 +// if (matchedTrgObjMuPt_l1 < 0.0) return 0; // if no match to trigger, discard events +// else return 1; +// } else { +// // use lep 2 +// pdgId = pdgId2; +// if (matchedTrgObjMuPt_l2 < 0.0) return 0; // if no match to trigger, discard events +// else return 1; +// } + +// } + + + +// float triggerSFforChargedLepton(int requiredCharge, // pass positive or negative number, depending on what you want +// int pdgid1, int pdgid2, // used to decide which lepton has the required charge +// float pt1, float pt2, +// float eta1, float eta2 +// ) { + +// int pdgId = 0; +// float pt = 0.0; +// float eta = 0.0; - // pdgID > 0 for negative leptons - if (requiredCharge * pdgid1 < 0) { - pdgId = pdgid1; - pt = pt1; - eta = eta1; - } else { - pdgId = pdgid2; - pt = pt2; - eta = eta2; - } - - return _get_muonSF_selectionToTrigger(pdgId, pt, eta, requiredCharge); - -} - -float triggerSFforChargedLeptonMatchingTrigger(int requiredCharge, // pass positive or negative number, depending on what you want - float matchedTrgObjMuPt_l1, float matchedTrgObjMuPt_l2, - int pdgid1, int pdgid2, // used to decide which lepton has the required charge - float pt1, float pt2, - float eta1, float eta2 - ) { - - float trigMatchPt = 0.0; - int pdgId = 0; - float pt = 0.0; - float eta = 0.0; - - float trigMatchPt_other = 0.0; - int pdgId_other = 0; - float pt_other = 0.0; - float eta_other = 0.0; +// // pdgID > 0 for negative leptons +// if (requiredCharge * pdgid1 < 0) { +// pdgId = pdgid1; +// pt = pt1; +// eta = eta1; +// } else { +// pdgId = pdgid2; +// pt = pt2; +// eta = eta2; +// } + +// return _get_muonSF_selectionToTrigger(pdgId, pt, eta, requiredCharge); + +// } + +// float triggerSFforChargedLeptonMatchingTrigger(int requiredCharge, // pass positive or negative number, depending on what you want +// float matchedTrgObjMuPt_l1, float matchedTrgObjMuPt_l2, +// int pdgid1, int pdgid2, // used to decide which lepton has the required charge +// float pt1, float pt2, +// float eta1, float eta2 +// ) { + +// float trigMatchPt = 0.0; +// int pdgId = 0; +// float pt = 0.0; +// float eta = 0.0; + +// float trigMatchPt_other = 0.0; +// int pdgId_other = 0; +// float pt_other = 0.0; +// float eta_other = 0.0; - // pdgID > 0 for negative leptons - if (requiredCharge * pdgid1 < 0) { - pdgId = pdgid1; - pt = pt1; - eta = eta1; - trigMatchPt = matchedTrgObjMuPt_l1; - pdgId_other = pdgid2; - pt_other = pt2; - eta_other = eta2; - trigMatchPt_other = matchedTrgObjMuPt_l2; - } else { - pdgId = pdgid2; - trigMatchPt = matchedTrgObjMuPt_l2; - pt = pt2; - eta = eta2; - pdgId_other = pdgid1; - pt_other = pt1; - eta_other = eta1; - trigMatchPt_other = matchedTrgObjMuPt_l1; - } - - // try using 1 if both lepton match trigger (efficiency for trigger in 2 lepton phase space is ~ 100%) - if (trigMatchPt > 0.0 and trigMatchPt_other > 0.0) { - return 1; - } else { - if (trigMatchPt > 0.0) - return _get_muonSF_selectionToTrigger(pdgId, pt, eta, requiredCharge); - else - return _get_muonSF_selectionToTrigger(pdgId_other, pt_other, eta_other, -1*requiredCharge); - } - -} - -float triggerSFforChargedLeptonMatchingTriggerV2(int requiredCharge, // pass positive or negative number, depending on what you want - bool matchTrigger_l1, bool matchTrigger_l2, - int pdgid1, int pdgid2, // used to decide which lepton has the required charge - float pt1, float pt2, - float eta1, float eta2 - ) { - - bool thisLepMatchesTrigger = false; - int pdgId = 0; - float pt = 0.0; - float eta = 0.0; - - bool otherLepMatchesTrigger = false; - int pdgId_other = 0; - float pt_other = 0.0; - float eta_other = 0.0; +// // pdgID > 0 for negative leptons +// if (requiredCharge * pdgid1 < 0) { +// pdgId = pdgid1; +// pt = pt1; +// eta = eta1; +// trigMatchPt = matchedTrgObjMuPt_l1; +// pdgId_other = pdgid2; +// pt_other = pt2; +// eta_other = eta2; +// trigMatchPt_other = matchedTrgObjMuPt_l2; +// } else { +// pdgId = pdgid2; +// trigMatchPt = matchedTrgObjMuPt_l2; +// pt = pt2; +// eta = eta2; +// pdgId_other = pdgid1; +// pt_other = pt1; +// eta_other = eta1; +// trigMatchPt_other = matchedTrgObjMuPt_l1; +// } + +// // try using 1 if both lepton match trigger (efficiency for trigger in 2 lepton phase space is ~ 100%) +// if (trigMatchPt > 0.0 and trigMatchPt_other > 0.0) { +// return 1; +// } else { +// if (trigMatchPt > 0.0) +// return _get_muonSF_selectionToTrigger(pdgId, pt, eta, requiredCharge); +// else +// return _get_muonSF_selectionToTrigger(pdgId_other, pt_other, eta_other, -1*requiredCharge); +// } + +// } + +// float triggerSFforChargedLeptonMatchingTriggerV2(int requiredCharge, // pass positive or negative number, depending on what you want +// bool matchTrigger_l1, bool matchTrigger_l2, +// int pdgid1, int pdgid2, // used to decide which lepton has the required charge +// float pt1, float pt2, +// float eta1, float eta2 +// ) { + +// bool thisLepMatchesTrigger = false; +// int pdgId = 0; +// float pt = 0.0; +// float eta = 0.0; + +// bool otherLepMatchesTrigger = false; +// int pdgId_other = 0; +// float pt_other = 0.0; +// float eta_other = 0.0; - bool isSameSign = (pdgid1*pdgid2 > 0) ? true : false; +// bool isSameSign = (pdgid1*pdgid2 > 0) ? true : false; - // pdgID > 0 for negative leptons - if (isSameSign || requiredCharge * pdgid1 < 0) { - pdgId = pdgid1; - pt = pt1; - eta = eta1; - thisLepMatchesTrigger = matchTrigger_l1; - pdgId_other = pdgid2; - pt_other = pt2; - eta_other = eta2; - otherLepMatchesTrigger = matchTrigger_l2; - } else { - pdgId = pdgid2; - pt = pt2; - eta = eta2; - thisLepMatchesTrigger = matchTrigger_l2; - pdgId_other = pdgid1; - pt_other = pt1; - eta_other = eta1; - otherLepMatchesTrigger = matchTrigger_l1; - } - - // try using 1 if both lepton match trigger (efficiency for trigger in 2 lepton phase space is ~ 100%) - if (thisLepMatchesTrigger and otherLepMatchesTrigger) { - return 1; - } else { - int sfCharge = thisLepMatchesTrigger ? requiredCharge : (-1*requiredCharge); - if (isSameSign) sfCharge = (pdgid1 > 0) ? -1 : 1; // for same sign uses the charge of the leading for the SF - - if (thisLepMatchesTrigger) - return _get_muonSF_selectionToTrigger(pdgId, pt, eta, sfCharge); - else if (otherLepMatchesTrigger) - return _get_muonSF_selectionToTrigger(pdgId_other, pt_other, eta_other, sfCharge); - else - return 0.0; // this should not happen, but just in case - } - -} - -float triggerSFforChargedLeptonMatchingTriggerWlike(bool isOddEvent, // pass positive or negative number, depending on what you want - bool matchTrigger_l1, bool matchTrigger_l2, - int pdgid1, int pdgid2, // used to decide which lepton has the required charge - float pt1, float pt2, - float eta1, float eta2 - ) { - - int requiredCharge = isOddEvent ? 1 : -1; - - bool thisLepMatchesTrigger = false; - int pdgId = 0; - float pt = 0.0; - float eta = 0.0; - - bool otherLepMatchesTrigger = false; - int pdgId_other = 0; - float pt_other = 0.0; - float eta_other = 0.0; +// // pdgID > 0 for negative leptons +// if (isSameSign || requiredCharge * pdgid1 < 0) { +// pdgId = pdgid1; +// pt = pt1; +// eta = eta1; +// thisLepMatchesTrigger = matchTrigger_l1; +// pdgId_other = pdgid2; +// pt_other = pt2; +// eta_other = eta2; +// otherLepMatchesTrigger = matchTrigger_l2; +// } else { +// pdgId = pdgid2; +// pt = pt2; +// eta = eta2; +// thisLepMatchesTrigger = matchTrigger_l2; +// pdgId_other = pdgid1; +// pt_other = pt1; +// eta_other = eta1; +// otherLepMatchesTrigger = matchTrigger_l1; +// } + +// // try using 1 if both lepton match trigger (efficiency for trigger in 2 lepton phase space is ~ 100%) +// if (thisLepMatchesTrigger and otherLepMatchesTrigger) { +// return 1; +// } else { +// int sfCharge = thisLepMatchesTrigger ? requiredCharge : (-1*requiredCharge); +// if (isSameSign) sfCharge = (pdgid1 > 0) ? -1 : 1; // for same sign uses the charge of the leading for the SF + +// if (thisLepMatchesTrigger) +// return _get_muonSF_selectionToTrigger(pdgId, pt, eta, sfCharge); +// else if (otherLepMatchesTrigger) +// return _get_muonSF_selectionToTrigger(pdgId_other, pt_other, eta_other, sfCharge); +// else +// return 0.0; // this should not happen, but just in case +// } + +// } + +// float triggerSFforChargedLeptonMatchingTriggerWlike(bool isOddEvent, // pass positive or negative number, depending on what you want +// bool matchTrigger_l1, bool matchTrigger_l2, +// int pdgid1, int pdgid2, // used to decide which lepton has the required charge +// float pt1, float pt2, +// float eta1, float eta2 +// ) { + +// int requiredCharge = isOddEvent ? 1 : -1; + +// bool thisLepMatchesTrigger = false; +// int pdgId = 0; +// float pt = 0.0; +// float eta = 0.0; + +// bool otherLepMatchesTrigger = false; +// int pdgId_other = 0; +// float pt_other = 0.0; +// float eta_other = 0.0; - bool isSameSign = (pdgid1*pdgid2 > 0) ? true : false; +// bool isSameSign = (pdgid1*pdgid2 > 0) ? true : false; - // pdgID > 0 for negative leptons - if (isSameSign || requiredCharge * pdgid1 < 0) { - pdgId = pdgid1; - pt = pt1; - eta = eta1; - thisLepMatchesTrigger = matchTrigger_l1; - pdgId_other = pdgid2; - pt_other = pt2; - eta_other = eta2; - otherLepMatchesTrigger = matchTrigger_l2; - } else { - pdgId = pdgid2; - pt = pt2; - eta = eta2; - thisLepMatchesTrigger = matchTrigger_l2; - pdgId_other = pdgid1; - pt_other = pt1; - eta_other = eta1; - otherLepMatchesTrigger = matchTrigger_l1; - } - - // consider only case where given lepton matches trigger - if (isSameSign) { - if (thisLepMatchesTrigger and otherLepMatchesTrigger) { - // charge is known, but what about which eta-pt ? - // this is a minor component for Z with SS in MC, might just randomly choose one - // use leading for now to be simple, it is really a small component - return _get_muonSF_selectionToTrigger(pdgId, pt, eta, -1 * pdgId); - } else if (thisLepMatchesTrigger) { - return _get_muonSF_selectionToTrigger(pdgId, pt, eta, -1 * pdgId); - } else if (otherLepMatchesTrigger) { - return _get_muonSF_selectionToTrigger(pdgId_other, pt_other, eta_other, -1 * pdgId_other); - } else { - return 0; // should not happen, but just in case - } - } else { - if (thisLepMatchesTrigger) { - int sfCharge = requiredCharge; - return _get_muonSF_selectionToTrigger(pdgId, pt, eta, sfCharge); - } else { - // if lepton does not match trigger, we decide to reject the event - return 0.0; - } - } - -} - - -bool triggerMatchV2(int requiredCharge, // pass positive or negative number, depending on what you want - float matchedTrgObjMuPt_l1, float matchedTrgObjMuPt_l2, - float matchedTrgObjTkMuPt_l1, float matchedTrgObjTkMuPt_l2, - int pdgId1, int pdgId2 // used to decide which lepton has the required charge - ) { - - // muon (negative charge) has positive pdgId, antimuon (postive charge) has negative pdgId - // so, product of charge and pdgId_n must be negative to use pdgId_n and not the pther pdgId_n' - if (requiredCharge * pdgId1 < 0) { - // use lep 1 - return (matchedTrgObjMuPt_l1 > 0.0 || matchedTrgObjTkMuPt_l1 > 0.0) ? 1 : 0; - } else { - // use lep 2 - return (matchedTrgObjMuPt_l2 > 0.0 || matchedTrgObjTkMuPt_l2 > 0.0) ? 1 : 0; - } - -} - - -bool triggerMatchWlike(bool isOddEvent, // pass positive or negative number, depending on what you want - float matchedTrgObjMuPt_l1, float matchedTrgObjMuPt_l2, - float matchedTrgObjTkMuPt_l1, float matchedTrgObjTkMuPt_l2, - int pdgId1, int pdgId2 // used to decide which lepton has the required charge - ) { - - if (pdgId1 * pdgId2 > 0) { - // same sign case - return ((matchedTrgObjMuPt_l1 > 0.0 || matchedTrgObjTkMuPt_l1 > 0.0) || (matchedTrgObjMuPt_l2 > 0.0 || matchedTrgObjTkMuPt_l2)); - } - - int requiredCharge = isOddEvent ? 1 : -1; - // muon (negative charge) has positive pdgId, antimuon (postive charge) has negative pdgId - // so, product of charge and pdgId_n must be negative to use pdgId_n and not the pther pdgId_n' - if (requiredCharge * pdgId1 < 0) { - // use lep 1 - return (matchedTrgObjMuPt_l1 > 0.0 || matchedTrgObjTkMuPt_l1 > 0.0) ? 1 : 0; - } else { - // use lep 2 - return (matchedTrgObjMuPt_l2 > 0.0 || matchedTrgObjTkMuPt_l2 > 0.0) ? 1 : 0; - } - -} - -bool isOddEvent(ULong64_t evt) { - - return (evt%2) ? 1 : 0; - -} - -bool isEvenEvent(ULong64_t evt) { - - return (evt%2) ? 0 : 1; - -} +// // pdgID > 0 for negative leptons +// if (isSameSign || requiredCharge * pdgid1 < 0) { +// pdgId = pdgid1; +// pt = pt1; +// eta = eta1; +// thisLepMatchesTrigger = matchTrigger_l1; +// pdgId_other = pdgid2; +// pt_other = pt2; +// eta_other = eta2; +// otherLepMatchesTrigger = matchTrigger_l2; +// } else { +// pdgId = pdgid2; +// pt = pt2; +// eta = eta2; +// thisLepMatchesTrigger = matchTrigger_l2; +// pdgId_other = pdgid1; +// pt_other = pt1; +// eta_other = eta1; +// otherLepMatchesTrigger = matchTrigger_l1; +// } + +// // consider only case where given lepton matches trigger +// if (isSameSign) { +// if (thisLepMatchesTrigger and otherLepMatchesTrigger) { +// // charge is known, but what about which eta-pt ? +// // this is a minor component for Z with SS in MC, might just randomly choose one +// // use leading for now to be simple, it is really a small component +// return _get_muonSF_selectionToTrigger(pdgId, pt, eta, -1 * pdgId); +// } else if (thisLepMatchesTrigger) { +// return _get_muonSF_selectionToTrigger(pdgId, pt, eta, -1 * pdgId); +// } else if (otherLepMatchesTrigger) { +// return _get_muonSF_selectionToTrigger(pdgId_other, pt_other, eta_other, -1 * pdgId_other); +// } else { +// return 0; // should not happen, but just in case +// } +// } else { +// if (thisLepMatchesTrigger) { +// int sfCharge = requiredCharge; +// return _get_muonSF_selectionToTrigger(pdgId, pt, eta, sfCharge); +// } else { +// // if lepton does not match trigger, we decide to reject the event +// return 0.0; +// } +// } + +// } + + +// bool triggerMatchV2(int requiredCharge, // pass positive or negative number, depending on what you want +// float matchedTrgObjMuPt_l1, float matchedTrgObjMuPt_l2, +// float matchedTrgObjTkMuPt_l1, float matchedTrgObjTkMuPt_l2, +// int pdgId1, int pdgId2 // used to decide which lepton has the required charge +// ) { + +// // muon (negative charge) has positive pdgId, antimuon (postive charge) has negative pdgId +// // so, product of charge and pdgId_n must be negative to use pdgId_n and not the pther pdgId_n' +// if (requiredCharge * pdgId1 < 0) { +// // use lep 1 +// return (matchedTrgObjMuPt_l1 > 0.0 || matchedTrgObjTkMuPt_l1 > 0.0) ? 1 : 0; +// } else { +// // use lep 2 +// return (matchedTrgObjMuPt_l2 > 0.0 || matchedTrgObjTkMuPt_l2 > 0.0) ? 1 : 0; +// } + +// } + + +// bool triggerMatchWlike(bool isOddEvent, // pass positive or negative number, depending on what you want +// float matchedTrgObjMuPt_l1, float matchedTrgObjMuPt_l2, +// float matchedTrgObjTkMuPt_l1, float matchedTrgObjTkMuPt_l2, +// int pdgId1, int pdgId2 // used to decide which lepton has the required charge +// ) { + +// if (pdgId1 * pdgId2 > 0) { +// // same sign case +// return ((matchedTrgObjMuPt_l1 > 0.0 || matchedTrgObjTkMuPt_l1 > 0.0) || (matchedTrgObjMuPt_l2 > 0.0 || matchedTrgObjTkMuPt_l2)); +// } + +// int requiredCharge = isOddEvent ? 1 : -1; +// // muon (negative charge) has positive pdgId, antimuon (postive charge) has negative pdgId +// // so, product of charge and pdgId_n must be negative to use pdgId_n and not the pther pdgId_n' +// if (requiredCharge * pdgId1 < 0) { +// // use lep 1 +// return (matchedTrgObjMuPt_l1 > 0.0 || matchedTrgObjTkMuPt_l1 > 0.0) ? 1 : 0; +// } else { +// // use lep 2 +// return (matchedTrgObjMuPt_l2 > 0.0 || matchedTrgObjTkMuPt_l2 > 0.0) ? 1 : 0; +// } + +// } bool triggerMatchWlike_nano(int match1, int ch1, int match2, int ch2, ULong64_t evt) { diff --git a/WMass/python/plotter/w-mass-13TeV/makePUweight.py b/WMass/python/plotter/w-mass-13TeV/makePUweight.py index 978d024a7816..ec34aac893ec 100644 --- a/WMass/python/plotter/w-mass-13TeV/makePUweight.py +++ b/WMass/python/plotter/w-mass-13TeV/makePUweight.py @@ -15,14 +15,21 @@ sys.path.append(os.getcwd() + "/plotUtils/") from utility import * +# from helicity analysis oldWeights = [0.3505407355600995, 0.8996968628890968, 1.100322319466069, 0.9562526765089195, 1.0366251229154624, 1.0713954619016586, 0.7593488199769544, 0.47490309461978414, 0.7059895997695581, 0.8447022252423783, 0.9169159386164522, 1.0248924033173097, 1.0848877947714115, 1.1350984224561655, 1.1589888429954602, 1.169048420382294, 1.1650383018054549, 1.1507200023444994, 1.1152571438041776, 1.0739529436969637, 1.0458014000030829, 1.032500407707141, 1.0391236062781293, 1.041283620738903, 1.0412963370894526, 1.0558823002770783, 1.073481674823461, 1.0887053272606795, 1.1041701696801014, 1.123218903738397, 1.1157169321377927, 1.1052520327174429, 1.0697489590429388, 1.0144652740600584, 0.9402657069968621, 0.857142825520793, 0.7527112615290031, 0.6420618248685722, 0.5324755829715156, 0.4306470627563325, 0.33289171600176093, 0.24686361729094983,0.17781595237914027, 0.12404411884835284, 0.08487088505600057, 0.056447805688061216, 0.03540829360547507, 0.022412461576677457, 0.013970541270658443, 0.008587896629717911, 0.004986410514292661, 0.00305102303701641, 0.001832072556146534, 0.0011570757619737708, 0.0008992999249003301, 0.0008241241729452477, 0.0008825716073180279, 0.001187003960081393, 0.0016454104270429153, 0.0022514113879764414, 0.003683196037880878, 0.005456695951503178, 0.006165248770884191, 0.007552675218762607, 0.008525338219226993, 0.008654690499815343, 0.006289068906974821, 0.00652551838513972, 0.005139581024893171, 0.005115751962934923, 0.004182527768384693, 0.004317593022028565, 0.0035749335962533355, 0.003773660372937113, 0.002618732319396435, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0] +# new with partial W MC preVFP +#oldWeights = [0.017867211276858426, 0.25019181678340197, 0.7305862075344697, 0.8203306355218927, 0.8568507658433443, 0.5021252568573517, 0.26598094658249777, 0.2525594126097894, 0.43091072564779115, 0.5816151668719733, 0.7400719694832786, 0.8635841784600747, 0.9396947027327512, 0.9867166485834531, 1.020291825978338, 1.058677896425578, 1.0951610451340548, 1.1270599475402712, 1.149199627966607, 1.161062844833281, 1.1570323009561523, 1.1408277403854514, 1.1237795117739837, 1.1080566938230716, 1.0897761375745778, 1.064304242937247, 1.0256371301024838, 0.974592047960344, 0.919208105883519, 0.8614029922190752, 0.80250010071568, 0.7447070188841107, 0.691304388080654, 0.6402835441510876, 0.5891723690900388, 0.5400972141379156, 0.49313582436893444, 0.4463956167604181, 0.400690015469447, 0.3570993263445747, 0.313769141057574, 0.272973076482914, 0.23756151770204517, 0.2052480930611912, 0.18165295449088267, 0.15154171165962477, 0.13020442654298184, 0.1060542785336088, 0.08931962151840153, 0.07320668426537356, 0.06699868236915886, 0.07342602448799117, 0.09022522247731071, 0.1221948811200131, 0.21751127388127575, 0.26185148964193156, 0.3993515054053398, 0.4259481886684673, 0.6348999885572649, 1.0768669803515931, 1.2073680188570837, 1.3977538479690192, 1.8560151439282793, 2.6159138791249634, 1.492621348422977, 2.030155370346692, 1.0, 1.0, 1.0, 1.0, 1.0, 2.608617469665849, 4.5109759375776735, 1.0, 1.0, 2.7995528359963338, 1.0, 1.0, 1.0, 4.043483083032464, 0.8278949263309181, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0] + +# new with partial W MC postVFP +# oldWeights = [1.5094769667755739, 0.5678507573322055, 1.0105884486266141, 0.7259960323564019, 0.6619453439299897, 0.37363396015230216, 0.15239333007202369, 0.10791755923476429, 0.07918472234473897, 0.05419619726622047, 0.14361053792634917, 0.34283985083406093, 0.5010734484221103, 0.5859542596067007, 0.6417013874657507, 0.7081679228576429, 0.7630928885638684, 0.7927011423655624, 0.7977355318365416, 0.804189334635704, 0.8379574350304874, 0.8991008934966008, 0.9625166892724227, 1.0100064501247878, 1.0501599728932576, 1.0991686204042044, 1.159807646806213, 1.230197853416741, 1.3121394462817406, 1.3989162630341463, 1.4799356011552773, 1.5557799985845535, 1.6310266488456922, 1.7003552120673373, 1.7676611780885065, 1.8405616412980672, 1.9250530644650858, 2.010419966610567, 2.10422235818776, 2.2195187847594804, 2.2997062399954857, 2.395010762430828, 2.4803953120930684, 2.5918893616537275, 2.7047108284644694, 2.71073345533101, 2.6519181014415363, 2.6277548910588657, 2.3664596415368297, 2.1655717980383105, 1.8274047657200394, 1.3313115741327561, 0.9113129353116672, 0.5869561379336159, 0.4284308024180917, 0.20595003106437168, 0.10999572232736675, 0.049536718778780756, 0.035006854789963834, 0.012922619333388894, 0.009214760376410974, 0.009219346474718641, 0.0015371306555079958, 0.001800361515424057, 0.0003153024223498953, 0.00010484990280832637, 1.0, 9.561632218479775e-05, 4.4263424947054785e-05, 1.0, 1.0, 8.750970959266416e-06, 1.9850705244600614e-06, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0235991128869821e-08, 1.3636783092893852e-09, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0] + newWeights = [] normalizeIntegralUpToBin = 100 # this would usually correspond to the max bin where there is enough stat in data and MC, above which weird weights can be observed. Those large weights are set to cropHighWeight, and we don't care about renormalizing the distributions again to correct the weights # It might make sense to run the script a first time with the full integral to get a clue about the ideal value, and then run again with customized range doDataVSdata = False # if True it overrides isPreVFP below -doInclusiveData = True # overrides isPreVFP, but overridden by doDataVSdata +doInclusiveData = False # overrides isPreVFP, but overridden by doDataVSdata isPreVFP = True maxWeightWarning = 5.0 # at the end issue a warning if weight > this value cropHighWeight = 1 # crop values larger than maxWeightWarning, setting them to this value (i.e. use 1 for no reweighting, or same as maxWeightWarning) @@ -58,13 +65,15 @@ #mcfile = "pileupStuff/MyMCPileupHistogram_2016Legacy_Wplus_preVFP.root" # with genWeight mcfile = "pileupStuff/MyMCPileupHistogram_2016Legacy_noGenWeights_preAndPostVFP.root" mcname = "Pileup_nTrueInt_Wplus_preVFP" + #mcfile = "/afs/cern.ch/user/m/mciprian/www/wmass/13TeV/testNanoAOD/PU_weights/PUprofilesMC_allEventsWmunu/plots_test.root" + #mcname = "Pileup_nTrueInt_Wmunu_preVFP" mcLabel = "W MC (preVFP)" # datafile = "pileupStuff/MyDataPileupHistogram_2016Legacy_upTo2016FwithHIPM.root" dataname = "pileup" dataLabel = "data" # - outdir = "plots/testNanoAOD/PU_weights/2016_preVFP/" + outdir = "plots/testNanoAOD/PU_weights/2016_preVFP_checkAllMC/" lumi = "19.3" ratioLabel = "data/MC::0.0,1.5" else: diff --git a/WMass/python/plotter/w-mass-13TeV/makeVertexStudy.py b/WMass/python/plotter/w-mass-13TeV/makeVertexStudy.py index 7f5c8f5a07a5..86d757a05b12 100644 --- a/WMass/python/plotter/w-mass-13TeV/makeVertexStudy.py +++ b/WMass/python/plotter/w-mass-13TeV/makeVertexStudy.py @@ -15,10 +15,18 @@ sys.path.append(os.getcwd() + "/plotUtils/") from utility import * +use2Lep = True # plots/vertexStudy/ask1orMoreLep -outdir = "/afs/cern.ch/work/m/mciprian/w_mass_analysis/heppy/rel_slc7/CMSSW_9_4_12/src/CMGTools/WMass/python/plotter/plots/vertexStudy/newNtuplesNoSkim_antiMatch/compareEfficiency" +outdir = "/afs/cern.ch/user/m/mciprian/www/wmass/13TeV/testNanoAOD/vertexStudy/WmunuSamples/compareEfficiency_minus" +#outdir = "/afs/cern.ch/user/m/mciprian/www/wmass/13TeV/testNanoAOD/vertexStudy/ZmumuSamples/compareEfficiency" +if use2Lep: + outdir = "/afs/cern.ch/user/m/mciprian/www/wmass/13TeV/testNanoAOD/vertexStudy/ZmumuSamples_2Lep/compareEfficiency" + +inputfolder = "/afs/cern.ch/user/m/mciprian/www/wmass/13TeV/testNanoAOD/vertexStudy/WmunuSamples/" +#inputfolder = "/afs/cern.ch/user/m/mciprian/www/wmass/13TeV/testNanoAOD/vertexStudy/ZmumuSamples/" +if use2Lep: + inputfolder = "/afs/cern.ch/user/m/mciprian/www/wmass/13TeV/testNanoAOD/vertexStudy/ZmumuSamples_2Lep/" -inputfolder = "/afs/cern.ch/work/m/mciprian/w_mass_analysis/heppy/rel_slc7/CMSSW_9_4_12/src/CMGTools/WMass/python/plotter/plots/vertexStudy/newNtuplesNoSkim_antiMatch/" # inputfiles = {"1::genEtaPt" : "W_94X_noRecoCuts_genEtaPt26to56", # "2::fullSel_NoMtNoIsoNoID" : "W_94X_allRecoCuts_noMtNoIsoNoID", # "3::fullSel_NoMtNoIso" : "W_94X_allRecoCuts_noMtNoIso", @@ -28,30 +36,32 @@ # "7::1lepInAccept" : "W_94X_1lepInAccept", # } -#workingPoints = ["alwaystrue", "genEtaPt", "vertexPresel", "muonInAccept", "muMediumId", "muTightIso", "mtl1pf40", "trigger"] -#colors = [ROOT.kBlack, ROOT.kCyan+1, ROOT.kRed, ROOT.kBlue, ROOT.kGreen+2, ROOT.kOrange+2, ROOT.kMagenta, ROOT.kAzure+2] -#markers = [ROOT.kFullCircle, ROOT.kFullCross, ROOT.kOpenSquare, ROOT.kOpenTriangleUp, ROOT.kOpenCircle, ROOT.kOpenSquareDiagonal, ROOT.kFullCircle, ROOT.kFullSquare] - -workingPoints = ["alwaystrue", "genMuNoEtaPt", "vertexPresel", "muonInAccept", "muMediumId", "muTightIso", "mtl1pf40", "trigger"] +#workingPoints = ["alwaystrue", "genMuNoEtaPt", "vertexPresel", "muonInAccept", "muMediumId", "muTightIso", "mtl1pf40", "trigger"] +workingPoints = ["alwaystrue", "onemuon", "trigger", "muonID", "pfRelIso04", "mtl1pf40", "vertex"] colors = [ROOT.kBlack, ROOT.kCyan+1, ROOT.kRed, ROOT.kBlue, ROOT.kGreen+2, ROOT.kOrange+2, ROOT.kMagenta, ROOT.kAzure+2] +if use2Lep: + workingPoints[1] = "twomuon" + markers = [ROOT.kFullCircle, ROOT.kFullCross, ROOT.kOpenSquare, ROOT.kOpenTriangleUp, ROOT.kOpenCircle, ROOT.kOpenSquareDiagonal, ROOT.kFullCircle, ROOT.kFullSquare] #range for efficiency plot effLow = 0.5 effHigh = 1.05 +#process = "Wmunu_minus" # to get the process name inside the root file +process = "Zmumu" # to get the process name inside the root file absDzVal = 0.1 # 1 mm # Wpt from 0 to 100 with 2 GeV width, dz from -1.0 to 1.0 with 0.01 width # dressed lepton pT from 26 to 100 with 1 GeV width, dz from -1.0 to 1.0 with 0.01 width var = "Wpt" genWPtLow = 0.0 genWPtHigh = 100.0 -rebinWPt = 5 # default 2 -var = "dressedLepPt" +rebinWPt = 1 # default binning is 2 GeV, so rebinWpt = 2 makes it 4 GeV +#var = "dressedLepPt" genLepPtLow = 26.0 genLepPtHigh = 100.0 -rebinLepPt = 8 # default 1 -hname = "dzVertex_gen_primary__{v}_Wnopt".format(v=var) +rebinLepPt = 2 # default binning is 1 GeV, so rebinLepPt = 2 makes it 2 GeV +hname = "dzVertex_gen_primary__{v}_{p}".format(v=var,p=process) if __name__ == "__main__": @@ -82,7 +92,7 @@ print "Cut: " + str(key) print "-"*30 print - inputfile = inputfolder + key + "/plots_forTest.root" + inputfile = inputfolder + key + "/plots_test.root" tf = ROOT.TFile.Open(inputfile) h2 = tf.Get(hname) h2.SetDirectory(0) @@ -164,7 +174,7 @@ print "Empty overflow bin" print "\n"*2 - sortkeys = sortkeys[:5] + #sortkeys = sortkeys[:5] adjustSettings_CMS_lumi() createPlotDirAndCopyPhp(outdir) @@ -185,7 +195,8 @@ hists[k].SetLineColor(colors[i]) hists[k].SetMarkerColor(colors[i]) hists[k].SetLineWidth(2) - hists[k].SetMarkerStyle(markers[i]) + hists[k].SetMarkerStyle(markers[i]) + print "%d) %s " % (i,k) if i: hists[k].Draw("LPSAME") else: @@ -201,7 +212,7 @@ hists[k].GetYaxis().SetTitleSize(0.05) hists[k].GetYaxis().SetLabelSize(0.04) hists[k].GetYaxis().SetRangeUser(effLow,effHigh) - leg = ROOT.TLegend(0.15,0.15,0.9,0.35) + leg = ROOT.TLegend(0.15,0.15,0.9,0.35+(0.05 if len(sortkeys) > 6 else 0.0)) leg.SetFillColor(0) leg.SetFillStyle(0) leg.SetFillColorAlpha(0,0.6) @@ -309,3 +320,4 @@ csel.SaveAs(outdir + "/selectionEfficiency.{ext}".format(v=var,ext=ext)) + diff --git a/WMass/python/plotter/w-mass-13TeV/make_fake_rates_data.py b/WMass/python/plotter/w-mass-13TeV/make_fake_rates_data.py index 9d189ee00e56..3b92af007a3a 100644 --- a/WMass/python/plotter/w-mass-13TeV/make_fake_rates_data.py +++ b/WMass/python/plotter/w-mass-13TeV/make_fake_rates_data.py @@ -1,57 +1,37 @@ #!/usr/bin/env python from shutil import copyfile import re, sys, os, os.path, subprocess +import ROOT from optparse import OptionParser -parser = OptionParser(usage="%prog testname ") -parser.add_option("--mu", dest="useMuon", default=False, action='store_true', help="Do fake rate for muons"); +parser = OptionParser(usage="%prog ") parser.add_option("--qcdmc", dest="addQCDMC", default=False, action='store_true', help="Add QCD MC in plots (but do not subtract from data)"); -parser.add_option("--full2016data", dest="useFullData2016", default=False, action='store_true', help="Use all 2016 data (B to H, 35.9/fb). By default, only B to F are used (19.3/fb. Luminosity is automatically set depending on this choice"); +parser.add_option("-d", "--dry-run", dest="dryRun", default=False, action='store_true', help="Do not execute commands, just print them"); parser.add_option("--charge", dest="charge", default="", type='string', help="Select charge: p for positive, n for negative"); +parser.add_option("--outdir", dest="outdir", default="./", type='string', help="Output folder"); +parser.add_option("--tree-path", dest="treePath", default="", type='string', help="Path to trees on eos"); parser.add_option("--lumi", dest="lumi", default=35.9 , type='float', help="Integrated luminosity"); -parser.add_option("--test", dest="test", default="", type='string', help="pass the name of a folder (mandatory) to store test FR plots. It is created in plots/fake-rate/test/"); -parser.add_option("--fqcd-ranges", dest="fqcd_ranges", default="0,40,50,120", type='string', help="Pass a list of 4 comma separated numbers that represents the ranges for the two mT regions to compute the fake rate"); -parser.add_option("--pt", dest="ptvar", default="pt_granular", type='string', help="Select pT definition: pt_granular (default) or pt_coarse, or pt_finer (for muons)"); -parser.add_option("--useSkim", dest="useSkim", default=False, action='store_true', help="Use skimmed sample for fake rates"); -parser.add_option("--usePickle", dest="usePickle", default=False, action='store_true', help="Read SumWeigth from pickle file (in case the hisotgram with this number is not present in the ntuples)"); +parser.add_option("--pt", dest="ptvar", default="pt", type='string', help="Select pT definition from make_fake_rates_xvars.txt"); parser.add_option("--no-scaleFactors", dest="noScaleFactors", default=False, action='store_true', help="Don't use lepton scale factors (only PU weight)"); parser.add_option("--useSignedEta", dest="useSignedEta", default=False, action='store_true', help="Make fake rate for eta bins distinguishing eta sign"); -parser.add_option("--makeTH3-eta-pt-passID", dest="makeTH3_eta_pt_passID", default=False, action='store_true', help="This option is special. It will make the following create only the TH3D histograms with |eta|, pt and passID. This will allow to compute the FR in any binning of pt and eta (using another macro). It overrides some other options"); parser.add_option("--addOpts", dest="addOpts", default="", type='string', help="Options to pass some other options from outside to build the command"); parser.add_option("--reweightZpt", dest="reweightZpt", default=False, action='store_true', help="Use W and Z with reweighted pT"); (options, args) = parser.parse_args() -useMuon = options.useMuon addQCDMC = options.addQCDMC # trying to add QCD MC to graphs to be compared charge = str(options.charge) -testDir = str(options.test) -fqcd_ranges = str(options.fqcd_ranges) ptvar = str(options.ptvar) -useFullData2016 = options.useFullData2016 -useSkim = options.useSkim -usePickle = options.usePickle useSignedEta = options.useSignedEta addOpts = options.addOpts luminosity = options.lumi reweightZpt = options.reweightZpt -print "# useFullData2016 = " + str(useFullData2016) - if useSignedEta: - fitvar = "etal1mu" if useMuon else "etal1" - etaRange = [ '-2.4', '2.4'] if useMuon else [ '-2.5', '2.5'] + fitvar = "eta" + etaRange = [ '-2.4', '2.4'] else: - fitvar = "absetal1mu" if useMuon else "absetal1" - etaRange = [ '0.0', '2.4'] if useMuon else [ '0.0', '2.5'] - - - -if not useMuon and ptvar not in ["pt_coarse", "pt_granular"]: - print "warning: unknown pt definition %s, use pt_coarse, pt_granular" % ptvar - quit() - -if useMuon: - addQCDMC = True + fitvar = "abseta" + etaRange = [ '0.0', '2.4'] plotterPath = str(os.environ.get('CMSSW_BASE')) plotterPath = plotterPath + "/src/CMGTools/WMass/python/plotter/" @@ -59,120 +39,76 @@ chargeSelection = "" if charge != "": if charge == "p": - chargeSelection = "-A onelep positive 'LepGood1_charge > 0'" + chargeSelection = "-A accept positive 'Muon_charge[0] > 0'" elif charge == "n": - chargeSelection = "-A onelep negative 'LepGood1_charge < 0'" + chargeSelection = "-A accept negative 'Muon_charge[0] < 0'" else: - print "%s is not a valid input for charge setting: use p or n" % charge + print "## %s is not a valid input for charge setting: use p or n" % charge quit() -T="/eos/cms/store/group/dpg_ecal/comm_ecal/localreco/TREES_1LEP_80X_V3/" -if useSkim: - #T="/eos/cms/store/group/dpg_ecal/comm_ecal/localreco/TREES_1LEP_80X_V3_FRELSKIM_V5/" - T="/eos/cms/store/cmst3/group/wmass/mciprian/TREES_1LEP_80X_V3_FRELSKIM_V9/" -if useMuon: - #T="/afs/cern.ch/work/e/emanuele/TREES/TREES_wlike_mu_V1/" - T="/eos/cms/store/cmst3/group/wmass/mciprian/TREE_4_WMASS_skimMuonFR_21Jan2020/" -objName='tree' # name of TTree object in Root file, passed to option --obj in tree2yield.py -print "# used trees from: ",T - -ptcorr = "ptMuFull(LepGood1_calPt,LepGood1_eta)" if useMuon else "ptElFull(LepGood1_calPt,LepGood1_eta)" -if useFullData2016: - print "# Using full 2016 dataset" - MCweightOption = ' -W "puw2016_nTrueInt_36fb(nTrueInt)*_get_electronSF_TriggerAndID(LepGood1_pdgId,LepGood1_calPt,LepGood1_eta)*LepGood1_SF2*eleSF_L1Eff(LepGood1_pt,LepGood1_eta)" ' # with L1 prefire - -if useMuon: - #MCweightOption = ' -W "puw2016_nTrueInt_36fb(nTrueInt)*_get_muonSF_recoToSelection(LepGood1_pdgId,LepGood1_calPt,LepGood1_eta)*_get_muonSF_selectionToTrigger(LepGood1_pdgId,LepGood1_calPt,LepGood1_eta,LepGood1_charge)*prefireJetsWeight(LepGood1_eta)" ' - # test no sf, use them only for numerator - #MCweightOption = ' -W "puw2016_nTrueInt_36fb(nTrueInt)*prefireJetsWeight(LepGood1_eta)*_get_muonSF_TriggerAndIDiso(LepGood1_pdgId,LepGood1_calPt,LepGood1_eta,LepGood1_charge,(LepGood1_relIso04 < 0.15))" ' - MCweightOption = ' -W "puw2016_nTrueInt_36fb(nTrueInt)*prefireJetsWeight(LepGood1_eta)*_get_muonSF_TriggerAndIDiso(LepGood1_pdgId,LepGood1_calPt,LepGood1_eta,LepGood1_charge)" ' - # _get_muonSF_recoToSelection(LepGood1_pdgId,LepGood1_calPt,LepGood1_eta)*_get_muonSF_selectionToTrigger(LepGood1_pdgId,LepGood1_calPt,LepGood1_eta,LepGood1_charge) +T = options.treePath +objName = 'Events' +print "## used trees from: ",T +MCweightOption = ' -W "puWeight*PrefireWeight*_get_muonSF_fast_wmass(Muon_pt[0],Muon_eta[0],Muon_charge[0])" ' if options.noScaleFactors: - print "# Warning: not using lepton scale factors: only PU weight" - MCweightOption = ' -W "puw2016_nTrueInt_36fb(nTrueInt)*prefireJetsWeight(LepGood1_eta)" ' + print "## Warning: not using lepton scale factors: only PU weight" + MCweightOption = ' -W "puWeight*PrefireWeight" ' J=4 -BASECONFIG = plotterPath + "w-mass-13TeV/wmass_e" -MCA = BASECONFIG+'/mca-80X_V5_FRskim.txt' -CUTFILE =BASECONFIG+'/qcd1l_SRtrees.txt' +BASECONFIG=plotterPath + "w-mass-13TeV/testingNano/cfg" +MCA=BASECONFIG+'/mca-fakeRate.txt' +CUTFILE=BASECONFIG+'/cuts_fakeRate.txt' XVAR=ptvar FITVAR=fitvar -NUM = "fakeRateNumerator_el" - -if useMuon: - BASECONFIG=plotterPath + "w-mass-13TeV/wmass_mu" - MCA=BASECONFIG+'/mca_forMuonFR.txt' - CUTFILE=BASECONFIG+'/cuts_forMuonFR.txt' - XVAR=ptvar - FITVAR=fitvar - NUM = "fakeRateNumerator_mu" - -OPTIONS = MCA + " " + CUTFILE + " -f -P " + T + " --obj " + objName + " --s2v -j " + str(J) + " -l " + str(luminosity) + " " + str(addOpts) - -# no friends for the moment -OPTIONS += ' -F Friends '+T+'/friends/tree_Friend_{cname}.root ' -# OPTIONS += ' -F Friends '+T+'/friends/tree_FRFriend_{cname}.root ' -# OPTIONS += ' --FMC Friends '+T+'/friends/tree_TrgFriend_{cname}.root ' # only for MC, they have trigger scale factors -OPTIONS += ' --fqcd-ranges %s' % fqcd_ranges.replace(","," ") -#OPTIONS += datasetOption - -if usePickle: - OPTIONS += ' --usePickle ' - -# event weight (NB: not needed for data, and efficiency sf not good for MC since here we have fake electrons) -# use PU reweighting for BF or BH -OPTIONS += MCweightOption - -PBASE = plotterPath + "plots/fake-rate/el/" -if useMuon: - PBASE = plotterPath + "plots/fake-rate/mu/" -if testDir != "": - PBASE = PBASE.replace('plots/fake-rate/','plots/fake-rate/test/'+str(testDir)+'/') - if useMuon: - PBASE = PBASE.replace("plots/fake-rate/test/","plots/fake-rate/test_mu/") +NUM = "fakeRateNumerator" +IDFILE = plotterPath + "w-mass-13TeV/make_fake_rates_sels.txt " +XVARFILE = plotterPath + "w-mass-13TeV/make_fake_rates_xvars.txt " + +OPTIONS = MCA + " " + CUTFILE + " " + IDFILE + XVARFILE +OPTIONS += " -f -P " + T + " --obj " + objName + " --s2v -j " + str(J) + " -l " + str(luminosity) + " " + str(addOpts) + " " + MCweightOption if charge == "p": - PBASE = PBASE + "pos/" -elif charge == "n": - PBASE = PBASE + "neg/" + WPROC = " --pg 'Wmunu := Wmunu_plus' --pg 'Wtaunu := Wtaunu_plus' " +elif charge == "m": + WPROC = " --pg 'Wmunu := Wmunu_minus' --pg 'Wtaunu := Wtaunu_minus' " else: - PBASE = PBASE + "comb/" + WPROC = " --pg 'Wmunu := Wmunu_plus,Wmunu_minus' --pg 'Wtaunu := Wtaunu_plus,Wtaunu_minus' " +DATAPROC = " --pg 'data := data_B,data_C,data_D,data_E,data_F,data_F_postVFP,data_G,data_H' " -# EWKSPLIT="-p 'W_fake,W,Z,Top,DiBosons,data'" -EWKSPLIT="-p 'W_fake,W,Z,data'" -EWKEXCLUDE="--xp 'W_LO,Z_LO'" -if addQCDMC: - EWKSPLIT="-p 'QCD,W,Z,Top,DiBosons,data'" -if reweightZpt: EWKSPLIT = EWKSPLIT.replace("W,Z,","Wpt,Zpt,") +EWKSPLIT = "-p 'Wmunu,Wtaunu,Zmumu,Ztautau,Top,DiBosons,data' " + DATAPROC + WPROC -MCEFF = "python " + plotterPath + "w-mass-13TeV/dataFakeRate.py " + OPTIONS + " " + EWKSPLIT + " " + EWKEXCLUDE +" --groupBy cut " + plotterPath + "w-mass-13TeV/make_fake_rates_sels.txt " + plotterPath + "w-mass-13TeV/make_fake_rates_xvars.txt " if addQCDMC: - MCEFF += "--sp QCD " -else: - MCEFF += "--sp W_fake " + EWKSPLIT += " -p QCD --sp QCD " +#if reweightZpt: EWKSPLIT = EWKSPLIT.replace("W,Z,","Wpt,Zpt,") # FIXME -MCEFF += " --sP " + NUM + " --sP " + XVAR + " --sP " + FITVAR + " " + FITVAR + " --ytitle 'Fake rate' " -MCEFF += " --fixRatioRange --maxRatioRange 0.7 1.29 " # ratio for other plots -LEGEND=" --legend=TL --fontsize 0.05 --legendWidth 0.4" -RANGES=" --showRatio --ratioRange 0.50 1.99 --yrange 0 1.0 --xcut 25 100 " +MCEFF = "python " + plotterPath + "w-mass-13TeV/dataFakeRateLite.py " + OPTIONS + " " + EWKSPLIT -MCEFF += (LEGEND+RANGES) +MCEFF += " --sP " + NUM + " --sP " + XVAR + " --sP " + FITVAR + " --fitVar " + FITVAR -if addQCDMC: - MCGO=MCEFF + " --algo=fQCD --compare QCD_prefit,data_fqcd,data_prefit " +thisRange = etaRange[0].replace(".","p").replace("-","m") + "_" + etaRange[-1].replace(".","p").replace("-","m") +fout = "/fr_sub_eta_" + thisRange + ".root " +if useSignedEta: + cut = " -A accept eta 'Muon_eta[0]>" + str(etaRange[0]) + " && Muon_eta[0]<" + str(etaRange[-1]) + "' " + str(chargeSelection) else: - MCGO=MCEFF + " --algo=fQCD --compare W_fake_prefit,data_fqcd,data_prefit " - -for i in range(0,len(etaRange)-1): - thisRange = etaRange[i].replace(".","p").replace("-","m") + "_" + etaRange[i+1].replace(".","p").replace("-","m") - if useSignedEta: - print MCEFF + " -o " + PBASE + "/fr_sub_eta_" + thisRange + ".root --bare -A onelep eta 'LepGood1_eta>" + str(etaRange[i]) + " && LepGood1_eta<" + str(etaRange[i+1]) + "' " + str(chargeSelection) + "\n" - else: - print MCEFF + " -o " + PBASE + "/fr_sub_eta_" + thisRange + ".root --bare -A onelep eta 'abs(LepGood1_eta)>" + str(etaRange[i]) + " && abs(LepGood1_eta)<" + str(etaRange[i+1]) + "' " + str(chargeSelection) + "\n" - - print "\n\n" + cut = " -A accept eta 'abs(Muon_eta[0])>" + str(etaRange[0]) + " && abs(Muon_eta[0])<" + str(etaRange[-1]) + "' " + str(chargeSelection) +finalCommand = MCEFF + " -o " + options.outdir + fout + cut + "\n" +# copy some stuff for reference +os.system("cp {f} {o}".format(f=MCA,o=options.outdir)) +os.system("cp {f} {o}".format(f=CUTFILE,o=options.outdir)) +try: + with open(options.outdir+'/command.txt', 'w') as f: + f.write(finalCommand+'\n') +except IOError as e: + print("## Couldn't open or write to file %s (%s)." % (options.outdir+'/command.txt', e)) +if options.dryRun: + print finalCommand +else: + print "## Executing the command\n" + print finalCommand + print "\n\n" + os.system(finalCommand) diff --git a/WMass/python/plotter/w-mass-13TeV/make_fake_rates_sels.txt b/WMass/python/plotter/w-mass-13TeV/make_fake_rates_sels.txt index dc170de02952..b7562a7570c2 100644 --- a/WMass/python/plotter/w-mass-13TeV/make_fake_rates_sels.txt +++ b/WMass/python/plotter/w-mass-13TeV/make_fake_rates_sels.txt @@ -1,12 +1 @@ -#fakeRateNumerator_el: LepGood1_hltId > 0 && pass_FakerateNumerator2016((abs(LepGood1_eta)<1.479),LepGood1_tightId,LepGood1_dxy,LepGood1_dz,LepGood1_lostHits,LepGood1_convVeto,LepGood1_relIso04EA) && LepGood1_tightChargeFix == 2: 2,-0.5,1.5; Title="medium ID EGM", MarkerColor=4, MarkerStyle=21, MarkerSize=1.3 -# -fakeRateNumerator_el: LepGood1_hltId > 0 && LepGood1_customId == 1 && LepGood1_tightChargeFix == 2: 2,-0.5,1.5; Title="custom ID EGM", MarkerColor=4, MarkerStyle=21, MarkerSize=1.3 -#fakeRateNumerator_el: LepGood1_hltId > 0 && pass_FakerateNumerator_medium2016(fabs(LepGood1_eta)<1.479,LepGood1_tightId,LepGood1_dxy,LepGood1_dz,LepGood1_lostHits,LepGood1_convVeto,LepGood1_relIso04EA): 2,-0.5,1.5; Title="custom ID EGM", MarkerColor=4, MarkerStyle=21, MarkerSize=1.3 -# -# Run2 cut-based ID: https://twiki.cern.ch/twiki/bin/viewauth/CMS/CutBasedElectronIdentificationRun2 -# -# muon cuts to be revisited, they are taken from 8 TeV -MuonIso: LepGood1_relIso04 < 0.15 : 2,-0.5,1.5; Title="muon isolation", MarkerColor=4, MarkerStyle=21, MarkerSize=1.3 -MuonTightIso: LepGood1_tightId > 0 && LepGood1_relIso04 < 0.12 : 2,-0.5,1.5; Title="muon isolation", MarkerColor=4, MarkerStyle=21, MarkerSize=1.3 - -fakeRateNumerator_mu: LepGood1_relIso04 < 0.15: 2,-0.5,1.5; Title="Muon isolation", MarkerColor=4, MarkerStyle=21, MarkerSize=1.3 +fakeRateNumerator: Muon_pfRelIso04_all[0] < 0.15: 2,-0.5,1.5; Title="Muon isolation", MarkerColor=4, MarkerStyle=21, MarkerSize=1.3 diff --git a/WMass/python/plotter/w-mass-13TeV/make_fake_rates_xvars.txt b/WMass/python/plotter/w-mass-13TeV/make_fake_rates_xvars.txt index ced67f0c4b04..48e345bc1c3d 100644 --- a/WMass/python/plotter/w-mass-13TeV/make_fake_rates_xvars.txt +++ b/WMass/python/plotter/w-mass-13TeV/make_fake_rates_xvars.txt @@ -1,28 +1,5 @@ -#pt_coarse: LepGood_pt: [ 25,27,30,35,40,50,65,100 ] ; XTitle="lepton p_{T} (GeV)", Density=True -#pt_coarse: LepGood_pt: [ 25,30,32,34,36,38,40,42,44,46,50,60 ] ; XTitle="lepton p_{T} (GeV)", Density=True -#pt_granular: ptElFull(LepGood1_calPt,LepGood1_eta) : [ 30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,46,48,50,54,60 ] ; XTitle="lepton p_{T} (GeV)", Density=True -pt_granular: ptElFull(LepGood1_calPt,LepGood1_eta) : [ 30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,52,54,57,60,65 ] ; XTitle="lepton p_{T} (GeV)" -pt_coarse: ptElFull(LepGood1_calPt,LepGood1_eta) : [ 30,34,38,42,46,50,54,60 ] ; XTitle="lepton p_{T} (GeV)" -# pt_granular: ptElFull(LepGood1_calPt,LepGood1_eta) : [ 25,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,46,50,54,60 ] ; XTitle="lepton p_{T} (GeV)", Density=True -# pt_coarse: ptElFull(LepGood1_calPt,LepGood1_eta) : [ 25,30,34,38,42,46,50,54,60 ] ; XTitle="lepton p_{T} (GeV)", Density=True -#pt_finer: LepGood_pt: [ 25,27,30,35,45,55,100 ] ; XTitle="lepton p_{T} (GeV)", Density=True -pt_finer: ptMuFull(LepGood1_calPt,LepGood1_eta): [ 26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,52,54,57,60,65 ] ; XTitle="lepton p_{T} (GeV)" +pt: Muon_pt[0] : [ 26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53, 54,55,56,57,58,59,60,61,62,63,64,65 ] ; XTitle="Muon p_{T} (GeV)" -pfmt : mt_2(met_pt, met_phi, ptElFull(LepGood1_calPt,LepGood1_eta), LepGood1_phi) : 30,0,120; XTitle="M_{T}(l\, E_{T}^{miss}) (GeV)" -trkmt : mt_2(met_trkPt,met_trkPhi,ptElFull(LepGood1_calPt,LepGood1_eta) ,LepGood1_phi) : 30,0,120; XTitle="M_{T}(l\, E_{T}^{miss}) (GeV)" -pfmtfix : mt_2(met_pt, met_phi, 35,LepGood1_phi) : 30,0,120; XTitle="M_{T}^{fix}(l\, E_{T}^{miss}) (GeV)" -#trkmtfix : mt_2(met_trkPt,met_trkPhi,35,LepGood1_phi) : 30,0,120; XTitle="M_{T}^{fix}(l\, E_{T}^{miss}) (GeV)" -trkmtfix : tkmt_tkmetEleCorr(met_trkPt,met_trkPhi,ptElFull(LepGood1_calPt,LepGood1_eta),LepGood1_phi, abs(LepGood1_dz)<0.1 ) : 30,0,120; XTitle="M_{T}^{fix}(l\, E_{T}^{miss}) (GeV)" -met : met_pt : 24,0,120; XTitle="E_{T}^{miss} (GeV)" +abseta: abs(Muon_eta[0]) : [ 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4]; XTitle="Muon |#eta|" - -absetal1: abs(LepGood1_eta) : [ 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.4442, 1.479, 1.5, 1.566, 1.6, 1.7, 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5 ]; XTitle="lepton |#eta|" -etal1: LepGood1_eta : [ -2.5, -2.4, -2.3, -2.2, -2.1, -2.0, -1.9, -1.8, -1.7, -1.6, -1.566, -1.5, -1.479, -1.4442, -1.4, -1.3, -1.2, -1.1, -1.0, -0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, -0.1, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.4442, 1.479, 1.5, 1.566, 1.6, 1.7, 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5 ]; XTitle="lepton #eta" - -# for muons -absetal1mu: abs(LepGood1_eta) : [ 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4 ]; XTitle="lepton |#eta|" - -etal1mu: LepGood1_eta : [ -2.4, -2.3, -2.2, -2.1, -2.0, -1.9, -1.8, -1.7, -1.6, -1.5, -1.4, -1.3, -1.2, -1.1, -1.0, -0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, -0.1, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4]; XTitle="lepton #eta" - -# as Marc (old) -#etal1mu: LepGood1_eta : [ -2.4, -2.2, -2.05, -1.9, -1.75, -1.6, -1.45, -1.3, -1.15, -1.0, -0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, -0.1, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.15, 1.3, 1.45, 1.6, 1.75, 1.9, 2.05, 2.2, 2.4]; XTitle="lepton #eta" +eta: Muon_eta[0] : [ -2.4, -2.3, -2.2, -2.1, -2.0, -1.9, -1.8, -1.7, -1.6, -1.5, -1.4, -1.3, -1.2, -1.1, -1.0, -0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, -0.1, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4 ]; XTitle="Muon #eta" diff --git a/WMass/python/plotter/w-mass-13TeV/make_wmass_cards.py b/WMass/python/plotter/w-mass-13TeV/make_wmass_cards.py index ec60bf87acee..060ac23f166d 100644 --- a/WMass/python/plotter/w-mass-13TeV/make_wmass_cards.py +++ b/WMass/python/plotter/w-mass-13TeV/make_wmass_cards.py @@ -3,6 +3,17 @@ import re, sys, os, os.path, subprocess, json, ROOT import numpy as np +def printReturnValueInScript(fileObj, scriptName=None): + fileObj.write('retval=$?\n') # must be evaluated immediately after the python command in the shell script + if scriptName != None: + fileObj.write('echo "Script name = %s"\n' % scriptName) + fileObj.write('echo "return value = ${retval}"\n') + fileObj.write('if [[ $retval != 0 ]]; then\n') + fileObj.write(' exit $retval\n') + fileObj.write('fi\n') + fileObj.write('\n') + + def getShFile(jobdir, name): tmp_srcfile_name = jobdir+'/job_{i}.sh'.format(i=name) tmp_srcfile = open(tmp_srcfile_name, 'w') @@ -44,9 +55,10 @@ def printSysts(systs=[],process="Wmunu"): print systs print '-'*30 - -NVPTBINS=2 # usually it would be 10, use less for tests -NPDFSYSTS=2 # Hessian variations (from 1 to 100), use less for tests +data_eras = ["B", "C", "D", "E", "F", "F_postVFP", "G", "H"] +MASSVARIATIONS = [10* i for i in range(1,3)] # max would be 11, to pick the proper branches such as massShift10MeVUp +NVPTBINS=2 # usually it would be 10, use less for tests, e.g. 2 +NPDFSYSTS=2 # Hessian variations (from 1 to 100), use less for tests, e.g. 2 nominals=[] # array containing the nominal for single process for which we have dedicated corrections (not included in bkg_and_data) # # dictionaries associating an array containing systs variations to each relevant process @@ -59,7 +71,6 @@ def printSysts(systs=[],process="Wmunu"): #coefficients = ['ac'] + ['a'+str(i) for i in range(8)] coefficients = [''] # simplifies life for now, but do not use empty array, or it will inhibit some loops -data_eras = ["B", "C", "D", "E", "F", "F_postVFP", "G", "H"] def getMcaIncl(mcafile,incl_mca='incl_sig'): incl_file='' @@ -132,23 +143,17 @@ def writeQCDScaleSystsToMCA(mcafile,odir,syst="qcd",incl_mca='incl_wmunu',scales ## make the mcas for the scales and mW and stuff for scale in scales: - ## mW now doesn't just have Up and Down. make many + ## mW weights managed here if scale == "mW": - ############################# - # FIXME: STILL TO BE UPDATED - ############################# - - ## loop on all the masses we want. in index of 5 MeV variations each - masses = ['mass_{m}'.format(m = j).replace('-','m') for j in range(-20,0)] - masses += ['mass_0'] - masses += ['mass_p{m}'.format(m = j).replace('-','m') for j in range(1,21)] + masses = [] + for idir in ['Up','Down']: + for mvar in MASSVARIATIONS: + masses.append("massShift{v}MeV{d}".format(v=mvar,d=idir)) for mass in masses: - postfix = "_{syst}{mval}".format(syst=scale,mval=mass) + postfix = "_{m}".format(m=mass) mcafile_syst = open(filename, 'a') if append else open("%s/mca_%s%s.txt" % (odir,process,postfix), "w") - - ## central mass is 80419 MeV, the closest we have to that is 80420. will scale +- 50 MeV, i.e. 80470 for Up and 80370 for Dn fstring = str(mass) mcafile_syst.write(incl_mca+postfix+' : + ; IncludeMca='+incl_file+', AddWeight="'+fstring+'", PostFix="'+postfix+'" \n') if process not in qcdsysts: @@ -282,6 +287,8 @@ def addKaMuCaSysts(): parser.add_option('--vpt-weight', dest='procsToPtReweight', action="append", default=[], help="processes to be reweighted according the measured/predicted DY pt. Default is none (possible W,Z)."); parser.add_option('--wlike', dest='wlike', action="store_true", default=False, help="Make cards for the wlike analysis. Default is wmass"); parser.add_option('--add-option', dest="addOptions", type="string", default=None, help="add these options to the option string when running the histograms"); + parser.add_option('--auto-resub', dest='automaticResubmission', action="store_true", default=False, help="Use condor features for automatic job resubmission in case of failures"); + parser.add_option("--n-resub", dest="nResubmissions", type=int, default=2, help="Number of automatic resubmission to be attempted in case of failure when running a job (needs --auto-resub)"); (options, args) = parser.parse_args() if len(sys.argv) < 6: @@ -342,15 +349,20 @@ def addKaMuCaSysts(): zmasses = [] # ["mW"] ptBinnedScalesForW = False else: - wmasses = [] #["mW"] + wmasses = ["mW"] zmasses = [] ptBinnedScalesForW = True + # overrideDecorrelation is used to avoid decorrelating systs by angular coefficients + # Wmunu writeQCDScaleSystsToMCA(MCA,outdir+"/mca",scales=scales+wmasses,incl_mca='incl_wmunu', ptBinned=ptBinnedScalesForW, overrideDecorrelation=False) + # Wtaunu writeQCDScaleSystsToMCA(MCA,outdir+"/mca",scales=scales ,incl_mca='incl_wtaunu', ptBinned=ptBinnedScalesForW, overrideDecorrelation=True) + # Zmumu writeQCDScaleSystsToMCA(MCA,outdir+"/mca",scales=scales+zmasses,incl_mca='incl_zmumu', ptBinned=options.wlike, overrideDecorrelation=True) + # Ztautau writeQCDScaleSystsToMCA(MCA,outdir+"/mca",scales=scales ,incl_mca='incl_ztautau', ptBinned=options.wlike, overrideDecorrelation=True) if options.addQEDSyst: @@ -360,7 +372,8 @@ def addKaMuCaSysts(): writeFSRSystsToMCA(MCA,outdir+"/mca") # on W + jets # apparently needed to make mca for nominal samples to run faster, to be checked - for proc in ['zmumu','wtaunu','ztautau']: + procs_nomi_mca = ['wtaunu','ztautau'] + (['wmunu'] if options.wlike else ['zmumu']) + for proc in procs_nomi_mca: if proc not in nominals: writeNominalSingleMCA(MCA,outdir+"/mca",incl_mca='incl_{p}'.format(p=proc)) @@ -384,8 +397,8 @@ def addKaMuCaSysts(): #print "-"*30 if options.wlike: - POSCUT=" -A alwaystrue positive 'evt%2 != 0' " - NEGCUT=" -A alwaystrue negative 'evt%2 == 0' " + POSCUT=" -A alwaystrue positive 'event%2 != 0' " + NEGCUT=" -A alwaystrue negative 'event%2 == 0' " SIGPROC='Zmumu' SIGSUFFIX='zmumu' else: @@ -448,10 +461,9 @@ def addKaMuCaSysts(): # let's not print too many things # print "Running the systematic: ",var ## --- - job_group = [] ## group ## now go and make the submit commands - xpsel=' --xp "{sig}_{antich}.*,{antisig}.*,Top,DiBosons,Ztautau.*,Wtaunu.*,data.*"'.format(sig=SIGPROC,antisig=antiSIGPROC,antich=antich,ch=charge) + xpsel=' --xp "{sig}_{antich}.*,{antisig}.*,Top,DiBosons,Ztautau.*,Wtaunu.*,data.*"'.format(sig=SIGPROC,antisig=antiSIGPROC,antich=antich,ch=charge) if len(anticoeff): excl_anticoeff = ','.join(SIGPROC+"_"+charge+'_'+ac+'.*' for ac in anticoeff) xpsel += " --xp {ahel}".format(ahel=excl_anticoeff) @@ -461,7 +473,17 @@ def addKaMuCaSysts(): syst = '' if ivar==0 else var ## for kamuca corrections, there is not any _sigsuffix, so add an "_" to distinguish better the files if 'kalPt' in var: syst = '_{sfx}_{var}'.format(sfx=SIGSUFFIX,var=var) - dcname = "{sig}_{charge}{coeff}{syst}".format(sig=SIGPROC, charge=charge, coeff="" if coeff=='' else ('_'+coeff+'_'),syst=syst) + dcname = "{sig}_{charge}{coeff}{syst}".format(sig=SIGPROC, charge=charge, coeff="" if coeff=='' else ('_'+coeff),syst=syst) + + ## for Wlike, must transform process name for signal (Zmumu) into Zmumu_plus or Zmumu_minus. + ## one could directly change the name of the histogram inside the output root file, after it has been created, but maybe better to do it now. + ## This can be achieved either by using the IncludeMca statement and adding the '_plus' or '_minus' postfix to the process name, or by using the --pg option to change the signal process name + ## for now we will try the second option, where the new process name is basically dcname (because one has to include the general case with systematics) + if options.wlike: + #xpsel += " -p Zmumu_{ch} --pg 'Zmumu_{ch} := Zmumu' ".format(ch=charge) + syst_postfix = "" if ivar==0 else syst + xpsel += " -p {dc} --pg '{dc} := Zmumu{s}' ".format(dc=dcname,s=syst_postfix) + ## reweight the boson-pT here zptWeight = 'dyptWeight(Vpt_preFSR,{isZ})'.format(isZ=0 if SIGPROC=="Wmunu" else 1) @@ -470,11 +492,6 @@ def addKaMuCaSysts(): fullWeight = options.weightExpr+'*'+zptWeight if SIGPROC in options.procsToPtReweight else options.weightExpr BIN_OPTS = OPTIONS + " -W '" + fullWeight+ "'" + " -o "+dcname+" --od "+outdir + xpsel + ycut + SYST_OPTION - ## do not do by pdf weight pdfmatch = re.search('pdf(\d+)',var) - ## do not do by pdf weight if pdfmatch: - ## do not do by pdf weight BIN_OPTS += " -W 'pdfRatioHel(abs(prefsrw_y),prefsrw_pt,prefsrw_costcs,evt,{pol},{ipdf})' ".format(pol=helmap[helicity],ipdf=pdfmatch.group(1)) - ## --- - ## now we accumulate all the commands to be run for all processes if options.queue: mkShCardsCmd = "python makeHistogramsWMass.py {args} \n".format(dir = os.getcwd(), args = IARGS+" "+BIN_OPTS) @@ -490,7 +507,7 @@ def addKaMuCaSysts(): print "Making histograms for other background processes with charge ", charge chargecut = POSCUT if charge=='plus' else NEGCUT ## remove W or Z signal processes and others that aren't needed - xpsel=' --xp "{sig}.*,{antisig}.*,Wtaunu.*,Ztautau.*,data.*" '.format(sig=SIGPROC,antisig=antiSIGPROC) + xpsel=' --asimov --xp "{sig}.*,{antisig}.*,Wtaunu.*,Ztautau.*,data.*" '.format(sig=SIGPROC,antisig=antiSIGPROC) ## now make the names of the cards etc dcname = "otherBkgHisto_{charge}".format(charge=charge) BIN_OPTS=OPTIONS + " -W '" + options.weightExpr + "'" + " -o "+dcname+" --od "+outdir + xpsel + chargecut @@ -505,7 +522,7 @@ def addKaMuCaSysts(): for era in data_eras: print "Making histograms for data {e} with charge {ch}".format(e=era,ch=charge) excluded_eras = ["data_{e}".format(e=e) for e in data_eras if e != era] - psel=" -p 'data,data_fakes' --pg 'data := data_{era}' --xp '{x}'".format(era=era, x=",".join(excluded_eras)) + psel=" -p 'data,data_fakes' --pg 'data := data_{era}' --pg 'data_fakes := data_{era}_fakes' --xp '{x}'".format(era=era, x=",".join(excluded_eras)) ## now make the names of the cards etc dcname = "dataHisto_{era}_{charge}".format(era=era,charge=charge) BIN_OPTS=OPTIONS + " -W '" + options.weightExpr + "'" + " -o "+dcname+" --od "+outdir + psel + chargecut @@ -534,12 +551,13 @@ def addKaMuCaSysts(): antich = 'plus' if charge == 'minus' else 'minus' ## loop on the Z(W) related systematics for Wmass (Wlike) for ivar,var in enumerate(antisigsyst): - + if antich in var: + #print "skipping because ",antich," is in ",var + continue ## nominal first, then the variations if ivar==0: - # the following would be faster with DY-only, but it misses the lines for the Z_lepeff systs - # IARGS = ARGS.replace(MCA,"{outdir}/mca/mca_zmumu_nominal.txt".format(outdir=outdir)) - IARGS = ARGS + # the following would be faster with DY-only, but it misses processes for possible systematics, like the lines for the Z_lepeff systs that we had in the past + IARGS = ARGS.replace(MCA,"{outdir}/mca/mca_{p}_nominal.txt".format(outdir=outdir,p=antiSIGSUFFIX)) else: IARGS = ARGS.replace(MCA,"{outdir}/mca/mca_{p}{syst}.txt".format(outdir=outdir,p=antiSIGSUFFIX,syst=var)) IARGS = IARGS.replace(SYSTFILE,"{outdir}/mca/systEnv-dummy.txt".format(outdir=outdir)) @@ -547,9 +565,9 @@ def addKaMuCaSysts(): ## --- # exclude everything that does not start with antiSIGPROC - # for Wmass the antisignal is the Zmumu, and the charge is not in process name in the mca file + # for Wmass the antisignal is the Zmumu, and charge should not be used in the histogram name # for Wlike, the antisignal is Wmunu and has to pick the samples with proper charge - psel=' -p "^{antisig}_{ch}.*" --asimov '.format(antisig=antiSIGPROC,ch="" if SIGPROC=='Wmunu' else charge) + psel=' -p "^{antisig}{ch}.*" --asimov '.format(antisig=antiSIGPROC,ch="" if SIGPROC=='Wmunu' else ("_"+charge)) syst = '' if ivar==0 else var ## make names for the files and outputs @@ -567,7 +585,7 @@ def addKaMuCaSysts(): fullJobList.add(mkShCardsCmd) ## --- - ## repetition for Wtau, but better to keep Z/Tau cards separated (faster jobs) + ## repetition for Wtau wtausyst = [''] # nominal if "wtaunu" in pdfsysts: wtausyst += pdfsysts["wtaunu"] @@ -583,7 +601,9 @@ def addKaMuCaSysts(): chcut = POSCUT if charge=='plus' else NEGCUT antich = 'plus' if charge == 'minus' else 'minus' for ivar,var in enumerate(wtausyst): - + if antich in var: + #print "skipping because ",antich," is in ",var + continue ## 0 is nominal again if ivar==0: IARGS = ARGS.replace(MCA,"{outdir}/mca/mca_wtaunu_nominal.txt".format(outdir=outdir)) @@ -593,7 +613,7 @@ def addKaMuCaSysts(): # print "Running the Wtaunu with systematic: ",var # exclude everything that does not start with Wtaunu with the proper charge - psel=' -p "^Wtaunu_{ch}.*" --asimov '.format(antisig=antiSIGPROC,ch=charge) + psel=' -p "^Wtaunu_{ch}.*" --asimov '.format(ch=charge) syst = '' if ivar==0 else var ## make names for files etc again @@ -629,7 +649,9 @@ def addKaMuCaSysts(): chcut = POSCUT if charge=='plus' else NEGCUT antich = 'plus' if charge == 'minus' else 'minus' for ivar,var in enumerate(ztausyst): - + if antich in var: + #print "skipping because ",antich," is in ",var + continue ## 0 is nominal again if ivar==0: IARGS = ARGS.replace(MCA,"{outdir}/mca/mca_ztautau_nominal.txt".format(outdir=outdir)) @@ -638,8 +660,8 @@ def addKaMuCaSysts(): IARGS = IARGS.replace(SYSTFILE,"{outdir}/mca/systEnv-dummy.txt".format(outdir=outdir)) # print "Running the Ztautau with systematic: ",var - # exclude everything that does not start with Ztautau with the proper charge - psel=' -p "^Ztautau_.*" --asimov ' + # exclude everything that does not start with Ztautau + psel=' -p "^Ztautau.*" --asimov ' syst = '' if ivar==0 else var ## make names for files etc again @@ -680,18 +702,22 @@ def addKaMuCaSysts(): bkglist = [] datalist = [] siglist = [] - for i in reslist: - if 'otherBkgHisto_' in i: + for n,i in enumerate(reslist): + #print "%d)\n %s\n\n" % (n,i) + if '-o otherBkgHisto_' in i: bkglist.append(i) - elif 'dataHisto_' in i: + elif '-o dataHisto_' in i: datalist.append(i) else: siglist.append(i) + print "\n#sig = %s\n#bkg = %d\n#data = %d" %(len(siglist),len(bkglist),len(datalist)) + print "Note: #sig is the number of real signal jobs when option -s was specified, otherwise it is simply the number of jobs that are not data or other backgrounds (currently they include W/Z->tau and anti-signal) \n" + ## get the number of total submit jobs from the bunching nj = len(siglist) print 'full number of python commands to submit', nj+len(bkglist)+len(datalist) - print ' ... grouping them into bunches of', options.groupJobs + print ' ... grouping #sig into bunches of', options.groupJobs if not nj%options.groupJobs: njobs = int(nj/options.groupJobs) @@ -712,6 +738,8 @@ def addKaMuCaSysts(): pm = 'plus' if '-A alwaystrue positive' in ib else 'minus' tmp_srcfile_name, tmp_srcfile = getShFile(jobdir, 'bkg_'+pm) tmp_srcfile.write(ib) + if options.automaticResubmission: + printReturnValueInScript(tmp_srcfile, tmp_srcfile_name) tmp_srcfile.close() sourcefiles.append(tmp_srcfile_name) @@ -720,18 +748,23 @@ def addKaMuCaSysts(): era = ib.split("data := data_")[1].split("'")[0] tmp_srcfile_name, tmp_srcfile = getShFile(jobdir, 'data_'+era+'_'+pm) tmp_srcfile.write(ib) + if options.automaticResubmission: + printReturnValueInScript(tmp_srcfile, tmp_srcfile_name) tmp_srcfile.close() sourcefiles.append(tmp_srcfile_name) ## now do the others. + tag = "sig_" if options.signalCards else "otherSig_" for ij in range(njobs): - tmp_srcfile_name, tmp_srcfile = getShFile(jobdir, "sig_"+str(ij)) + tmp_srcfile_name, tmp_srcfile = getShFile(jobdir, tag+str(ij)) tmp_n = options.groupJobs while len(siglist) and tmp_n: tmp_pycmd = siglist[0] tmp_srcfile.write(tmp_pycmd+'\n') siglist.remove(tmp_pycmd) tmp_n -= 1 + if options.automaticResubmission: + printReturnValueInScript(tmp_srcfile, tmp_srcfile_name) tmp_srcfile.close() sourcefiles.append(tmp_srcfile_name) ## --- @@ -739,21 +772,37 @@ def addKaMuCaSysts(): ## now on to the usual condor magic dummy_exec = open(jobdir+'/dummy_exec.sh','w') dummy_exec.write('#!/bin/bash\n') - dummy_exec.write('bash $*\n') + dummy_exec.write('script=$1\n') + dummy_exec.write('bash $script\n') + dummy_exec.write('retval=$?\n') + # make exit code for success explicit, it can be used by condor to resubmit jobs + if options.automaticResubmission: + dummy_exec.write('attempt=$2\n') + dummy_exec.write('echo "attempt = ${attempt}"\n') + dummy_exec.write('echo "script = ${script}"\n') + dummy_exec.write('echo "final return value = ${retval}"\n') + dummy_exec.write('exit $retval\n') dummy_exec.close() condor_file_name = jobdir+'/condor_submit_'+('background' if options.bkgdataCards else 'signal')+'.condor' condor_file = open(condor_file_name,'w') - condor_file.write('''Universe = vanilla -Executable = {de} -use_x509userproxy = true -Log = {ld}/$(ProcId).log -Output = {od}/$(ProcId).out -Error = {ed}/$(ProcId).error + condor_file.write('Universe = vanilla\n') + condor_file.write('Executable = {de}\n'.format(de=os.path.abspath(dummy_exec.name))) + condor_file.write('use_x509userproxy = true\n') + # keep one .log in case of resubmission, text is appended there + # but create a different .err and .out when resubmitting failures automatically + condor_file.write(''' +Log = {ld}/{sb}_$(ClusterId)_$(ProcId).log +Output = {od}/{sb}_$(ClusterId)_$(ProcId){text}.out +Error = {ed}/{sb}_$(ClusterId)_$(ProcId){text}.error getenv = True environment = "LS_SUBCWD={here}" request_memory = 2000 -+MaxRuntime = {rt}\n'''.format(de=os.path.abspath(dummy_exec.name), ld=os.path.abspath(logdir), od=os.path.abspath(outdirCondor), ed=os.path.abspath(errdir), rt=getCondorTime(options.queue), here=os.environ['PWD'] ) ) ++MaxRuntime = {rt}\n'''.format(ld=os.path.abspath(logdir), od=os.path.abspath(outdirCondor), + ed=os.path.abspath(errdir), + sb="sig" if options.signalCards else "bkg", + text="_trial$$([NumJobStarts])" if options.automaticResubmission else "", + rt=getCondorTime(options.queue), here=os.environ['PWD'] ) ) ## --- if options.jobName != None: @@ -762,11 +811,22 @@ def addKaMuCaSysts(): if os.environ['USER'] in ['mdunser', 'psilva', 'bendavid', 'kelong']: condor_file.write('+AccountingGroup = "group_u_CMST3.all"\n') if os.environ['USER'] in ['mciprian']: - condor_file.write('+AccountingGroup = "group_u_CMS.CAF.ALCA.all"\n') + condor_file.write('+AccountingGroup = "group_u_CMS.CAF.ALCA"\n') condor_file.write('\n\n') + # can retry up tp N times, if the job fails + # when it fails, keep it on hold for 1 minute before releasing it again + # (in case the error was due to temporary problems in either the filesystem or eos itself) + if options.automaticResubmission: + condor_file.write(''' +max_retries = {n} +success_exit_code = 0 +retry_until = (ExitCode == 0) && (NumJobStarts < {n1}) ++OnExitHold = (ExitCode != 0) && (NumJobStarts < {n1}) +periodic_release = (NumJobStarts < {n1}) && ((time() - EnteredCurrentStatus) > 60)\n\n'''.format(n=options.nResubmissions,n1=options.nResubmissions+1)) + for sf in sourcefiles: - condor_file.write('arguments = {sf} \nqueue 1 \n\n'.format(sf=os.path.abspath(sf))) + condor_file.write('arguments = {sf} {trial}\nqueue 1 \n\n'.format(sf=os.path.abspath(sf),trial="$$([NumJobStarts])" if options.automaticResubmission else "")) condor_file.close() ## --- diff --git a/WMass/python/plotter/w-mass-13TeV/rollingFunctions.py b/WMass/python/plotter/w-mass-13TeV/rollingFunctions.py index 2f656d72572d..1b7384b36446 100644 --- a/WMass/python/plotter/w-mass-13TeV/rollingFunctions.py +++ b/WMass/python/plotter/w-mass-13TeV/rollingFunctions.py @@ -27,10 +27,10 @@ def dressed2D(h1d,binning,name,title=''): h2_1 = ROOT.TH2F(name, title, n1, min1, max1, n2, min2, max2) #h2_backrolled_1 = roll1Dto2D(h1_1, h2_1 ) h2_backrolled_1 = roll1Dto2D(h1d, h2_1 ) - h2_backrolled_1 .GetXaxis().SetTitle('lepton #eta') - h2_backrolled_1 .GetYaxis().SetTitle('lepton p_{T} (GeV)') - h2_backrolled_1 .GetZaxis().SetRangeUser(0.01*h2_backrolled_1.GetMaximum(),1.1*h2_backrolled_1.GetMaximum()) - #h2_backrolled_1 .GetZaxis().SetRangeUser(0,1.1*h2_backrolled_1.GetMaximum()) + # better to avoid these settings here + #h2_backrolled_1 .GetXaxis().SetTitle('lepton #eta') + #h2_backrolled_1 .GetYaxis().SetTitle('lepton p_{T} (GeV)') + #h2_backrolled_1 .GetZaxis().SetRangeUser(0.01*h2_backrolled_1.GetMaximum(),1.1*h2_backrolled_1.GetMaximum()) return h2_backrolled_1 def unroll2Dto1D(h,newname='',cropNegativeBins=True, silent=False): diff --git a/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/cuts_fakeRate.txt b/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/cuts_fakeRate.txt new file mode 100644 index 000000000000..cef70e7149de --- /dev/null +++ b/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/cuts_fakeRate.txt @@ -0,0 +1,12 @@ +alwaystrue : 1 +onemuon : nMuon == 1 && nVetoElectrons == 0 +trigger : HLT_SingleMu24 > 0 && Muon_hasTriggerMatch[0] != 0 +accept : abs(Muon_eta[0]) < 2.4 && Muon_pt[0] > 26 && Muon_pt[0] < 65 +muonID : Muon_mediumId[0] == 1 +jets : nJet_MuonClean >=1 && Jet_pt[Jet_MuonClean_jetIdx[0]] > 30 && Jet_jetId[Jet_MuonClean_jetIdx[0]]>=6 && (Jet_pt[Jet_MuonClean_jetIdx[0]] > 50 || Jet_puId[Jet_MuonClean_jetIdx[0]]>=4) +dxy : abs(Muon_dxy[0]) < 0.05 +dz : abs(Muon_dz[0]) < 0.2 +## isolation is not used here +#pfRelIso04 : Muon_pfRelIso04_all[0] < 0.15 +## mT cut to be added once we understand what MET to use +mtl1pf40 : mt_2(Muon_pt[0],Muon_phi[0],MET_T1_pt,MET_T1_phi) < 40. diff --git a/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/cuts_test.txt b/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/cuts_test.txt index ccf913066ea8..42fd23bc382f 100644 --- a/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/cuts_test.txt +++ b/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/cuts_test.txt @@ -1,9 +1,10 @@ alwaystrue : 1 -onemuon : nMuon == 1 && nElectron == 0 -trigger : HLT_IsoMu24 > 0 || HLT_IsoTkMu24 > 0 -accept : abs(Muon_eta[0]) < 2.4 && Muon_pt[0] > 26 && Muon_pt[0] < 60 +onemuon : nMuon == 1 && nVetoElectrons == 0 +trigger : HLT_SingleMu24 > 0 && Muon_hasTriggerMatch[0] != 0 +accept : abs(Muon_eta[0]) < 2.4 && valueInsideRange(Muon_pt[0],26,45) muonID : Muon_mediumId[0] == 1 pfRelIso04 : Muon_pfRelIso04_all[0] < 0.15 -dxy : abs(Muon_dxy[0]) < 0.02 -dz : abs(Muon_dz[0]) < 0.1 -mt_ChsMET: mt_2(Muon_pt[0],Muon_phi[0],ChsMET_pt,ChsMET_phi) > 40. +dxy : abs(Muon_dxy[0]) < 0.05 +dz : abs(Muon_dz[0]) < 0.2 +## mT cut to be added once we understand what MET to use +mtl1pf40 : mt_2(Muon_pt[0],Muon_phi[0],MET_T1_pt,MET_T1_phi) > 40. diff --git a/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/cuts_testHistForCard.txt b/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/cuts_testHistForCard.txt index 2ed2fd011f0d..9a4700e4252b 100644 --- a/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/cuts_testHistForCard.txt +++ b/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/cuts_testHistForCard.txt @@ -1,9 +1,11 @@ alwaystrue : 1 onemuon : nMuon == 1 && nVetoElectrons == 0 trigger : HLT_SingleMu24 > 0 && Muon_hasTriggerMatch[0] != 0 -accept : abs(Muon_eta[0]) < 2.4 && Muon_pt[0] > 26 && Muon_pt[0] < 45 +accept : abs(Muon_eta[0]) < 2.4 && valueInsideRange(Muon_pt[0],26,45) muonID : Muon_mediumId[0] == 1 pfRelIso04 : Muon_pfRelIso04_all[0] < 0.15 dxy : abs(Muon_dxy[0]) < 0.05 dz : abs(Muon_dz[0]) < 0.2 ## mT cut to be added once we understand what MET to use +mtl1pf40 : mt_2(Muon_pt[0],Muon_phi[0],MET_T1_pt,MET_T1_phi) > 40. + diff --git a/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/cuts_testHistForCard_wlike.txt b/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/cuts_testHistForCard_wlike.txt new file mode 100644 index 000000000000..e7d345586676 --- /dev/null +++ b/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/cuts_testHistForCard_wlike.txt @@ -0,0 +1,13 @@ +alwaystrue : 1 +twomuon : nMuon == 2 && nVetoElectrons == 0 +trigger : HLT_SingleMu24 > 0 && triggerMatchWlike_nano(Muon_hasTriggerMatch[0],Muon_charge[0],Muon_hasTriggerMatch[1],Muon_charge[1],event) +oppositecharge : Muon_pdgId[0] * Muon_pdgId[1] == -169 +accept : abs(Muon_eta[0]) < 2.4 && abs(Muon_eta[1]) < 2.4 && valueInsideRange(Muon_pt[0],26,45) && valueInsideRange(Muon_pt[1],26,45) +muonID : Muon_mediumId[0] == 1 && Muon_mediumId[1] == 1 +pfRelIso04 : Muon_pfRelIso04_all[0] < 0.15 && Muon_pfRelIso04_all[1] < 0.15 +dxy : abs(Muon_dxy[0]) < 0.05 && abs(Muon_dxy[1]) < 0.05 +dz : abs(Muon_dz[0]) < 0.2 && abs(Muon_dz[1]) < 0.2 +mZ : valueInsideRange(mass_2(Muon_pt[0],Muon_eta[0],Muon_phi[0],0.1057,Muon_pt[1],Muon_eta[1],Muon_phi[1],0.1057), 60., 120.) +## mT cut to be added once we understand what MET to use +mtl1pf40 : mt_wlike(Muon_pt[0],Muon_phi[0],Muon_charge[0],Muon_pt[1],Muon_phi[1],Muon_charge[1],MET_T1_pt,MET_T1_phi,event) < 40. + diff --git a/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/mca-fakeRate.txt b/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/mca-fakeRate.txt new file mode 100644 index 000000000000..b5cbc5f1b767 --- /dev/null +++ b/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/mca-fakeRate.txt @@ -0,0 +1,26 @@ +# use options --pg 'data := data_B,data_C,data_D,data_E,data_F' --xp data_G,data_H +# to exlude samples you don't want to run on (G and H) and group all the remaining data together +# reminder: mcAnalysis identify data as "data", while "dataXXX" will not be considered data (unless you use the --pg trick) +# +# data per era (but need to use trick above when running mcAnalysis.py +data_B: .*; SubPath=".*DATA_NanoV8/Run2016B/" +data_C: .*; SubPath=".*DATA_NanoV8/Run2016C/" +data_D: .*; SubPath=".*DATA_NanoV8/Run2016D/" +data_E: .*; SubPath=".*DATA_NanoV8/Run2016E/" +data_F: .*; SubPath=".*DATA_NanoV8/Run2016F/" +data_F_postVFP: .*; SubPath=".*DATA_NanoV8/Run2016F_postVFP/" +data_G: .*; SubPath=".*DATA_NanoV8/Run2016G/" +data_H: .*; SubPath=".*DATA_NanoV8/Run2016H/" + +#data: .*; SubPath=".*DATA_NanoV8/" + +Wmunu_plus : .* : 11572.19; FillColor=ROOT.kRed+2, Label="W^{+}\#rightarrow\#mu\#nu", SubPath=".*WplusJetsToMuNu_(post|pre)VFP_addVars" +Wmunu_minus : .* : 8562.66; FillColor=ROOT.kRed+2, Label="W^{-}\#rightarrow\#mu\#nu", SubPath=".*WminusJetsToMuNu_(post|pre)VFP_addVars" + +Wtaunu_plus : .* : 0.17394*11572.19; FillColor=ROOT.kRed+2, Label="W^{+}\#rightarrow\#tau\#nu", SubPath=".*WplusJetsToTauNu_(post|pre)VFP_addVars" +Wtaunu_minus : .* : 0.17394*8562.66; FillColor=ROOT.kRed+2, Label="W^{-}\#rightarrow\#tau\#nu", SubPath=".*WminusJetsToTauNu_(post|pre)VFP_addVars" + +Zmumu : .* : 1976.17 ; FillColor=ROOT.kAzure+2, Label="Z\#rightarrow\#mu\#mu", SubPath=".*DYJetsToMuMu_(post|pre)VFP_addVars" + +Ztautau : .* : 0.5802*1976.17 ; FillColor=ROOT.kAzure+2, Label="Z\#rightarrow\#tau\#tau", SubPath=".*DYJetsToTauTau_(post|pre)VFP_addVars" + diff --git a/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/mca-includes/mca-data.txt b/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/mca-includes/mca-data.txt new file mode 100644 index 000000000000..34e753bc937e --- /dev/null +++ b/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/mca-includes/mca-data.txt @@ -0,0 +1,27 @@ +# use options --pg 'data := data_B,data_C,data_D,data_E,data_F' --xp data_G,data_H +# to exlude samples you don't want to run on (G and H) and group all the remaining data together +# reminder: mcAnalysis identify data as "data", while "dataXXX" will not be considered data (unless you use the --pg trick) + +# inclusive data +#data: .*_0_.*; SubPath=".*DATA_NanoV8/" + +# data per era (but need to use trick above when running mcAnalysis.py +# data_B: .*; SubPath=".*DATA_NanoV8/Run2016B/" +# data_C: .*; SubPath=".*DATA_NanoV8/Run2016C/" +# data_D: .*; SubPath=".*DATA_NanoV8/Run2016D/" +# data_E: .*; SubPath=".*DATA_NanoV8/Run2016E/" +# data_F: .*; SubPath=".*DATA_NanoV8/Run2016F/" +# data_F_postVFP: .*; SubPath=".*DATA_NanoV8/Run2016F_postVFP/" +# data_G: .*; SubPath=".*DATA_NanoV8/Run2016G/" +# data_H: .*; SubPath=".*DATA_NanoV8/Run2016H/" + +## for tests with a single file +data_B: .*; SubPath=".*DATA_NanoV8/Run2016B/" +data_C: .*; SubPath=".*DATA_NanoV8/Run2016C/" +data_D: .*; SubPath=".*DATA_NanoV8/Run2016D/" +data_E: .*; SubPath=".*DATA_NanoV8/Run2016E/" +data_F: .*; SubPath=".*DATA_NanoV8/Run2016F/" +data_F_postVFP: .*; SubPath=".*DATA_NanoV8/Run2016F_postVFP/" +data_G: .*; SubPath=".*DATA_NanoV8/Run2016G/" +data_H: .*; SubPath=".*DATA_NanoV8/Run2016H/" + diff --git a/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/mca-includes/mca-wmunu.txt b/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/mca-includes/mca-wmunu.txt new file mode 100644 index 000000000000..becc47ae55ff --- /dev/null +++ b/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/mca-includes/mca-wmunu.txt @@ -0,0 +1,5 @@ +Wmunu_plus : .* : 19.3*11572.19; FillColor=ROOT.kRed+2, Label="W^{+}\#rightarrow\#mu\#nu", SubPath=".*WplusJetsToMuNu_preVFP_addVars" +Wmunu_plus : .* : 16.6*11572.19; FillColor=ROOT.kRed+2, Label="W^{+}\#rightarrow\#mu\#nu", SubPath=".*WplusJetsToMuNu_postVFP_addVars" + +Wmunu_minus : .* : 19.3*8562.66; FillColor=ROOT.kRed+2, Label="W^{-}\#rightarrow\#mu\#nu", SubPath=".*WminusJetsToMuNu_preVFP_addVars" +Wmunu_minus : .* : 16.6*8562.66; FillColor=ROOT.kRed+2, Label="W^{-}\#rightarrow\#mu\#nu", SubPath=".*WminusJetsToMuNu_postVFP_addVars" diff --git a/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/mca-includes/mca-wtaunu.txt b/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/mca-includes/mca-wtaunu.txt new file mode 100644 index 000000000000..377f47192cf0 --- /dev/null +++ b/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/mca-includes/mca-wtaunu.txt @@ -0,0 +1,5 @@ +Wtaunu_plus : .* : 19.3*0.17394*11572.19; FillColor=ROOT.kRed+2, Label="W^{+}\#rightarrow\#tau\#nu", SubPath=".*WplusJetsToTauNu_preVFP_addVars" +Wtaunu_plus : .* : 16.6*0.17394*11572.19; FillColor=ROOT.kRed+2, Label="W^{+}\#rightarrow\#tau\#nu", SubPath=".*WplusJetsToTauNu_postVFP_addVars" + +Wtaunu_minus : .* : 19.3*0.17394*8562.66; FillColor=ROOT.kRed+2, Label="W^{-}\#rightarrow\#tau\#nu", SubPath=".*WminusJetsToTauNu_preVFP_addVars" +Wtaunu_minus : .* : 16.6*0.17394*8562.66; FillColor=ROOT.kRed+2, Label="W^{-}\#rightarrow\#tau\#nu", SubPath=".*WminusJetsToTauNu_postVFP_addVars" diff --git a/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/mca-includes/mca-zmumu.txt b/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/mca-includes/mca-zmumu.txt new file mode 100644 index 000000000000..cb4e40914df8 --- /dev/null +++ b/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/mca-includes/mca-zmumu.txt @@ -0,0 +1,2 @@ +Zmumu : .* : 19.3*1976.17 ; FillColor=ROOT.kAzure+2, Label="Z\#rightarrow\#mu\#mu", SubPath=".*DYJetsToMuMu_preVFP_addVars" +Zmumu : .* : 16.6*1976.17 ; FillColor=ROOT.kAzure+2, Label="Z\#rightarrow\#mu\#mu", SubPath=".*DYJetsToMuMu_postVFP_addVars" diff --git a/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/mca-includes/mca-ztautau.txt b/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/mca-includes/mca-ztautau.txt new file mode 100644 index 000000000000..e0c365cda3ba --- /dev/null +++ b/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/mca-includes/mca-ztautau.txt @@ -0,0 +1,4 @@ +# 19.3*0.5802*1976.17 = 22128.875 +# 16.6*0.5802*1976.17 = 19033.126 +Ztautau : .* : 22128.875 ; FillColor=ROOT.kAzure+2, Label="Z\#rightarrow\#tau\#tau", SubPath=".*DYJetsToTauTau_preVFP_addVars" +Ztautau : .* : 19033.126 ; FillColor=ROOT.kAzure+2, Label="Z\#rightarrow\#tau\#tau", SubPath=".*DYJetsToTauTau_postVFP_addVars" diff --git a/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/mca-test.txt b/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/mca-test.txt index b2e5f9b50e6a..79d9327d9015 100644 --- a/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/mca-test.txt +++ b/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/mca-test.txt @@ -40,3 +40,16 @@ WplusPartPrefireUp: SMP-RunIISummer16NanoAODv7-00336_[1-3]1.*: 11572.19: L1PreFi # nJet with cleaning or ID WplusPartNomi: SMP-RunIISummer16NanoAODv7-00336_[1-2]1.* : 11572.19: Jet_jetId>0; FillColor=ROOT.kRed+2, Label="W+", NormSystematic=0.04, ObjName="Events", SubPath=".*WplusJetsToMuNu_TuneCP5_13TeV-powhegMiNNLO-pythia8-photos/NanoAODv7/201022_231658/0000/", FillStyle=3002 + + + +### +### to get PU profile (will use unweighted events, so the cross section and luminosity could be omitted) +# sum charges + and - +Wmunu_preVFP : .* : 19.3*11572.19; FillColor=ROOT.kRed+2, Label="W\#rightarrow\#mu\#nu preVFP", SubPath=".*WplusJetsToMuNu_preVFP_addVars" +Wmunu_preVFP : .* : 19.3*8562.66; FillColor=ROOT.kRed+2, Label="W\#rightarrow\#mu\#nu preVFP", SubPath=".*WminusJetsToMuNu_preVFP_addVars" +# sum charges + and - +Wmunu_postVFP : .* : 16.6*11572.19; FillColor=ROOT.kBlack, Label="W\#rightarrow\#mu\#nu postVFP", SubPath=".*WplusJetsToMuNu_postVFP_addVars" +Wmunu_postVFP : .* : 19.3*8562.66; FillColor=ROOT.kBlack, Label="W\#rightarrow\#mu\#nu postVFP", SubPath=".*WminusJetsToMuNu_postVFP_addVars" +########## +########## diff --git a/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/plots_test.txt b/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/plots_test.txt index befba880fb0f..077ac77a637e 100644 --- a/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/plots_test.txt +++ b/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/plots_test.txt @@ -1,23 +1,23 @@ # add variables for Wlike below -muon_pt: Muon_pt[0]: 35,25,60; XTitle="Muon p_{T} (GeV)", Legend='TR', IncludeOverflows=True +muon_pt: Muon_pt[Idx_mu1]: 35,25,60; XTitle="Muon p_{T} (GeV)", Legend='TR', IncludeOverflows=True -muon_eta: Muon_eta[0]: 48,-2.4,2.4; XTitle="Muon #eta", Legend='TC', IncludeOverflows=True +muon_eta: Muon_eta[Idx_mu1]: 48,-2.4,2.4; XTitle="Muon #eta", Legend='TC', IncludeOverflows=True -mt_ChsMET: mt_2(Muon_pt[0],Muon_phi[0],ChsMET_pt,ChsMET_phi): 50,20,120; XTitle="m_{T}(#mu\,ChsMET) (GeV)", Legend='TC', IncludeOverflows=True +mt_ChsMET: mt_2(Muon_pt[Idx_mu1],Muon_phi[Idx_mu1],ChsMET_pt,ChsMET_phi): 50,20,120; XTitle="m_{T}(#mu\,ChsMET) (GeV)", Legend='TC', IncludeOverflows=True MET_pt: MET_pt: 40,0,80; XTitle="MET (GeV)", Legend='TC', IncludeOverflows=True ChsMET_pt: ChsMET_pt: 40,0,80; XTitle="ChsMET (GeV)", Legend='TC', IncludeOverflows=True -mt_MET: mt_2(Muon_pt[0],Muon_phi[0],MET_pt,MET_phi): 50,20,120; XTitle="m_{T}(#mu\,MET) (GeV)", Legend='TC', IncludeOverflows=True +mt_MET: mt_2(Muon_pt[Idx_mu1],Muon_phi[Idx_mu1],MET_pt,MET_phi): 50,20,120; XTitle="m_{T}(#mu\,MET) (GeV)", Legend='TC', IncludeOverflows=True -mt_DeepMetRespTune: mt_2(Muon_pt[0],Muon_phi[0],DeepMETResponseTune_pt,DeepMETResponseTune_phi): 50,20,120; XTitle="m_{T}(#mu\,DeepMETResponseTune) (GeV)", Legend='TC', IncludeOverflows=True +mt_DeepMetRespTune: mt_2(Muon_pt[Idx_mu1],Muon_phi[Idx_mu1],DeepMETResponseTune_pt,DeepMETResponseTune_phi): 50,20,120; XTitle="m_{T}(#mu\,DeepMETResponseTune) (GeV)", Legend='TC', IncludeOverflows=True -mt_DeepMetResoTune: mt_2(Muon_pt[0],Muon_phi[0],DeepMETResolutionTune_pt,DeepMETResolutionTune_phi): 50,20,120; XTitle="m_{T}(#mu\,DeepMETResolutionTune) (GeV)", Legend='TC', IncludeOverflows=True +mt_DeepMetResoTune: mt_2(Muon_pt[Idx_mu1],Muon_phi[Idx_mu1],DeepMETResolutionTune_pt,DeepMETResolutionTune_phi): 50,20,120; XTitle="m_{T}(#mu\,DeepMETResolutionTune) (GeV)", Legend='TC', IncludeOverflows=True -muon_pt_eta: Muon_pt[0]\:Muon_eta[0]: 48,-2.4,2.4,34,26,60 ; XTitle='muon #eta', YTitle='muon p_{T} (GeV)', Legend='TR' +muon_pt_eta: Muon_pt[Idx_mu1]\:Muon_eta[Idx_mu1]: 48,-2.4,2.4,34,26,60 ; XTitle='muon #eta', YTitle='muon p_{T} (GeV)', Legend='TR' PV_z: PV_z: 100,-20,20; XTitle="Primary vertex z (cm)", Legend='TC', IncludeOverflows=True @@ -25,19 +25,36 @@ OtherPV_z: OtherPV_z: 100,-20,20; XTitle="Other primary vertex z (cm)", Legend=' ## W like variables -muon_pt_wlike: returnChargeVal(Muon_pt[0],Muon_charge[0],Muon_pt[1],Muon_charge[1],event): 35,25,60; XTitle="Muon p_{T} (GeV)", Legend='TR', IncludeOverflows=True +muon_pt_wlike: returnChargeVal(Muon_pt[Idx_mu1],Muon_charge[Idx_mu1],Muon_pt[Idx_mu2],Muon_charge[Idx_mu2],event): 30,25,55; XTitle="Muon p_{T} (GeV)", Legend='TR', IncludeOverflows=True -muon_eta_wlike: returnChargeVal(Muon_eta[0],Muon_charge[0],Muon_eta[1],Muon_charge[1],event): 48,-2.4,2.4; XTitle="Muon #eta", Legend='TC', IncludeOverflows=True +muon_eta_wlike: returnChargeVal(Muon_eta[Idx_mu1],Muon_charge[Idx_mu1],Muon_eta[Idx_mu2],Muon_charge[Idx_mu2],event): 48,-2.4,2.4; XTitle="Muon #eta", Legend='TC', IncludeOverflows=True -muon_eta_wlike_rebin: returnChargeVal(Muon_eta[0],Muon_charge[0],Muon_eta[1],Muon_charge[1],event): 24,-2.4,2.4; XTitle="Muon #eta", Legend='TC', IncludeOverflows=True +muon_eta_wlike_rebin: returnChargeVal(Muon_eta[Idx_mu1],Muon_charge[Idx_mu1],Muon_eta[Idx_mu2],Muon_charge[Idx_mu2],event): 24,-2.4,2.4; XTitle="Muon #eta", Legend='TC', IncludeOverflows=True -mt_wlike_ChsMET: mt_wlike(Muon_pt[0],Muon_phi[0],Muon_charge[0],Muon_pt[1],Muon_phi[1],Muon_charge[1],ChsMET_pt,ChsMET_phi,event): 40,40,120; XTitle="W-like m_{T}(#mu\,ChsMET) (GeV)", Legend='TC', IncludeOverflows=True +muon_pt_wlike_other: returnChargeVal(Muon_pt[Idx_mu1],Muon_charge[Idx_mu2],Muon_pt[Idx_mu2],Muon_charge[Idx_mu1],event): 30,25,55; XTitle="Other muon p_{T} (GeV)", Legend='TR', IncludeOverflows=True -zmass : mass_2(Muon_pt[0],Muon_eta[0],Muon_phi[0],0.1057128,Muon_pt[1],Muon_eta[1],Muon_phi[1],0.1057128): 60,60,120; XTitle="reco Z mass (GeV)", Legend='TC', IncludeOverflows=True +muon_eta_wlike_other: returnChargeVal(Muon_eta[Idx_mu1],Muon_charge[Idx_mu2],Muon_eta[Idx_mu2],Muon_charge[Idx_mu1],event): 48,-2.4,2.4; XTitle="Other muon #eta", Legend='TC', IncludeOverflows=True -zpt : pt_2(Muon_pt[0],Muon_phi[0],Muon_pt[1],Muon_phi[1]): 50,0,100 ; XTitle="reco Z p_{T} (GeV)", Legend='TR' +muon_eta_wlike_rebin_other: returnChargeVal(Muon_eta[Idx_mu1],Muon_charge[Idx_mu2],Muon_eta[Idx_mu2],Muon_charge[Idx_mu1],event): 24,-2.4,2.4; XTitle="Other muon #eta", Legend='TC', IncludeOverflows=True + + +muon_pt_eta_wlike: returnChargeVal(Muon_pt[Idx_mu1],Muon_charge[Idx_mu1],Muon_pt[Idx_mu2],Muon_charge[Idx_mu2],event)\:returnChargeVal(Muon_eta[Idx_mu1],Muon_charge[Idx_mu1],Muon_eta[Idx_mu2],Muon_charge[Idx_mu2],event): 24,-2.4,2.4,29,26,55 ; XTitle='muon #eta', YTitle='muon p_{T} (GeV)', Legend='TR' + + +mt_wlike_ChsMET: mt_wlike(Muon_pt[Idx_mu1],Muon_phi[Idx_mu1],Muon_charge[Idx_mu1],Muon_pt[Idx_mu2],Muon_phi[Idx_mu2],Muon_charge[Idx_mu2],ChsMET_pt,ChsMET_phi,event): 60,0,120; XTitle="W-like m_{T}(#mu\,ChsMET) (GeV)", Legend='TC', IncludeOverflows=True + +mt_wlike_T1MET: mt_wlike(Muon_pt[Idx_mu1],Muon_phi[Idx_mu1],Muon_charge[Idx_mu1],Muon_pt[Idx_mu2],Muon_phi[Idx_mu2],Muon_charge[Idx_mu2],MET_T1_pt,MET_T1_phi,event): 60,0,120; XTitle="W-like m_{T}(#mu\,T1MET) (GeV)", Legend='TC', IncludeOverflows=True + +zmass : mass_2(Muon_pt[Idx_mu1],Muon_eta[Idx_mu1],Muon_phi[Idx_mu1],0.1057128,Muon_pt[Idx_mu2],Muon_eta[Idx_mu2],Muon_phi[Idx_mu2],0.1057128): 60,60,120; XTitle="reco Z mass (GeV)", Legend='TC', IncludeOverflows=True + +zpt : pt_2(Muon_pt[Idx_mu1],Muon_phi[Idx_mu1],Muon_pt[Idx_mu2],Muon_phi[Idx_mu2]): 50,0,100 ; XTitle="reco Z p_{T} (GeV)", Legend='TR' + +zy : rapidity_2(Muon_pt[Idx_mu1],Muon_eta[Idx_mu1],Muon_phi[Idx_mu1],0.1057128,Muon_pt[Idx_mu2],Muon_eta[Idx_mu2],Muon_phi[Idx_mu2],0.1057128): 50,-2.5,2.5 ; XTitle="reco Z rapidity", Legend='TR' + +index_muon: returnChargeVal(Idx_mu1,Muon_charge[Idx_mu1],Idx_mu2,Muon_charge[Idx_mu2]): 6,-0.5,5.5; XTitle="Muon index", Legend='TC', IncludeOverflows=True + +index_muon_other: returnChargeVal(Idx_mu1,Muon_charge[Idx_mu2],Idx_mu2,Muon_charge[Idx_mu1]): 6,-0.5,5.5; XTitle="Other muon index", Legend='TC', IncludeOverflows=True -zy : rapidity_2(Muon_pt[0],Muon_eta[0],Muon_phi[0],0.1057128,Muon_pt[1],Muon_eta[1],Muon_phi[1],0.1057128): 50,-2.5,2.5 ; XTitle="reco Z rapidity", Legend='TR' nJet : nJet: 6,-0.5,5.5 ; XTitle="number of jets", Legend='TR' @@ -47,16 +64,32 @@ muon_pt_ss: Muon_pt: 35,25,60; XTitle="Muon p_{T} (GeV)", Legend='TR', IncludeOv muon_eta_ss: Muon_eta: 48,-2.4,2.4; XTitle="Muon #eta", Legend='TC', IncludeOverflows=True -deltaRgenMu: deltaR(GenDressedLepton_eta[0],GenDressedLepton_phi[0],GenDressedLepton_eta[1],GenDressedLepton_phi[1]): 80,0,4; XTitle="#DeltaR(#mu\,#mu) (dressed gen muons)", Legend='TC', IncludeOverflows=True +deltaRgenMu: deltaR(GenPart_eta[GenPart_preFSRLepIdx1],GenPart_phi[GenPart_preFSRLepIdx1],GenPart_eta[GenPart_preFSRLepIdx2],GenPart_phi[GenPart_preFSRLepIdx2]): 80,0,4; XTitle="#DeltaR(#mu\,#mu) (dressed gen muons)", Legend='TC', IncludeOverflows=True # eta and pt of gen muon from Z that was not reconstructed when selecting events in W phase space -genMuFailReco_eta: varGenLepFailReco(Muon_pdgId[0], GenDressedLepton_pdgId[0], GenDressedLepton_eta[0], GenDressedLepton_eta[1]): 80,-4.0,4.0; XTitle="gen muon #eta (failed reco)", Legend='TC', IncludeOverflows=True +genMuFailReco_eta: varGenLepFailReco(Muon_pdgId[Idx_mu1], GenPart_pdgId[GenPart_preFSRLepIdx1], GenPart_eta[GenPart_preFSRLepIdx1], GenPart_eta[GenPart_preFSRLepIdx2]): 80,-4.0,4.0; XTitle="gen muon #eta (failed reco)", Legend='TC', IncludeOverflows=True -genMuFailReco_pt: varGenLepFailReco(Muon_pdgId[0], GenDressedLepton_pdgId[0], GenDressedLepton_pt[0], GenDressedLepton_pt[1]): 35,20,80; XTitle="gen muon p_{T} (GeV) (failed reco)", Legend='TC', IncludeOverflows=True +genMuFailReco_pt: varGenLepFailReco(Muon_pdgId[Idx_mu1], GenPart_pdgId[GenPart_preFSRLepIdx1], GenPart_pt[GenPart_preFSRLepIdx1], GenPart_pt[GenPart_preFSRLepIdx2]): 35,20,80; XTitle="gen muon p_{T} (GeV) (failed reco)", Legend='TC', IncludeOverflows=True -genMuFailReco_pt_eta: varGenLepFailReco(Muon_pdgId[0], GenDressedLepton_pdgId[0], GenDressedLepton_pt[0], GenDressedLepton_pt[1])\:varGenLepFailReco(Muon_pdgId[0], GenDressedLepton_pdgId[0], GenDressedLepton_eta[0], GenDressedLepton_eta[1]) : 80,-4.0,4.0,35,20,80; XTitle="gen muon #eta (failed reco)", YTitle="gen muon p_{T} (GeV) (failed reco)", Legend='TC', IncludeOverflows=True +genMuFailReco_pt_eta: varGenLepFailReco(Muon_pdgId[Idx_mu1], GenPart_pdgId[GenPart_preFSRLepIdx1], GenPart_pt[GenPart_preFSRLepIdx1], GenPart_pt[GenPart_preFSRLepIdx2])\:varGenLepFailReco(Muon_pdgId[Idx_mu1], GenPart_pdgId[GenPart_preFSRLepIdx1], GenPart_eta[GenPart_preFSRLepIdx1], GenPart_eta[GenPart_preFSRLepIdx2]) : 80,-4.0,4.0,35,20,80; XTitle="gen muon #eta (failed reco)", YTitle="gen muon p_{T} (GeV) (failed reco)", Legend='TC', IncludeOverflows=True + +### +# for PU profile Pileup_nTrueInt: Pileup_nTrueInt: 100,0,100; XTitle="Pileup_nTrueInt", Legend='TC', IncludeOverflows=False PV_npvsGood: PV_npvsGood: 80,0,80; XTitle="PV_npvsGood", Legend='TC', IncludeOverflows=False + +#### +# for vertex study + +dzVertex_gen_primary__Wpt: (GenVtx_z-PV_z)\:pt_2(GenPart_pt[GenPart_preFSRLepIdx1],GenPart_phi[GenPart_preFSRLepIdx1],GenPart_pt[GenPart_preFSRLepIdx2],GenPart_phi[GenPart_preFSRLepIdx2]) : 50,0,100,200,-1.0,1.0; YTitle="vertex #Deltaz (gen-reco) [cm]",XTitle="W-p_{T} (dressed) [GeV]", Legend='TC', IncludeOverflows=False + +dzVertex_gen_primary__dressedLepPt: (GenVtx_z-PV_z)\:if3(fabs(GenPart_pdgId[GenPart_preFSRLepIdx1])==13,GenPart_pt[GenPart_preFSRLepIdx1],GenPart_pt[GenPart_preFSRLepIdx2]): 74,26,100,200,-1.0,1.0; YTitle="vertex #Deltaz (gen-reco) [cm]",XTitle=" leading dressed lepton p_{T} [GeV]", Legend='TC', IncludeOverflows=False + +#### +# some gen vars +vpt : Vpt_preFSR: [0., 4., 8., 12., 16., 20., 24., 28., 32., 40., 60., 100., 200.] ; XTitle="PreFSR boson p_{T} (GeV)", Legend='TR' +vrap : fabs(Vrap_preFSR): [0, 0.4, 0.8, 1.2, 1.6, 2.0, 2.4, 3.0, 6.0] ; XTitle="PreFSR boson rapidity", Legend='TR' +vpt_vrap: Vpt_preFSR\:Vrap_preFSR: 50,-5,5,50,0,100 ; XTitle='PreFSR boson rapidity', YTitle='PreFSR boson p_{T} (GeV)', Legend='TR' diff --git a/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/test/cuts_testSF.txt b/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/test/cuts_testSF.txt new file mode 100644 index 000000000000..20a59f76bda6 --- /dev/null +++ b/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/test/cuts_testSF.txt @@ -0,0 +1,13 @@ +alwaystrue : 1 +twomuon : nVetoElectrons == 0 && nMuon >= 2 && Idx_mu1 >= 0 && Idx_mu2 >= 0 +trigger : HLT_SingleMu24 > 0 && triggerMatchWlike_nano(Muon_hasTriggerMatch[Idx_mu1],Muon_charge[Idx_mu1],Muon_hasTriggerMatch[Idx_mu2],Muon_charge[Idx_mu2],event) +oppositecharge : Vtype_subcat%2 == 0 +accept : abs(Muon_eta[Idx_mu1]) < 2.4 && abs(Muon_eta[Idx_mu2]) < 2.4 && valueInsideRange(Muon_pt[Idx_mu1],26,55) && valueInsideRange(Muon_pt[Idx_mu2],26,55) +muonID : Muon_mediumId[Idx_mu1] == 1 && Muon_mediumId[Idx_mu2] == 1 +pfRelIso04 : Muon_pfRelIso04_all[Idx_mu1] < 0.15 && Muon_pfRelIso04_all[Idx_mu2] < 0.15 +dxy : abs(Muon_dxy[Idx_mu1]) < 0.05 && abs(Muon_dxy[Idx_mu2]) < 0.05 +dz : abs(Muon_dz[Idx_mu1]) < 0.2 && abs(Muon_dz[Idx_mu2]) < 0.2 +mZ : valueInsideRange(mass_2(Muon_pt[Idx_mu1],Muon_eta[Idx_mu1],Muon_phi[Idx_mu1],0.1057,Muon_pt[Idx_mu2],Muon_eta[Idx_mu2],Muon_phi[Idx_mu2],0.1057), 60., 120.) +## mT cut to be added once we understand what MET to use +mtl1pf40 : mt_wlike(Muon_pt[Idx_mu1],Muon_phi[Idx_mu1],Muon_charge[Idx_mu1],Muon_pt[Idx_mu2],Muon_phi[Idx_mu2],Muon_charge[Idx_mu2],MET_T1_pt,MET_T1_phi,event) > 40. + diff --git a/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/test/cuts_zmm_testLepVeto.txt b/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/test/cuts_zmm_testLepVeto.txt index b2e28ccebc68..7fe823758681 100644 --- a/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/test/cuts_zmm_testLepVeto.txt +++ b/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/test/cuts_zmm_testLepVeto.txt @@ -2,12 +2,13 @@ # cut on mT is at 40 because the test is done in the W phase space, where Z events are selected when one # muon is not reconstructed or outside acceptance alwaystrue : 1 -genDressedMu: nGenDressedLepton > 1 && GenDressedLepton_pdgId[0]*GenDressedLepton_pdgId[1] == -169 -trigger : HLT_IsoMu24 > 0 || HLT_IsoTkMu24 > 0 -onemuon : nMuon == 1 && nElectron == 0 -accept : abs(Muon_eta[0]) < 2.4 && valueInsideRange(Muon_pt[0],26.0,60.0) +genMuOs : GenPart_pdgId[GenPart_preFSRLepIdx1]*GenPart_pdgId[GenPart_preFSRLepIdx2] == -169 +onemuon : nMuon == 1 && nVetoElectrons == 0 +trigger : HLT_SingleMu24 > 0 && Muon_hasTriggerMatch[0] != 0 +accept : abs(Muon_eta[0]) < 2.4 && valueInsideRange(Muon_pt[0],26,60) muonID : Muon_mediumId[0] == 1 pfRelIso04 : Muon_pfRelIso04_all[0] < 0.15 -dxy : abs(Muon_dxy[0]) < 0.02 -dz : abs(Muon_dz[0]) < 0.1 -mt_ChsMET : mt_2(Muon_pt[0],Muon_phi[0],ChsMET_pt,ChsMET_phi) > 40. +dxy : abs(Muon_dxy[0]) < 0.05 +dz : abs(Muon_dz[0]) < 0.2 +## mT cut to be added once we understand what MET to use +mtl1pf40 : mt_2(Muon_pt[0],Muon_phi[0],MET_T1_pt,MET_T1_phi) > 40. diff --git a/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/test/mca_testSF.txt b/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/test/mca_testSF.txt new file mode 100644 index 000000000000..39ef9ff94dd3 --- /dev/null +++ b/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/test/mca_testSF.txt @@ -0,0 +1,40 @@ +data_B: .*; SubPath=".*DATA_NanoV8/Run2016B/" +data_C: .*; SubPath=".*DATA_NanoV8/Run2016C/" +data_D: .*; SubPath=".*DATA_NanoV8/Run2016D/" +data_E: .*; SubPath=".*DATA_NanoV8/Run2016E/" +data_F: .*; SubPath=".*DATA_NanoV8/Run2016F/" +data_F_postVFP: .*; SubPath=".*DATA_NanoV8/Run2016F_postVFP/" +data_G: .*; SubPath=".*DATA_NanoV8/Run2016G/" +data_H: .*; SubPath=".*DATA_NanoV8/Run2016H/" + + +Zmumu_preVFP : .* : 38140.081 ; FillColor=ROOT.kAzure+2, Label="Z\#rightarrow\#mu\#mu", SubPath=".*DYJetsToMuMu_preVFP_addVars", AddWeight="_get_AllMuonSF_fast_wlike(Muon_pt[0]\,Muon_eta[0]\,Muon_charge[0]\,Muon_hasTriggerMatch[0]\,Muon_pt[1]\,Muon_eta[1]\,Muon_charge[1]\,Muon_hasTriggerMatch[1]\,event\,1)" + +Zmumu_postVFP : .* : 32804.422 ; FillColor=ROOT.kAzure+2, Label="Z\#rightarrow\#mu\#mu", SubPath=".*DYJetsToMuMu_postVFP_addVars", AddWeight="_get_AllMuonSF_fast_wlike(Muon_pt[0]\,Muon_eta[0]\,Muon_charge[0]\,Muon_hasTriggerMatch[0]\,Muon_pt[1]\,Muon_eta[1]\,Muon_charge[1]\,Muon_hasTriggerMatch[1]\,event\,2)" + +Zmumu_globSF_preVFP : .* : 38140.081 ; FillColor=ROOT.kAzure+2, Label="Z\#rightarrow\#mu\#mu", SubPath=".*DYJetsToMuMu_preVFP_addVars", AddWeight="_get_AllMuonSF_fast_wlike(Muon_pt[0]\,Muon_eta[0]\,Muon_charge[0]\,Muon_hasTriggerMatch[0]\,Muon_pt[1]\,Muon_eta[1]\,Muon_charge[1]\,Muon_hasTriggerMatch[1]\,event\,0)" + +Zmumu_globSF_postVFP : .* : 32804.422 ; FillColor=ROOT.kAzure+2, Label="Z\#rightarrow\#mu\#mu", SubPath=".*DYJetsToMuMu_postVFP_addVars", AddWeight="_get_AllMuonSF_fast_wlike(Muon_pt[0]\,Muon_eta[0]\,Muon_charge[0]\,Muon_hasTriggerMatch[0]\,Muon_pt[1]\,Muon_eta[1]\,Muon_charge[1]\,Muon_hasTriggerMatch[1]\,event\,0)" + +Ztautau_preVFP : .* : 22128.875 ; FillColor=ROOT.kSpring+9, Label="Z\#rightarrow\#tau\#tau", SubPath=".*DYJetsToTauTau_preVFP_addVars", AddWeight="_get_AllMuonSF_fast_wlike(Muon_pt[0]\,Muon_eta[0]\,Muon_charge[0]\,Muon_hasTriggerMatch[0]\,Muon_pt[1]\,Muon_eta[1]\,Muon_charge[1]\,Muon_hasTriggerMatch[1]\,event\,1)" + +Ztautau_postVFP : .* : 19033.126 ; FillColor=ROOT.kSpring+9, Label="Z\#rightarrow\#tau\#tau", SubPath=".*DYJetsToTauTau_postVFP_addVars", AddWeight="_get_AllMuonSF_fast_wlike(Muon_pt[0]\,Muon_eta[0]\,Muon_charge[0]\,Muon_hasTriggerMatch[0]\,Muon_pt[1]\,Muon_eta[1]\,Muon_charge[1]\,Muon_hasTriggerMatch[1]\,event\,2)" + +Ztautau_globSF_preVFP : .* : 22128.875 ; FillColor=ROOT.kSpring+9, Label="Z\#rightarrow\#tau\#tau", SubPath=".*DYJetsToTauTau_preVFP_addVars", AddWeight="_get_AllMuonSF_fast_wlike(Muon_pt[0]\,Muon_eta[0]\,Muon_charge[0]\,Muon_hasTriggerMatch[0]\,Muon_pt[1]\,Muon_eta[1]\,Muon_charge[1]\,Muon_hasTriggerMatch[1]\,event\,0)" + +Ztautau_globSF_postVFp : .* : 19033.126 ; FillColor=ROOT.kSpring+9, Label="Z\#rightarrow\#tau\#tau", SubPath=".*DYJetsToTauTau_postVFP_addVars", AddWeight="_get_AllMuonSF_fast_wlike(Muon_pt[0]\,Muon_eta[0]\,Muon_charge[0]\,Muon_hasTriggerMatch[0]\,Muon_pt[1]\,Muon_eta[1]\,Muon_charge[1]\,Muon_hasTriggerMatch[1]\,event\,0)" + +# ZallPerEra : .* : 38140.081 ; FillColor=ROOT.kRed+2, Label="Z (perEra)", SubPath=".*DYJetsToMuMu_preVFP_addVars", AddWeight="_get_AllMuonSF_fast_wlike(Muon_pt[0]\,Muon_eta[0]\,Muon_charge[0]\,Muon_hasTriggerMatch[0]\,Muon_pt[1]\,Muon_eta[1]\,Muon_charge[1]\,Muon_hasTriggerMatch[1]\,event\,1)" +# ZallPerEra : .* : 22128.875 ; FillColor=ROOT.kRed+2, Label="Z (perEra)", SubPath=".*DYJetsToTauTau_preVFP_addVars", AddWeight="_get_AllMuonSF_fast_wlike(Muon_pt[0]\,Muon_eta[0]\,Muon_charge[0]\,Muon_hasTriggerMatch[0]\,Muon_pt[1]\,Muon_eta[1]\,Muon_charge[1]\,Muon_hasTriggerMatch[1]\,event\,1)" +# ZallPerEra : .* : 32804.422 ; FillColor=ROOT.kRed+2, Label="Z (perEra)", SubPath=".*DYJetsToMuMu_postVFP_addVars", AddWeight="_get_AllMuonSF_fast_wlike(Muon_pt[0]\,Muon_eta[0]\,Muon_charge[0]\,Muon_hasTriggerMatch[0]\,Muon_pt[1]\,Muon_eta[1]\,Muon_charge[1]\,Muon_hasTriggerMatch[1]\,event\,2)" +# ZallPerEra : .* : 19033.126 ; FillColor=ROOT.kRed+2, Label="Z (perEra)", SubPath=".*DYJetsToTauTau_postVFP_addVars", AddWeight="_get_AllMuonSF_fast_wlike(Muon_pt[0]\,Muon_eta[0]\,Muon_charge[0]\,Muon_hasTriggerMatch[0]\,Muon_pt[1]\,Muon_eta[1]\,Muon_charge[1]\,Muon_hasTriggerMatch[1]\,event\,2)" + +Z_noSF_preVFP : .* : 38140.081 ; FillColor=ROOT.kPink+1, Label="Z (no SF)", SubPath=".*DYJetsToMuMu_preVFP_addVars" +Z_noSF_preVFP : .* : 22128.875 ; FillColor=ROOT.kPink+1, Label="Z (no SF)", SubPath=".*DYJetsToTauTau_preVFP_addVars" +Z_noSF_postVFP : .* : 32804.422 ; FillColor=ROOT.kPink+1, Label="Z (no SF)", SubPath=".*DYJetsToMuMu_postVFP_addVars" +Z_noSF_postVFP : .* : 19033.126 ; FillColor=ROOT.kPink+1, Label="Z (no SF)", SubPath=".*DYJetsToTauTau_postVFP_addVars" + +Z_globSF_preVFP : .* : 38140.081 ; FillColor=ROOT.kRed+2, Label="Z (average SF)", SubPath=".*DYJetsToMuMu_preVFP_addVars", AddWeight="_get_AllMuonSF_fast_wlike(Muon_pt[0]\,Muon_eta[0]\,Muon_charge[0]\,Muon_hasTriggerMatch[0]\,Muon_pt[1]\,Muon_eta[1]\,Muon_charge[1]\,Muon_hasTriggerMatch[1]\,event\,0)" +Z_globSF_preVFP : .* : 22128.875 ; FillColor=ROOT.kRed+2, Label="Z (average SF)", SubPath=".*DYJetsToTauTau_preVFP_addVars", AddWeight="_get_AllMuonSF_fast_wlike(Muon_pt[0]\,Muon_eta[0]\,Muon_charge[0]\,Muon_hasTriggerMatch[0]\,Muon_pt[1]\,Muon_eta[1]\,Muon_charge[1]\,Muon_hasTriggerMatch[1]\,event\,0)" +Z_globSF_postVFP : .* : 32804.422 ; FillColor=ROOT.kRed+2, Label="Z (average SF)", SubPath=".*DYJetsToMuMu_postVFP_addVars", AddWeight="_get_AllMuonSF_fast_wlike(Muon_pt[0]\,Muon_eta[0]\,Muon_charge[0]\,Muon_hasTriggerMatch[0]\,Muon_pt[1]\,Muon_eta[1]\,Muon_charge[1]\,Muon_hasTriggerMatch[1]\,event\,0)" +Z_globSF_postVFp : .* : 19033.126 ; FillColor=ROOT.kRed+2, Label="Z (average SF)", SubPath=".*DYJetsToTauTau_postVFP_addVars", AddWeight="_get_AllMuonSF_fast_wlike(Muon_pt[0]\,Muon_eta[0]\,Muon_charge[0]\,Muon_hasTriggerMatch[0]\,Muon_pt[1]\,Muon_eta[1]\,Muon_charge[1]\,Muon_hasTriggerMatch[1]\,event\,0)" diff --git a/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/test/mca_zmm_testLepVeto.txt b/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/test/mca_zmm_testLepVeto.txt index 69bb1f815f30..3d17aebeac06 100644 --- a/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/test/mca_zmm_testLepVeto.txt +++ b/WMass/python/plotter/w-mass-13TeV/testingNano/cfg/test/mca_zmm_testLepVeto.txt @@ -1,5 +1,3 @@ -#Z : .* : 1976.17 ; FillColor=ROOT.kAzure+2, Label="Z", NormSystematic=0.04, ObjName="Events", SubPath=".*DYJetsToMuMu_M-50_TuneCP5_13TeV-powhegMiNNLO-pythia8-photos/NanoAODv7/201025_173845/0000/" +incl_zmumu_1GenInAccept : + ; IncludeMca="w-mass-13TeV/testingNano/cfg/mca-includes/mca-zmumu.txt", FillColor=ROOT.kRed+2, Label="Z (1 out acc)", PostFix="_1GenInAccept", AddWeight="isOutAccEtaPt(GenPart_eta[GenPart_preFSRLepIdx1]\,GenPart_pt[GenPart_preFSRLepIdx1]\,-2.4\,2.4\,26\,60) || isOutAccEtaPt(GenPart_eta[GenPart_preFSRLepIdx2]\,GenPart_pt[GenPart_preFSRLepIdx2]\,-2.4\,2.4\,26\,60)", ALLOW_OVERWRITE_SETTINGS=True -Z_1GenInAccept: SMP-RunIISummer16NanoAODv7-00336_.* : 1976.17: isOutAccEtaPt(GenDressedLepton_eta[0],GenDressedLepton_pt[0],-2.4,2.4,26,60) || isOutAccEtaPt(GenDressedLepton_eta[1],GenDressedLepton_pt[1],-2.4,2.4,26,60); FillColor=ROOT.kRed+2, Label="Z (1 out acc)", NormSystematic=0.04, ObjName="Events", SubPath=".*DYJetsToMuMu_M-50_TuneCP5_13TeV-powhegMiNNLO-pythia8-photos/NanoAODv7/201025_173845/0000/" - -Z_2GenInAccept: SMP-RunIISummer16NanoAODv7-00336_.* : 1976.17: isInAccEtaPt(GenDressedLepton_eta[0],GenDressedLepton_pt[0],-2.4,2.4,26,60) && isInAccEtaPt(GenDressedLepton_eta[1],GenDressedLepton_pt[1],-2.4,2.4,26,60); FillColor=ROOT.kAzure+2, Label="Z (2 in acc)", NormSystematic=0.04, ObjName="Events", SubPath=".*DYJetsToMuMu_M-50_TuneCP5_13TeV-powhegMiNNLO-pythia8-photos/NanoAODv7/201025_173845/0000/" +incl_zmumu_2GenInAccept : + ; IncludeMca="w-mass-13TeV/testingNano/cfg/mca-includes/mca-zmumu.txt", FillColor=ROOT.kAzure+2, Label="Z (2 in acc)", PostFix="_2GenInAccept", AddWeight="isInAccEtaPt(GenPart_eta[GenPart_preFSRLepIdx1]\,GenPart_pt[GenPart_preFSRLepIdx1]\,-2.4\,2.4\,26\,60) && isInAccEtaPt(GenPart_eta[GenPart_preFSRLepIdx2]\,GenPart_pt[GenPart_preFSRLepIdx2]\,-2.4\,2.4\,26\,60)", ALLOW_OVERWRITE_SETTINGS=True diff --git a/WMass/python/plotter/w-mass-13TeV/wmass_mu/make_cards_mu.py b/WMass/python/plotter/w-mass-13TeV/wmass_mu/make_cards_mu.py index 3433ad1a6f0b..18a5c00c51b3 100644 --- a/WMass/python/plotter/w-mass-13TeV/wmass_mu/make_cards_mu.py +++ b/WMass/python/plotter/w-mass-13TeV/wmass_mu/make_cards_mu.py @@ -1,14 +1,22 @@ import os from datetime import datetime +# example +# python w-mass-13TeV/wmass_mu/make_cards_mu.py --syst [--wlike] +# without --syst only the nominal histogram are made +# use -d or -p for tests (-p only prints command created here, while -d also runs PROG but without submitting jobs) +# use '-r s' or '-r b' to run on only signal or only backgrounds+data (default is '-r sb' for both) +# use -s to specify a suffix for folder name +# use -o to specify full name for output folder (might be useful when running signal and backgrounds separately in different days, but please check that important files are not overwritten (should not)) + PROG = 'w-mass-13TeV/make_wmass_cards.py' BASECONFIG = 'w-mass-13TeV/testingNano/cfg' -#MCA = BASECONFIG+'/mca-test.txt' MCA = BASECONFIG+'/mca-testHistForCard.txt' -#CUTFILE = BASECONFIG+'/cuts_test.txt' CUTFILE = BASECONFIG+'/cuts_testHistForCard.txt' +CUTFILE_WLIKE = BASECONFIG+'/cuts_testHistForCard_wlike.txt' SYSTFILE = BASECONFIG+'/systsEnv.txt' +LUMIWEIGHT = 1.0 # because MC samples defined in the MCA are already normalized to the luminosity corresponding to either pre or postVFP (otherwise if using 35.9 here one should divide the event weight in WEIGHTSTRING by 35.9) QUEUE = '1nd' VAR = '\'Muon_pt[0]:Muon_eta[0]\'' @@ -24,6 +32,7 @@ BINNING = '\''+etabinning+'*'+ptbinning+'\'' WEIGHTSTRING = ' \'puWeight*_get_muonSF_fast_wmass(Muon_pt[0],Muon_eta[0],Muon_charge[0])*PrefireWeight\' ' # _get_muonSF_fast_wmass applies trigger and selection SF all at once +WEIGHTSTRING_WLIKE = ' \'puWeight*_get_muonSF_fast_wlike(Muon_pt[0],Muon_eta[0],Muon_charge[0],Muon_pt[1],Muon_eta[1],Muon_charge[1],event)*PrefireWeight\' ' OUTDIR = 'wmass_%s' % datetime.now().strftime('%Y_%m_%d') if __name__ == '__main__': @@ -36,8 +45,13 @@ parser.add_option("--syst" , dest="addSyst", action="store_true", default=False, help="Add PDF systematics to the signal (need incl_sig directive in the MCA file)"); parser.add_option("-r", "--run", dest="run", type="string", default="sb", help="Which components to run: s for signal, b for backgrounds or sb for both"); parser.add_option("--max-genWeight", dest="maxGenWeight", type="string", default="50000.0", help="Maximum gen weight to be used for Z and W samples (with any decay). Weights larger than this value will be set to it."); + parser.add_option('--wlike', dest='wlike', action="store_true", default=False, help="Make cards for the wlike analysis. Default is wmass"); + parser.add_option('--auto-resub', dest='automaticResubmission', action="store_true", default=False, help="Use condor features for automatic job resubmission in case of failures"); + parser.add_option('-g', "--group-jobs", dest="groupJobs", type=int, default=5, help="group signal or signal-like jobs (e.g. Wmunu or Wtaunu) so that one job runs multiple makeHistogramsWMass commands"); (options, args) = parser.parse_args() + if options.wlike: + OUTDIR = OUTDIR.replace("wmass_","wlike_") if options.suffix: OUTDIR += ('_%s' % options.suffix) if options.outdir != "": @@ -49,21 +63,30 @@ if "b" in options.run: components.append(" -b ") + if options.wlike: + CUTFILE = CUTFILE_WLIKE + WEIGHTSTRING = WEIGHTSTRING_WLIKE for c in components: - cmd='python ' + ' '.join([PROG,MCA,CUTFILE,VAR,BINNING,SYSTFILE,OUTDIR,'-C mu']) + \ - (' -W %s ' % WEIGHTSTRING) + (' -P %s ' % TREEPATH) + (' -q %s ' % QUEUE) + c - if options.dryRun: cmd += ' --dry-run ' - if options.addSyst: cmd += ' --pdf-syst --qcd-syst ' + cmd='python ' + ' '.join([PROG,MCA,CUTFILE,VAR,BINNING,SYSTFILE,OUTDIR,c]) + cmd += ' -W {w} -P {p} -l {l} -q {q} -C mu '.format(w=WEIGHTSTRING,p=TREEPATH,l=LUMIWEIGHT,q=QUEUE) + if options.dryRun: + cmd += ' --dry-run ' + if options.addSyst: + cmd += ' --pdf-syst --qcd-syst ' + if options.wlike: + cmd += ' --wlike ' if 'b' in c: cmd += ' -n bkg ' elif 's' in c: cmd += ' -n sig ' + if options.automaticResubmission: + cmd += ' --auto-resub --n-resub 2 ' optsForHisto = ' --nanoaod-tree --max-genWeight-procs \'W.*|Z.*\' \'{m}\' --clip-genWeight-toMax '.format(m=options.maxGenWeight) cmd += ' --add-option "{opt}"'.format(opt=optsForHisto) - cmd += ' -g 5 ' + cmd += ' -g {g} '.format(g=options.groupJobs) cmd += ' --decorrelateSignalScales ' - cmd += ' --vpt-weight Zmumu --vpt-weight Ztautau' #--vpt-weight Wmunu --vpt-weight Wtaunu ' # check if easier to use regular expressions to catch cases inside PROG + cmd += ' --vpt-weight Zmumu --vpt-weight Ztautau' #--vpt-weight Wmunu --vpt-weight Wtaunu ' # check if easier to use regular expressions to catch cases inside PROG if options.printOnly: print cmd print "" diff --git a/WMass/python/plotter/w-mass-13TeV/wmass_mu/systsEnv.txt b/WMass/python/plotter/w-mass-13TeV/wmass_mu/systsEnv.txt index ba432c4a6797..804aed9aa1c5 100644 --- a/WMass/python/plotter/w-mass-13TeV/wmass_mu/systsEnv.txt +++ b/WMass/python/plotter/w-mass-13TeV/wmass_mu/systsEnv.txt @@ -34,7 +34,7 @@ CMS_Tau : TauDecaysW : .* : 1.04 #CMS_Wmu_FR_norm : data_fakes : .* : 1.30 # shape uncertainties (slope of FR with pt up/down, and continuous variation in eta, and awayjet 45) -CMS_Wmu_FRmu_slope : data_fakes : .* : FRmu_slope : templatesShapeOnly +#CMS_Wmu_FRmu_slope : data_fakes : .* : FRmu_slope : templatesShapeOnly #CMS_Wmu_FRmu_continuous : data_fakes : .* : FRmu_continuous : templates #CMS_Wmu_FRmu_awayJetPt45 : data_fakes : .* : data_fakes_FRmu_awayJetPt45 : alternateShapeOnly diff --git a/WMass/python/postprocessing/lxbatch_runner.sh b/WMass/python/postprocessing/lxbatch_runner.sh index 82fd5dde7ddc..eecae2be866d 100755 --- a/WMass/python/postprocessing/lxbatch_runner.sh +++ b/WMass/python/postprocessing/lxbatch_runner.sh @@ -2,7 +2,7 @@ if [[ "$VO_CMS_SW_DIR" != "" ]] && test -f $VO_CMS_SW_DIR/cmsset_default.sh; then source $VO_CMS_SW_DIR/cmsset_default.sh fi; -export SCRAM_ARCH=slc7_amd64_gcc630 +export SCRAM_ARCH=slc7_amd64_gcc700 #export SCRAM_ARCH=slc7_amd64_gcc630 WORK=$1; shift SRC=$1; shift