CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_5_3_3/src/FWCore/PythonUtilities/scripts/generateEDF.py

Go to the documentation of this file.
00001 #! /usr/bin/env python
00002 
00003 import sys
00004 import re
00005 import optparse
00006 from pprint import pprint
00007 import array
00008 import ROOT
00009 import math
00010 
00011 sepRE      = re.compile (r'[\s,;:]+')
00012 nonSpaceRE = re.compile (r'\S')
00013 
00014 ##########################
00015 ## #################### ##
00016 ## ## LumiInfo Class ## ##
00017 ## #################### ##
00018 ##########################
00019 
00020 class LumiInfo (object):
00021 
00022     lastSingleXingRun = 136175
00023     lumiSectionLength = 23.310779
00024 
00025     def __init__ (self, line):
00026         self.totInstLum  = 0.
00027         self.aveInstLum  = 0.
00028         self.numXings    = 0
00029         self.instLums    = []
00030         self.events      = []
00031         self.xingInfo    = False
00032         self.badXingInfo = False
00033         pieces = sepRE.split (line.strip())
00034         size = len (pieces)
00035         if size % 2:
00036             raise RuntimeError, "Odd number of pieces"
00037         if size < 4:
00038             raise RuntimeError, "Not enough pieces"
00039         try:
00040             self.run       = int   (pieces[0])
00041             self.lumi      = int   (pieces[1])
00042             self.delivered = float (pieces[2])
00043             self.recorded  = float (pieces[3])
00044         except:
00045             raise RuntimeError, "Pieces not right format"
00046         if size > 4:
00047             try:
00048                 for xing, lum in zip (pieces[4::2],pieces[5::2]):
00049                     xing = int   (xing)
00050                     lum  = float (lum)
00051                     self.instLums.append( (xing, lum) )
00052                     self.totInstLum += lum
00053                     self.numXings += 1
00054             except:
00055                 raise RuntimeError, "Inst Lumi Info malformed"
00056             self.aveInstLum = self.totInstLum / (self.numXings)
00057             self.xingInfo   = True
00058         self.key       = (self.run, self.lumi)
00059         self.keyString = self.key.__str__()
00060 
00061 
00062     def fixXingInfo (self):
00063         if self.numXings:
00064             # You shouldn't try and fix an event if it already has
00065             # xing information.
00066             raise RuntimeError, "This event %s already has Xing information" \
00067                   % self.keyString
00068         if self.run > LumiInfo.lastSingleXingRun:
00069             # this run may have more than one crossing.  I don't know
00070             # how to fix this.
00071             self.badXingInfo = True
00072             return False
00073         self.numXings = 1
00074         xing = 1
00075         self.aveInstLum = self.totInstLum = lum = \
00076                           self.delivered / LumiInfo.lumiSectionLength
00077         self.instLums.append( (xing, lum) )
00078         self.xingInfo = True
00079         return True
00080         
00081 
00082     def deadtime (self):
00083         if not self.delivered:
00084             return 1
00085         return 1 - (self.recorded / self.delivered)
00086 
00087 
00088     def __str__ (self):
00089         return "%6d, %4d: %6.1f (%4.1f%%) %4.2f (%3d)" % \
00090                (self.run,
00091                 self.lumi,
00092                 self.delivered,
00093                 self.deadtime(),
00094                 self.totInstLum,
00095                 self.numXings)
00096 
00097 
00098 ##############################
00099 ## ######################## ##
00100 ## ## LumiInfoCont Class ## ##
00101 ## ######################## ##
00102 ##############################
00103 
00104 class LumiInfoCont (dict):
00105 
00106     def __init__ (self, filename, **kwargs):
00107         print "loading luminosity information from '%s'." % filename
00108         source = open (filename, 'r')
00109         self.minMaxKeys = ['totInstLum', 'aveInstLum', 'numXings',
00110                      'delivered', 'recorded']
00111         self._min = {}
00112         self._max = {}
00113         self.totalRecLum = 0.
00114         self.xingInfo    = False
00115         self.allowNoXing = kwargs.get ('ignore')
00116         self.noWarnings  = kwargs.get ('noWarnings')
00117         self.minRun      = 0
00118         self.maxRun      = 0
00119         self.minIntLum   = 0
00120         self.maxIntLum   = 0
00121         
00122         for key in self.minMaxKeys:
00123             self._min[key] = -1
00124             self._max[key] =  0
00125         for line in source:
00126             try:
00127                 lumi = LumiInfo (line)
00128             except:
00129                 continue
00130             self[lumi.key] = lumi
00131             self.totalRecLum += lumi.recorded
00132             if not self.xingInfo and lumi.xingInfo:
00133                 self.xingInfo = True
00134             if lumi.xingInfo:
00135                 #print "yes", lumi.keyString
00136                 if not self.xingInfo:
00137                     print "huh?"
00138             for key in self.minMaxKeys:
00139                 val = getattr (lumi, key)
00140                 if val < self._min[key] or self._min[key] < 0:
00141                     self._min[key] = val
00142                 if val > self._max[key] or not self._max[key]:
00143                     self._max[key] = val
00144         source.close()
00145         ######################################################
00146         ## Now that everything is setup, switch integrated  ##
00147         ## luminosity to more reasonable units.             ##
00148         ######################################################
00149         # the default is '1/mb', but that's just silly.
00150         self.invunits = 'nb'
00151         lumFactor = 1e3        
00152         if   self.totalRecLum > 1e9:
00153             lumFactor = 1e9
00154             self.invunits = 'fb'
00155         elif self.totalRecLum > 1e6:
00156             lumFactor = 1e6
00157             self.invunits = 'pb'
00158         # use lumFactor to make everything consistent
00159         #print "units", self.invunits, "factor", lumFactor
00160         self.totalRecLum /= lumFactor
00161         for lumis in self.values():
00162             lumis.delivered /= lumFactor
00163             lumis.recorded  /= lumFactor
00164         # Probably want to rename this next subroutine, but I'll leave
00165         # it alone for now...
00166         self._integrateContainer()
00167 
00168 
00169 
00170     def __str__ (self):
00171         retval = 'run,     lum     del ( dt  ) inst (#xng)\n'
00172         for key, value in sorted (self.iteritems()):
00173             retval += "%s\n" % value
00174         return retval
00175 
00176 
00177     def min (self, key):
00178         return self._min[key]
00179 
00180 
00181     def max (self, key):
00182         return self._max[key]
00183 
00184 
00185     def keys (self):
00186         return sorted (dict.keys (self))
00187 
00188 
00189     def iteritems (self):
00190         return sorted (dict.iteritems (self))
00191 
00192 
00193     def _integrateContainer (self):
00194         # calculate numbers for recorded integrated luminosity
00195         total = 0.
00196         for key, lumi in self.iteritems():
00197             total += lumi.recorded
00198             lumi.totalRecorded = total
00199             lumi.fracRecorded  = total / self.totalRecLum
00200         # calculate numbers for average xing instantaneous luminosity
00201         if not self.xingInfo:
00202             # nothing to do here
00203             return
00204         xingKeyList = []
00205         maxAveInstLum = 0.
00206         for key, lumi in self.iteritems():
00207             if not lumi.xingInfo and not lumi.fixXingInfo():
00208                 if not self.noWarnings:
00209                     print "Do not have lumi xing info for %s" % lumi.keyString
00210                 if not self.allowNoXing:
00211                     print "Setting no Xing info flag"
00212                     self.xingInfo = False
00213                     return
00214                 continue
00215             xingKeyList.append( (lumi.aveInstLum, key) )
00216             if lumi.aveInstLum > maxAveInstLum:
00217                 maxAveInstLum = lumi.aveInstLum
00218         xingKeyList.sort()
00219         total = 0.
00220         for tup in xingKeyList:
00221             lumi = self[tup[1]]
00222             total += lumi.recorded
00223             lumi.totalAXILrecorded = total
00224             lumi.fracAXILrecorded  = total / self.totalRecLum
00225             lumi.fracAXIL = lumi.aveInstLum / maxAveInstLum
00226 
00227 
00228 #############################
00229 ## ####################### ##
00230 ## ## General Functions ## ##
00231 ## ####################### ##
00232 #############################
00233 
00234 def loadEvents (filename, cont, options):
00235     eventsDict = {}
00236     print "loading events from '%s'" % filename
00237     events = open (filename, 'r')
00238     runIndex, lumiIndex, eventIndex, weightIndex = 0, 1, 2, 3
00239     if options.relOrder:
00240         lumiIndex, eventIndex = 2,1
00241     minPieces = 3
00242     totalWeight = 0.
00243     if options.weights:
00244         minPieces = 4
00245     for line in events:
00246         pieces = sepRE.split (line.strip())
00247         if len (pieces) < minPieces:
00248             if nonSpaceRE.search (line):
00249                 print "skipping", line
00250             continue
00251         try:
00252             run, lumi, event = int( pieces[runIndex]   ), \
00253                                int( pieces[lumiIndex]  ), \
00254                                int( pieces[eventIndex] )
00255         except:
00256             continue
00257         key = (run, lumi)
00258         if not cont.has_key (key):
00259             if options.ignore:
00260                 print "Warning, %s is not found in the lumi information" \
00261                       % key.__str__()
00262                 continue
00263             else:
00264                 raise RuntimeError, "%s is not found in lumi information.  Use '--ignoreNoLumiEvents' option to ignore these events and continue." \
00265                       % key.__str__()
00266         if options.edfMode != 'time' and not cont[key].xingInfo:
00267             if options.ignore:
00268                 print "Warning, %s does not have Xing information" \
00269                       % key.__str__()
00270                 continue
00271             else:
00272                 raise RuntimeError, "%s  does not have Xing information.  Use '--ignoreNoLumiEvents' option to ignore these events and continue." \
00273                       % key.__str__()            
00274         if options.weights:
00275             weight = float (pieces[weightIndex])
00276         else:
00277             weight = 1
00278         eventsDict.setdefault( key, []).append( (event, weight) )
00279         totalWeight += weight
00280     events.close()
00281     return eventsDict, totalWeight
00282 
00283 
00284 def makeEDFplot (lumiCont, eventsDict, totalWeight, outputFile, options):
00285     # make TGraph
00286     xVals      = [0]
00287     yVals      = [0]
00288     expectedVals = [0]
00289     predVals   = [0]
00290     weight = 0
00291     expectedChunks = []
00292     ########################
00293     ## Time Ordering Mode ##
00294     ########################
00295     if 'time' == options.edfMode:
00296         # if we have a minimum run number, clear the lists
00297         if lumiCont.minRun or lumiCont.minIntLum:
00298             xVals      = []
00299             yVals      = []
00300             expectedVals = []
00301             predVals   = []
00302         # loop over events
00303         for key, eventList in sorted( eventsDict.iteritems() ):
00304             usePoints = True
00305             # should we add this point?
00306             if lumiCont.minRun and lumiCont.minRun > key[0] or \
00307                lumiCont.maxRun and lumiCont.maxRun < key[0]:
00308                 usePoints = False
00309             for event in eventList:
00310                 weight += event[1]
00311                 if not usePoints:
00312                     continue
00313                 factor = weight / totalWeight
00314                 try:
00315                     intLum = lumiCont[key].totalRecorded
00316                 except:
00317                     raise RuntimeError, "key %s not found in lumi information" \
00318                           % key.__str__()
00319                 if lumiCont.minIntLum and lumiCont.minIntLum > intLum or \
00320                    lumiCont.maxIntLum and lumiCont.maxIntLum < intLum:
00321                     continue
00322                 lumFrac = intLum / lumiCont.totalRecLum
00323                 xVals.append( lumiCont[key].totalRecorded)
00324                 yVals.append (factor)
00325                 expectedVals.append (lumFrac)
00326                 predVals.append   (lumFrac * options.pred)
00327         # put on the last point if we aren't giving a maximum run
00328         if not lumiCont.maxRun and not lumiCont.maxIntLum:
00329             xVals.append (lumiCont.totalRecLum)
00330             yVals.append (1)
00331             expectedVals.append (1)
00332             predVals.append (options.pred)
00333         ####################
00334         ## Reset Expected ##
00335         ####################
00336         if options.resetExpected:
00337             slope = (yVals[-1] - yVals[0]) / (xVals[-1] - xVals[0])
00338             print "slope", slope
00339             for index, old in enumerate (expectedVals):
00340                 expectedVals[index] = yVals[0] + \
00341                                     slope * (xVals[index] - xVals[0])
00342         #############################################
00343         ## Break Expected by Integrated Luminosity ##
00344         #############################################
00345         if options.breakExpectedIntLum:
00346             breakExpectedIntLum = []
00347             for chunk in options.breakExpectedIntLum:
00348                 pieces = sepRE.split (chunk)
00349                 try:
00350                     for piece in pieces:
00351                         breakExpectedIntLum.append( float(piece) )
00352                 except:
00353                     raise RuntimeError, "'%s' from '%s' is not a valid float" \
00354                           % (piece, chunk)
00355             breakExpectedIntLum.sort()
00356             boundaries = []
00357             breakIndex = 0
00358             done = False
00359             for index, xPos in enumerate (xVals):
00360                 if xPos > breakExpectedIntLum[breakIndex]:
00361                     boundaries.append (index)
00362                     while breakIndex < len (breakExpectedIntLum):
00363                         breakIndex += 1
00364                         if breakIndex >= len (breakExpectedIntLum):
00365                             done = True
00366                             break
00367                         # If this next position is different, than
00368                         # we're golden.  Otherwise, let it go through
00369                         # the loop again.
00370                         if xPos <= breakExpectedIntLum[breakIndex]:
00371                             break
00372                     if done:
00373                         break
00374             # do we have any boundaries?
00375             if not boundaries:
00376                 raise RuntimeError, "No values of 'breakExpectedIntLum' are in current range."
00377             # is the first boundary at 0?  If not, add 0
00378             if boundaries[0]:
00379                 boundaries.insert (0, 0)
00380             # is the last boundary at the end?  If not, make the end a
00381             # boundary
00382             if boundaries[-1] != len (xVals) - 1:
00383                 boundaries.append( len (xVals) - 1 )
00384             rangeList = zip (boundaries, boundaries[1:])
00385             for thisRange in rangeList:
00386                 upper = thisRange[1]
00387                 lower = thisRange[0]
00388                 slope = (yVals[upper] - yVals[lower]) / \
00389                         (xVals[upper] - xVals[lower])
00390                 print "slope", slope
00391                 # now go over the range inclusively
00392                 pairList = []
00393                 for index in range (lower, upper + 1):
00394                     newExpected = yVals[lower] + \
00395                                 slope * (xVals[index] - xVals[lower])
00396                     pairList.append( (xVals[index], newExpected) )
00397                     expectedVals[index] = newExpected
00398                 expectedChunks.append (pairList)
00399     ###########################################
00400     ## Instantanous Luminosity Ordering Mode ##
00401     ###########################################
00402     elif 'instLum' == options.edfMode or 'instIntLum' == options.edfMode:
00403         eventTupList = []
00404         if not lumiCont.xingInfo:
00405             raise RuntimeError, "Luminosity Xing information missing."
00406         for key, eventList in sorted( eventsDict.iteritems() ):
00407             try:
00408                 lumi =  lumiCont[key]
00409                 instLum   = lumi.aveInstLum
00410                 fracAXIL  = lumi.fracAXILrecorded
00411                 totalAXIL = lumi.totalAXILrecorded
00412             except:
00413                 raise RuntimeError, "key %s not found in lumi information" \
00414                       % key.__str__()
00415             for event in eventList:
00416                 eventTupList.append( (instLum, fracAXIL, totalAXIL, key,
00417                                       event[0], event[1], ) )
00418         eventTupList.sort()
00419         for eventTup in eventTupList:
00420             weight += eventTup[5]
00421             factor = weight / totalWeight
00422             if 'instLum' == options.edfMode:
00423                 xVals.append (eventTup[0])
00424             else:
00425                 xVals.append (eventTup[2])
00426             yVals.append (factor)
00427             expectedVals.append (eventTup[1])
00428             predVals.append   (eventTup[1] * options.pred)
00429     else:
00430         raise RuntimeError, "It looks like Charles screwed up if you are seeing this."
00431 
00432     size = len (xVals)
00433     step = int (math.sqrt(size) / 2 + 1)
00434     if options.printValues:
00435         for index in range (size):
00436             print "%8f %8f %8f" % (xVals[index], yVals[index], expectedVals[index]),
00437             if index > step:
00438                 denom = xVals[index] - xVals[index - step]
00439                 numer = yVals[index] - yVals[index - step]
00440                 if denom:
00441                     print " %8f" % (numer / denom),
00442             if 0 == index % step:
00443                 print " **", ## indicates statistically independent
00444                              ## slope measurement
00445             print
00446         print
00447 
00448     xArray = array.array ('d', xVals)
00449     yArray = array.array ('d', yVals)
00450     expected = array.array ('d', expectedVals)
00451     graph = ROOT.TGraph( size, xArray, yArray)
00452     graph.SetTitle (options.title)
00453     graph.SetMarkerStyle (20)
00454     expectedGraph = ROOT.TGraph( size, xArray, expected)
00455     expectedGraph.SetLineColor (ROOT.kRed)
00456     expectedGraph.SetLineWidth (3)
00457     if options.noDataPoints:
00458         expectedGraph.SetLineStyle (2)
00459 
00460     # run statistical tests
00461     if options.weights:
00462         print "average weight per event:", weight / ( size - 1)
00463     maxDistance = ROOT.TMath.KolmogorovTest (size, yArray,
00464                                              size, expected,
00465                                              "M")
00466     prob = ROOT.TMath.KolmogorovProb( maxDistance * math.sqrt( size ) )
00467 
00468     # display everything
00469     ROOT.gROOT.SetStyle('Plain')
00470     ROOT.gROOT.SetBatch()
00471     c1 = ROOT.TCanvas()
00472     graph.GetXaxis().SetRangeUser (min (xVals), max (xVals))
00473     minValue = min (min(yVals), min(expected))
00474     if options.pred:
00475         minValue = min (minValue, min (predVals))
00476     graph.GetYaxis().SetRangeUser (minValue,
00477                                    max (max(yVals), max(expected), max(predVals)))
00478     graph.SetLineWidth (3)
00479     if options.noDataPoints:
00480         graph.Draw ("AL")
00481     else:
00482         graph.Draw ("ALP")
00483     if 'instLum' == options.edfMode:
00484         graph.GetXaxis().SetTitle ("Average Xing Inst. Luminosity (1/ub/s)")
00485         graph.GetXaxis().SetRangeUser (0., lumiCont.max('aveInstLum'))
00486     else:
00487         if 'instIntLum' == options.edfMode:
00488             graph.GetXaxis().SetTitle ("Integrated Luminosity - Inst. Lum. Ordered (1/%s)" \
00489                                        % lumiCont.invunits)
00490         else:
00491             graph.GetXaxis().SetTitle ("Integrated Luminosity (1/%s)" \
00492                                        % lumiCont.invunits)
00493     graph.GetYaxis().SetTitle ("Fraction of Events Seen")
00494     expectedGraphs = []
00495     if expectedChunks:
00496         for index, chunk in enumerate (expectedChunks):
00497             expectedXarray = array.array ('d', [item[0] for item in chunk])
00498             expectedYarray = array.array ('d', [item[1] for item in chunk])
00499             expectedGraph = ROOT.TGraph( len(chunk),
00500                                          expectedXarray,
00501                                          expectedYarray )
00502             expectedGraph.SetLineWidth (3)
00503             if options.noDataPoints:
00504                 expectedGraph.SetLineStyle (2)
00505             if index % 2:
00506                 expectedGraph.SetLineColor (ROOT.kBlue)
00507             else:
00508                 expectedGraph.SetLineColor (ROOT.kRed)
00509             expectedGraph.Draw("L")
00510             expectedGraphs.append (expectedGraph)
00511         exptectedGraph = expectedGraphs[0]
00512     else:
00513         expectedGraph.Draw ("L")
00514     green = 0
00515     if options.pred:
00516         predArray = array.array ('d', predVals)
00517         green = ROOT.TGraph (size, xArray, predArray)
00518         green.SetLineWidth (3)
00519         green.SetLineColor (8)
00520         green.Draw ('l')
00521     legend = ROOT.TLegend(0.15, 0.65, 0.50, 0.85)
00522     legend.SetFillStyle (0)
00523     legend.SetLineColor(ROOT.kWhite)
00524     observed = 'Observed'
00525     if options.weights:
00526         observed += ' (weighted)'
00527     legend.AddEntry(graph, observed,"PL")
00528     if options.resetExpected:
00529         legend.AddEntry(expectedGraph,  "Expected from partial yield","L")
00530     else:
00531         legend.AddEntry(expectedGraph,  "Expected from total yield","L")
00532     if options.pred:
00533         legend.AddEntry(green, options.predLabel,"L")
00534     legend.AddEntry("","D_{stat}=%.3f, N=%d" % (maxDistance, size),"")
00535     legend.AddEntry("","P_{KS}=%.3f" % prob,"")
00536     legend.Draw()
00537 
00538     # save file
00539     c1.Print (outputFile)
00540 
00541 
00542 ######################
00543 ## ################ ##
00544 ## ## ########## ## ##
00545 ## ## ## Main ## ## ##
00546 ## ## ########## ## ##
00547 ## ################ ##
00548 ######################
00549 
00550 if __name__ == '__main__':
00551     ##########################
00552     ## command line options ##
00553     ##########################
00554     allowedEDF = ['time', 'instLum', 'instIntLum']
00555     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.')
00556     plotGroup  = optparse.OptionGroup (parser, "Plot Options")
00557     rangeGroup = optparse.OptionGroup (parser, "Range Options")
00558     inputGroup = optparse.OptionGroup (parser, "Input Options")
00559     modeGroup  = optparse.OptionGroup (parser, "Mode Options")
00560     plotGroup.add_option ('--title', dest='title', type='string',
00561                           default = 'Empirical Distribution Function',
00562                           help = 'title of plot (default %default)')
00563     plotGroup.add_option ('--predicted', dest='pred', type='float',
00564                           default = 0,
00565                           help = 'factor by which predicted curve is greater than observed')
00566     plotGroup.add_option ('--predLabel', dest='predLabel', type='string',
00567                           default = 'Predicted',
00568                           help = 'label of predicted in legend')
00569     plotGroup.add_option ('--noDataPoints', dest='noDataPoints',
00570                           action='store_true',
00571                           help="Draw lines but no points for data")
00572     rangeGroup.add_option ('--minRun', dest='minRun', type='int', default=0,
00573                            help='Minimum run number to consider')
00574     rangeGroup.add_option ('--maxRun', dest='maxRun', type='int', default=0,
00575                            help='Maximum run number to consider')
00576     rangeGroup.add_option ('--minIntLum', dest='minIntLum', type='float', default=0,
00577                            help='Minimum integrated luminosity to consider')
00578     rangeGroup.add_option ('--maxIntLum', dest='maxIntLum', type='float', default=0,
00579                            help='Maximum integrated luminosity to consider')
00580     rangeGroup.add_option ('--resetExpected', dest='resetExpected',
00581                            action='store_true',
00582                            help='Reset expected from total yield to highest point considered')
00583     rangeGroup.add_option ('--breakExpectedIntLum', dest='breakExpectedIntLum',
00584                            type='string', action='append', default=[],
00585                            help='Break expected curve into pieces at integrated luminosity boundaries')
00586     inputGroup.add_option ('--ignoreNoLumiEvents', dest='ignore',
00587                            action='store_true',
00588                            help = 'Ignore (with a warning) events that do not have a lumi section')
00589     inputGroup.add_option ('--noWarnings', dest='noWarnings',
00590                            action='store_true',
00591                            help = 'Do not print warnings about missing luminosity information')
00592     inputGroup.add_option ('--runEventLumi', dest='relOrder',
00593                            action='store_true',
00594                            help = 'Parse event list assuming Run, Event #, Lumi# order')
00595     inputGroup.add_option ('--weights', dest='weights', action='store_true',
00596                            help = 'Read fourth column as a weight')
00597     modeGroup.add_option ('--print', dest='printValues', action='store_true',
00598                           help = 'Print X and Y values of EDF plot')
00599     modeGroup.add_option ('--runsWithLumis', dest='runsWithLumis',
00600                           type='string',action='append', default=[],
00601                           help='Print out run and lumi sections corresponding to integrated luminosities provided and then exits')
00602     modeGroup.add_option ('--edfMode', dest='edfMode', type='string',
00603                           default='time',
00604                           help="EDF Mode %s (default '%%default')" % allowedEDF)
00605     parser.add_option_group (plotGroup)
00606     parser.add_option_group (rangeGroup)
00607     parser.add_option_group (inputGroup)
00608     parser.add_option_group (modeGroup)
00609     (options, args) = parser.parse_args()
00610 
00611     if options.edfMode not in allowedEDF:
00612         raise RuntimeError, "edfMode (currently '%s') must be one of %s" \
00613               % (options.edfMode, allowedEDF)
00614 
00615     if len (args) != 3 and not (options.runsWithLumis and len(args) >= 1):
00616         raise RuntimeError, "Must provide lumi.csv, events.txt, and output.png"
00617 
00618 
00619     ##########################
00620     ## load Luminosity info ##
00621     ##########################
00622     cont = LumiInfoCont (args[0], **options.__dict__)
00623     cont.minRun    = options.minRun
00624     cont.maxRun    = options.maxRun
00625     cont.minIntLum = options.minIntLum
00626     cont.maxIntLum = options.maxIntLum
00627 
00628     ##################################################
00629     ## look for which runs correspond to what total ##
00630     ## recorded integrated luminosity               ##
00631     ##################################################
00632     if options.runsWithLumis:
00633         recLumis = []
00634         for line in options.runsWithLumis:
00635             pieces = sepRE.split (line)
00636             for piece in pieces:
00637                 try:
00638                     recLumValue = float (piece)
00639                 except:
00640                     raise RuntimeError, "'%s' in '%s' is not a float" % \
00641                           (piece, line)
00642                 if recLumValue <= 0:
00643                     raise RuntimeError, "You must provide positive values for -runsWithLumis ('%f' given)" % recLumValue
00644                 recLumis.append (recLumValue)
00645         if not recLumis:
00646             raise RuntimeError, "What did Charles do now?"
00647         recLumis.sort()
00648         recLumIndex = 0
00649         recLumValue = recLumis [recLumIndex]
00650         prevRecLumi = 0.
00651         done = False
00652         for key, lumi in cont.iteritems():
00653             if prevRecLumi >= recLumValue and recLumValue < lumi.totalRecorded:
00654                 # found it
00655                 print "%s contains total recorded lumi %f" % \
00656                       (key.__str__(), recLumValue)
00657                 while True:
00658                     recLumIndex += 1
00659                     if recLumIndex == len (recLumis):
00660                         done = True
00661                         break
00662                     recLumValue = recLumis [recLumIndex]
00663                     if prevRecLumi >= recLumValue and recLumValue < lumi.totalRecorded:
00664                         # found it
00665                         print "%s contains total recorded lumi %f" % \
00666                               (key.__str__(), recLumValue)
00667                     else:
00668                         break
00669                 if done:
00670                     break
00671             prevRecLumi = lumi.totalRecorded
00672         if recLumIndex < len (recLumis):
00673             print "Theses lumis not found: %s" % recLumis[recLumIndex:]
00674         sys.exit()
00675 
00676     ####################
00677     ## make EDF plots ##
00678     ####################
00679     if options.edfMode != 'time' and not cont.xingInfo:
00680         raise RuntimeError, "'%s' does not have Xing info" % args[0]
00681     eventsDict, totalWeight = loadEvents (args[1], cont, options)
00682     makeEDFplot (cont, eventsDict, totalWeight, args[2], options)