6 from pprint
import pprint
11 sepRE = re.compile (
r'[\s,;:]+')
12 nonSpaceRE = re.compile (
r'\S')
22 lastSingleXingRun = 136175
23 lumiSectionLength = 23.310779
33 pieces = sepRE.split (line.strip())
36 raise RuntimeError,
"Odd number of pieces"
38 raise RuntimeError,
"Not enough pieces"
40 self.
run = int (pieces[0])
41 self.
lumi = int (pieces[1])
45 raise RuntimeError,
"Pieces not right format"
48 for xing, lum
in zip (pieces[4::2],pieces[5::2]):
51 self.instLums.append( (xing, lum) )
55 raise RuntimeError,
"Inst Lumi Info malformed"
66 raise RuntimeError,
"This event %s already has Xing information" \
68 if self.
run > LumiInfo.lastSingleXingRun:
76 self.
delivered / LumiInfo.lumiSectionLength
77 self.instLums.append( (xing, lum) )
89 return "%6d, %4d: %6.1f (%4.1f%%) %4.2f (%3d)" % \
107 print "loading luminosity information from '%s'." % filename
108 source = open (filename,
'r')
110 'delivered',
'recorded']
127 lumi = LumiInfo (line)
130 self[lumi.key] = lumi
132 if not self.
xingInfo and lumi.xingInfo:
139 val = getattr (lumi, key)
140 if val < self.
_min[key]
or self.
_min[key] < 0:
142 if val > self.
_max[key]
or not self.
_max[key]:
161 for lumis
in self.values():
162 lumis.delivered /= lumFactor
163 lumis.recorded /= lumFactor
171 retval =
'run, lum del ( dt ) inst (#xng)\n'
172 for key, value
in sorted (self.
iteritems()):
173 retval +=
"%s\n" % value
178 return self.
_min[key]
182 return self.
_max[key]
186 return sorted (dict.keys (self))
190 return sorted (dict.iteritems (self))
197 total += lumi.recorded
198 lumi.totalRecorded = total
207 if not lumi.xingInfo
and not lumi.fixXingInfo():
209 print "Do not have lumi xing info for %s" % lumi.keyString
211 print "Setting no Xing info flag"
215 xingKeyList.append( (lumi.aveInstLum, key) )
216 if lumi.aveInstLum > maxAveInstLum:
217 maxAveInstLum = lumi.aveInstLum
220 for tup
in xingKeyList:
222 total += lumi.recorded
223 lumi.totalAXILrecorded = total
225 lumi.fracAXIL = lumi.aveInstLum / maxAveInstLum
236 print "loading events from '%s'" % filename
237 events = open (filename,
'r')
238 runIndex, lumiIndex, eventIndex, weightIndex = 0, 1, 2, 3
240 lumiIndex, eventIndex = 2,1
246 pieces = sepRE.split (line.strip())
247 if len (pieces) < minPieces:
248 if nonSpaceRE.search (line):
249 print "skipping", line
252 run, lumi, event = int( pieces[runIndex] ), \
253 int( pieces[lumiIndex] ), \
254 int( pieces[eventIndex] )
258 if not cont.has_key (key):
260 print "Warning, %s is not found in the lumi information" \
264 raise RuntimeError,
"%s is not found in lumi information. Use '--ignoreNoLumiEvents' option to ignore these events and continue." \
266 if options.edfMode !=
'time' and not cont[key].xingInfo:
268 print "Warning, %s does not have Xing information" \
272 raise RuntimeError,
"%s does not have Xing information. Use '--ignoreNoLumiEvents' option to ignore these events and continue." \
275 weight = float (pieces[weightIndex])
278 eventsDict.setdefault( key, []).
append( (event, weight) )
279 totalWeight += weight
281 return eventsDict, totalWeight
284 def makeEDFplot (lumiCont, eventsDict, totalWeight, outputFile, options):
295 if 'time' == options.edfMode:
297 if lumiCont.minRun
or lumiCont.minIntLum:
303 for key, eventList
in sorted( eventsDict.iteritems() ):
306 if lumiCont.minRun
and lumiCont.minRun > key[0]
or \
307 lumiCont.maxRun
and lumiCont.maxRun < key[0]:
309 for event
in eventList:
313 factor = weight / totalWeight
315 intLum = lumiCont[key].totalRecorded
317 raise RuntimeError,
"key %s not found in lumi information" \
319 if lumiCont.minIntLum
and lumiCont.minIntLum > intLum
or \
320 lumiCont.maxIntLum
and lumiCont.maxIntLum < intLum:
322 lumFrac = intLum / lumiCont.totalRecLum
323 xVals.append( lumiCont[key].totalRecorded)
324 yVals.append (factor)
325 expectedVals.append (lumFrac)
326 predVals.append (lumFrac * options.pred)
328 if not lumiCont.maxRun
and not lumiCont.maxIntLum:
329 xVals.append (lumiCont.totalRecLum)
331 expectedVals.append (1)
332 predVals.append (options.pred)
336 if options.resetExpected:
337 slope = (yVals[-1] - yVals[0]) / (xVals[-1] - xVals[0])
339 for index, old
in enumerate (expectedVals):
340 expectedVals[index] = yVals[0] + \
341 slope * (xVals[index] - xVals[0])
345 if options.breakExpectedIntLum:
346 breakExpectedIntLum = []
347 for chunk
in options.breakExpectedIntLum:
348 pieces = sepRE.split (chunk)
351 breakExpectedIntLum.append( float(piece) )
353 raise RuntimeError,
"'%s' from '%s' is not a valid float" \
355 breakExpectedIntLum.sort()
359 for index, xPos
in enumerate (xVals):
360 if xPos > breakExpectedIntLum[breakIndex]:
361 boundaries.append (index)
362 while breakIndex < len (breakExpectedIntLum):
364 if breakIndex >= len (breakExpectedIntLum):
370 if xPos <= breakExpectedIntLum[breakIndex]:
376 raise RuntimeError,
"No values of 'breakExpectedIntLum' are in current range."
379 boundaries.insert (0, 0)
382 if boundaries[-1] != len (xVals) - 1:
383 boundaries.append( len (xVals) - 1 )
384 rangeList = zip (boundaries, boundaries[1:])
385 for thisRange
in rangeList:
388 slope = (yVals[upper] - yVals[lower]) / \
389 (xVals[upper] - xVals[lower])
393 for index
in range (lower, upper + 1):
394 newExpected = yVals[lower] + \
395 slope * (xVals[index] - xVals[lower])
396 pairList.append( (xVals[index], newExpected) )
397 expectedVals[index] = newExpected
398 expectedChunks.append (pairList)
402 elif 'instLum' == options.edfMode
or 'instIntLum' == options.edfMode:
404 if not lumiCont.xingInfo:
405 raise RuntimeError,
"Luminosity Xing information missing."
406 for key, eventList
in sorted( eventsDict.iteritems() ):
409 instLum = lumi.aveInstLum
410 fracAXIL = lumi.fracAXILrecorded
411 totalAXIL = lumi.totalAXILrecorded
413 raise RuntimeError,
"key %s not found in lumi information" \
415 for event
in eventList:
416 eventTupList.append( (instLum, fracAXIL, totalAXIL, key,
417 event[0], event[1], ) )
419 for eventTup
in eventTupList:
420 weight += eventTup[5]
421 factor = weight / totalWeight
422 if 'instLum' == options.edfMode:
423 xVals.append (eventTup[0])
425 xVals.append (eventTup[2])
426 yVals.append (factor)
427 expectedVals.append (eventTup[1])
428 predVals.append (eventTup[1] * options.pred)
430 raise RuntimeError,
"It looks like Charles screwed up if you are seeing this."
433 step = int (math.sqrt(size) / 2 + 1)
434 if options.printValues:
435 for index
in range (size):
436 print "%8f %8f %8f" % (xVals[index], yVals[index], expectedVals[index]),
438 denom = xVals[index] - xVals[index - step]
439 numer = yVals[index] - yVals[index - step]
441 print " %8f" % (numer / denom),
442 if 0 == index % step:
448 xArray = array.array (
'd', xVals)
449 yArray = array.array (
'd', yVals)
450 expected = array.array (
'd', expectedVals)
451 graph = ROOT.TGraph( size, xArray, yArray)
452 graph.SetTitle (options.title)
453 graph.SetMarkerStyle (20)
454 expectedGraph = ROOT.TGraph( size, xArray, expected)
455 expectedGraph.SetLineColor (ROOT.kRed)
456 expectedGraph.SetLineWidth (3)
457 if options.noDataPoints:
458 expectedGraph.SetLineStyle (2)
462 print "average weight per event:", weight / ( size - 1)
463 maxDistance = ROOT.TMath.KolmogorovTest (size, yArray,
466 prob = ROOT.TMath.KolmogorovProb( maxDistance * math.sqrt( size ) )
469 ROOT.gROOT.SetStyle(
'Plain')
470 ROOT.gROOT.SetBatch()
472 graph.GetXaxis().SetRangeUser (min (xVals), max (xVals))
473 minValue = min (
min(yVals),
min(expected))
475 minValue = min (minValue, min (predVals))
476 graph.GetYaxis().SetRangeUser (minValue,
477 max (
max(yVals),
max(expected),
max(predVals)))
478 graph.SetLineWidth (3)
479 if options.noDataPoints:
483 if 'instLum' == options.edfMode:
484 graph.GetXaxis().SetTitle (
"Average Xing Inst. Luminosity (1/ub/s)")
485 graph.GetXaxis().SetRangeUser (0., lumiCont.max(
'aveInstLum'))
487 if 'instIntLum' == options.edfMode:
488 graph.GetXaxis().SetTitle (
"Integrated Luminosity - Inst. Lum. Ordered (1/%s)" \
491 graph.GetXaxis().SetTitle (
"Integrated Luminosity (1/%s)" \
493 graph.GetYaxis().SetTitle (
"Fraction of Events Seen")
496 for index, chunk
in enumerate (expectedChunks):
497 expectedXarray = array.array (
'd', [item[0]
for item
in chunk])
498 expectedYarray = array.array (
'd', [item[1]
for item
in chunk])
499 expectedGraph = ROOT.TGraph( len(chunk),
502 expectedGraph.SetLineWidth (3)
503 if options.noDataPoints:
504 expectedGraph.SetLineStyle (2)
506 expectedGraph.SetLineColor (ROOT.kBlue)
508 expectedGraph.SetLineColor (ROOT.kRed)
509 expectedGraph.Draw(
"L")
510 expectedGraphs.append (expectedGraph)
511 exptectedGraph = expectedGraphs[0]
513 expectedGraph.Draw (
"L")
516 predArray = array.array (
'd', predVals)
517 green = ROOT.TGraph (size, xArray, predArray)
518 green.SetLineWidth (3)
519 green.SetLineColor (8)
521 legend = ROOT.TLegend(0.15, 0.65, 0.50, 0.85)
522 legend.SetFillStyle (0)
523 legend.SetLineColor(ROOT.kWhite)
524 observed =
'Observed'
526 observed +=
' (weighted)'
527 legend.AddEntry(graph, observed,
"PL")
528 if options.resetExpected:
529 legend.AddEntry(expectedGraph,
"Expected from partial yield",
"L")
531 legend.AddEntry(expectedGraph,
"Expected from total yield",
"L")
533 legend.AddEntry(green, options.predLabel,
"L")
534 legend.AddEntry(
"",
"D_{stat}=%.3f, N=%d" % (maxDistance, size),
"")
535 legend.AddEntry(
"",
"P_{KS}=%.3f" % prob,
"")
539 c1.Print (outputFile)
550 if __name__ ==
'__main__':
554 allowedEDF = [
'time',
'instLum',
'instIntLum']
555 parser = optparse.OptionParser (
"Usage: %prog [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.')
556 plotGroup = optparse.OptionGroup (parser,
"Plot Options")
557 rangeGroup = optparse.OptionGroup (parser,
"Range Options")
558 inputGroup = optparse.OptionGroup (parser,
"Input Options")
559 modeGroup = optparse.OptionGroup (parser,
"Mode Options")
560 plotGroup.add_option (
'--title', dest=
'title', type=
'string',
561 default =
'Empirical Distribution Function',
562 help =
'title of plot (default %default)')
563 plotGroup.add_option (
'--predicted', dest=
'pred', type=
'float',
565 help =
'factor by which predicted curve is greater than observed')
566 plotGroup.add_option (
'--predLabel', dest=
'predLabel', type=
'string',
567 default =
'Predicted',
568 help =
'label of predicted in legend')
569 plotGroup.add_option (
'--noDataPoints', dest=
'noDataPoints',
571 help=
"Draw lines but no points for data")
572 rangeGroup.add_option (
'--minRun', dest=
'minRun', type=
'int', default=0,
573 help=
'Minimum run number to consider')
574 rangeGroup.add_option (
'--maxRun', dest=
'maxRun', type=
'int', default=0,
575 help=
'Maximum run number to consider')
576 rangeGroup.add_option (
'--minIntLum', dest=
'minIntLum', type=
'float', default=0,
577 help=
'Minimum integrated luminosity to consider')
578 rangeGroup.add_option (
'--maxIntLum', dest=
'maxIntLum', type=
'float', default=0,
579 help=
'Maximum integrated luminosity to consider')
580 rangeGroup.add_option (
'--resetExpected', dest=
'resetExpected',
582 help=
'Reset expected from total yield to highest point considered')
583 rangeGroup.add_option (
'--breakExpectedIntLum', dest=
'breakExpectedIntLum',
584 type=
'string', action=
'append', default=[],
585 help=
'Break expected curve into pieces at integrated luminosity boundaries')
586 inputGroup.add_option (
'--ignoreNoLumiEvents', dest=
'ignore',
588 help =
'Ignore (with a warning) events that do not have a lumi section')
589 inputGroup.add_option (
'--noWarnings', dest=
'noWarnings',
591 help =
'Do not print warnings about missing luminosity information')
592 inputGroup.add_option (
'--runEventLumi', dest=
'relOrder',
594 help =
'Parse event list assuming Run, Event #, Lumi# order')
595 inputGroup.add_option (
'--weights', dest=
'weights', action=
'store_true',
596 help =
'Read fourth column as a weight')
597 modeGroup.add_option (
'--print', dest=
'printValues', action=
'store_true',
598 help =
'Print X and Y values of EDF plot')
599 modeGroup.add_option (
'--runsWithLumis', dest=
'runsWithLumis',
600 type=
'string',action=
'append', default=[],
601 help=
'Print out run and lumi sections corresponding to integrated luminosities provided and then exits')
602 modeGroup.add_option (
'--edfMode', dest=
'edfMode', type=
'string',
604 help=
"EDF Mode %s (default '%%default')" % allowedEDF)
605 parser.add_option_group (plotGroup)
606 parser.add_option_group (rangeGroup)
607 parser.add_option_group (inputGroup)
608 parser.add_option_group (modeGroup)
609 (options, args) = parser.parse_args()
611 if options.edfMode
not in allowedEDF:
612 raise RuntimeError,
"edfMode (currently '%s') must be one of %s" \
613 % (options.edfMode, allowedEDF)
615 if len (args) != 3
and not (options.runsWithLumis
and len(args) >= 1):
616 raise RuntimeError,
"Must provide lumi.csv, events.txt, and output.png"
622 cont = LumiInfoCont (args[0], **options.__dict__)
623 cont.minRun = options.minRun
624 cont.maxRun = options.maxRun
625 cont.minIntLum = options.minIntLum
626 cont.maxIntLum = options.maxIntLum
632 if options.runsWithLumis:
634 for line
in options.runsWithLumis:
635 pieces = sepRE.split (line)
638 recLumValue = float (piece)
640 raise RuntimeError,
"'%s' in '%s' is not a float" % \
643 raise RuntimeError,
"You must provide positive values for -runsWithLumis ('%f' given)" % recLumValue
644 recLumis.append (recLumValue)
646 raise RuntimeError,
"What did Charles do now?"
649 recLumValue = recLumis [recLumIndex]
652 for key, lumi
in cont.iteritems():
653 if prevRecLumi >= recLumValue
and recLumValue < lumi.totalRecorded:
655 print "%s contains total recorded lumi %f" % \
656 (key.__str__(), recLumValue)
659 if recLumIndex == len (recLumis):
662 recLumValue = recLumis [recLumIndex]
663 if prevRecLumi >= recLumValue
and recLumValue < lumi.totalRecorded:
665 print "%s contains total recorded lumi %f" % \
666 (key.__str__(), recLumValue)
671 prevRecLumi = lumi.totalRecorded
672 if recLumIndex < len (recLumis):
673 print "Theses lumis not found: %s" % recLumis[recLumIndex:]
679 if options.edfMode !=
'time' and not cont.xingInfo:
680 raise RuntimeError,
"'%s' does not have Xing info" % args[0]
681 eventsDict, totalWeight = loadEvents (args[1], cont, options)
682 makeEDFplot (cont, eventsDict, totalWeight, args[2], options)
invunits
Now that everything is setup, switch integrated ## luminosity to more reasonable units.
def loadEvents
General Functions