3 from __future__
import print_function
4 from __future__
import division
5 from builtins
import zip
6 from builtins
import object
7 from past.utils
import old_div
8 from builtins
import range
12 from pprint
import pprint
17 sepRE = re.compile (
r'[\s,;:]+')
18 nonSpaceRE = re.compile (
r'\S')
28 lastSingleXingRun = 136175
29 lumiSectionLength = 23.310779
39 pieces = sepRE.split (line.strip())
42 raise RuntimeError(
"Odd number of pieces")
44 raise RuntimeError(
"Not enough pieces")
46 self.
run = int (pieces[0])
47 self.
lumi = int (pieces[1])
51 raise RuntimeError(
"Pieces not right format")
54 for xing, lum
in zip (pieces[4::2],pieces[5::2]):
61 raise RuntimeError(
"Inst Lumi Info malformed")
72 raise RuntimeError(
"This event %s already has Xing information" \
74 if self.
run > LumiInfo.lastSingleXingRun:
82 old_div(self.
delivered, LumiInfo.lumiSectionLength)
95 return "%6d, %4d: %6.1f (%4.1f%%) %4.2f (%3d)" % \
113 print(
"loading luminosity information from '%s'." % filename)
114 source = open (filename,
'r') 116 'delivered',
'recorded']
133 lumi = LumiInfo (line)
136 self[lumi.key] = lumi
138 if not self.
xingInfo and lumi.xingInfo:
145 val = getattr (lumi, key)
146 if val < self.
_min[key]
or self.
_min[key] < 0:
148 if val > self.
_max[key]
or not self.
_max[key]:
167 for lumis
in self.values():
168 lumis.delivered /= lumFactor
169 lumis.recorded /= lumFactor
177 retval =
'run, lum del ( dt ) inst (#xng)\n' 178 for key, value
in sorted (self.items()):
179 retval +=
"%s\n" % value
184 return self.
_min[key]
188 return self.
_max[key]
192 return sorted (dict.keys (self))
196 return sorted (dict.iteritems (self))
202 for key, lumi
in self.items():
203 total += lumi.recorded
204 lumi.totalRecorded = total
205 lumi.fracRecorded = old_div(total, self.
totalRecLum)
212 for key, lumi
in self.items():
213 if not lumi.xingInfo
and not lumi.fixXingInfo():
215 print(
"Do not have lumi xing info for %s" % lumi.keyString)
217 print(
"Setting no Xing info flag")
221 xingKeyList.append( (lumi.aveInstLum, key) )
222 if lumi.aveInstLum > maxAveInstLum:
223 maxAveInstLum = lumi.aveInstLum
226 for tup
in xingKeyList:
228 total += lumi.recorded
229 lumi.totalAXILrecorded = total
230 lumi.fracAXILrecorded = old_div(total, self.
totalRecLum)
231 lumi.fracAXIL = old_div(lumi.aveInstLum, maxAveInstLum)
242 print(
"loading events from '%s'" % filename)
243 events = open (filename,
'r') 244 runIndex, lumiIndex, eventIndex, weightIndex = 0, 1, 2, 3 246 lumiIndex, eventIndex = 2,1
252 pieces = sepRE.split (line.strip())
253 if len (pieces) < minPieces:
254 if nonSpaceRE.search (line):
255 print(
"skipping", line)
258 run, lumi, event =
int( pieces[runIndex] ), \
259 int( pieces[lumiIndex] ), \
260 int( pieces[eventIndex] )
266 print(
"Warning, %s is not found in the lumi information" \
270 raise RuntimeError(
"%s is not found in lumi information. Use '--ignoreNoLumiEvents' option to ignore these events and continue." \
272 if options.edfMode !=
'time' and not cont[key].xingInfo:
274 print(
"Warning, %s does not have Xing information" \
278 raise RuntimeError(
"%s does not have Xing information. Use '--ignoreNoLumiEvents' option to ignore these events and continue." \
281 weight = float (pieces[weightIndex])
284 eventsDict.setdefault( key, []).
append( (event, weight) )
285 totalWeight += weight
287 return eventsDict, totalWeight
290 def makeEDFplot (lumiCont, eventsDict, totalWeight, outputFile, options):
301 if 'time' == options.edfMode:
303 if lumiCont.minRun
or lumiCont.minIntLum:
309 for key, eventList
in sorted( eventsDict.items() ):
312 if lumiCont.minRun
and lumiCont.minRun > key[0]
or \
313 lumiCont.maxRun
and lumiCont.maxRun < key[0]:
315 for event
in eventList:
319 factor = old_div(weight, totalWeight)
321 intLum = lumiCont[key].totalRecorded
323 raise RuntimeError(
"key %s not found in lumi information" \
325 if lumiCont.minIntLum
and lumiCont.minIntLum > intLum
or \
326 lumiCont.maxIntLum
and lumiCont.maxIntLum < intLum:
328 lumFrac = old_div(intLum, lumiCont.totalRecLum)
329 xVals.append( lumiCont[key].totalRecorded)
330 yVals.append (factor)
331 expectedVals.append (lumFrac)
332 predVals.append (lumFrac * options.pred)
334 if not lumiCont.maxRun
and not lumiCont.maxIntLum:
335 xVals.append (lumiCont.totalRecLum)
337 expectedVals.append (1)
338 predVals.append (options.pred)
342 if options.resetExpected:
343 slope = old_div((yVals[-1] - yVals[0]), (xVals[-1] - xVals[0]))
344 print(
"slope", slope)
345 for index, old
in enumerate (expectedVals):
346 expectedVals[index] = yVals[0] + \
347 slope * (xVals[index] - xVals[0])
351 if options.breakExpectedIntLum:
352 breakExpectedIntLum = []
353 for chunk
in options.breakExpectedIntLum:
354 pieces = sepRE.split (chunk)
357 breakExpectedIntLum.append(
float(piece) )
359 raise RuntimeError(
"'%s' from '%s' is not a valid float" \
361 breakExpectedIntLum.sort()
365 for index, xPos
in enumerate (xVals):
366 if xPos > breakExpectedIntLum[breakIndex]:
367 boundaries.append (index)
368 while breakIndex < len (breakExpectedIntLum):
370 if breakIndex >= len (breakExpectedIntLum):
376 if xPos <= breakExpectedIntLum[breakIndex]:
382 raise RuntimeError(
"No values of 'breakExpectedIntLum' are in current range.")
385 boundaries.insert (0, 0)
388 if boundaries[-1] != len (xVals) - 1:
389 boundaries.append( len (xVals) - 1 )
390 rangeList = list(zip (boundaries, boundaries[1:]))
391 for thisRange
in rangeList:
394 slope = old_div((yVals[upper] - yVals[lower]), \
395 (xVals[upper] - xVals[lower]))
396 print(
"slope", slope)
399 for index
in range (lower, upper + 1):
400 newExpected = yVals[lower] + \
401 slope * (xVals[index] - xVals[lower])
402 pairList.append( (xVals[index], newExpected) )
403 expectedVals[index] = newExpected
404 expectedChunks.append (pairList)
408 elif 'instLum' == options.edfMode
or 'instIntLum' == options.edfMode:
410 if not lumiCont.xingInfo:
411 raise RuntimeError(
"Luminosity Xing information missing.")
412 for key, eventList
in sorted( eventsDict.items() ):
415 instLum = lumi.aveInstLum
416 fracAXIL = lumi.fracAXILrecorded
417 totalAXIL = lumi.totalAXILrecorded
419 raise RuntimeError(
"key %s not found in lumi information" \
421 for event
in eventList:
422 eventTupList.append( (instLum, fracAXIL, totalAXIL, key,
423 event[0], event[1], ) )
425 for eventTup
in eventTupList:
426 weight += eventTup[5]
427 factor = old_div(weight, totalWeight)
428 if 'instLum' == options.edfMode:
429 xVals.append (eventTup[0])
431 xVals.append (eventTup[2])
432 yVals.append (factor)
433 expectedVals.append (eventTup[1])
434 predVals.append (eventTup[1] * options.pred)
436 raise RuntimeError(
"It looks like Charles screwed up if you are seeing this.")
439 step = int (old_div(math.sqrt(size), 2) + 1)
440 if options.printValues:
441 for index
in range (size):
442 print(
"%8f %8f %8f" % (xVals[index], yVals[index], expectedVals[index]), end=
' ')
444 denom = xVals[index] - xVals[index - step]
445 numer = yVals[index] - yVals[index - step]
447 print(
" %8f" % (old_div(numer, denom)), end=
' ')
448 if 0 == index % step:
449 print(
" **", end=
' ')
454 xArray = array.array (
'd', xVals)
455 yArray = array.array (
'd', yVals)
456 expected = array.array (
'd', expectedVals)
457 graph = ROOT.TGraph( size, xArray, yArray)
458 graph.SetTitle (options.title)
459 graph.SetMarkerStyle (20)
460 expectedGraph = ROOT.TGraph( size, xArray, expected)
461 expectedGraph.SetLineColor (ROOT.kRed)
462 expectedGraph.SetLineWidth (3)
463 if options.noDataPoints:
464 expectedGraph.SetLineStyle (2)
468 print(
"average weight per event:", old_div(weight, ( size - 1)))
469 maxDistance = ROOT.TMath.KolmogorovTest (size, yArray,
472 prob = ROOT.TMath.KolmogorovProb( maxDistance * math.sqrt( size ) )
475 ROOT.gROOT.SetStyle(
'Plain')
476 ROOT.gROOT.SetBatch()
478 graph.GetXaxis().SetRangeUser (min (xVals), max (xVals))
479 minValue = min (
min(yVals),
min(expected))
481 minValue = min (minValue, min (predVals))
482 graph.GetYaxis().SetRangeUser (minValue,
483 max (
max(yVals),
max(expected),
max(predVals)))
484 graph.SetLineWidth (3)
485 if options.noDataPoints:
489 if 'instLum' == options.edfMode:
490 graph.GetXaxis().SetTitle (
"Average Xing Inst. Luminosity (1/ub/s)")
491 graph.GetXaxis().SetRangeUser (0., lumiCont.max(
'aveInstLum'))
493 if 'instIntLum' == options.edfMode:
494 graph.GetXaxis().SetTitle (
"Integrated Luminosity - Inst. Lum. Ordered (1/%s)" \
497 graph.GetXaxis().SetTitle (
"Integrated Luminosity (1/%s)" \
499 graph.GetYaxis().SetTitle (
"Fraction of Events Seen")
502 for index, chunk
in enumerate (expectedChunks):
503 expectedXarray = array.array (
'd', [item[0]
for item
in chunk])
504 expectedYarray = array.array (
'd', [item[1]
for item
in chunk])
505 expectedGraph = ROOT.TGraph( len(chunk),
508 expectedGraph.SetLineWidth (3)
509 if options.noDataPoints:
510 expectedGraph.SetLineStyle (2)
512 expectedGraph.SetLineColor (ROOT.kBlue)
514 expectedGraph.SetLineColor (ROOT.kRed)
515 expectedGraph.Draw(
"L")
516 expectedGraphs.append (expectedGraph)
517 exptectedGraph = expectedGraphs[0]
519 expectedGraph.Draw (
"L")
522 predArray = array.array (
'd', predVals)
523 green = ROOT.TGraph (size, xArray, predArray)
524 green.SetLineWidth (3)
525 green.SetLineColor (8)
527 legend = ROOT.TLegend(0.15, 0.65, 0.50, 0.85)
528 legend.SetFillStyle (0)
529 legend.SetLineColor(ROOT.kWhite)
530 observed =
'Observed' 532 observed +=
' (weighted)' 533 legend.AddEntry(graph, observed,
"PL")
534 if options.resetExpected:
535 legend.AddEntry(expectedGraph,
"Expected from partial yield",
"L")
537 legend.AddEntry(expectedGraph,
"Expected from total yield",
"L")
539 legend.AddEntry(green, options.predLabel,
"L")
540 legend.AddEntry(
"",
"D_{stat}=%.3f, N=%d" % (maxDistance, size),
"")
541 legend.AddEntry(
"",
"P_{KS}=%.3f" % prob,
"")
545 c1.Print (outputFile)
556 if __name__ ==
'__main__':
560 allowedEDF = [
'time',
'instLum',
'instIntLum']
561 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.')
562 plotGroup = optparse.OptionGroup (parser,
"Plot Options")
563 rangeGroup = optparse.OptionGroup (parser,
"Range Options")
564 inputGroup = optparse.OptionGroup (parser,
"Input Options")
565 modeGroup = optparse.OptionGroup (parser,
"Mode Options")
566 plotGroup.add_option (
'--title', dest=
'title', type=
'string',
567 default =
'Empirical Distribution Function',
568 help =
'title of plot (default %default)')
569 plotGroup.add_option (
'--predicted', dest=
'pred', type=
'float',
571 help =
'factor by which predicted curve is greater than observed')
572 plotGroup.add_option (
'--predLabel', dest=
'predLabel', type=
'string',
573 default =
'Predicted',
574 help =
'label of predicted in legend')
575 plotGroup.add_option (
'--noDataPoints', dest=
'noDataPoints',
577 help=
"Draw lines but no points for data")
578 rangeGroup.add_option (
'--minRun', dest=
'minRun', type=
'int', default=0,
579 help=
'Minimum run number to consider')
580 rangeGroup.add_option (
'--maxRun', dest=
'maxRun', type=
'int', default=0,
581 help=
'Maximum run number to consider')
582 rangeGroup.add_option (
'--minIntLum', dest=
'minIntLum', type=
'float', default=0,
583 help=
'Minimum integrated luminosity to consider')
584 rangeGroup.add_option (
'--maxIntLum', dest=
'maxIntLum', type=
'float', default=0,
585 help=
'Maximum integrated luminosity to consider')
586 rangeGroup.add_option (
'--resetExpected', dest=
'resetExpected',
588 help=
'Reset expected from total yield to highest point considered')
589 rangeGroup.add_option (
'--breakExpectedIntLum', dest=
'breakExpectedIntLum',
590 type=
'string', action=
'append', default=[],
591 help=
'Break expected curve into pieces at integrated luminosity boundaries')
592 inputGroup.add_option (
'--ignoreNoLumiEvents', dest=
'ignore',
594 help =
'Ignore (with a warning) events that do not have a lumi section')
595 inputGroup.add_option (
'--noWarnings', dest=
'noWarnings',
597 help =
'Do not print warnings about missing luminosity information')
598 inputGroup.add_option (
'--runEventLumi', dest=
'relOrder',
600 help =
'Parse event list assuming Run, Event #, Lumi# order')
601 inputGroup.add_option (
'--weights', dest=
'weights', action=
'store_true',
602 help =
'Read fourth column as a weight')
603 modeGroup.add_option (
'--print', dest=
'printValues', action=
'store_true',
604 help =
'Print X and Y values of EDF plot')
605 modeGroup.add_option (
'--runsWithLumis', dest=
'runsWithLumis',
606 type=
'string',action=
'append', default=[],
607 help=
'Print out run and lumi sections corresponding to integrated luminosities provided and then exits')
608 modeGroup.add_option (
'--edfMode', dest=
'edfMode', type=
'string',
610 help=
"EDF Mode %s (default '%%default')" % allowedEDF)
611 parser.add_option_group (plotGroup)
612 parser.add_option_group (rangeGroup)
613 parser.add_option_group (inputGroup)
614 parser.add_option_group (modeGroup)
615 (options, args) = parser.parse_args()
617 if options.edfMode
not in allowedEDF:
618 raise RuntimeError(
"edfMode (currently '%s') must be one of %s" \
619 % (options.edfMode, allowedEDF))
621 if len (args) != 3
and not (options.runsWithLumis
and len(args) >= 1):
622 raise RuntimeError(
"Must provide lumi.csv, events.txt, and output.png")
628 cont = LumiInfoCont (args[0], **options.__dict__)
629 cont.minRun = options.minRun
630 cont.maxRun = options.maxRun
631 cont.minIntLum = options.minIntLum
632 cont.maxIntLum = options.maxIntLum
638 if options.runsWithLumis:
640 for line
in options.runsWithLumis:
641 pieces = sepRE.split (line)
644 recLumValue = float (piece)
646 raise RuntimeError(
"'%s' in '%s' is not a float" % \
649 raise RuntimeError(
"You must provide positive values for -runsWithLumis ('%f' given)" % recLumValue)
650 recLumis.append (recLumValue)
652 raise RuntimeError(
"What did Charles do now?")
655 recLumValue = recLumis [recLumIndex]
658 for key, lumi
in cont.items():
659 if prevRecLumi >= recLumValue
and recLumValue < lumi.totalRecorded:
661 print(
"%s contains total recorded lumi %f" % \
662 (key.__str__(), recLumValue))
665 if recLumIndex == len (recLumis):
668 recLumValue = recLumis [recLumIndex]
669 if prevRecLumi >= recLumValue
and recLumValue < lumi.totalRecorded:
671 print(
"%s contains total recorded lumi %f" % \
672 (key.__str__(), recLumValue))
677 prevRecLumi = lumi.totalRecorded
678 if recLumIndex < len (recLumis):
679 print(
"Theses lumis not found: %s" % recLumis[recLumIndex:])
685 if options.edfMode !=
'time' and not cont.xingInfo:
686 raise RuntimeError(
"'%s' does not have Xing info" % args[0])
687 eventsDict, totalWeight = loadEvents (args[1], cont, options)
688 makeEDFplot (cont, eventsDict, totalWeight, args[2], 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)