class MuHistMaker: def __init__(self): # Control output level self.verbose = True # Luminosity Channel self.lumiChan = 103 # Lucid_HitOR # self.lumiChan = 201 # BCM Event OR # self.lumiChan = 102 # Lucid Event OR # self.lumiChan = 0 # Use preferred (doesn't work?) # Stable only self.stableOnly = True # Ready only self.readyOnly = True # Apply deadtime self.deadtime = False # List of (integer) run numbers specified on the command line self.runList = [] # Dict of (lblo, lbhi) pairs giving extent of StableBeams self.stableDict = dict() # Dict of (lblo, lbhi) pairs giving extent of ATLAS Ready self.readyDict = 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.lhcReader = None self.trigReader = None self.bgReader = None self.rdyReader = None # Object which stores the luminosity calibration self.caliObj = LumiCalib() # Object which stores the BCID information self.maskObj = BCIDMask() # Object to store the bunch group definition self.bgObj = BunchGroup() # Histogram parameters self.nbins = 500 self.mulo = 0. self.muhi = 50. # 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 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() # Find ATLAS ready self.findReady() # Skip if no stable beams if self.stableOnly and len(self.stableTime) == 0: continue # Skip of no ATLAS ready if self.readyOnly and len(self.readyTime) == 0: continue # Open new output file filename = 'run%d_mu.root' % run rootfile = TFile(filename, 'recreate') # Precompute deadtime into dictionary if self.deadtime: self.findDeadtime() if self.readyOnly: htitle = 'readyMuDist' elif self.stableOnly: htitle = 'stableMuDist' else: htitle = 'allMuDist' hall = TH1D(htitle, htitle, self.nbins, self.mulo, self.muhi) delivered = 0. recorded = 0. average = 0. navg = 0 # Loop over lumi blocks and calibrate for obj in self.lumiReader.data: startTime = obj.since() endTime = obj.until() runlb = obj.payload()['RunLB'] run = runlb >> 32 lb = runlb & 0xFFFFFFFF valid = obj.payload()['Valid'] & 0x3FF dtime = (endTime-startTime)/1E9 if self.verbose: print 'Run %d LB %d ' % (run, lb), # Check whether this is in stable beams if self.stableOnly: isStable = False for stable in self.stableTime: if not stable[0] <= startTime < stable[1]: continue isStable = True break if not isStable: continue if self.verbose: print 'stable ', # Check whether this is in ATLAS ready if self.readyOnly: isReady = False for ready in self.readyTime: if not ready[0] <= runlb < ready[1]: continue isReady = True break if not isReady: if self.verbose: print continue if self.verbose: print 'ready', if run == 189610 and lb < 310: if self.verbose: print ' - skipped' continue # Global timing shift if run == 201494 and lb > 220 and lb < 241: if self.verbose: print ' - skipped' continue if self.verbose: print # Make sure lumi data is valid #if valid != 0: # print 'Invalid data %d found in Run %d LB %d!' % (valid, run, lb) # continue # These all change slowly, so checking them every run/lb is OK # Make sure calibration is valid if not self.updateCalibration(startTime): print 'Error finding calibration for Run %d LB %d!' % (run, lb) continue # 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 # 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 # 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, self.maskObj.coll, normValue) bcidavg = 0. nbcid = 0 h = TH1D(str(lb), '', self.nbins, self.mulo, self.muhi) for i in range(len(rawLumi)): # Check if this is in our bunch group bcid = bcidVec[i] # Off by one, check if *following* BCID is in bunch group # If so, this previous bcid is where the actual data is if run >= 189639 and run <= 189660 and bcid > 1: bcid += 1 if run == 191933 and bcid > 1: bcid += 1 if not bcid in self.bgObj.bg: continue ldel = self.caliObj.calibrate(rawLumi[i]) muval = ldel / self.caliObj.muToLumi lumi = ldel * dtime delivered += lumi if self.deadtime: lrec = ldel * self.liveFrac[runlb][bcid] lumi = lrec * dtime recorded += lumi bcidavg += self.liveFrac[runlb][bcid] nbcid += 1 # Note, mu only depends on delivered # Weighting of recorded data depends on recorded h.Fill(muval, lumi) hall.Fill(muval, lumi) if nbcid > 0: bcidavg /= nbcid average += bcidavg navg += 1 h.Write() # Close output file hall.Write() rootfile.Close() print 'Lumi Delivered:', delivered print 'Lumi Recorded:', recorded if delivered > 0.: print 'True live fraction:', recorded/delivered else: print 'True live fraction: 0.0' if navg > 0: print 'BCID average frac: ', average/navg else: print 'BCID average frac: 0.0' # 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) # Check if this run exists 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 ATLAS ready data self.loadReadyData(runnum) # Read the bunch group (so we sum over the right thing) self.loadBGData(runnum) # Read BCID Data self.loadBCIDMask(iov) self.loadBCIDCali(iov) self.loadBCIDLumi(iov) # Read turn counters (for livetime) if self.deadtime: self.loadTrigData(runnum) 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/COMP200', '/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) if len(self.lblbReader.data) > 1: print 'Last LB %d/%d' % (self.lblbReader.data[-1].since() >> 32, self.lblbReader.data[-1].since() & 0xFFFFFFFF) def loadTrigData(self, run): if self.verbose: print 'Loading Trigger data' # Instantiate new COOL data reader if not already done if self.trigReader == None: self.trigReader = CoolDataReader('COOLONL_TRIGGER/COMP200', '/TRIGGER/LUMI/PerBcidDeadtime') self.trigReader.setIOVRangeFromRun(run) self.trigReader.readData() if self.verbose: print 'Read %d Trig records' % len(self.trigReader.data) 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/COMP200', '/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/COMP200', '/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 loadBCIDCali(self, iov): if self.verbose: print 'Loading BCID luminosity calibrations' # Instantiate new COOL data reader if not already done if self.caliReader == None: self.caliReader = CoolDataReader('COOLONL_TDAQ/COMP200', '/TDAQ/OLC/CALIBRATIONS') self.caliReader.setIOVRange(iov[0], iov[1]) self.caliReader.setChannel([self.lumiChan]) self.caliReader.readData() if self.verbose: print 'Read %d Calibration records' % len(self.caliReader.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: # self.lumiReader = CoolDataReader('COOLONL_TDAQ/MONP200', '/TDAQ/OLC/BUNCHLUMIS') self.lumiReader = CoolDataReader('COOLONL_TDAQ/COMP200', '/TDAQ/OLC/BUNCHLUMIS') self.lumiReader.setIOVRange(iov[0], iov[1]) self.lumiReader.setChannel([self.lumiChan]) self.lumiReader.readData() if self.verbose: print 'Read %d Lumi records' % len(self.lumiReader.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/COMP200', '/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) # Information about ATLAS ready def loadReadyData(self, run): if self.verbose: print 'Loading ATLAS ready information' # Instantiate new COOL data reader if not already done if self.rdyReader == None: self.rdyReader = CoolDataReader('COOLONL_TDAQ/COMP200', '/TDAQ/RunCtrl/DataTakingMode') self.rdyReader.setIOVRangeFromRun(run) self.rdyReader.readData() if self.verbose: print 'Read %d ATLAS ready records' % len(self.rdyReader.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 # Fill the stable beam information in the OflLumiRunData object def findReady(self): if self.verbose: print 'Finding ATLAS ready beam periods' # First, fill stable beam time periods for this run tlo = cool.ValidityKeyMax thi = cool.ValidityKeyMin self.readyTime = [] for obj in self.rdyReader.data: if obj.payload()['ReadyForPhysics'] == 0: continue if tlo > thi: # First ready tlo = obj.since() thi = obj.until() elif thi == obj.since(): # Extension of existing ready thi = obj.until() else: # Not contiguous, add old to list and start again self.readyTime.append((tlo, thi)) tlo = obj.since() thi = obj.until() if tlo < thi: self.readyTime.append((tlo, thi)) if self.verbose: print 'ATLAS ready periods found:', self.readyTime # Precompute the deadtime for this run into a dictionary indexed by lumi block and BCID def findDeadtime(self): if self.verbose: print 'Calculating per-BCID deadtime' # First dictionary index is lumiblock IOV self.liveFrac = dict() # Loop over each lumi block for obj in self.trigReader.data: key = obj.since() run = key >> 32 lb = key & 0xFFFFFFFF bloblength = obj.payload()['HighPriority'].size() if self.verbose: print '%d %d Found trigger counter blob of length %d' % (run, lb, bloblength) # Unpack High Priority blob here liveVec = unpackLiveFraction(obj.payload()) self.liveFrac[key] = liveVec # Each BCID is one 24-bit integer if self.verbose: for i in range(10): print 'BICD: %d Live: %f' % (i+1, liveVec[i]) 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 updateCalibration(self, startTime): if not self.caliObj.isValid(startTime): self.caliObj.clearValidity() # Find the proper calibration object for cali in self.caliReader.data: if not cali.since() <= startTime < cali.until(): continue self.caliObj.setCalibration(cali) break if not self.caliObj.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") (options, args) = parser.parse_args() if options.help: parser.print_help() sys.exit() self.verbose = options.verbose # 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
class LumiDeadtimeHandler: # Constructor def __init__(self): self.verbose = False # Data readers self.vetoReader = None self.menuReader = None self.countsReader = None # Trigger channels to read for live fractions self.trigList = ['L1_EM30'] # Storage of per-BCID deadtime (index by [runlb][bcid]) self.liveFracBCID = dict() # Storage of L1 trigger counts deadtime (index by [runlb][trigname]) self.liveFracTrig = dict() # Storage for L1 trigger name -> value mapping self.trigChan = dict() def calculateAll(self, run): self.loadData(run) self.findBCIDDeadtime() def loadData(self, run): self.loadVetoData(run) self.loadTrigChannels(run) self.loadTrigCounts(run) def loadVetoData(self, run): if self.verbose: print('Loading trigger veto data') # Instantiate new COOL data reader if not already done if self.vetoReader is None: self.vetoReader = CoolDataReader('COOLONL_TRIGGER/COMP200', '/TRIGGER/LUMI/PerBcidDeadtime') self.vetoReader.setIOVRangeFromRun(run) self.vetoReader.readData() if self.verbose: print('Read %d Trig veto records' % len(self.vetoReader.data)) # Read trigger channel mappings # Fills self.trigChan based on values in self.trigList def loadTrigChannels(self, run): if self.verbose: print('Loading trigger channel data') self.trigChan = dict() for trig in self.trigList: self.trigChan[trig] = -1 if self.menuReader is None: self.menuReader = CoolDataReader('COOLONL_TRIGGER/COMP200', '/TRIGGER/LVL1/Menu') self.menuReader.setIOVRangeFromRun(run) self.menuReader.readData() for obj in self.menuReader.data: trigName = obj.payload()['ItemName'] if trigName in self.trigList: self.trigChan[trigName] = int(obj.channelId()) for trig in self.trigList: if self.trigChan[trig] == -1: print("Couldn't find", trig, "in run", run) if self.verbose: print('Found', trig, 'in channel', self.trigChan[trig]) # Load all trigger counts for the given run # Fills counts for all triggers with channels found in self.trigChan def loadTrigCounts(self, run): if self.verbose: print('loading Trigger Counts data') self.liveFracTrig = dict() if self.countsReader is None: self.countsReader = CoolDataReader('COOLONL_TRIGGER/COMP200', '/TRIGGER/LUMI/LVL1COUNTERS') self.countsReader.setIOVRangeFromRun(run) # Build channel list chanList = self.trigChan.values() chanList.sort() # Skip any trigger we didn't find tmpList = [] for chan in chanList: if chan < 0: continue tmpList.append(chan) chanList = tmpList self.countsReader.setChannel(chanList) self.countsReader.readData() for obj in self.countsReader.data: #if self.verbose: # print obj.since()>>32, '/', obj.since()&0xFFFFFFFF, obj.channelId(), obj.payload()['BeforePrescale'], obj.payload()['AfterPrescale'], obj.payload()['L1Accept'] # use the string as the dictionary key ss = obj.since() if ss not in self.liveFracTrig: self.liveFracTrig[ss] = dict() for (trig, chan) in self.trigChan.iteritems(): if chan != obj.channelId(): continue ratio = 0. if obj.payload()['AfterPrescale'] > 0: ratio = float(obj.payload()['L1Accept']) / obj.payload( )['AfterPrescale'] self.liveFracTrig[ss][trig] = ratio if self.verbose: print(obj.since() >> 32, '/', obj.since() & 0xFFFFFFFF, trig, ratio) def findBCIDDeadtime(self): if self.verbose: print('Calculating per-BCID deadtime') # First dictionary index is lumiblock IOV self.liveFracBCID = dict() # Loop over each lumi block for obj in self.vetoReader.data: key = obj.since() if self.verbose: run = key >> 32 lb = key & 0xFFFFFFFF bloblength = obj.payload()['HighPriority'].size() print('%d %d Found trigger counter blob of length %d' % (run, lb, bloblength)) # Unpack High Priority blob here liveVec = unpackLiveFraction(obj.payload()) self.liveFracBCID[key] = liveVec
class TriggerHandler: def __init__(self): # Database parameters self.menuReader = CoolDataReader('COOLONL_TRIGGER/COMP200', '/TRIGGER/LVL1/Menu') self.countsReader = CoolDataReader('COOLONL_TRIGGER/COMP200', '/TRIGGER/LUMI/LVL1COUNTERS') self.lbtimeReader = CoolDataReader('COOLONL_TRIGGER/COMP200', '/TRIGGER/LUMI/LBTIME') self.lblbReader = CoolDataReader('COOLONL_TRIGGER/COMP200', '/TRIGGER/LUMI/LBLB') self.verbose = False #self.verbose = True # Dict of all TrigL1Data objects for the given time interval (keyed by RunLB IOV) self.trigL1Dict = dict() self.allL1Triggers = False # List of all trigger items to read self.trigList = ['L1_MBTS_2', 'L1_EM30'] # Dictionary of trigger channel number keyed by trigger name self.trigChan = dict() self.chanTrig = dict() # reverse order # Store the lumi block times self.lblbDict = dict() # Clear all data def clear(self): # Clear trigger dict self.trigL1Dict.clear() # Find trigger information in iovrange by time def loadData(self, startIOV, endIOV): self.clear() # Runlist holds specific runs in this time range self.runlist = [] if self.verbose: print 'Searching for trigger information for max IOVRange', timeString( startIOV), timeString(endIOV) # Load the run based information as we fundamentally need to do this by run number # Prepare the lbtime reader self.lbtimeReader.setIOVRange(startIOV, endIOV) self.lbtimeReader.readData() for obj in self.lbtimeReader.data: runnum = int(obj.payload()['Run']) if not runnum in self.runlist: self.runlist.append(runnum) # Loop over each run, getting the trigger counts/Lumi # Must do this by run, as trigger menu can change # Here we are storing this in a separate list for runnum in self.runlist: self.loadDataByRun(runnum, clear=False) # Find trigger information by run def loadDataByRun(self, runnum, clear=True): if self.verbose: print 'TriggerHandler.loadDataByRun(%d) called' % runnum if clear: self.clear() # Figure out the channel mappings for the L1 trigger items self.loadTrigChannels(runnum) # Get the LB durations self.loadLBLBData(runnum) # Third, get the trigger counts self.loadTrigCounts(runnum) # Read LBLB data def loadLBLBData(self, runnum): if self.verbose: print 'TriggerHandler.loadLBLBData(%d) called' % runnum self.lblbDict.clear() self.lblbReader.setIOVRangeFromRun(runnum) self.lblbReader.readData() for obj in self.lblbReader.data: self.lblbDict[obj.since()] = (obj.payload()['StartTime'], obj.payload()['EndTime']) # Read trigger channel mappings # Fills self.trigChan based on values in self.trigList def loadTrigChannels(self, runnum): if self.verbose: print 'TriggerHandler.loadTrigChannels(%d) called' % runnum # Trigger channels keyed by name self.trigChan = dict() # Trigger name keyed by channel self.chanTrig = dict() for trig in self.trigList: self.trigChan[trig] = -1 self.menuReader.setIOVRangeFromRun(runnum) self.menuReader.readData() for obj in self.menuReader.data: if self.verbose or True: print int(obj.channelId()), obj.payload()['ItemName'] trigName = obj.payload()['ItemName'] trigChan = int(obj.channelId()) if self.allL1Triggers or self.trigList.count(trigName) > 0: self.trigChan[trigName] = trigChan self.chanTrig[trigChan] = trigName for trig in self.trigList: if self.trigChan[trig] == -1: print "Couldn't find", trig, "in run", str(runnum) if self.verbose: for (trig, chan) in self.trigChan.iteritems(): print 'Found', trig, 'in channel', chan # Load all trigger counts for the given run # Fills counts for all triggers with channels found in self.trigChan def loadTrigCounts(self, runnum): if self.verbose: print 'TriggerHandler.loadTrigCounts(%d) called' % runnum self.countsReader.setIOVRangeFromRun(runnum) # Build channel list chanList = self.trigChan.values() chanList.sort() nMaxChan = 50 nChanBlock = 0 chanBlock = [] nChannels = 0 # Skip any trigger we didn't find tmpList = [] for chan in chanList: if chan < 0: continue tmpList.append(chan) chanList = tmpList if self.verbose: print 'breaking up', len( chanList), 'into', nMaxChan, 'for run', runnum # There is a 50 item limit somehow hardcoded into browseObjects. # Use this code from Elliot to get around the limitation. # Break up list of indices into blocks: for x in range(0, len(chanList), nMaxChan): top = min([x + nMaxChan, len(chanList)]) if self.verbose: print 'Initializing block [%d] from %d to %d' % (nChanBlock, x, top) chanBlock.append(chanList[x:top]) nChanBlock += 1 for x in range(nChanBlock): if self.verbose: print 'Channel Selector', chanBlock[x] self.countsReader.setChannel(chanBlock[x]) self.countsReader.readData() for obj in self.countsReader.data: since = obj.since() until = obj.until() if self.verbose: print runLBString(since), runLBString( until), obj.channelId(), obj.payload( )['BeforePrescale'], obj.payload( )['AfterPrescale'], obj.payload()['L1Accept'] # use the string as the dictionary key ss = since chan = int(obj.channelId()) trig = self.chanTrig.get(chan, "") if len(trig) == 0: print 'TriggerHandler.loadTrigCounts(%d) - found unknown channel %d in %s!' % ( runnum, chan, runLBString(ss)) continue if ss not in self.trigL1Dict: self.trigL1Dict[ss] = TriggerL1Data() self.trigL1Dict[ss].runlb = obj.since() self.trigL1Dict[ss].startTime = self.lblbDict.get( ss, (0., 0.))[0] self.trigL1Dict[ss].endTime = self.lblbDict.get( ss, (0., 0.))[1] self.trigL1Dict[ss].dtime = ( self.trigL1Dict[ss].endTime - self.trigL1Dict[ss].startTime) / 1.E9 self.trigL1Dict[ss].TBP[trig] = obj.payload()['BeforePrescale'] self.trigL1Dict[ss].TAP[trig] = obj.payload()['AfterPrescale'] self.trigL1Dict[ss].TAV[trig] = obj.payload()['L1Accept']
class CompareLumi: def __init__(self): # Control output level self.verbose = False # Channels for comparision self.lumi1Channel = 0 self.lumi2Channel = 261 self.lumi1Tag = 'OflLumi-7TeV-002' self.lumi2Tag = 'OflLumi-7TeV-003' # Difference (in percent) to complain about self.threshold = 5. # Stable only self.stableOnly = True # List of IOVRanges with stable beams self.stableTime = [] # ATLAS Ready only self.readyOnly = True #Dict of (runlblo, runlblbhi) pairs giving extent of ATLAS ready self.readyTime = [] # List of (integer) run numbers specified on the command line self.runList = [] # Utlity routine for handling COOL connections self.dbHandler = LumiDBHandler() # Data readers self.lumi1Reader = None self.lumi2Reader = None self.lblbReader = None self.lhcReader = None self.rdyReader = 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() lumi1Sum = dict() lumi2Sum = dict() # Process each run in self.runList for run in self.runList: # Load all data from COOL self.loadCOOLData(run) # Skip if run doesn't exist if len(self.lblbReader.data) == 0: continue # Find stable beams, output goes to self.stableTime self.findStable() # Find ATLAS ready, result goes to self.readyTime self.findReady() if self.stableOnly and len(self.stableTime) == 0: continue if self.readyOnly and len(self.readyTime) == 0: continue # Storage objects keyed by [lb] lumi1Dict = dict() lumi2Dict = dict() lumi1Sum[run] = 0. lumi2Sum[run] = 0. # Keep track of LB range lbLo = 99999 lbHi = 0 # Loop over all objects and sort by runlb and algo for obj in self.lumi1Reader.data: runlb = obj.since() lumi1Dict[runlb] = obj.payload() for obj in self.lumi2Reader.data: runlb = obj.since() lumi2Dict[runlb] = obj.payload() # if self.verbose: # run = runlb >> 32 # lb = runlb & 0xFFFFFFFF # print 'Found Run %d LB %d chan %d' % (run, lb, channel) # Loop over defined data for obj in self.lblbReader.data: runlb = obj.since() run = runlb >> 32 lb = runlb & 0xFFFFFFFF startTime = obj.payload()['StartTime'] endTime = obj.payload()['EndTime'] dtime = (endTime - startTime) / 1E9 # 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 # Check whether this in in ATLAS ready isReady = False for ready in self.readyTime: if not ready[0] <= runlb < ready[1]: continue isReady = True break #if self.verbose: # print 'Found stable Run %d LB %d' % (run, lb) if lb < lbLo: lbLo = lb if lb > lbHi: lbHi = lb # Check if lumi record exists missing1 = False missing2 = False if runlb not in lumi1Dict: missing1 = True if runlb not in lumi2Dict: missing2 = True if missing1 and missing2: if isStable: print 'Run: %d LB: %4d does not have any luminosity record in stable beams!' % ( run, lb) else: print 'Run: %d LB: %4d does not have any luminosity record!' % ( run, lb) continue elif missing1: if isStable: print 'Run: %d LB: %4d does not have first lumi record in stable beams!' % ( run, lb) else: print 'Run: %d LB: %4d does not have first lumi record!' % ( run, lb) elif missing2: if isStable: print 'Run: %d LB: %4d does not have second lumi record in stable beams!' % ( run, lb) else: print 'Run: %d LB: %4d does not have second lumi record!' % ( run, lb) # Get lumi lumi1 = 0. valid1 = 999 chan1 = self.lumi1Channel lumi2 = 0. valid2 = 999 chan2 = self.lumi2Channel if not missing1: lumi1 = lumi1Dict[runlb]['LBAvInstLumi'] valid1 = lumi1Dict[runlb]['Valid'] & 0x3FF if chan1 == 0: chan1 = lumi1Dict[runlb]['Valid'] >> 22 lumi1Sum[run] += (lumi1 * dtime) / 1.E6 if not missing2: lumi2 = lumi2Dict[runlb]['LBAvInstLumi'] valid2 = lumi2Dict[runlb]['Valid'] & 0x3FF if chan2 == 0: chan2 = lumi2Dict[runlb]['Valid'] >> 22 lumi2Sum[run] += (lumi2 * dtime) / 1.E6 try: ratio = 100 * (lumi2 / lumi1 - 1.) except ZeroDivisionError: ratio = -99. if self.verbose: print 'Run: %6d LB: %4d Lumi1: %6.1f Chan1: %d Valid1: %d Lumi2: %6.1f Chan2: %d Valid2: %d Ratio: %.3f%%' % ( run, lb, lumi1, chan1, valid1, lumi2, chan2, valid2, ratio) # Compare if (abs(ratio) > self.threshold and (lumi1 > 1. or lumi2 > 1.)): # or valid1 != 0 or valid2 != 0: print '>>> Run: %6d LB: %4d dTime: %f Lumi1: %6.1f Chan1: %d Valid1: %d Lumi2: %6.1f Chan2: %d Valid2: %d Ratio: %.3f%%' % ( run, lb, dtime, lumi1, chan1, valid1, lumi2, chan2, valid2, ratio) # End of loop over LBs try: ratio = 100 * (lumi2Sum[run] / lumi1Sum[run] - 1.) except ZeroDivisionError: ratio = -99. print 'Run: %6d LBLo: %4d LBHi: %4d IntLumi1: %8.3f IntLumi2: %8.3f Ratio: %.3f%%' % ( run, lbLo, lbHi, lumi1Sum[run], lumi2Sum[run], ratio) # End of loop over runs totalLumi1 = 0. totalLumi2 = 0. for lumi in lumi1Sum.itervalues(): totalLumi1 += lumi for lumi in lumi2Sum.itervalues(): totalLumi2 += lumi try: ratio = 100 * (totalLumi2 / totalLumi1 - 1.) except ZeroDivisionError: ratio = -99. print 'Total Luminosity1: %8.3f Luminosity2: %8.3f => 2/1 = %.3f%%' % ( totalLumi1, totalLumi2, ratio) # Load all data necessary to make bunch-by-bunch lumi for a single run def loadCOOLData(self, runnum): if self.verbose: print 'LumiChecker.loadCOOLData(%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 Ready Data self.loadReadyData(runnum) # Read the luminosity self.loadLumi(runnum) 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/COMP200', '/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 loadLumi(self, runnum): if self.verbose: print 'Loading luminosity values' # Instantiate new COOL data reader if not already done if self.lumi1Reader == None: self.lumi1Reader = CoolDataReader('COOLOFL_TRIGGER/COMP200', '/TRIGGER/OFLLUMI/LBLESTOFL') self.lumi1Reader.setIOVRangeFromRun(runnum) self.lumi1Reader.setChannel([self.lumi1Channel]) self.lumi1Reader.setTag(self.lumi1Tag) self.lumi1Reader.readData() if self.verbose: print 'Read %d Lumi records' % len(self.lumi1Reader.data) # Instantiate new COOL data reader if not already done if self.lumi2Reader == None: self.lumi2Reader = CoolDataReader('COOLOFL_TRIGGER/COMP200', '/TRIGGER/OFLLUMI/LBLESTOFL') self.lumi2Reader.setIOVRangeFromRun(runnum) self.lumi2Reader.setChannel([self.lumi2Channel]) self.lumi2Reader.setTag(self.lumi2Tag) self.lumi2Reader.readData() if self.verbose: print 'Read %d Lumi records' % len(self.lumi2Reader.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/COMP200', '/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) # Information about ATLAS ready def loadReadyData(self, run): if self.verbose: print 'Loading ATLAS ready information' # Instantiate new COOL data reader if not already done if self.rdyReader == None: self.rdyReader = CoolDataReader('COOLONL_TDAQ/COMP200', '/TDAQ/RunCtrl/DataTakingMode') self.rdyReader.setIOVRangeFromRun(run) self.rdyReader.readData() if self.verbose: print 'Read %d ATLAS ready records' % len(self.rdyReader.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 # Fill the stable beam information in the OflLumiRunData object def findReady(self): if self.verbose: print 'Finding ATLAS ready beam periods' # First, fill stable beam time periods for this run tlo = cool.ValidityKeyMax thi = cool.ValidityKeyMin self.readyTime = [] for obj in self.rdyReader.data: if obj.payload()['ReadyForPhysics'] == 0: continue if tlo > thi: # First ready tlo = obj.since() thi = obj.until() elif thi == obj.since(): # Extension of existing ready thi = obj.until() else: # Not contiguous, add old to list and start again self.readyTime.append((tlo, thi)) tlo = obj.since() thi = obj.until() if tlo < thi: self.readyTime.append((tlo, thi)) if self.verbose: print 'ATLAS ready periods found:', self.readyTime 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("--tag1", dest="lumi1tag", metavar="TAG", default=self.lumi1Tag, help='first luminosity tag (default: %s)' % self.lumi1Tag) parser.add_option("--chan1", dest="lumi1chan", metavar="CHAN", default=self.lumi1Channel, help='first luminosity channel (default: %d)' % self.lumi1Channel) parser.add_option("--tag2", dest="lumi2tag", metavar="TAG", default=self.lumi2Tag, help='first luminosity tag (default: %s)' % self.lumi2Tag) parser.add_option("--chan2", dest="lumi2chan", metavar="CHAN", default=self.lumi2Channel, help='second luminosity channel (default: %d)' % self.lumi2Channel) parser.add_option( "--noStable", action="store_false", default=self.stableOnly, dest="stable", help="turn off stable beams requirement (default: stable only)") parser.add_option( "--noReady", action="store_false", default=self.readyOnly, dest="ready", help="turn off ATLAS ready requirement (default: ready only)") (options, args) = parser.parse_args() if options.help: parser.print_help() sys.exit() self.verbose = options.verbose self.lumi1Tag = options.lumi1tag self.lumi2Tag = options.lumi2tag self.stableOnly = options.stable self.readyOnly = options.ready self.lumi1Channel = int(options.lumi1chan) self.lumi2Channel = int(options.lumi2chan) # 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
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()
bunchDescriptionReader.setIOVRangeFromRun(215589) bunchDescriptionReader.readData() bgd = BunchDescription() for obj in bunchDescriptionReader.data: print obj # bgd.setValue(obj.payload()) # print bgd.nBunchD1() ##### BunchDataUtil ########################################################################## print "--------------------Testing BunchDataUtil----------------" from ROOT import BunchDataUtil bunchDataUtilReader = CoolDataReader("COOLONL_TDAQ/COMP200", "/TDAQ/OLC/LHC/BUNCHDATA") bunchDataUtilReader.setIOVRange(iovSince, iovUntil) bunchDataUtilReader.setChannel([0]) bunchDataUtilReader.readData() count = 0 bdu = BunchDataUtil() for obj in bunchDataUtilReader.data: runlb = obj.payload()['RunLB'] run = runlb >> 32 lb = runlb & 0xFFFF # print "lb ", lb count += 1 x1 = bdu.nx1Storage(obj.payload()) y1 = bdu.ny1Storage(obj.payload()) x2 = bdu.nx2Storage(obj.payload()) y2 = bdu.ny2Storage(obj.payload()) if (y1 == 0):
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