class LumiDumper: def __init__(self): # Control output level self.verbose = True # Channel to chose (preferred by default) self.lumiChan = 0 # Run list self.runList = [] # Luminosity tag self.lumiTag = 'OflLumi-7TeV-002' # Use online instead self.online = False # Instantiate the LumiDBHandler, so we can cleanup all COOL connections in the destructor self.dbHandler = LumiDBHandler() # Output file (default stdout) self.outFile = None # Output directory (default none - pwd) self.outDir = None # Write stable beams only self.checkStable = True # Predefine data readers self.lumi = None self.fill = None self.ardy = None self.lhc = None self.lblb = None # Explicitly clean up our DB connections def __del__(self): self.dbHandler.closeAllDB() # Called in command-line mode def execute(self): # Handle command-line switches self.parseOpts() # Process each run in the runlist for runnum in self.runList: # Read all COOL data self.readData(runnum) self.printData(runnum) def parseOpts(self): parser = OptionParser(usage="usage: %prog [options]", add_help_option=False) parser.add_option("-?", "--usage", action="store_true", default=False, dest="help", help="show this help message and exit") parser.add_option("-v", "--verbose", action="store_true", default=self.verbose, dest="verbose", help="turn on verbose output") parser.add_option( "-r", "--run", dest="runlist", metavar="RUN", help="Specific run, range, or comma-separated list of both") parser.add_option("--channel", dest='chan', metavar='N', default=self.lumiChan, help='specify luminosity channel (default: %d)' % self.lumiChan) parser.add_option("--lumiTag", dest='lumitag', metavar='TAG', default=self.lumiTag, help='specify luminosity tag (default: %s)' % self.lumiTag) parser.add_option("--online", action='store_true', default=self.online, dest='online', help='use online luminosity (default: use offline)') parser.add_option("--outDir", dest='outdir', metavar='DIR', default=self.outDir, help='change default output directory') parser.add_option( "--noStable", action="store_false", default=self.checkStable, dest="checkstable", help="write non-stable beam luminosity (default: stable only)") (options, args) = parser.parse_args() if options.help: parser.print_help() sys.exit() if options.verbose: self.verbose = options.verbose self.lumiChan = int(options.chan) self.lumiTag = options.lumitag self.online = options.online self.outDir = options.outdir self.checkStable = options.checkstable # Parse run list if options.runlist != None: # Clear the old one self.runList = [] # Can be comma-separated list of run ranges runlist = options.runlist.split(',') if len(runlist) == 0: print 'Invalid run list specified!' sys.exit() # Go through and check for run ranges for runstr in runlist: subrunlist = runstr.split('-') if len(subrunlist) == 1: # Single run self.runList.append(int(subrunlist[0])) elif len(subrunlist) == 2: # Range of runs for runnum in range(int(subrunlist[0]), int(subrunlist[1]) + 1): self.runList.append(runnum) else: # Too many parameters print 'Invalid run list segment found:', runstr sys.exit() self.runList.sort() if self.verbose: print 'Finished parsing run list:', for runnum in self.runList: print runnum, print def readData(self, runnum): # Luminosity folder if self.verbose: print 'Reading lumi for run %d' % runnum if self.lumi == None: if self.online: self.lumi = CoolDataReader('COOLONL_TRIGGER/COMP200', '/TRIGGER/LUMI/LBLESTONL') else: self.lumi = CoolDataReader('COOLOFL_TRIGGER/COMP200', '/TRIGGER/OFLLUMI/LBLESTOFL') self.lumi.setTag(self.lumiTag) self.lumi.setChannelId(self.lumiChan) self.lumi.setIOVRangeFromRun(runnum) self.lumi.readData() if self.verbose: print 'Read %d Luminosity records' % len(self.lumi.data) # Load stable beam flag ( if self.verbose: print 'Reading ATLAS ready flag' if self.ardy == None: self.ardy = LumiDBCache('COOLONL_TDAQ/COMP200', '/TDAQ/RunCtrl/DataTakingMode') self.ardy.reader.setIOVRangeFromRun(runnum) self.ardy.reader.readData() if self.verbose: print 'Read %d ATLAS ready records' % len(self.ardy.reader.data) # Load LBLB data (needed to convert to time) if self.verbose: print 'Reading LBLB data' if self.lblb == None: self.lblb = CoolDataReader('COOLONL_TRIGGER/COMP200', '/TRIGGER/LUMI/LBLB') self.lblb.setIOVRangeFromRun(runnum) self.lblb.readData() if self.verbose: print 'Read %d LBLB records' % len(self.lblb.data) if len(self.lblb.data) > 0: print 'First LB %d/%d' % (self.lblb.data[0].since() >> 32, self.lblb.data[0].since() & 0xFFFFFFFF) print 'Last LB %d/%d' % (self.lblb.data[-1].since() >> 32, self.lblb.data[-1].since() & 0xFFFFFFFF) # Now figure out starting/ending time if len(self.lblb.data) < 1: print 'No LBLB data found!' return # Nothing to work with tlo = self.lblb.data[0].payload()['StartTime'] thi = self.lblb.data[-1].payload()['EndTime'] # Fillparams (slow) if self.verbose: print 'Reading Fillparams' if self.fill == None: self.fill = LumiDBCache('COOLONL_TDAQ/COMP200', '/TDAQ/OLC/LHC/FILLPARAMS') self.fill.reader.setIOVRange(tlo, thi) self.fill.reader.readData() if self.verbose: print 'Read %d FILLPARAMS records' % len(self.fill.reader.data) # LHC information (for stable beams) if self.verbose: print 'Reading LHC information' if self.lhc == None: self.lhc = LumiDBCache('COOLOFL_DCS/COMP200', '/LHC/DCS/FILLSTATE') self.lhc.reader.setIOVRange(tlo, thi) self.lhc.reader.readData() if self.verbose: print 'Read %d LHC records' % len(self.lhc.reader.data) def printData(self, runnum): # Only proceed if we have actual lumi data if len(self.lumi.data) == 0: return f = None # Make time map lblbMap = dict() for obj in self.lblb.data: lblbMap[obj.since()] = (obj.payload()['StartTime'], obj.payload()['EndTime']) # OK, now we want to go through the luminosity records and match the other data for obj in self.lumi.data: run = obj.since() >> 32 lb = obj.since() & 0xFFFFFFFF startTime = lblbMap.get(obj.since(), (0., 0.))[0] endTime = lblbMap.get(obj.since(), (0., 0.))[1] lumi = obj.payload()['LBAvInstLumi'] mu = obj.payload()['LBAvEvtsPerBX'] payload = self.fill.getPayload(startTime) if payload == None: ncol = 0 else: ncol = payload['LuminousBunches'] payload = self.lhc.getPayload(startTime) if payload == None: stable = 0 else: stable = payload['StableBeams'] payload = self.ardy.getPayload(obj.since()) if self.ardy == None: ready = 0 else: ready = payload['ReadyForPhysics'] if self.checkStable and not stable: continue # Open file if not open already if f == None: # Open if self.outDir != None: self.outFile = '%s/run%d.txt' % (self.outDir, runnum) else: self.outFile = 'run%d.txt' % runnum print 'Writing file %s' % self.outFile f = open(self.outFile, 'w') # OK, print it out print >> f, run, lb, startTime / 1.E9, endTime / 1.E9, lumi, mu, ncol, ready # Close file if f != None: f.close()
class OflLumiMaker: def __init__(self): # Control output level self.verbose = False # Output root file name self.fileName = 'scan.root' # Input file with turn information (from Nitesh) self.turnFile = None # Location of scan data self.tdaqDB = 'COOLONL_TDAQ/COMP200' self.tdaqMonpDB = 'COOLONL_TDAQ/MONP200' self.monp = False # Use MONP or COMP DB self.scanFolder = '/TDAQ/OLC/LHC/SCANDATA' # vdM Scan parameter data self.beamFolder = '/TDAQ/OLC/LHC/BEAMPOSITION' self.fillFolder = '/TDAQ/OLC/LHC/FILLPARAMS' self.lbdataFolder = '/TDAQ/OLC/LHC/LBDATA' self.bunchFolder = '/TDAQ/OLC/LHC/BUNCHDATA' self.bunchLumiFolder = '/TDAQ/OLC/BUNCHLUMIS' self.lumiFolder = '/TDAQ/OLC/LUMINOSITY' # Calendar time range to look for vdM scan data self.startTime = '2010-10-01:07:00:00/UTC' self.endTime = '2010-10-01:14:00:00/UTC' # Time as COOL IOV self.startTimeIOV = None self.endTimeIOV = None self.startLBIOV = None self.endLBIOV = None # Pointers to CoolDataReader return objects self.lhcData = None self.lumiData = None self.scanData = None self.lbdataData = None self.bunchdataData = None self.ions = False # Object to store BCID information self.maskObj = BCIDMask() # Object to store the bunch group definition self.bgObj = BunchGroup() # Channels to store self.lumiChanList = [ 101, 102, 103, 104, 105, 106, 201, 202, 206, 207, 211, 212, 216, 217, 221, 222, 226, 1001, 1002, 1004, 1011, 1012, 1014 ] # Called in command-line mode def execute(self): # Handle command-line switches self.parseOpts() # Find the scan data self.findScanData() # Write the data to ntuple #nt = ScanNtupleHandler() #nt.fileName = self.fileName #nt.ions = self.ions #nt.open() #nt.init() #nt.fill(self) # Must pass self reference to get access to data #nt.close() nt = NtupleHandler() nt.chan2011 = False nt.chan2012 = True nt.fibers = False nt.fileName = self.fileName nt.open() nt.init() nfilled = 0 # Sort raw data and save by [iov][algo] rawDict = dict() for obj in self.bunchLumi.data: channel = obj.channelId() iov = obj.since() if iov not in rawDict: rawDict[iov] = dict() rawDict[iov][channel] = obj # PMT current data pmtDict = dict() fibDict = dict() # Fiber currents for obj in self.pmtReader.data: if obj.channelId() == 0: pmtDict[obj.since()] = obj elif obj.channelId() == 1: fibDict[obj.since()] = obj else: print 'Found channel %d in pmtReader!' % obj.channel() # Bunch current data currDict = dict() for obj in self.bunchData.data: currDict[obj.since()] = obj # Loop over scandata entries for plbobj in self.scanData.data: iov = plbobj.since() iovString = timeString(iov) runlb = plbobj.payload()['RunLB'] run = plbobj.payload()['RunLB'] >> 32 lb = plbobj.payload()['RunLB'] & 0xFFFFFFFF dtime = (plbobj.until() - plbobj.since()) / 1E9 print '%s (%6d/%3d) t=%5.2fs Acq:%5.2f d=%6.3fmm IP:%2d Plane:%2d' % ( iovString, run, lb, dtime, plbobj.payload()['AcquisitionFlag'], plbobj.payload()['NominalSeparation'], plbobj.payload()['ScanningIP'], plbobj.payload()['ScanInPlane']), # Check if beams are moving at IP1 if run == 0 and plbobj.payload( )['ScanningIP'] == 1 and plbobj.payload()['AcquisitionFlag'] < 1.: print " --> moving" continue print nt.fillLBData(plbobj) nt.lbDataStruct.fStable = True # Ensure true if iov not in rawDict: print "Can't find time %s in raw lumi!" % iovString continue nt.clearBCIDData() # Make sure BCID mask is valid if not self.updateBCIDMask(iov): print "Couldn't find valid BCID mask data for IOV %s!" % iov continue # Make sure BunchGroup is valid #if run > 0 and not self.updateBunchGroup(runlb): # print "Couldn't find valid BunchGroup data for %s (%d/%d)!" % (iov, run, lb) if iov in pmtDict: nt.lbDataStruct.fPmtA = pmtDict[iov].payload()['CurrentSideA'] nt.lbDataStruct.fPmtC = pmtDict[iov].payload()['CurrentSideC'] # print 'Found Run %d LB %d PMTA %f PMTC %f' % (run, lb, nt.lbDataStruct.fPmtA, nt.lbDataStruct.fPmtC) if iov in fibDict: nt.lbDataStruct.fFibA = fibDict[iov].payload()['CurrentSideA'] nt.lbDataStruct.fFibC = fibDict[iov].payload()['CurrentSideC'] # print 'Found Run %d LB %d FIBA %f FIBC %f' % (run, lb, nt.lbDataStruct.fFibA, nt.lbDataStruct.fFibC) if iov in currDict: nt.fillCurrentData(currDict[iov], self.maskObj) for chan in self.lumiChanList: if chan not in rawDict[iov]: print "Can't find channel", chan, "in", iovString continue rawobj = rawDict[iov][chan] if chan != rawobj.channelId(): print 'Channel', chan, '!=', rawobj.channelId(), '!' continue # Get raw lumi normValue = rawobj.payload()['AverageRawInstLum'] blobValue = rawobj.payload()['BunchRawInstLum'] bcidVec, rawLumi = unpackBCIDValues(blobValue, self.maskObj.coll, normValue) # dict to hold BCID lumi keyed by BCID for i in range(len(rawLumi)): # Check if this is in our bunch group (only really need to fill this once) bcid = bcidVec[i] # Protect against any weird values if bcid >= nt.nBCID: print 'BCID %d found >= %d!' % (bcid, nt.nBCID) continue #if bcid in self.bgObj.bg: # nt.bcidStruct.fStatus[bcid] = 1 #else: # nt.bcidStruct.fStatus[bcid] = 0 # Now need to save bcid, mu, and calibLumi lraw = rawLumi[i] muval = 0. # Uncalibrated nt.fillBCIDData(chan, bcid, lraw, muval) # End of loop over BCIDs # End of loop over channels nt.tree.Fill() # End of loop over IOVs nt.close() def parseOpts(self): parser = OptionParser(usage="usage: %prog [options]", add_help_option=False) parser.add_option("-?", "--usage", action="store_true", default=False, dest="help", help="show this help message and exit") parser.add_option("-v", "--verbose", action="store_true", default=self.verbose, dest="verbose", help="turn on verbose output") parser.add_option("-o", "--output", dest="outfile", metavar="FILE", default=self.fileName, help="specify output ROOT file name - default: " + self.fileName) parser.add_option("--startTime", dest="starttime", metavar="TIME", help="set starting time (YYYY-MM-DD:HH:MM:SS)") parser.add_option("--endTime", dest="endtime", metavar="TIME", help="set ending time (YYYY-MM-DD:HH:MM:SS)") parser.add_option( "--ions", dest="ions", default=self.ions, action="store_true", help="Use Heavy Ion variable list (not used currently!)") parser.add_option( "--monp", dest="monp", default=self.monp, action="store_true", help= "Use MONP200 rather than COMP200 DB for per-bunch lumi - default: " + str(self.monp)) (options, args) = parser.parse_args() if options.help: parser.print_help() sys.exit() self.verbose = options.verbose self.ions = options.ions self.monp = options.monp # Parse times if options.starttime != None: self.startTime = options.starttime if options.endtime != None: self.endTime = options.endtime self.fileName = options.outfile def findScanData(self): print 'vdMScanMaker.findScanData() called' # Based on the (text) starting and ending times, find the available scan entries in COOL # First, convert time strings to COOL IOV times self.startTimeIOV = timeVal(self.startTime) if self.startTimeIOV == None: print 'OflLumiMaker.findScanData - Error converting start time', self.startTime, '!' sys.exit() self.endTimeIOV = timeVal(self.endTime) if self.endTimeIOV == None: print 'OflLumiMaker.findScanData - Error converting end time', self.endTime, '!' sys.exit() # Load the scan data self.scanData = CoolDataReader(self.tdaqDB, self.scanFolder) self.scanData.setIOVRange(self.startTimeIOV, self.endTimeIOV) if not self.scanData.readData(): print 'OflLumiMaker.findScanData - No scan data found in range', self.startTime, 'to', self.endTime, '!' sys.exit() # for obj in self.scanData.data: # run = obj.payload()['RunLB'] >> 32 # lb = obj.payload()['RunLB'] & 0xFFFFFFFF # print '%s (%6d/%3d) t=%5.2fs Acq:%5.2f d=%6.3fmm IP:%2d Plane:%2d' % (timeString(obj.since()), run, lb, (obj.until()-obj.since())/1E9, obj.payload()['AcquisitionFlag'], obj.payload()['NominalSeparation'], obj.payload()['ScanningIP'], obj.payload()['ScanInPlane']) # Load the beam positions # self.beamData = CoolDataReader(self.tdaqDB, self.beamFolder) # self.beamData.setIOVRange(self.startTimeIOV, self.endTimeIOV) # if not self.beamData.readData(): # print 'OflLumiMaker.findScanData - No beam separation data found in range', self.startTime, 'to', self.endTime,'!' # sys.exit() # if self.verbose: # for obj in self.beamData.data: # run = obj.payload()['RunLB'] >> 32 # lb = obj.payload()['RunLB'] & 0xFFFFFFFF # print run, lb, obj.payload()['B1_PositionAtIP_H'], obj.payload()['B1_PositionAtIP_V'], obj.payload()['B2_PositionAtIP_H'], obj.payload()['B2_PositionAtIP_V'] # Load the fill parameters self.fillData = CoolDataReader(self.tdaqDB, self.fillFolder) self.fillData.setIOVRange(self.startTimeIOV, self.endTimeIOV) if not self.fillData.readData(): print 'OflLumiMaker.findScanData - No fill parameters data found in range', self.startTime, 'to', self.endTime, '!' sys.exit() if self.verbose: for obj in self.fillData.data: print obj.payload()['Beam1Bunches'], obj.payload( )['Beam2Bunches'], obj.payload()['LuminousBunches'] # Load the lbdata parameters self.lbdataData = CoolDataReader(self.tdaqDB, self.lbdataFolder) self.lbdataData.setIOVRange(self.startTimeIOV, self.endTimeIOV) if not self.lbdataData.readData(): print 'OflLumiMaker.findScanData - No LBDATA data found in range', self.startTime, 'to', self.endTime, '!' sys.exit() if self.verbose: for obj in self.lbdataData.data: print 'LBDATA', obj.channelId(), obj.payload( )['Beam1Intensity'], obj.payload()['Beam2Intensity'] # Load the BUNCHDATA parameters if self.monp: self.bunchData = CoolDataReader(self.tdaqMonpDB, self.bunchFolder) else: self.bunchData = CoolDataReader(self.tdaqDB, self.bunchFolder) self.bunchData.setIOVRange(self.startTimeIOV, self.endTimeIOV) self.bunchData.setChannelId(1) # 0 = BPTX, 1 = Fast BCT if not self.bunchData.readData(): print 'OflLumiMaker.findScanData - No BUNCHDATA data found in range', self.startTime, 'to', self.endTime, '!' sys.exit() if self.verbose: for obj in self.bunchData.data: print 'BUNCHDATA', obj.channelId(), obj.payload( )['B1BunchAverage'], obj.payload()['B2BunchAverage'] # Load the BUNCHLUMI parameters if self.monp: self.bunchLumi = CoolDataReader(self.tdaqMonpDB, self.bunchLumiFolder) else: self.bunchLumi = CoolDataReader(self.tdaqDB, self.bunchLumiFolder) self.bunchLumi.setIOVRange(self.startTimeIOV, self.endTimeIOV) if not self.bunchLumi.readData(): print 'OflLumiMaker.findScanData - No BUNCHLUMIS data found in range', self.startTime, 'to', self.endTime, '!' sys.exit() if self.verbose: for obj in self.bunchLumi.data: print 'BUNCHLUMI', obj.channelId(), obj.payload( )['AverageRawInstLum'] # Load the luminosity data self.lumiData = CoolDataReader(self.tdaqDB, self.lumiFolder) self.lumiData.setIOVRange(self.startTimeIOV, self.endTimeIOV) if not self.lumiData.readData(): print 'OflLumiMaker.findScanData - No LUMINOSITY data found in range', self.startTime, 'to', self.endTime, '!' sys.exit() # Load the Lucid currents self.pmtReader = CoolDataReader('COOLONL_TDAQ/COMP200', '/TDAQ/OLC/LUCIDCURRENTS') self.pmtReader.setIOVRange(self.startTimeIOV, self.endTimeIOV) self.pmtReader.setChannel([0, 1]) # Load total PMT and fiber currents if not self.pmtReader.readData(): print 'No PMT current data found in range', self.startTime, 'to', self.endTime, '!' if self.verbose: for obj in self.pmtReader.data: print 'LUCIDCURRENTS', obj.channelId(), obj.payload( )['CurrentSideA'], obj.payload()['CurrentSideC'] def updateBCIDMask(self, startTime): if not self.maskObj.isValid(startTime): self.maskObj.clearValidity() # Find the proper mask object maskData = None for mask in self.fillData.data: if not mask.since() <= startTime < mask.until(): continue self.maskObj.setMask(mask) break if not self.maskObj.isValid(startTime): return False return True def updateBunchGroup(self, runlb): if not self.bgObj.isValid(runlb): self.bgObj.clearValidity() # Find the proper BG object for bg in self.bgReader.data: if not bg.since() <= runlb < bg.until(): continue self.bgObj.setBG(bg) break if not self.bgObj.isValid(runlb): return False return True
class CalibNtupleMaker: def __init__(self): # Control output level self.verbose = False # Luminosity Channels self.lumiChanList = [] # Luminosity Channel Map self.lumiChanNames = dict() self.lumiMapFile = 'defaultChannels.txt' # Stable only self.stableOnly = False # Write output ntuple self.ntuple = True # Write extra current information self.writeExtraCurrents = True # List of (integer) run numbers specified on the command line self.runList = [] # Dict of (lblo, lbhi) pairs giving extent of StableBeams self.stableDict = dict() # Utlity routine for handling COOL connections self.dbHandler = LumiDBHandler() # Data readers self.maskReader = None self.lumiReader = None self.caliReader = None self.lblbReader = None self.currReader = None self.lhcReader = None self.bgReader = None self.pmtReader = None self.lbdataReader = None # Object which stores the BCID information self.maskObj = BCIDMask() # Object to store the bunch group definition self.bgObj = BunchGroup() self.currentRun = 0 self.nBCID = 3564 self.outdir = '.' # Explicitly clean up our DB connections def __del__(self): self.dbHandler.closeAllDB() # Called in command-line mode def execute(self): # Handle command-line switches self.parseOpts() # Fill channel list self.fillChannelList() # Process each run in self.runList for run in self.runList: # Load all data from COOL self.loadBCIDData(run) # Skip if run doesn't exist if len(self.lblbReader.data) == 0: continue # Find stable beams, output goes to self.stableTime self.findStable() if self.stableOnly and len(self.stableTime) == 0: continue # Open new output file and init ntuple if self.ntuple: nt = NtupleHandler() nt.chanMap = self.lumiChanNames nt.writeExtraCurrents = self.writeExtraCurrents nt.fileName = '%s/r%d.root' % (self.outdir, run) nt.open() nt.init() # Storage objects keyed by [runlb][algo] objDict = dict() runlbList = [] # Loop over all objects and sort by runlb and algo for obj in self.lumiReader.data: channel = obj.channelId() runlb = obj.payload()['RunLB'] if runlb not in objDict: objDict[runlb] = dict() runlbList.append(runlb) objDict[runlb][channel] = obj # if self.verbose: # run = runlb >> 32 # lb = runlb & 0xFFFFFFFF # print 'Found Run %d LB %d chan %d' % (run, lb, channel) # LHC Current objects keyed by [runlb] currDict = dict() for obj in self.currReader.data: runlb = obj.payload()['RunLB'] if runlb not in currDict: currDict[runlb] = dict() currDict[runlb][obj.channelId()] = obj #if self.writeExtraCurrents: lbdataDict = dict() for obj in self.lbdataReader.data: runlb = obj.payload()['RunLB'] if runlb not in lbdataDict: lbdataDict[runlb] = dict() lbdataDict[runlb][obj.channelId()] = obj # Loop over all lumi blocks and calibrate each algorithm runlbList.sort() for runlb in runlbList: run = runlb >> 32 lb = runlb & 0xFFFFFFFF self.currentRun = run # Make sure bunch group is valid (keyed by run/lb) if not self.updateBunchGroup(runlb): print "Couldn't find valid Bunch Group definition for Run %d LB %d!" % ( run, lb) continue # Get integer to make average mu value below nBunch = len(self.bgObj.bg) if nBunch < 1: nBunch = 1 # Zero all storage locations nt.clearBCIDData() first = True lbSum = dict() for chan in self.lumiChanList: if chan not in objDict[runlb]: print "Can't find channel", chan, "in run/lb", run, '/', lb continue obj = objDict[runlb][chan] if chan != obj.channelId(): print 'Channel', chan, '!=', obj.channelId(), '!' continue if runlb != obj.payload()['RunLB']: print 'RunLB', runlb, '!=', obj.payload()['RunLB'], '!' continue startTime = obj.since() endTime = obj.until() dtime = (endTime - startTime) / 1E9 valid = obj.payload()['Valid'] & 0x03 # Hack for lucid validity if 100 < chan < 200 and valid == 1: valid = 0 # Check whether this is in stable beams isStable = False for stable in self.stableTime: if not stable[0] <= startTime < stable[1]: continue isStable = True break if self.stableOnly and not isStable: continue # Clear lumi block sum counters lbSum[chan] = 0. # Only do this once per lumi block if first: first = False if self.verbose: print 'Found stable Run %d LB %d' % (run, lb) # Fill general LB information if self.ntuple: nt.fillLBData(obj) nt.lbDataStruct.fStable = isStable # These change slowly, so checking them every run/lb is OK # Make sure BCID mask is valid if not self.updateBCIDMask(startTime): print "Couldn't find valid BCID mask data for Run %d LB %d!" % ( run, lb) continue # Do this here so the BCID mask is up to date if self.ntuple: if runlb in currDict: if 1 in currDict[runlb]: nt.fillCurrentData(currDict[runlb], self.maskObj, 1) if 0 in currDict[ runlb] and self.writeExtraCurrents: nt.fillCurrentData(currDict[runlb], self.maskObj, 0) if runlb in lbdataDict: nt.fillMoreCurrentData(lbdataDict[runlb]) # Now we want to start extracting bunch-by-bunch information # Get raw lumi normValue = obj.payload()['AverageRawInstLum'] blobValue = obj.payload()['BunchRawInstLum'] bcidVec, rawLumi = unpackBCIDValues(blobValue) # dict to hold BCID lumi keyed by BCID bcidLumi = dict() for i in range(len(rawLumi)): # Check if this is in our bunch group (only really need to fill this once) bcid = bcidVec[i] # Protect against any weird values if bcid >= self.nBCID: print 'BCID %d found >= %d!' % (bcid, self.nBCID) continue if bcid in self.bgObj.bg: nt.bcidArray['Status'][bcid] = 1 else: nt.bcidArray['Status'][bcid] = 0 # Now need to save bcid, mu, and calibLumi lraw = rawLumi[i] nt.fillBCIDData(chan, bcid, lraw) # End loop over BCIDs # End of loop over channels nt.tree.Fill() # End of loop over LBs nt.close() # End of loop over runs # Load all data necessary to make bunch-by-bunch lumi for a single run def loadBCIDData(self, runnum): print 'MuHistMaker.loadBCIDData(%s) called' % runnum # Many folders are indexed by time stamp. Load RunLB -> time conversion here self.loadLBLB(runnum) if len(self.lblbReader.data) == 0: return # Determine start and end time of this run startTime = self.lblbReader.data[0].payload()['StartTime'] endTime = self.lblbReader.data[-1].payload()['EndTime'] iov = (startTime, endTime) # Read LHC Data (for stable beams) self.loadLHCData(iov) # Read the bunch group (so we sum over the right thing) self.loadBGData(runnum) # Read BCID Data self.loadBCIDMask(iov) self.loadBCIDLumi(iov) self.loadBCIDCurrents(iov) self.loadOtherCurrents(iov) def loadLBLB(self, run): if self.verbose: print 'Loading LBLB data' # Instantiate new COOL data reader if not already done if self.lblbReader == None: self.lblbReader = CoolDataReader('COOLONL_TRIGGER/CONDBR2', '/TRIGGER/LUMI/LBLB') self.lblbReader.setIOVRangeFromRun(run) self.lblbReader.readData() if self.verbose: print 'Read %d LBLB records' % len(self.lblbReader.data) if len(self.lblbReader.data) > 0: print 'First LB %d/%d' % ( self.lblbReader.data[0].since() >> 32, self.lblbReader.data[0].since() & 0xFFFFFFFF) print 'Last LB %d/%d' % ( self.lblbReader.data[-1].since() >> 32, self.lblbReader.data[-1].since() & 0xFFFFFFFF) def loadBGData(self, run): if self.verbose: print 'Loading Bunch group data' # Instantiate new COOL reader if not already done if self.bgReader == None: self.bgReader = CoolDataReader('COOLONL_TRIGGER/CONDBR2', '/TRIGGER/LVL1/BunchGroupContent') self.bgReader.setIOVRangeFromRun(run) self.bgReader.readData() if self.verbose: print 'Read %d bunch group records' % len(self.bgReader.data) def loadBCIDMask(self, iov): if self.verbose: print 'Loading BCID masks' # Instantiate new COOL data reader if not already done if self.maskReader == None: self.maskReader = CoolDataReader('COOLONL_TDAQ/CONDBR2', '/TDAQ/OLC/LHC/FILLPARAMS') self.maskReader.setIOVRange(iov[0], iov[1]) self.maskReader.readData() if self.verbose: print 'Read %d BCID Mask records' % len(self.maskReader.data) def loadBCIDLumi(self, iov): if self.verbose: print 'Loading BCID luminosity values' # Instantiate new COOL data reader if not already done if self.lumiReader == None: # Switch at start of September self.lumiReader = CoolDataReader('COOLONL_TDAQ/CONDBR2', '/TDAQ/OLC/BUNCHLUMIS') #self.lumiReader.verbose = True self.lumiReader.setIOVRange(iov[0], iov[1]) self.lumiReader.setChannel(self.lumiChanList) self.lumiReader.readData() #self.lumiReader.verbose = False if self.verbose: print 'Read %d Lumi records' % len(self.lumiReader.data) # Bunch currents def loadBCIDCurrents(self, iov): if self.verbose: print 'Loading Bunch Current information' if self.currReader == None: # self.currReader = CoolDataReader('COOLONL_TDAQ/MONP200', '/TDAQ/OLC/LHC/BUNCHDATA') self.currReader = CoolDataReader('COOLONL_TDAQ/CONDBR2', '/TDAQ/OLC/LHC/BUNCHDATA') self.currReader.setIOVRange(iov[0], iov[1]) if self.writeExtraCurrents: self.currReader.setChannel([0, 1]) # 0 = BPTX, 1 = Fast BCT else: self.currReader.setChannelId(1) # 0 = BPTX, 1 = Fast BCT self.currReader.readData() if self.verbose: print 'Read %d Current records' % len(self.currReader.data) def loadOtherCurrents(self, iov): if self.verbose: print 'Loading LBDATA Bunch Current information' if self.lbdataReader == None: self.lbdataReader = CoolDataReader('COOLONL_TDAQ/CONDBR2', '/TDAQ/OLC/LHC/LBDATA') self.lbdataReader.setIOVRange(iov[0], iov[1]) self.lbdataReader.setChannel([0, 1, 2, 3]) # 0 = BPTX, 1 = Fast BCT self.lbdataReader.readData() if self.verbose: print 'Read %d LBDATA Current records' % len( self.lbdataReader.data) # Information about stable beams def loadLHCData(self, iov): if self.verbose: print 'Loading LHC information' # Instantiate new COOL data reader if not already done if self.lhcReader == None: self.lhcReader = CoolDataReader('COOLOFL_DCS/CONDBR2', '/LHC/DCS/FILLSTATE') self.lhcReader.setIOVRange(iov[0], iov[1]) self.lhcReader.readData() if self.verbose: print 'Read %d LHC records' % len(self.lhcReader.data) # Fill the stable beam information in the OflLumiRunData object def findStable(self): if self.verbose: print 'Finding stable beam periods' # First, fill stable beam time periods for this run tlo = cool.ValidityKeyMax thi = cool.ValidityKeyMin self.stableTime = [] for obj in self.lhcReader.data: if obj.payload()['StableBeams'] == 0: continue if tlo > thi: # First stable beams tlo = obj.since() thi = obj.until() elif thi == obj.since(): # Extension of existing stable beams thi = obj.until() else: # Not contiguous, add old to list and start again self.stableTime.append((tlo, thi)) tlo = obj.since() thi = obj.until() if tlo < thi: self.stableTime.append((tlo, thi)) if self.verbose: print 'Stable beam periods found:', self.stableTime def updateBCIDMask(self, startTime): if not self.maskObj.isValid(startTime): self.maskObj.clearValidity() # Find the proper mask object maskData = None for mask in self.maskReader.data: if not mask.since() <= startTime < mask.until(): continue self.maskObj.setMask(mask) break if not self.maskObj.isValid(startTime): return False return True def updateBunchGroup(self, runlb): if not self.bgObj.isValid(runlb): self.bgObj.clearValidity() # Find the proper BG object for bg in self.bgReader.data: if not bg.since() <= runlb < bg.until(): continue self.bgObj.setBG(bg) break if not self.bgObj.isValid(runlb): return False return True def parseOpts(self): parser = OptionParser(usage="usage: %prog [options]", add_help_option=False) parser.add_option("-?", "--usage", action="store_true", default=False, dest="help", help="show this help message and exit") parser.add_option("-v", "--verbose", action="store_true", default=self.verbose, dest="verbose", help="turn on verbose output") parser.add_option("-r", "--updateRun", dest="runlist", metavar="RUN", help="update specific run, or comma separated list") parser.add_option("--noNtuple", action="store_false", default=self.ntuple, dest='ntuple', help="Don't store output ntuple (default: Do)") parser.add_option("-o", "--outputDir", dest="outdir", metavar="DIR", default=self.outdir, help='directory for output ntuple (default: %s)' % self.outdir) parser.add_option( "--noStable", action="store_false", default=self.stableOnly, dest="stable", help="turn off stable beams requirements (default: stable only)") parser.add_option("--channelList", dest='chanlist', metavar="FILE", default=self.lumiMapFile, help='file to read channel list from (default: %s)' % self.lumiMapFile) (options, args) = parser.parse_args() if options.help: parser.print_help() sys.exit() self.verbose = options.verbose self.outdir = options.outdir self.stableOnly = options.stable self.lumiMapFile = options.chanlist # Parse run list if options.runlist != None: # Clear the old one self.runList = [] # Can be comma-separated list of run ranges runlist = options.runlist.split(',') if len(runlist) == 0: print 'Invalid run list specified!' sys.exit() # Go through and check for run ranges for runstr in runlist: subrunlist = runstr.split('-') if len(subrunlist) == 1: # Single run self.runList.append(int(subrunlist[0])) elif len(subrunlist) == 2: # Range of runs for runnum in range(int(subrunlist[0]), int(subrunlist[1]) + 1): self.runList.append(runnum) else: # Too many parameters print 'Invalid run list segment found:', runstr sys.exit() self.runList.sort() if self.verbose: print 'Finished parsing run list:', for runnum in self.runList: print runnum, print def fillChannelList(self): print 'Reading channel list from', self.lumiMapFile # Make sure these are empty self.lumiChanList = [] self.lumiChanNames = dict() f = open(self.lumiMapFile) for line in f.readlines(): line = string.lstrip(line) # Skip obvious comments if len(line) == 0: continue if line[0] == "!": continue if line[0] == "#": continue # Now parse tokens = line.split() chanID = int(tokens[0]) chanName = tokens[1] print 'Found Channel %d: %s' % (chanID, chanName) self.lumiChanList.append(chanID) self.lumiChanNames[chanID] = chanName # End of loop over channels f.close()
def execute(self): self.parseOpts() # Read offline luminosity lumiReader = CoolDataReader('COOLOFL_TRIGGER/COMP200', '/TRIGGER/OFLLUMI/LBLESTOFL') lumiReader.setChannelId(self.lumiChannel) lumiReader.setTag(self.lumiTag) # Read LAr noise bursts larReader = CoolDataReader('COOLOFL_LAR/COMP200', '/LAR/BadChannelsOfl/EventVeto') larReader.setTag('LARBadChannelsOflEventVeto-UPD4-04') # Time to use with LAr noise # lbtimeReader = CoolDataReaderCache('COOLONL_TRIGGER/COMP200', '/TRIGGER/LUMI/LBTIME') lblbReader = CoolDataReader('COOLONL_TRIGGER/COMP200', '/TRIGGER/LUMI/LBLB') # Read ATLAS ready flag readyReader = LumiDBCache('COOLONL_TDAQ/COMP200', '/TDAQ/RunCtrl/DataTakingMode') for run in self.runList: print print 'Generating run', run rootfile = self.outdir + '/run' + str(run) + '.root' # Define ntuple - will open existing file if present nt = TrigNtupleHandler() nt.fileName = rootfile nt.open(update=False) nt.initLBData() nt.initL1TrigData() # Load run information print 'Load trigger information' th = TriggerHandler() th.allL1Triggers = True th.trigList = [] th.loadDataByRun(run) # Load lumi information print 'Load lumi information' lumiReader.setIOVRangeFromRun(run) lumiReader.readData() # Read ATLAS ready information print 'Load ATLAS ready information' readyReader.reader.setIOVRangeFromRun(run) readyReader.reader.readData() # Load time stamps print 'Load LBLB information' lblbReader.setIOVRangeFromRun(run) lblbReader.readData() startTime = lblbReader.data[0].payload()["StartTime"] endTime = lblbReader.data[-1].payload()["EndTime"] # Read bad LAr periods print 'Load LAr information' larReader.setIOVRange(startTime, endTime) larReader.readData() # Now make a list of bad lumi blocks print 'Finding bad LBs' badLB = set() for larData in larReader.data: if larData.payload()["EventVeto"] == 0: continue tlo = larData.since() thi = larData.until() # Find all lumi blocks spanned by this range for lb in lblbReader.data: if lb.payload()["EndTime"] <= tlo: continue ss = lb.since() if lb.payload()["StartTime"] < tlo: badLB.add(ss) print runLBString(ss) if lb.payload()["StartTime"] < thi: badLB.add(ss) print runLBString(ss) if lb.payload()["StartTime"] > thi: break # Process for obj in lumiReader.data: ss = obj.since() lumi = obj.payload()["LBAvInstLumi"] mu = obj.payload()["LBAvEvtsPerBX"] if ss not in th.trigL1Dict: continue trigcount = th.trigL1Dict[ss].TBP[self.trigChan] dtime = th.trigL1Dict[ss].dtime if (dtime > 0.): trigrate = trigcount / dtime else: trigrate = 0. atlasReady = False readypay = readyReader.getPayload(obj.since()) if readypay != None: atlasReady = readypay['ReadyForPhysics'] print runLBString( ss), atlasReady, lumi, mu, trigcount, trigrate, if trigrate > 0.: print lumi / trigrate else: print # ATLAS Ready only if self.ready and (not atlasReady): continue nt.clear() nt.lbData.coolStartTime = th.trigL1Dict[ss].startTime nt.lbData.coolEndTime = th.trigL1Dict[ss].endTime nt.lbData.startTime = nt.lbData.coolStartTime / 1.E9 nt.lbData.endTime = nt.lbData.coolEndTime / 1.E9 nt.lbData.lbTime = dtime nt.lbData.run = obj.since() >> 32 nt.lbData.lb = obj.since() & 0xFFFFFFFF nt.lbData.onlInstLum = lumi nt.lbData.onlEvtsPerBX = mu nt.lbData.ready = atlasReady nt.lbData.larVeto = (ss in badLB) # And save trigger counts nt.fillL1Trig(th.trigL1Dict[ss], th.trigChan) nt.save() #for chan in range(256): # print chan, nt.l1TBP[chan] nt.close()