115 parser = argparse.ArgumentParser(description=
"Produce a BinnedValues-JSON file for pileup reweighting, using data pileup distributions obtained with `pileupCalc.py -i analysis-lumi-json.txt --inputLumiJSON pileup-json.txt --calcMode true --minBiasXsec MBXSECINNB --maxPileupBin NMAX --numPileupBins N outname.root` (see also https://twiki.cern.ch/twiki/bin/viewauth/CMS/PileupJSONFileforData#Pileup_JSON_Files_For_Run_II)")
116 parser.add_argument(
"-o",
"--output", default=
"puweights.json", type=str, help=
"Output file name")
117 parser.add_argument(
"-f",
"--format", type=str, choices=[
"correctionlib",
"cp3-llbb"], default=
"cp3-llbb", help=
"Output JSON format")
118 parser.add_argument(
"--name", type=str, default=
"puweights", help=
"Name of the correction inside the CorrectionSet (only used for the correctionlib format)")
119 parser.add_argument(
"--mcprofile", help=
"Pileup profile used to generate the MC sample (use --listmcprofiles to see the list of defined profiles)")
120 parser.add_argument(
"--listmcprofiles", action=
"store_true", help=
"list the available MC pileup profiles")
121 parser.add_argument(
"--nominal", type=str, help=
"File with the data (true) pileup distribution histogram assuming the nominal minimum bias cross-section value")
122 parser.add_argument(
"--up", type=str, help=
"File with the data (true) pileup distribution histogram assuming the nominal+1sigma minimum bias cross-section value")
123 parser.add_argument(
"--down", type=str, help=
"File with the data (true) pileup distribution histogram assuming the nominal-1sigma minimum bias cross-section value")
124 parser.add_argument(
"--rebin", type=int, help=
"Factor to rebin the data histograms by")
125 parser.add_argument(
"--makePlot", action=
"store_true", help=
"Make a plot of the PU profiles and weights (requires matplotlib)")
126 parser.add_argument(
"mcfiles", nargs=
"*", help=
"MC ROOT files to extract a pileup profile from (if used)")
127 parser.add_argument(
"--mctreename", type=str, default=
"Events", help=
"Name of the tree to use in mcfiles")
128 parser.add_argument(
"--mcreweightvar", type=str, default=
"Pileup_nTrueInt", help=
"Name of the branch in the tree of the mcfiles to use for getting a histogram")
129 parser.add_argument(
"-v",
"--verbose", action=
"store_true", help=
"Print verbose output")
130 parser.add_argument(
"--gzip", action=
"store_true", help=
"Save the output as gzip file")
131 args = parser.parse_args()
132 logging.basicConfig(level=(logging.DEBUG
if args.verbose
else logging.INFO))
136 matplotlib.use(
"agg")
137 from matplotlib
import pyplot
as plt
138 except Exception
as ex:
139 logger.warning(
"matplotlib could not be imported, so no plot will be produced")
140 args.makePlot =
False
144 except Exception
as ex:
145 logger.warning(
"gzip or io could not be imported, output will be stored as regular file")
147 if args.listmcprofiles:
148 logger.info(
"The known PU profiles are: {0}".format(
", ".join(repr(k)
for k
in mcPUProfiles)))
152 logger.warning(
"MC PU profile and MC files are passed - extracting from the files")
153 logger.info(
"Extracting the MC profile from {0} in the {1} tree of: {2}".format(args.mcreweightvar, args.mctreename,
", ".join(args.mcfiles)))
154 from cppyy
import gbl
155 tup = gbl.TChain(args.mctreename)
156 for mcfn
in args.mcfiles:
158 hMCPU = gbl.TH1F(
"hMCPU",
"MC PU profile", 100, 0., 100.)
159 tup.Draw(f
"{args.mcreweightvar}>>hMCPU",
"",
"GOFF")
162 if args.mcprofile
not in mcPUProfiles:
163 raise ValueError(
"No MC PU profile with tag '{0}' is known".format(args.mcprofile))
165 mcPUBins, mcPUVals = mcPUProfiles[args.mcprofile]
166 if len(mcPUBins) != len(mcPUVals)+1:
167 logger.verbose(len(mcPUBins), len(mcPUVals))
169 raise RuntimeError(
"Either one of --listmcprofiles or --mcprofile, or a list of MC files to extract a MC profile from, must be passed")
172 raise RuntimeError(
"No --nominal argument")
175 fNom, hNom =
getHist(args.nominal)
177 hNom.Rebin(args.rebin)
179 ratioBins, nomRatio =
getRatio(nomBins, nomCont, mcPUBins, mcPUVals)
181 upCont, upRatio, downCont, downRatio =
None,
None,
None,
None
182 if bool(args.up) != bool(args.down):
183 raise ValueError(
"If either one of --up and --down is specified, both should be")
184 if args.up
and args.down:
187 hUp.Rebin(args.rebin)
191 _, upRatio =
getRatio(upBins, upCont, mcPUBins, mcPUVals)
192 fDown, hDown =
getHist(args.down)
194 hDown.Rebin(args.rebin)
198 _, downRatio =
getRatio(downBins, downCont, mcPUBins, mcPUVals)
200 if args.format ==
"correctionlib":
208 "name":
"NumTrueInteractions",
210 "description":
"Number of true interactions"
215 "description":
"nominal, up, or down"
221 "description":
"Event weight for pileup reweighting"
224 "nodetype":
"category",
229 "nodetype":
"binning",
230 "input":
"NumTrueInteractions",
232 "edges": list(ratioBins),
233 "content": list(nomRatio)
237 "nodetype":
"binning",
238 "input":
"NumTrueInteractions",
240 "edges": list(ratioBins),
241 "content": list(upRatio)
242 }}]
if upRatio
is not None else []
246 "nodetype":
"binning",
247 "input":
"NumTrueInteractions",
249 "edges": list(ratioBins),
250 "content": list(downRatio)
251 }}]
if downRatio
is not None else [])
256 elif args.format ==
"cp3-llbb":
259 "variables" : [
"NumTrueInteractions"],
260 "binning" : {
"x": list(ratioBins)},
261 "error_type" :
"absolute",
264 "bin" : [ratioBins[i], ratioBins[i+1]],
265 "value" : nomRatio[i],
266 "error_low" : (nomRatio[i]-downRatio[i]
if downRatio
is not None else 0.),
267 "error_high" : (upRatio[i]-nomRatio[i]
if upRatio
is not None else 0.)
268 }
for i
in range(nomRatio.shape[0])
272 raise ValueError(f
"Unsupported output format: {args.format}")
275 if not outN.endswith(
".gz"):
277 with gzip.open(outN,
"wb")
as outF, io.TextIOWrapper(outF, encoding=
"utf-8")
as outE:
280 with open(args.output,
"w")
as outF:
284 fig,(ax,rax) = plt.subplots(2,1, figsize=(6,6), sharex=
True)
285 rax.set_yscale(
"log", nonposy=
"clip")
287 dBinCenters = .5*(mcPUBins[:-1]+mcPUBins[1:])
288 nBinCenters = .5*(nomBins[:-1]+nomBins[1:])
289 rBinCenters = .5*(ratioBins[:-1]+ratioBins[1:])
290 ax.hist(dBinCenters, bins=mcPUBins, weights=mcPUVals, histtype=
"step", label=
"MC")
291 ax.hist(nBinCenters, bins=nomBins, weights=nomCont, histtype=
"step", label=
"Nominal", color=
"k")
292 rax.hist(rBinCenters, bins=ratioBins, weights=nomRatio, histtype=
"step", color=
"k")
293 if upCont
is not None:
294 ax.hist(nBinCenters, bins=nomBins, weights=upCont, histtype=
"step", label=
"Up", color=
"r")
295 ax.hist(nBinCenters, bins=nomBins, weights=downCont, histtype=
"step", label=
"Down", color=
"b")
296 rax.hist(rBinCenters, bins=ratioBins, weights=upRatio, histtype=
"step", color=
"r")
297 rax.hist(rBinCenters, bins=ratioBins, weights=downRatio, histtype=
"step", color=
"b")
300 rax.set_ylim(.02, 2.)
301 rax.set_xlim(ratioBins[0], ratioBins[-1])
303 rax.set_xlabel(args.mcreweightvar)
305 ax.set_title(args.mcprofile)
306 if args.output.endswith(
".json"):
307 plt.savefig(args.output.replace(
".json",
".png"))