3 from builtins
import zip
4 from builtins
import object
5 from past.utils
import old_div
6 from builtins
import range
9 from argparse
import ArgumentParser, ArgumentDefaultsHelpFormatter
10 from pprint
import pprint
15 sepRE = re.compile (
r'[\s,;:]+')
16 nonSpaceRE = re.compile (
r'\S')
26 lastSingleXingRun = 136175
27 lumiSectionLength = 23.310779
37 pieces = sepRE.split (line.strip())
40 raise RuntimeError(
"Odd number of pieces")
42 raise RuntimeError(
"Not enough pieces")
44 self.
run = int (pieces[0])
45 self.
lumi = int (pieces[1])
49 raise RuntimeError(
"Pieces not right format")
52 for xing, lum
in zip (pieces[4::2],pieces[5::2]):
59 raise RuntimeError(
"Inst Lumi Info malformed")
70 raise RuntimeError(
"This event %s already has Xing information" \
72 if self.
run > LumiInfo.lastSingleXingRun:
80 old_div(self.
delivered, LumiInfo.lumiSectionLength)
93 return "%6d, %4d: %6.1f (%4.1f%%) %4.2f (%3d)" % \
111 print(
"loading luminosity information from '%s'." % filename)
112 source = open (filename,
'r') 114 'delivered',
'recorded']
131 lumi = LumiInfo (line)
134 self[lumi.key] = lumi
136 if not self.
xingInfo and lumi.xingInfo:
143 val = getattr (lumi, key)
144 if val < self.
_min[key]
or self.
_min[key] < 0:
146 if val > self.
_max[key]
or not self.
_max[key]:
165 for lumis
in self.values():
166 lumis.delivered /= lumFactor
167 lumis.recorded /= lumFactor
175 retval =
'run, lum del ( dt ) inst (#xng)\n' 176 for key, value
in sorted (self.items()):
177 retval +=
"%s\n" % value
182 return self.
_min[key]
186 return self.
_max[key]
190 return sorted (dict.keys (self))
194 return sorted (dict.iteritems (self))
200 for key, lumi
in self.items():
201 total += lumi.recorded
202 lumi.totalRecorded = total
203 lumi.fracRecorded = old_div(total, self.
totalRecLum)
210 for key, lumi
in self.items():
211 if not lumi.xingInfo
and not lumi.fixXingInfo():
213 print(
"Do not have lumi xing info for %s" % lumi.keyString)
215 print(
"Setting no Xing info flag")
219 xingKeyList.append( (lumi.aveInstLum, key) )
220 if lumi.aveInstLum > maxAveInstLum:
221 maxAveInstLum = lumi.aveInstLum
224 for tup
in xingKeyList:
226 total += lumi.recorded
227 lumi.totalAXILrecorded = total
228 lumi.fracAXILrecorded = old_div(total, self.
totalRecLum)
229 lumi.fracAXIL = old_div(lumi.aveInstLum, maxAveInstLum)
240 print(
"loading events from '%s'" % filename)
241 events = open (filename,
'r') 242 runIndex, lumiIndex, eventIndex, weightIndex = 0, 1, 2, 3 244 lumiIndex, eventIndex = 2,1
250 pieces = sepRE.split (line.strip())
251 if len (pieces) < minPieces:
252 if nonSpaceRE.search (line):
253 print(
"skipping", line)
256 run, lumi, event =
int( pieces[runIndex] ), \
257 int( pieces[lumiIndex] ), \
258 int( pieces[eventIndex] )
264 print(
"Warning, %s is not found in the lumi information" \
268 raise RuntimeError(
"%s is not found in lumi information. Use '--ignoreNoLumiEvents' option to ignore these events and continue." \
270 if options.edfMode !=
'time' and not cont[key].xingInfo:
272 print(
"Warning, %s does not have Xing information" \
276 raise RuntimeError(
"%s does not have Xing information. Use '--ignoreNoLumiEvents' option to ignore these events and continue." \
279 weight = float (pieces[weightIndex])
282 eventsDict.setdefault( key, []).
append( (event, weight) )
283 totalWeight += weight
285 return eventsDict, totalWeight
288 def makeEDFplot (lumiCont, eventsDict, totalWeight, outputFile, options):
299 if 'time' == options.edfMode:
301 if lumiCont.minRun
or lumiCont.minIntLum:
307 for key, eventList
in sorted( eventsDict.items() ):
310 if lumiCont.minRun
and lumiCont.minRun > key[0]
or \
311 lumiCont.maxRun
and lumiCont.maxRun < key[0]:
313 for event
in eventList:
317 factor = old_div(weight, totalWeight)
319 intLum = lumiCont[key].totalRecorded
321 raise RuntimeError(
"key %s not found in lumi information" \
323 if lumiCont.minIntLum
and lumiCont.minIntLum > intLum
or \
324 lumiCont.maxIntLum
and lumiCont.maxIntLum < intLum:
326 lumFrac = old_div(intLum, lumiCont.totalRecLum)
327 xVals.append( lumiCont[key].totalRecorded)
328 yVals.append (factor)
329 expectedVals.append (lumFrac)
330 predVals.append (lumFrac * options.pred)
332 if not lumiCont.maxRun
and not lumiCont.maxIntLum:
333 xVals.append (lumiCont.totalRecLum)
335 expectedVals.append (1)
336 predVals.append (options.pred)
340 if options.resetExpected:
341 slope = old_div((yVals[-1] - yVals[0]), (xVals[-1] - xVals[0]))
342 print(
"slope", slope)
343 for index, old
in enumerate (expectedVals):
344 expectedVals[index] = yVals[0] + \
345 slope * (xVals[index] - xVals[0])
349 if options.breakExpectedIntLum:
350 breakExpectedIntLum = []
351 for chunk
in options.breakExpectedIntLum:
352 pieces = sepRE.split (chunk)
355 breakExpectedIntLum.append(
float(piece) )
357 raise RuntimeError(
"'%s' from '%s' is not a valid float" \
359 breakExpectedIntLum.sort()
363 for index, xPos
in enumerate (xVals):
364 if xPos > breakExpectedIntLum[breakIndex]:
365 boundaries.append (index)
366 while breakIndex < len (breakExpectedIntLum):
368 if breakIndex >= len (breakExpectedIntLum):
374 if xPos <= breakExpectedIntLum[breakIndex]:
380 raise RuntimeError(
"No values of 'breakExpectedIntLum' are in current range.")
383 boundaries.insert (0, 0)
386 if boundaries[-1] != len (xVals) - 1:
387 boundaries.append( len (xVals) - 1 )
388 rangeList = list(zip (boundaries, boundaries[1:]))
389 for thisRange
in rangeList:
392 slope = old_div((yVals[upper] - yVals[lower]), \
393 (xVals[upper] - xVals[lower]))
394 print(
"slope", slope)
397 for index
in range (lower, upper + 1):
398 newExpected = yVals[lower] + \
399 slope * (xVals[index] - xVals[lower])
400 pairList.append( (xVals[index], newExpected) )
401 expectedVals[index] = newExpected
402 expectedChunks.append (pairList)
406 elif 'instLum' == options.edfMode
or 'instIntLum' == options.edfMode:
408 if not lumiCont.xingInfo:
409 raise RuntimeError(
"Luminosity Xing information missing.")
410 for key, eventList
in sorted( eventsDict.items() ):
413 instLum = lumi.aveInstLum
414 fracAXIL = lumi.fracAXILrecorded
415 totalAXIL = lumi.totalAXILrecorded
417 raise RuntimeError(
"key %s not found in lumi information" \
419 for event
in eventList:
420 eventTupList.append( (instLum, fracAXIL, totalAXIL, key,
421 event[0], event[1], ) )
423 for eventTup
in eventTupList:
424 weight += eventTup[5]
425 factor = old_div(weight, totalWeight)
426 if 'instLum' == options.edfMode:
427 xVals.append (eventTup[0])
429 xVals.append (eventTup[2])
430 yVals.append (factor)
431 expectedVals.append (eventTup[1])
432 predVals.append (eventTup[1] * options.pred)
434 raise RuntimeError(
"It looks like Charles screwed up if you are seeing this.")
437 step = int (old_div(math.sqrt(size), 2) + 1)
438 if options.printValues:
439 for index
in range (size):
440 print(
"%8f %8f %8f" % (xVals[index], yVals[index], expectedVals[index]), end=
' ')
442 denom = xVals[index] - xVals[index - step]
443 numer = yVals[index] - yVals[index - step]
445 print(
" %8f" % (old_div(numer, denom)), end=
' ')
446 if 0 == index % step:
447 print(
" **", end=
' ')
452 xArray = array.array (
'd', xVals)
453 yArray = array.array (
'd', yVals)
454 expected = array.array (
'd', expectedVals)
455 graph = ROOT.TGraph( size, xArray, yArray)
456 graph.SetTitle (options.title)
457 graph.SetMarkerStyle (20)
458 expectedGraph = ROOT.TGraph( size, xArray, expected)
459 expectedGraph.SetLineColor (ROOT.kRed)
460 expectedGraph.SetLineWidth (3)
461 if options.noDataPoints:
462 expectedGraph.SetLineStyle (2)
466 print(
"average weight per event:", old_div(weight, ( size - 1)))
467 maxDistance = ROOT.TMath.KolmogorovTest (size, yArray,
470 prob = ROOT.TMath.KolmogorovProb( maxDistance * math.sqrt( size ) )
473 ROOT.gROOT.SetStyle(
'Plain')
474 ROOT.gROOT.SetBatch()
476 graph.GetXaxis().SetRangeUser (min (xVals), max (xVals))
477 minValue = min (
min(yVals),
min(expected))
479 minValue = min (minValue, min (predVals))
480 graph.GetYaxis().SetRangeUser (minValue,
481 max (
max(yVals),
max(expected),
max(predVals)))
482 graph.SetLineWidth (3)
483 if options.noDataPoints:
487 if 'instLum' == options.edfMode:
488 graph.GetXaxis().SetTitle (
"Average Xing Inst. Luminosity (1/ub/s)")
489 graph.GetXaxis().SetRangeUser (0., lumiCont.max(
'aveInstLum'))
491 if 'instIntLum' == options.edfMode:
492 graph.GetXaxis().SetTitle (
"Integrated Luminosity - Inst. Lum. Ordered (1/%s)" \
495 graph.GetXaxis().SetTitle (
"Integrated Luminosity (1/%s)" \
497 graph.GetYaxis().SetTitle (
"Fraction of Events Seen")
500 for index, chunk
in enumerate (expectedChunks):
501 expectedXarray = array.array (
'd', [item[0]
for item
in chunk])
502 expectedYarray = array.array (
'd', [item[1]
for item
in chunk])
503 expectedGraph = ROOT.TGraph( len(chunk),
506 expectedGraph.SetLineWidth (3)
507 if options.noDataPoints:
508 expectedGraph.SetLineStyle (2)
510 expectedGraph.SetLineColor (ROOT.kBlue)
512 expectedGraph.SetLineColor (ROOT.kRed)
513 expectedGraph.Draw(
"L")
514 expectedGraphs.append (expectedGraph)
515 exptectedGraph = expectedGraphs[0]
517 expectedGraph.Draw (
"L")
520 predArray = array.array (
'd', predVals)
521 green = ROOT.TGraph (size, xArray, predArray)
522 green.SetLineWidth (3)
523 green.SetLineColor (8)
525 legend = ROOT.TLegend(0.15, 0.65, 0.50, 0.85)
526 legend.SetFillStyle (0)
527 legend.SetLineColor(ROOT.kWhite)
528 observed =
'Observed' 530 observed +=
' (weighted)' 531 legend.AddEntry(graph, observed,
"PL")
532 if options.resetExpected:
533 legend.AddEntry(expectedGraph,
"Expected from partial yield",
"L")
535 legend.AddEntry(expectedGraph,
"Expected from total yield",
"L")
537 legend.AddEntry(green, options.predLabel,
"L")
538 legend.AddEntry(
"",
"D_{stat}=%.3f, N=%d" % (maxDistance, size),
"")
539 legend.AddEntry(
"",
"P_{KS}=%.3f" % prob,
"")
543 c1.Print (outputFile)
554 if __name__ ==
'__main__':
558 allowedEDF = [
'time',
'instLum',
'instIntLum']
559 parser = ArgumentParser(formatter_class=ArgumentDefaultsHelpFormatter, usage=
'%(prog)s [options] lumi.csv events.txt output.png', description=
'Script for generating EDF curves. See https://twiki.cern.ch/twiki/bin/viewauth/CMS/SWGuideGenerateEDF for more details.')
560 plotGroup = parser.add_argument_group(
"Plot Options")
561 rangeGroup = parser.add_argument_group(
"Range Options")
562 inputGroup = parser.add_argument_group(
"Input Options")
563 modeGroup = parser.add_argument_group(
"Mode Options")
564 plotGroup.add_argument(
'--title', dest=
'title', type=str,
565 default =
'Empirical Distribution Function',
566 help =
'title of plot')
567 plotGroup.add_argument(
'--predicted', dest=
'pred', type=float,
569 help =
'factor by which predicted curve is greater than observed')
570 plotGroup.add_argument(
'--predLabel', dest=
'predLabel', type=str,
571 default =
'Predicted',
572 help =
'label of predicted in legend')
573 plotGroup.add_argument(
'--noDataPoints', dest=
'noDataPoints',
574 default =
False, action=
'store_true',
575 help=
"Draw lines but no points for data")
576 rangeGroup.add_argument(
'--minRun', dest=
'minRun', type=int, default=0,
577 help=
'Minimum run number to consider')
578 rangeGroup.add_argument(
'--maxRun', dest=
'maxRun', type=int, default=0,
579 help=
'Maximum run number to consider')
580 rangeGroup.add_argument(
'--minIntLum', dest=
'minIntLum', type=float, default=0,
581 help=
'Minimum integrated luminosity to consider')
582 rangeGroup.add_argument(
'--maxIntLum', dest=
'maxIntLum', type=float, default=0,
583 help=
'Maximum integrated luminosity to consider')
584 rangeGroup.add_argument(
'--resetExpected', dest=
'resetExpected',
585 default =
False, action=
'store_true',
586 help=
'Reset expected from total yield to highest point considered')
587 rangeGroup.add_argument(
'--breakExpectedIntLum', dest=
'breakExpectedIntLum',
588 type=str, action=
'append', default=[],
589 help=
'Break expected curve into pieces at integrated luminosity boundaries')
590 inputGroup.add_argument(
'--ignoreNoLumiEvents', dest=
'ignore',
591 default =
False, action=
'store_true',
592 help =
'Ignore (with a warning) events that do not have a lumi section')
593 inputGroup.add_argument(
'--noWarnings', dest=
'noWarnings',
594 default =
False,action=
'store_true',
595 help =
'Do not print warnings about missing luminosity information')
596 inputGroup.add_argument(
'--runEventLumi', dest=
'relOrder',
597 default =
False, action=
'store_true',
598 help =
'Parse event list assuming Run, Event #, Lumi# order')
599 inputGroup.add_argument(
'--weights', dest=
'weights', default =
False, action=
'store_true',
600 help =
'Read fourth column as a weight')
601 modeGroup.add_argument(
'--print', dest=
'printValues', default =
False, action=
'store_true',
602 help =
'Print X and Y values of EDF plot')
603 modeGroup.add_argument(
'--runsWithLumis', dest=
'runsWithLumis',
604 type=str,action=
'append', default=[],
605 help=
'Print out run and lumi sections corresponding to integrated luminosities provided and then exits')
606 modeGroup.add_argument(
'--edfMode', dest=
'edfMode', type=str,
608 help=
"EDF Mode", choices=allowedEDF)
609 parser.add_argument(
"lumi_csv", metavar=
"lumi.csv", type=str)
610 parser.add_argument(
"events_txt", metavar=
"events.txt", type=str, nargs=
'?')
611 parser.add_argument(
"output_png", metavar=
"output.png", type=str, nargs=
'?')
612 options = parser.parse_args()
614 if not options.runsWithLumis
and (options.events_txt
is None or options.output_png
is None):
615 parser.error(
"Must provide lumi.csv, events.txt, and output.png")
620 cont = LumiInfoCont (options.lumi_csv, **options.__dict__)
621 cont.minRun = options.minRun
622 cont.maxRun = options.maxRun
623 cont.minIntLum = options.minIntLum
624 cont.maxIntLum = options.maxIntLum
630 if options.runsWithLumis:
632 for line
in options.runsWithLumis:
633 pieces = sepRE.split (line)
636 recLumValue = float (piece)
638 raise RuntimeError(
"'%s' in '%s' is not a float" % \
641 raise RuntimeError(
"You must provide positive values for -runsWithLumis ('%f' given)" % recLumValue)
642 recLumis.append (recLumValue)
644 raise RuntimeError(
"What did Charles do now?")
647 recLumValue = recLumis [recLumIndex]
650 for key, lumi
in cont.items():
651 if prevRecLumi >= recLumValue
and recLumValue < lumi.totalRecorded:
653 print(
"%s contains total recorded lumi %f" % \
654 (key.__str__(), recLumValue))
657 if recLumIndex == len (recLumis):
660 recLumValue = recLumis [recLumIndex]
661 if prevRecLumi >= recLumValue
and recLumValue < lumi.totalRecorded:
663 print(
"%s contains total recorded lumi %f" % \
664 (key.__str__(), recLumValue))
669 prevRecLumi = lumi.totalRecorded
670 if recLumIndex < len (recLumis):
671 print(
"Theses lumis not found: %s" % recLumis[recLumIndex:])
677 if options.edfMode !=
'time' and not cont.xingInfo:
678 raise RuntimeError(
"'%s' does not have Xing info" % options.lumi_csv)
679 eventsDict, totalWeight = loadEvents (options.events_txt, cont, options)
680 makeEDFplot (cont, eventsDict, totalWeight, options.output_png, options)
def _integrateContainer(self)
def __init__(self, filename, kwargs)
def loadEvents(filename, cont, options)
General Functions
invunits
Now that everything is setup, switch integrated ## luminosity to more reasonable units.
void print(TMatrixD &m, const char *label=nullptr, bool mathematicaFormat=false)
def makeEDFplot(lumiCont, eventsDict, totalWeight, outputFile, options)