diff --git a/Database/CoolLumiUtilities/CMakeLists.txt b/Database/CoolLumiUtilities/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..3b0812060f62d738d13d242bef755ff466afd155 --- /dev/null +++ b/Database/CoolLumiUtilities/CMakeLists.txt @@ -0,0 +1,45 @@ +################################################################################ +# Package: CoolLumiUtilities +################################################################################ + +# Declare the package name: +atlas_subdir( CoolLumiUtilities ) + +# Declare the package's dependencies: +atlas_depends_on_subdirs( PUBLIC + Control/AthenaBaseComps + Control/AthenaKernel + Control/StoreGate + GaudiKernel + PRIVATE + Database/AthenaPOOL/AthenaPoolUtilities ) + +# External dependencies: +find_package( COOL COMPONENTS CoolKernel ) +find_package( CORAL COMPONENTS CoralBase CoralKernel RelationalAccess ) +find_package( ROOT COMPONENTS Core Tree MathCore Hist RIO pthread ) + +# Component(s) in the package: +atlas_add_library( CoolLumiUtilitiesLib + src/*.cxx + PUBLIC_HEADERS CoolLumiUtilities + INCLUDE_DIRS ${COOL_INCLUDE_DIRS} ${CORAL_INCLUDE_DIRS} + PRIVATE_INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${COOL_LIBRARIES} ${CORAL_LIBRARIES} AthenaBaseComps AthenaKernel GaudiKernel StoreGateLib SGtests + PRIVATE_LINK_LIBRARIES ${ROOT_LIBRARIES} AthenaPoolUtilities ) + +atlas_add_component( CoolLumiUtilities + src/components/*.cxx + INCLUDE_DIRS ${COOL_INCLUDE_DIRS} ${CORAL_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${COOL_LIBRARIES} ${CORAL_LIBRARIES} ${ROOT_LIBRARIES} AthenaBaseComps AthenaKernel StoreGateLib SGtests GaudiKernel AthenaPoolUtilities CoolLumiUtilitiesLib ) + +atlas_add_dictionary( CoolLumiUtilitiesDict + CoolLumiUtilities/CoolLumiUtilitiesDict.h + CoolLumiUtilities/selection.xml + INCLUDE_DIRS ${COOL_INCLUDE_DIRS} ${CORAL_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${COOL_LIBRARIES} ${CORAL_LIBRARIES} ${ROOT_LIBRARIES} AthenaBaseComps AthenaKernel StoreGateLib SGtests GaudiKernel AthenaPoolUtilities CoolLumiUtilitiesLib ) + +# Install files from the package: +atlas_install_python_modules( python/*.py ) +atlas_install_scripts( share/*.py ) + diff --git a/Database/CoolLumiUtilities/python/CoolDataReader.py b/Database/CoolLumiUtilities/python/CoolDataReader.py index e9ad5c0f8771b26560424499cfe4dccd2d33af9c..969b30c752eec8462dab62dd7f9488f487f79d83 100644 --- a/Database/CoolLumiUtilities/python/CoolDataReader.py +++ b/Database/CoolLumiUtilities/python/CoolDataReader.py @@ -100,24 +100,46 @@ class CoolDataReader: # Create the channel list if len(self.channelIdList) == 0: channels = cool.ChannelSelection.all() - + self.readChannelList(channels) + else: # Build the channel list here self.channelIdList.sort() # Must be sorted! - channels = None - firstChan = True - - for channelId in self.channelIdList: - if firstChan: - firstChan = False - channels = cool.ChannelSelection(channelId) - else: - channels.addChannel(channelId) - - if self.verbose: - print 'CoolDataReader.readData() - browsing', self.iovstart, self.iovend, 'with channel', channels, 'and tag', self.tag + # Must read channels 50 at a time due to COOL limit... + ichan = 0 + while (ichan < len(self.channelIdList)) : + + jchan = 0 + channels = None + firstChan = True + for channelId in self.channelIdList[ichan:]: + jchan += 1 + if firstChan: + firstChan = False + channels = cool.ChannelSelection(channelId) + else: + channels.addChannel(channelId) + if jchan == 50: break + + # Remeber how many we have read for next time + if self.verbose: + print 'CoolDataReader.readData() - loaded %d channels from %d' % (jchan, ichan) + ichan += jchan + + if self.verbose: + print 'CoolDataReader.readData() - browsing', self.iovstart, self.iovend, 'with channel', channels, 'and tag', self.tag + + self.readChannelList(channels) + + # End of loop building channel list and reading + + # End of if statement reading data + return self.data + + def readChannelList(self, channels): + # Open iterator over our defined IOV range try: itr = self.folder.browseObjects(self.iovstart, self.iovend, channels, self.tag) @@ -146,10 +168,10 @@ class CoolDataReader: while itr.goToNext(): obj = itr.currentRef() + # print obj.payload() self.data.append(obj.clone()) itr.close() - return self.data diff --git a/Database/CoolLumiUtilities/python/LumiBlobConversion.py b/Database/CoolLumiUtilities/python/LumiBlobConversion.py index abcd1cb535eedb5fb6de6e47a88515c03eec4eef..b182eb89a8014c196a0eac57ad85e08b7b55f4ee 100644 --- a/Database/CoolLumiUtilities/python/LumiBlobConversion.py +++ b/Database/CoolLumiUtilities/python/LumiBlobConversion.py @@ -100,8 +100,44 @@ def unpackBunchGroupList(blob, bgrp=[1]): return physBG -# routine to unpack the BCID mask stored in COOL +# Generic routine to unpack BCID mask def unpackBCIDMask(blob,nb1,nb2,nlumi): + + bloblength = blob.size() + + if bloblength == 3564: + return unpackRun2BCIDMask(blob,nb1,nb2,nlumi) + else: + return unpackRun1BCIDMask(blob,nb1,nb2,nlumi) + +# routine to unpack the BCID mask stored in COOL +# This is the run2 version +def unpackRun2BCIDMask(blob,nb1,nb2,nlumi): + beam1=[] + beam2=[] + coll=[] + blobCopy = blob.read() + rawData = bConvertList(blobCopy, 1, 3564) + + for i in range(3564): + val = rawData[i] + if val & 0x01: + beam1.append(i) + if val & 0x02: + beam2.append(i) + if (val & 0x03) == 0x03: + coll.append(i) + + print 'unpackRun2BCIDMask found:' + print ' Beam1:', beam1 + print ' Beam2:', beam2 + print ' Coll: ', coll + + return beam1,beam2,coll + +# routine to unpack the BCID mask stored in COOL +# This is the run1 version +def unpackRun1BCIDMask(blob,nb1,nb2,nlumi): beam1=[] beam2=[] coll=[] @@ -145,7 +181,7 @@ def unpackBCIDMask(blob,nb1,nb2,nlumi): # Note, the normValue is only used in certain storage modes. If you want to renormalize, do this yourself. # Specifying a different value for the normValue will likely cause unpredictable results. -def unpackBCIDValues(blob, mask, normValue=1): +def unpackBCIDValues(blob, mask=[], normValue=1): bss, bcidVec, lvec = unpackBunches(blob, mask) @@ -169,7 +205,7 @@ def unpackBCIDValues(blob, mask, normValue=1): else: return [],[] -def unpackBunches(blob,mask): +def unpackBunches(blob,mask=[]): # routine to unpack Intensity/Luminosity info stored in COOL # the mask given as input has to match the quantity to be # unpacked (beam1, beam2, beamsand for B1, B2 intensities and diff --git a/Database/CoolLumiUtilities/python/LumiChannelDefs.py b/Database/CoolLumiUtilities/python/LumiChannelDefs.py index 54f48ca8b79baaab71f0dc338bc782a97cd0e8ff..9e5ac9dccaf76454fcc0746871af17cdbf182ad9 100644 --- a/Database/CoolLumiUtilities/python/LumiChannelDefs.py +++ b/Database/CoolLumiUtilities/python/LumiChannelDefs.py @@ -12,121 +12,76 @@ class LumiChannelDefs: names[5] = 'CMS Lumi' names[17] = 'ATLAS Preferred BGRP7' - names[101] = 'Onl Lucid Evt AND' - names[102] = 'Onl Lucid Evt OR' - names[103] = 'Onl Lucid Hit OR' - names[104] = 'Onl Lucid Hit AND' - names[105] = 'Onl Lucid Evt A' - names[106] = 'Onl Lucid Evt C' + names[101] = 'Lucid Evt AND' + names[102] = 'Lucid Evt OR' + names[103] = 'Lucid Hit OR' + names[104] = 'Lucid Hit AND' + names[105] = 'Lucid Evt A' + names[106] = 'Lucid Evt C' - names[111] = 'Onl LucidFib Evt AND' - names[112] = 'Onl LucidFib Evt OR' - names[113] = 'Onl LucidFib Hit OR' - names[114] = 'Onl LucidFib Hit AND' - names[115] = 'Onl LucidFib Evt A' - names[116] = 'Onl LucidFib Evt C' - - # Offline versions of online numbers - names[151] = 'Lucid Evt AND' - names[152] = 'Lucid Evt OR' - names[153] = 'Lucid Hit OR' - names[154] = 'Lucid Hit AND' - names[155] = 'Lucid Evt A' - names[156] = 'Lucid Evt C' - - names[161] = 'LucidFib Evt AND' - names[162] = 'LucidFib Evt OR' - names[163] = 'LucidFib Hit OR' - names[164] = 'LucidFib Hit AND' - names[165] = 'LucidFib Evt A' - names[166] = 'LucidFib Evt C' - - names[201] = 'Onl BCMH Evt OR' - names[202] = 'Onl BCMH Evt AND' - names[203] = 'Onl BCMH XORA' - names[204] = 'Onl BCMH XORC' - names[205] = 'Onl BCMH ORA' - names[206] = 'Onl BCMH ORC' - names[207] = 'Onl BCMH AND25' + names[111] = 'LucidBis Evt AND' + names[112] = 'LucidBis Evt OR' + names[113] = 'LucidBis Hit OR' + names[114] = 'LucidBis Hit AND' + names[115] = 'LucidBis Evt A' + names[116] = 'LucidBis Evt C' - names[211] = 'Onl BCMV Evt OR' - names[212] = 'Onl BCMV Evt AND' - names[213] = 'Onl BCMV XORA' - names[214] = 'Onl BCMV XORC' - names[216] = 'Onl BCMV ORC' - names[217] = 'Onl BCMV AND25' + names[121] = 'LucidMod Evt AND' + names[122] = 'LucidMod Evt OR' + names[123] = 'LucidMod Hit OR' + names[124] = 'LucidMod Hit AND' + names[125] = 'LucidMod Evt A' + names[126] = 'LucidMod Evt C' - names[221] = 'Onl BCMT Evt OR' - names[222] = 'Onl BCMT Evt AND' - names[226] = 'Onl BCMT ORC' - - names[251] = 'BCMH Evt OR' - names[252] = 'BCMH Evt AND' - names[253] = 'BCMH XORC' - names[254] = 'BCMH XORA' - names[255] = 'BCMH ORA' - names[256] = 'BCMH ORC' - names[257] = 'BCMH AND25' - - names[261] = 'BCMV Evt OR' - names[262] = 'BCMV Evt AND' - names[263] = 'BCMV XORC' - names[264] = 'BCMV XORA' - names[266] = 'BCMV ORC' - names[267] = 'BCMV AND25' - - names[271] = 'BCMT Evt OR' - names[272] = 'BCMT Evt AND' - names[276] = 'BCMT ORC' - - names[301] = 'Onl MBTS Evt OR' - names[302] = 'Onl MBTS Evt AND' - names[303] = 'Onl MBTS Hit OR' - - names[351] = 'MBTS Evt OR' - names[352] = 'MBTS Evt AND' - names[353] = 'MBTS Hit OR' - - names[401] = 'Onl ZDC Evt AND' - names[402] = 'Onl ZDC Evt ORA' - names[403] = 'Onl ZDC Evt ORC' + names[131] = 'LucidBis A1' + names[132] = 'LucidBis A5' + names[133] = 'LucidBis A9' + names[134] = 'LucidBis A13' + names[135] = 'LucidBis C1' + names[136] = 'LucidBis C5' + names[137] = 'LucidBis C9' + names[138] = 'LucidBis C13' + + # Lucid Charge algorithms + names[151] = 'Lucid Charge A' + names[152] = 'Lucid Charge C' + names[153] = 'LucidBis Charge A' + names[154] = 'LucidBis Charge C' + names[155] = 'LucidFib Charge A' + names[156] = 'LucidFib Charge C' - names[411] = 'Onl ZDCL Evt AND' - names[412] = 'Onl ZDCL Evt OR' - names[413] = 'Onl ZDCL Evt ORA' - names[414] = 'Onl ZDCL Evt ORC' - - names[451] = 'ZDC Evt AND' - names[452] = 'ZDC Evt ORA' - names[453] = 'ZDC Evt ORC' + # BCM + names[201] = 'BCMH Evt OR' + names[202] = 'BCMH Evt AND' + names[205] = 'BCMH ORA' + names[206] = 'BCMH ORC' - names[461] = 'ZDCL Evt AND' - names[462] = 'ZDCL Evt OR' - names[463] = 'ZDCL Evt ORA' - names[464] = 'ZDCL Evt ORC' + names[211] = 'BCMV Evt OR' + names[212] = 'BCMV Evt AND' + names[215] = 'BCMV ORA' + names[216] = 'BCMV ORC' - names[501] = 'FCAL_A' - names[502] = 'FCAL_C' + names[221] = 'BCMT Evt OR' + names[222] = 'BCMT Evt AND' + names[225] = 'BCMT ORA' + names[226] = 'BCMT ORC' - names[521] = 'RPC' - - names[902] = 'Vtx Count' + names[231] = 'BCMH Early Evt OR' + names[235] = 'BCMH Early Evt A' + names[236] = 'BCMH Early Evt C' - names[1001] = 'Onl BCM11H Evt OR' - names[1002] = 'Onl BCM11H Evt AND' - names[1004] = 'Onl BCM11H Evt XORC' - - names[1011] = 'Onl BCM11V Evt OR' - names[1012] = 'Onl BCM11V Evt AND' - names[1014] = 'Onl BCM11V Evt XORC' - - names[1051] = 'BCM11H Evt OR' - names[1052] = 'BCM11H Evt AND' - names[1054] = 'BCM11H Evt XORC' + names[241] = 'BCMV Early Evt OR' + names[245] = 'BCMV Early Evt A' + names[246] = 'BCMV Early Evt C' + + # MBTS + names[301] = 'MBTS Evt OR' + names[302] = 'MBTS Evt AND' + names[303] = 'MBTS2' - names[1061] = 'BCM11V Evt OR' - names[1062] = 'BCM11V Evt AND' - names[1064] = 'BCM11V Evt XORC' + names[501] = 'FCAL_A' + names[502] = 'FCAL_C' + # Sorted list of valid channel numbers numbers = sorted(names.keys()) diff --git a/Database/CoolLumiUtilities/python/LumiChannelDefsRun1.py b/Database/CoolLumiUtilities/python/LumiChannelDefsRun1.py new file mode 100644 index 0000000000000000000000000000000000000000..54f48ca8b79baaab71f0dc338bc782a97cd0e8ff --- /dev/null +++ b/Database/CoolLumiUtilities/python/LumiChannelDefsRun1.py @@ -0,0 +1,135 @@ +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration + +# Simple utility class to provide channel number - name mappings +class LumiChannelDefs: + + # Define here to give class scope + names = dict() + + # Mapping of channel numbers to channel names + names[0] = 'ATLAS Preferred' + names[1] = 'LHC Lumi' + names[5] = 'CMS Lumi' + names[17] = 'ATLAS Preferred BGRP7' + + names[101] = 'Onl Lucid Evt AND' + names[102] = 'Onl Lucid Evt OR' + names[103] = 'Onl Lucid Hit OR' + names[104] = 'Onl Lucid Hit AND' + names[105] = 'Onl Lucid Evt A' + names[106] = 'Onl Lucid Evt C' + + names[111] = 'Onl LucidFib Evt AND' + names[112] = 'Onl LucidFib Evt OR' + names[113] = 'Onl LucidFib Hit OR' + names[114] = 'Onl LucidFib Hit AND' + names[115] = 'Onl LucidFib Evt A' + names[116] = 'Onl LucidFib Evt C' + + # Offline versions of online numbers + names[151] = 'Lucid Evt AND' + names[152] = 'Lucid Evt OR' + names[153] = 'Lucid Hit OR' + names[154] = 'Lucid Hit AND' + names[155] = 'Lucid Evt A' + names[156] = 'Lucid Evt C' + + names[161] = 'LucidFib Evt AND' + names[162] = 'LucidFib Evt OR' + names[163] = 'LucidFib Hit OR' + names[164] = 'LucidFib Hit AND' + names[165] = 'LucidFib Evt A' + names[166] = 'LucidFib Evt C' + + names[201] = 'Onl BCMH Evt OR' + names[202] = 'Onl BCMH Evt AND' + names[203] = 'Onl BCMH XORA' + names[204] = 'Onl BCMH XORC' + names[205] = 'Onl BCMH ORA' + names[206] = 'Onl BCMH ORC' + names[207] = 'Onl BCMH AND25' + + names[211] = 'Onl BCMV Evt OR' + names[212] = 'Onl BCMV Evt AND' + names[213] = 'Onl BCMV XORA' + names[214] = 'Onl BCMV XORC' + names[216] = 'Onl BCMV ORC' + names[217] = 'Onl BCMV AND25' + + names[221] = 'Onl BCMT Evt OR' + names[222] = 'Onl BCMT Evt AND' + names[226] = 'Onl BCMT ORC' + + names[251] = 'BCMH Evt OR' + names[252] = 'BCMH Evt AND' + names[253] = 'BCMH XORC' + names[254] = 'BCMH XORA' + names[255] = 'BCMH ORA' + names[256] = 'BCMH ORC' + names[257] = 'BCMH AND25' + + names[261] = 'BCMV Evt OR' + names[262] = 'BCMV Evt AND' + names[263] = 'BCMV XORC' + names[264] = 'BCMV XORA' + names[266] = 'BCMV ORC' + names[267] = 'BCMV AND25' + + names[271] = 'BCMT Evt OR' + names[272] = 'BCMT Evt AND' + names[276] = 'BCMT ORC' + + names[301] = 'Onl MBTS Evt OR' + names[302] = 'Onl MBTS Evt AND' + names[303] = 'Onl MBTS Hit OR' + + names[351] = 'MBTS Evt OR' + names[352] = 'MBTS Evt AND' + names[353] = 'MBTS Hit OR' + + names[401] = 'Onl ZDC Evt AND' + names[402] = 'Onl ZDC Evt ORA' + names[403] = 'Onl ZDC Evt ORC' + + names[411] = 'Onl ZDCL Evt AND' + names[412] = 'Onl ZDCL Evt OR' + names[413] = 'Onl ZDCL Evt ORA' + names[414] = 'Onl ZDCL Evt ORC' + + names[451] = 'ZDC Evt AND' + names[452] = 'ZDC Evt ORA' + names[453] = 'ZDC Evt ORC' + + names[461] = 'ZDCL Evt AND' + names[462] = 'ZDCL Evt OR' + names[463] = 'ZDCL Evt ORA' + names[464] = 'ZDCL Evt ORC' + + names[501] = 'FCAL_A' + names[502] = 'FCAL_C' + + names[521] = 'RPC' + + names[902] = 'Vtx Count' + + names[1001] = 'Onl BCM11H Evt OR' + names[1002] = 'Onl BCM11H Evt AND' + names[1004] = 'Onl BCM11H Evt XORC' + + names[1011] = 'Onl BCM11V Evt OR' + names[1012] = 'Onl BCM11V Evt AND' + names[1014] = 'Onl BCM11V Evt XORC' + + names[1051] = 'BCM11H Evt OR' + names[1052] = 'BCM11H Evt AND' + names[1054] = 'BCM11H Evt XORC' + + names[1061] = 'BCM11V Evt OR' + names[1062] = 'BCM11V Evt AND' + names[1064] = 'BCM11V Evt XORC' + + # Sorted list of valid channel numbers + numbers = sorted(names.keys()) + + def name(self, chan): + return self.names.get(chan, 'Unknown') diff --git a/Database/CoolLumiUtilities/python/OnlineLumiCalibrationToolDefault.py b/Database/CoolLumiUtilities/python/OnlineLumiCalibrationToolDefault.py index 68de7468310b64f2a77d22d818ee8dd7d0a513b9..0c9fb9e9564c1148948c0740d98da69912a4d721 100644 --- a/Database/CoolLumiUtilities/python/OnlineLumiCalibrationToolDefault.py +++ b/Database/CoolLumiUtilities/python/OnlineLumiCalibrationToolDefault.py @@ -15,31 +15,23 @@ def OnlineLumiCalibrationToolDefault(name="OnlineLumiCalibrationTool"): mlog.info("OnlineLumiCalibrationToolDefault returning existing tool %s", name) return getattr(svcMgr.ToolSvc, name) + # Check if this is MC, return unconfigured tool (which will do nothing) if so # Instantiate new tool, by default configuration will do nothing olcTool = OnlineLumiCalibrationTool(name) # Now configure based on the environment from IOVDbSvc.CondDB import conddb + if conddb.isMC: + return olcTool - # Run1 - if conddb.dbdata == "COMP200": + # Need this in both Run1 and Run2 + folder = '/TDAQ/OLC/CALIBRATIONS' + olcTool.CalibrationFolderName = folder - folder = '/TDAQ/OLC/CALIBRATIONS' - olcTool.CalibrationFolderName = folder - - # Mistakenly created as multi-version folder, must specify HEAD - if not conddb.folderRequested( folder ): - conddb.addFolder('TDAQ', folder) - mlog.info("OnlineLumiCalibrationToolDefault requested %s", folder) - - # Run2 - do nothing - elif conddb.dbdata == "CONDBR2": - pass - - # Unknown, complain and do nothing - else: - mlog.warning("OnlineLumiCalibrationToolDefault can't resolve conddb.dbdata = %s, assume Run2!" % conddb.dbdata) - pass + # Mistakenly created as multi-version folder, must specify HEAD + if not conddb.folderRequested( folder ): + conddb.addFolder('TDAQ', folder) + mlog.info("OnlineLumiCalibrationToolDefault requested %s", folder) return olcTool diff --git a/Database/CoolLumiUtilities/python/ScanNtupleHandler.py b/Database/CoolLumiUtilities/python/ScanNtupleHandler.py index 621899707389a8c9eb2f1dd7736378ee85b8902b..66ca4bb0f0d3b875074794131aa2387a149c0e68 100755 --- a/Database/CoolLumiUtilities/python/ScanNtupleHandler.py +++ b/Database/CoolLumiUtilities/python/ScanNtupleHandler.py @@ -7,7 +7,7 @@ # # Utility to unpack BCID blobs -from AtlDataSummary.AtlDataSumLumiData import LumiBCIDData +from CoolLumiUtilities.CoolBCIDData import LumiBCIDData from ROOT import TFile, TTree, gROOT, AddressOf from array import array @@ -33,55 +33,64 @@ class ScanNtupleHandler: self.algDict[105] = 'lucidEvtA' self.algDict[106] = 'lucidEvtC' - self.algDict[111] = 'fiberEvtAND' - self.algDict[112] = 'fiberEvtOR' - self.algDict[113] = 'fiberHitOR' - self.algDict[114] = 'fiberHitAND' - self.algDict[115] = 'fiberEvtA' - self.algDict[116] = 'fiberEvtC' + self.algDict[111] = 'lucBiEvtAND' + self.algDict[112] = 'lucBiEvtOR' + self.algDict[113] = 'lucBiHitOR' + self.algDict[115] = 'lucBiEvtA' + self.algDict[116] = 'lucBiEvtC' + self.algDict[121] = 'lucModEvtAND' + self.algDict[122] = 'lucModEvtOR' + self.algDict[123] = 'lucModHitOR' + self.algDict[124] = 'lucModHitAND' + self.algDict[125] = 'lucModEvtA' + self.algDict[126] = 'lucModEvtC' + + self.algDict[131] = 'lucBiPMTA1' + self.algDict[132] = 'lucBiPMTA5' + self.algDict[133] = 'lucBiPMTA9' + self.algDict[134] = 'lucBiPMTA13' + self.algDict[135] = 'lucBiPMTC1' + self.algDict[136] = 'lucBiPMTC5' + self.algDict[137] = 'lucBiPMTC9' + self.algDict[138] = 'lucBiPMTC13' + + self.algDict[151] = 'lucChA' + self.algDict[152] = 'lucChC' + self.algDict[153] = 'lucBiChA' + self.algDict[154] = 'lucBiChC' + self.algDict[155] = 'lucFibChA' + self.algDict[156] = 'lucFibChC' + self.algDict[201] = 'bcmHEvtOR' self.algDict[202] = 'bcmHEvtAND' - # self.algDict[203] = 'bcmXORA' - # self.algDict[204] = 'bcmHXORC' # Remove in 2012 + self.algDict[205] = 'bcmHORA' self.algDict[206] = 'bcmHORC' - self.algDict[207] = 'bcmHAND25' self.algDict[211] = 'bcmVEvtOR' self.algDict[212] = 'bcmVEvtAND' - # self.algDict[214] = 'bcmVXORC' # Remove in 2012 + self.algDict[215] = 'bcmVORA' self.algDict[216] = 'bcmVORC' - self.algDict[217] = 'bcmVAND25' self.algDict[221] = 'bcmTEvtOR' self.algDict[222] = 'bcmTEvtAND' - self.algDict[226] = 'bcmTORC' + #self.algDict[225] = 'bcmTORA' + #self.algDict[226] = 'bcmTORC' + + self.algDict[231] = 'bcmHEarlyOR' + self.algDict[235] = 'bcmHEarlyA' + self.algDict[236] = 'bcmHEarlyC' + + self.algDict[241] = 'bcmVEarlyOR' + self.algDict[245] = 'bcmVEarlyA' + self.algDict[246] = 'bcmVEarlyC' self.algDict[301] = 'mbtsEvtOR' self.algDict[302] = 'mbtsEvtAND' - # self.algDict[303] = 'mbtsHitOR' - - self.algDict[401] = 'zdcEvtAND' - self.algDict[402] = 'zdcEvtORA' - self.algDict[403] = 'zdcEvtORC' - - self.algDict[411] = 'zdclEvtAND' - self.algDict[412] = 'zdclEvtOR' - self.algDict[413] = 'zdclEvtORA' - self.algDict[414] = 'zdclEvtORC' + self.algDict[303] = 'mbtsEvt2' self.algDict[501] = 'fcalA' self.algDict[502] = 'fcalC' - self.algDict[521] = 'rpc' - - self.algDict[1001] = 'bcm11HEvtOR' - self.algDict[1002] = 'bcm11HEvtAND' - self.algDict[1004] = 'bcm11HXORC' - - self.algDict[1011] = 'bcm11VEvtOR' - self.algDict[1012] = 'bcm11VEvtAND' - self.algDict[1014] = 'bcm11VXORC' - # Algorithms with bunch-by-bunch information self.bbbAlgDict = dict() @@ -92,43 +101,58 @@ class ScanNtupleHandler: self.bbbAlgDict[105] = 'lucidEvtA' self.bbbAlgDict[106] = 'lucidEvtC' - self.bbbAlgDict[111] = 'fiberEvtAND' - self.bbbAlgDict[112] = 'fiberEvtOR' - self.bbbAlgDict[113] = 'fiberHitOR' - self.bbbAlgDict[114] = 'fiberHitAND' - self.bbbAlgDict[115] = 'fiberEvtA' - self.bbbAlgDict[116] = 'fiberEvtC' + self.bbbAlgDict[111] = 'lucBiEvtAND' + self.bbbAlgDict[112] = 'lucBiEvtOR' + self.bbbAlgDict[113] = 'lucBiHitOR' + self.bbbAlgDict[114] = 'lucBiHitAND' + self.bbbAlgDict[115] = 'lucBiEvtA' + self.bbbAlgDict[116] = 'lucBiEvtC' + + self.bbbAlgDict[121] = 'lucModEvtAND' + self.bbbAlgDict[122] = 'lucModEvtOR' + self.bbbAlgDict[123] = 'lucModHitOR' + self.bbbAlgDict[125] = 'lucModEvtA' + self.bbbAlgDict[126] = 'lucModEvtC' + self.bbbAlgDict[131] = 'lucBiPMTA1' + self.bbbAlgDict[132] = 'lucBiPMTA5' + self.bbbAlgDict[133] = 'lucBiPMTA9' + self.bbbAlgDict[134] = 'lucBiPMTA13' + self.bbbAlgDict[135] = 'lucBiPMTC1' + self.bbbAlgDict[136] = 'lucBiPMTC5' + self.bbbAlgDict[137] = 'lucBiPMTC9' + self.bbbAlgDict[138] = 'lucBiPMTC13' + + self.bbbAlgDict[151] = 'lucChA' + self.bbbAlgDict[152] = 'lucChC' + self.bbbAlgDict[153] = 'lucBiChA' + self.bbbAlgDict[154] = 'lucBiChC' + self.bbbAlgDict[155] = 'lucFibChA' + self.bbbAlgDict[156] = 'lucFibChC' + self.bbbAlgDict[201] = 'bcmHEvtOR' self.bbbAlgDict[202] = 'bcmHEvtAND' - # self.bbbAlgDict[203] = 'bcmXORA' - # self.bbbAlgDict[204] = 'bcmHXORC' # Remove for 2012 + self.bbbAlgDict[205] = 'bcmHORA' self.bbbAlgDict[206] = 'bcmHORC' - self.bbbAlgDict[207] = 'bcmHAND25' self.bbbAlgDict[211] = 'bcmVEvtOR' self.bbbAlgDict[212] = 'bcmVEvtAND' - # self.bbbAlgDict[214] = 'bcmVXORC' # Remove for 2012 + self.bbbAlgDict[215] = 'bcmVORA' self.bbbAlgDict[216] = 'bcmVORC' - self.bbbAlgDict[217] = 'bcmVAND25' - + self.bbbAlgDict[221] = 'bcmTEvtOR' self.bbbAlgDict[222] = 'bcmTEvtAND' - self.bbbAlgDict[226] = 'bcmTORC' - - self.bbbAlgDict[411] = 'zdclEvtAND' - self.bbbAlgDict[412] = 'zdclEvtOR' - self.bbbAlgDict[413] = 'zdclEvtORA' - self.bbbAlgDict[414] = 'zdclEvtORC' + #self.bbbAlgDict[225] = 'bcmTORA' + #self.bbbAlgDict[226] = 'bcmTORC' + + self.bbbAlgDict[231] = 'bcmHEarlyOR' + self.bbbAlgDict[235] = 'bcmHEarlyA' + self.bbbAlgDict[236] = 'bcmHEarlyC' - self.bbbAlgDict[1001] = 'bcm11HEvtOR' - self.bbbAlgDict[1002] = 'bcm11HEvtAND' - self.bbbAlgDict[1004] = 'bcm11HXORC' + self.bbbAlgDict[241] = 'bcmVEarlyOR' + self.bbbAlgDict[245] = 'bcmVEarlyA' + self.bbbAlgDict[246] = 'bcmVEarlyC' - self.bbbAlgDict[1011] = 'bcm11VEvtOR' - self.bbbAlgDict[1012] = 'bcm11VEvtAND' - self.bbbAlgDict[1014] = 'bcm11VXORC' - def open(self): print 'ScanNtupleHandler.open() called' @@ -145,7 +169,7 @@ class ScanNtupleHandler: self.initBunchData() self.initBunchLumi() self.initLumiData() - self.initTurnData() + self.initLiveData() # Must pass data object as a reference where extracted COOL data can be found # This relies on naming conventions, such as: @@ -191,10 +215,6 @@ class ScanNtupleHandler: # LUMINOSITY self.fillLumiData(obj, data.lumiData.data) - # Turns - if data.turnData != None: - self.fillTurnData(obj, data.turnData.data) - self.tree.Fill() nfilled += 1 @@ -744,6 +764,8 @@ class ScanNtupleHandler: foundAny = False found = dict() + liveDict = dict() + for chId in self.algDict.iterkeys(): found[chId] = False @@ -754,7 +776,11 @@ class ScanNtupleHandler: chId = obj.channelId() if chId == 5: continue # Ignore CMS luminosity - + + elif chId >= 50 and chId <=70: + liveDict[chId] = obj.payload()['LBAvOLCInstLum'] + continue + elif not chId in self.algDict: print 'scanNtupleHandler.fillLumiData - Unknown lumi channel', chId, '!' continue @@ -812,92 +838,44 @@ class ScanNtupleHandler: self.lumiStruct[chId].fDetectorState = 0 self.lumiStruct[chId].fValid = 0xFFFFFFFF - # turn and count data per algorithm from Nitesh's files - def initTurnData(self): - print 'scanNtupleHandler.initTurnData() called' - - # - # Define tree - # Try to abstract this for different lumi algorithms - gROOT.ProcessLine("struct TurnDataStruct {\ - Float_t fTurnsPhys;\ - Float_t fCountsPhys;\ - Float_t fTurnsAll;\ - Float_t fCountsAll;\ - Float_t fTurnsOLC;\ - Float_t fCountsOLC;\ - };") - from ROOT import TurnDataStruct - - self.turnStruct = dict() - for (chId, algstr) in self.algDict.iteritems(): - if chId == 0: continue - print 'scanNtupleHandler.initTurnData - initializing', algstr, 'as channel', chId - self.turnStruct[chId] = TurnDataStruct() - branchString = 'ALG_BXPhys/F:ALG_CountsPhys/F:ALG_BXAll/F:ALG_CountsAll/F:ALG_BXOLC/F:ALG_CountsOLC/F' - - self.tree.Branch(algstr+'_TURN', self.turnStruct[chId], branchString.replace('ALG', algstr)) - - - def fillTurnData(self, timeobj, data): - - # Must match by IOV - exact match - # Keep track of every algorithm separately - foundAny = False - - found = dict() - for chId in self.algDict.iterkeys(): - found[chId] = False - - # Insert invalid values here - for chId in self.algDict.iterkeys(): - if chId == 0: continue - self.turnStruct[chId].fTurnsPhys = -1. - self.turnStruct[chId].fCountsPhys = -1. - self.turnStruct[chId].fTurnsAll = -1. - self.turnStruct[chId].fCountsAll = -1. - self.turnStruct[chId].fTurnsOLC = -1. - self.turnStruct[chId].fCountsOLC = -1. - - # Look for our lumi block - run = timeobj.payload()['RunLB'] >> 32 - lb = timeobj.payload()['RunLB'] & 0xFFFFFFFF - - if not lb in data: - print 'scanNtupleHandler.fillTurnData - Found no turn data to match IOV %d/%d !' % (run, lb) - + # Fill the livefraction data (if present) + self.fillLive(liveDict, 50, 51, self.liveDataStruct.fRD0_Filled) + self.fillLive(liveDict, 54, 55, self.liveDataStruct.fMBTS_1_1) + self.fillLive(liveDict, 56, 57, self.liveDataStruct.fMBTS_2) + self.fillLive(liveDict, 58, 59, self.liveDataStruct.fEM12) + self.fillLive(liveDict, 60, 61, self.liveDataStruct.fRD0_BGRP9) + self.fillLive(liveDict, 62, 63, self.liveDataStruct.fMBTS_1_BGRP9) + self.fillLive(liveDict, 66, 67, self.liveDataStruct.fMBTS_2_BGRP9) + + print self.liveDataStruct.fEM12 + + def fillLive(self, liveDict, denchan, numchan, dest): + num = liveDict.get(numchan, 0.) + den = liveDict.get(denchan, 0.) + if den > 0.: + dest = num/den else: + dest = 0. - # Search for channels based on our list - for (chId, chName) in self.algDict.iteritems(): - - if chId == 0: continue - - # Change my naming to match Nitesh's naming - chStrBase = chName.replace('Evt', 'Event') - chStrBase = chStrBase.replace('bcmH', 'bcm') - chStrBase = chStrBase.replace('bcmXORC', 'bcmEventXORC') - - # Three types of data in tree - for ext in ['_OLCLBAv', '_PHYS', '_LBAvALL']: - chStr = chStrBase+ext - if not chStr in data[lb]: - print 'scanNtupleHandler.fillTurnData - no data in lb', lb, 'for', chStr - continue - - (turns, counts) = data[lb][chStr] + self.liveDataStruct.fRD0_Filled = 0. - if ext == '_OLCLBAv': - self.turnStruct[chId].fTurnsOLC = turns - self.turnStruct[chId].fCountsOLC = counts - if ext == '_PHYS': - self.turnStruct[chId].fTurnsPhys = turns - self.turnStruct[chId].fCountsPhys = counts + def initLiveData(self): - if ext == '_LBAvALL': - self.turnStruct[chId].fTurnsAll = turns - self.turnStruct[chId].fCountsAll = counts + # + # Define LIVEDATA tree + gROOT.ProcessLine("struct LiveDataStruct {\ + Float_t fRD0_Filled;\ + Float_t fMBTS_1_1;\ + Float_t fMBTS_2;\ + Float_t fEM12;\ + Float_t fRD0_BGRP9;\ + Float_t fMBTS_1_BGRP9;\ + Float_t fMBTS_2_BGRP9;\ + };") + from ROOT import LiveDataStruct + self.liveDataStruct = LiveDataStruct() + self.tree.Branch('LiveFractions', AddressOf(self.liveDataStruct, 'fRD0_Filled'), 'RD0_Filled/f,MBTS_1_1/f,MBTS_2/f,EM12/f,RD0_BGRP9/f,MBTS_1_BGRP9/f,MBTS_2_BGRP9/f') - + diff --git a/Database/CoolLumiUtilities/python/TrigNtupleHandler.py b/Database/CoolLumiUtilities/python/TrigNtupleHandler.py new file mode 100644 index 0000000000000000000000000000000000000000..5b7505d56f68b53e0f6a40165248fa7a67e8d6e0 --- /dev/null +++ b/Database/CoolLumiUtilities/python/TrigNtupleHandler.py @@ -0,0 +1,396 @@ +#!/bin/env python + +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +# +# AtlDataSumNtuple +# +# Eric Torrence - September 2011 +# +# Contents: +# NtupleHandler - Utility to define and fill the per-BCID ntuple +# + +import os +import array +from ROOT import TObject, TFile, TH1D, TTree, gROOT, AddressOf + +class TrigNtupleHandler: + + def __init__(self): + + self.fileName = 'lumi.root' + self.treeName = 'lumiData' + self.file = None + self.tree = None + self.updatemode = False + + # Flag showing whether BCID data is initialized + self.bcidData = False + + # Flag showing whether L1 trigger counts are initialized + self.l1TrigData = True + + def open(self, update=True): + print 'NtupleHandler.open() called' + + if os.path.exists(self.fileName) and update: + print 'Opening %s for updating' % self.fileName + self.updatemode = True + self.file = TFile(self.fileName, 'update') + self.tree = self.file.Get(self.treeName) + + else: + print 'Creating %s for writing' % self.fileName + self.updatemode = False + self.file = TFile(self.fileName, 'create') + self.tree = TTree(self.treeName, self.treeName) + + + def close(self): + print 'ScanNtupleHandler.close() called' + + self.tree.Write('', TObject.kOverwrite) + self.file.Close() + + def init(self): + print 'ScanNtupleHandler.init() called' + + self.initLBData() + self.initBCIDData() + + def save(self): + self.tree.Fill() + + def readLastEntry(self): + entries = self.tree.GetEntries() + self.tree.GetEntry(entries-1) + + # Fill information from LumiLBData object + def fillLumi(self, lumi): + + # Erase any old data + self.clear() + + # Time in COOL format (ns) + self.lbData.coolStartTime = lumi.startTime.timerunlb() + self.lbData.coolEndTime = lumi.endTime.timerunlb() + # Time in seconds + self.lbData.startTime = lumi.startTime.timerunlb()/1.E9 + self.lbData.endTime = lumi.endTime.timerunlb()/1.E9 + # LB duration in seconds + self.lbData.lbTime = (lumi.endTime.timerunlb() - lumi.startTime.timerunlb())/1.E9 + + self.lbData.run = lumi.runLB.run + self.lbData.lb = lumi.runLB.lb + + # Need to fill these elsewhere + # self.lbData.fill = 0 + # self.lbData.eBeam = 0. + # self.lbData.stable = False + # self.lbData.ready = False + # self.lbData.physics = False + + # if lumi.onlEvtsPerBX > 0.: + # self.lbData.muToLumi = lumi.onlInstLumi/lumi.onlEvtsPerBX + + self.lbData.onlInstLum = lumi.onlInstLumi + self.lbData.onlInstLumAll = lumi.onlInstLumiAll + self.lbData.onlEvtsPerBX = lumi.onlEvtsPerBX + + self.lbData.onlPrefChan = lumi.onlPrefChan + self.lbData.onlValid = lumi.onlValid + self.lbData.olcValid = lumi.olcValid + + self.lbData.nColl = lumi.bcid.nbcol() + self.lbData.nBeam1 = lumi.bcid.nb1() + self.lbData.nBeam2 = lumi.bcid.nb2() + self.lbData.qBeam1Col = lumi.IBeam1 + self.lbData.qBeam2Col = lumi.IBeam2 + self.lbData.qBeam1All = lumi.IBeam1All + self.lbData.qBeam2All = lumi.IBeam2All + + self.lbData.specLumi = lumi.specLumi + self.lbData.geomLumi = lumi.geomLumi + self.lbData.maxEvtsPerBX = lumi.maxEvtsPerBX + + self.lbData.l1LiveFrac = lumi.l1Livefrac + + # Get this from the veto folders + # self.lbData.avgLiveFrac = -1. + # self.lbData.lumiWtLiveFrac = -1. + + self.lbData.matched = lumi.matched + + if not self.bcidData: return + + # And fill the per-BCID values + for (bcid, caliLumi) in lumi.bcid.caliLumi.iteritems(): + self.lumiDel[int(bcid)] = caliLumi + + for (bcid, q) in lumi.bcid.b1Curr.iteritems(): + self.qBeam1[int(bcid)] = q + + for (bcid, q) in lumi.bcid.b2Curr.iteritems(): + self.qBeam2[int(bcid)] = q + + i=0 + for bcid in sorted(list(lumi.bcid.b1BCID)): + self.b1BCID[i] = bcid + i += 1 + + i=0 + for bcid in sorted(list(lumi.bcid.b2BCID)): + self.b2BCID[i] = bcid + i += 1 + + i=0 + for bcid in sorted(list(lumi.bcid.colBCID)): + self.colBCID[i] = bcid + i += 1 + + # Still need live fraction + + # Pass TriggerL1Data object for lumi block filled by TriggerHandler + # Also need mapping of channel names to channel values + def fillL1Trig(self, trigData, trigChan): + for (trig, chan) in trigChan.iteritems(): + self.l1TBP[chan] = trigData.TBP[trig] + self.l1TAP[chan] = trigData.TAP[trig] + self.l1TAV[chan] = trigData.TAV[trig] + + def defineBranch(self, name, type): + self.tree.Branch(name, AddressOf(self.lbData, name), name+'/'+type) + + def loadBranch(self, name): + branch = self.tree.GetBranch(name) + branch.SetAddress(AddressOf(self.lbData, name)) + + def initLBData(self): + + # Define the main lumiblock data + # Time is in ns + +# ULong64_t startTime;\ +# ULong64_t endTime;\ + + LBDataStructStr = "struct LBDataStruct {\ + ULong64_t coolStartTime;\ + ULong64_t coolEndTime;\ + Double_t startTime;\ + Double_t endTime;\ + Float_t lbTime;\ + UInt_t fill;\ + UInt_t run;\ + UInt_t lb;\ + Float_t eBeam;\ + Bool_t stable;\ + Bool_t ready;\ + Bool_t physics;\ + Bool_t larVeto;\ + \ + UInt_t onlValid;\ + UInt_t olcValid;\ + UInt_t onlPrefChan;\ + Float_t muToLumi;\ + Float_t onlInstLum;\ + Float_t onlInstLumAll;\ + Float_t onlEvtsPerBX;\ + \ + UInt_t nColl;\ + UInt_t nBeam1;\ + UInt_t nBeam2;\ + Float_t qBeam1Col;\ + Float_t qBeam2Col;\ + Float_t qBeam1All;\ + Float_t qBeam2All;\ + \ + Float_t specLumi;\ + Float_t geomLumi;\ + Float_t maxEvtsPerBX;\ + \ + Float_t l1LiveFrac;\ + Float_t avgLiveFrac;\ + Float_t lumiWtLiveFrac;\ + \ + UInt_t matched;\ + };" + + # Replace sizes if needed + gROOT.ProcessLine(LBDataStructStr) + from ROOT import LBDataStruct + self.lbData = LBDataStruct() + + self.varList = [] + + self.varList.append(('startTime', 'D')) + self.varList.append(('endTime', 'D')) + self.varList.append(('coolStartTime', 'l')) + self.varList.append(('coolEndTime', 'l')) + self.varList.append(('lbTime', 'F')) + + self.varList.append(('fill', 'i')) + self.varList.append(('run', 'i')) + self.varList.append(('lb', 'i')) + self.varList.append(('eBeam', 'F')) + + # Boolean status flags + self.varList.append(('stable', 'O')) + self.varList.append(('ready', 'O')) + self.varList.append(('physics', 'O')) + self.varList.append(('larVeto', 'O')) + + # Luminosity information + self.varList.append(('onlPrefChan', 'i')) + self.varList.append(('muToLumi', 'F')) + self.varList.append(('onlInstLum', 'F')) + self.varList.append(('onlInstLumAll', 'F')) + self.varList.append(('onlEvtsPerBX', 'F')) + self.varList.append(('onlValid', 'i')) # From LBLESTONL & 0x3FF + self.varList.append(('olcValid', 'i')) # From LUMINOSITY + + # Total bunch information + self.varList.append(('nColl', 'i')) + self.varList.append(('nBeam1', 'i')) + self.varList.append(('nBeam2', 'i')) + self.varList.append(('qBeam1Col', 'F')) # Total charge colliding + self.varList.append(('qBeam2Col', 'F')) + self.varList.append(('qBeam1All', 'F')) # Total charge in all BCIDs + self.varList.append(('qBeam2All', 'F')) + + self.varList.append(('specLumi', 'F')) + self.varList.append(('geomLumi', 'F')) + self.varList.append(('maxEvtsPerBX', 'F')) + + # Livetime information + self.varList.append(('l1LiveFrac', 'F')) + self.varList.append(('avgLiveFrac', 'F')) + self.varList.append(('lumiWtLiveFrac', 'F')) # lumi-weighted per-BCID livefraction + + # Where the lumi information came from + self.varList.append(('matched', 'i')) + + for (var, type) in self.varList: + if self.updatemode: + self.loadBranch(var) + + else: + self.defineBranch(var, type) + + def initBCIDData(self): + + self.bcidData = True + + # Delivered luminosity + self.lumiDel = array.array('f', (0.,)*3564) + self.qBeam1 = array.array('f', (0.,)*3564) # Charge per BCID + self.qBeam2 = array.array('f', (0.,)*3564) + self.liveFrac = array.array('f', (0.,)*3564) # Deadtime + + if self.updatemode: + self.tree.GetBranch('lumiDel').SetAddress(self.lumiDel) + self.tree.GetBranch('qBeam1').SetAddress(self.qBeam1) + self.tree.GetBranch('qBeam2').SetAddress(self.qBeam2) + self.tree.GetBranch('liveFrac').SetAddress(self.liveFrac) + + + else: + self.tree.Branch('lumiDel', self.lumiDel, 'lumiDel[3564]/F') + self.tree.Branch('qBeam1', self.qBeam1, 'qBeam1[3564]/F') + self.tree.Branch('qBeam2', self.qBeam2, 'qBeam2[3564]/F') + self.tree.Branch('liveFrac', self.liveFrac, 'liveFrac[3564]/F') # Per-BCID livetime from lumi counters + + # BCID arrays (unsigned shorts) + self.b1BCID = array.array('H', (0,)*3564) + self.b2BCID = array.array('H', (0,)*3564) + self.colBCID = array.array('H', (0,)*3564) + + if self.updatemode: + self.tree.GetBranch('b1BCID').SetAddress(self.b1BCID) + self.tree.GetBranch('b2BCID').SetAddress(self.b2BCID) + self.tree.GetBranch('colBCID').SetAddress(self.colBCID) + else: + self.tree.Branch('b1BCID', self.b1BCID, 'b1BCID[nBeam1]/s') # Unsigned short + self.tree.Branch('b2BCID', self.b2BCID, 'b2BCID[nBeam2]/s') # Unsigned short + self.tree.Branch('colBCID', self.colBCID, 'colBCID[nColl]/s') # Unsigned short + + def initL1TrigData(self): + + self.l1TrigData = True + + # Counts by channel ID + self.l1TBP = array.array('I', (0,)*256) + self.l1TAP = array.array('I', (0,)*256) + self.l1TAV = array.array('I', (0,)*256) + + if self.updatemode: + self.tree.GetBranch('l1TBP').SetAddress(self.l1TBP) + self.tree.GetBranch('l1TAP').SetAddress(self.l1TAP) + self.tree.GetBranch('l1TAV').SetAddress(self.l1TAV) + + else: + self.tree.Branch('l1TBP', self.l1TBP, 'l1TBP[256]/i') + self.tree.Branch('l1TAP', self.l1TAP, 'l1TAP[256]/i') + self.tree.Branch('l1TAV', self.l1TAV, 'l1TAV[256]/i') + + + # Set all ntuple variables to default values + def clear(self): + + self.lbData.startTime = 0 + self.lbData.endTime = 0 + self.lbData.lbTime = 0. + self.lbData.fill = 0 + self.lbData.run = 0 + self.lbData.lb = 0 + self.lbData.eBeam = 0. + + self.lbData.stable = False + self.lbData.ready = False + self.lbData.physics = False + self.lbData.larVeto = False + + self.lbData.onlPrefChan = 0 + self.lbData.muToLumi = 0. + self.lbData.onlInstLum = -1. + self.lbData.onlInstLumAll = -1. + self.lbData.onlEvtsPerBX = -1. + self.lbData.onlValid = 0xFFFFFF + self.lbData.olcValid = 0xFFFFFF + + self.lbData.nColl = 0 + self.lbData.nBeam1 = 0 + self.lbData.nBeam2 = 0 + self.lbData.qBeam1Col = -1. + self.lbData.qBeam2Col = -1. + self.lbData.qBeam1All = -1. + self.lbData.qBeam2All = -1. + + self.lbData.specLumi = -1. + self.lbData.geomLumi = -1. + self.lbData.maxEvtsPerBX = -1. + + self.lbData.l1LiveFrac = -1. + self.lbData.avgLiveFrac = -1. + self.lbData.lumiWtLiveFrac = -1. + + self.lbData.matched = 0 + + if self.bcidData: + + # Per-BCID arrays + for i in range(3564): + self.lumiDel[i] = 0. + self.qBeam1[i] = 0. + self.qBeam2[i] = 0. + self.liveFrac[i] = 0. + self.b1BCID[i] = 0 + self.b2BCID[i] = 0 + self.colBCID[i] = 0 + + if self.l1TrigData: + + # L1 trigger counts + for i in range(256): + self.l1TBP[i] = 0 + self.l1TAP[i] = 0 + self.l1TAV[i] = 0 diff --git a/Database/CoolLumiUtilities/python/TriggerHandler.py b/Database/CoolLumiUtilities/python/TriggerHandler.py new file mode 100755 index 0000000000000000000000000000000000000000..185b4bc4926b2f80f2cc1c5b541f7ee24965f369 --- /dev/null +++ b/Database/CoolLumiUtilities/python/TriggerHandler.py @@ -0,0 +1,302 @@ +#!/bin/env python + +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +# +# TriggerHandler +# +# Eric Torrence - October 2011 +# +# Contents: +# TriggerL1Data - L1 data object +# TriggerHandler - utility tool to find trigger-based information from COOL +# + +import sys +import time +import calendar + +from PyCool import cool +from CoolLumiUtilities.CoolDataReader import CoolDataReader + +# +# Data object to hold L1 trigger count information +# +class TriggerL1Data: + + def __init__(self): + + self.clear() + + def clear(self): + # Dictionaries keyed by L1 trigger name + self.TBP = dict() + self.TAP = dict() + self.TAV = dict() + + self.startTime = 0. + self.endtime = 0. + self.runlb = 0 + + # Duration of this lumi block (in seconds) + self.dtime = 0. + +# Main LumiHandler class for retrieving luminosity data from DB + +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'] + +def timeVal(val): + "Convert argument to time in seconds, treating as a literal or date" + try: + a=int(val) + return a + except ValueError: + try: + ts=time.strptime(val,'%Y-%m-%d:%H:%M:%S/%Z') + return int(calendar.timegm(ts))*1000000000L + + # Try again with UTC attached + except ValueError: + try: + ts=time.strptime(val+'/UTC', '%Y-%m-%d:%H:%M:%S/%Z') + return int(calendar.timegm(ts))*1000000000L + + except ValueError,e: + print "ERROR in time specification:",val,"- use e.g. 2007-05-25:14:01:00/UTC" + sys.exit(-1) + +def timeString(iovkey): + "Convert the IOVtime (63 bit) to a string representing timestamp" + if (iovkey==cool.ValidityKeyMin): + return "ValidityKeyMin" + elif (iovkey==cool.ValidityKeyMax): + return "ValidityKeyMax" + else: + # Round to avoid bias if microseconds exist + stime=int(round(iovkey/1000000000L)) + return time.strftime('%Y-%m-%d:%H:%M:%S/UTC', time.gmtime(stime)) + +def runLBString(iovkey): + "Convert the IOVtime (63 bit) to a string representing timestamp" + if (iovkey==cool.ValidityKeyMin): + return "ValidityKeyMin" + elif (iovkey==cool.ValidityKeyMax): + return "ValidityKeyMax" + else: + # Round to avoid bias if microseconds exist + run = iovkey >> 32 + lb = iovkey & 0xFFFFFFFF + return "%d/%d" % (run, lb) + + +# Executed from the command line, for testing only +if __name__ == '__main__': + th = TriggerHandler() + th.verbose = True + th.allL1Triggers = True + tstart = '2011-10-16:06:00:00' + tend = '2011-10-17:04:00:00' + + th.loadData(timeVal(tstart), timeVal(tend)) diff --git a/Database/CoolLumiUtilities/share/calibNtupleMaker12vdM.py b/Database/CoolLumiUtilities/share/calibNtupleMaker12vdM.py new file mode 100755 index 0000000000000000000000000000000000000000..aa6323aceee3c6f31bc21d7cb8fac69a91573b8a --- /dev/null +++ b/Database/CoolLumiUtilities/share/calibNtupleMaker12vdM.py @@ -0,0 +1,1163 @@ +#!/usr/bin/env python +# +# vdMScanMaker.py +# +# Main application script to generate ntuples of vdM scan data +# 27 May 2014 - Adapted to produce identical output as calibNtupleMaker12 for Benedetto +# +import os +import sys +import shutil +import array +import time, calendar + +from optparse import OptionParser + +# Utility to unpack BCID blobs +from AtlDataSummary.AtlDataSumLumiData import LumiBCIDData +from CoolLumiUtilities.LumiBlobConversion import unpackBCIDMask, unpackBCIDValues + +# General COOL reader object +from CoolLumiUtilities.CoolDataReader import CoolDataReader + +# Get our global DB handler object +from CoolLumiUtilities.LumiDBHandler import LumiDBHandler + +from PyCool import cool + +from ROOT import TFile, TTree, gROOT, AddressOf + +# Simple utility for converting time strings +def timeVal(val): + "Convert argument to time in seconds, treating as a literal or date" + try: + a=int(val) + return a + + except ValueError: + try: + ts=time.strptime(val,'%Y-%m-%d:%H:%M:%S/%Z') + return int(calendar.timegm(ts))*1000000000L + + # Try again with UTC attached + except ValueError: + try: + ts=time.strptime(val+'/UTC', '%Y-%m-%d:%H:%M:%S/%Z') + return int(calendar.timegm(ts))*1000000000L + + except ValueError,e: + print "ERROR in time specification:",val,"- use e.g. 2007-05-25:14:01:00/UTC" + return None + +def timeString(iovkey): + # Convert the IOVkey (63 bit) to a string representing time stamp + if (iovkey == cool.ValidityKeyMin): + return 'ValidityKeyMin' + elif (iovkey == cool.ValidityKeyMax): + return 'ValidityKeyMax' + else: + stime=int(round(iovkey/1000000000L)) + return time.strftime('%Y-%m-%d:%H:%M:%S/UTC', time.gmtime(stime)) + + +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 + + +# Utility object to keep track of valid BCID mask +class BCIDMask(): + + def __init__(self): + + self.clearValidity() + + self.nb1 = 0 + self.nb2 = 0 + self.ncol = 0 + + self.beam1 = [] + self.beam2 = [] + self.coll = [] + + def clearValidity(self): + self.validStartTime = cool.ValidityKeyMax + self.validEndTime = cool.ValidityKeyMin + + def setMask(self, maskObj): + self.setValidity(maskObj) + + self.nb1 = maskObj.payload()['Beam1Bunches'] + self.nb2 = maskObj.payload()['Beam2Bunches'] + self.ncol = maskObj.payload()['LuminousBunches'] + bmask = maskObj.payload()['BCIDmasks'] + + self.beam1, self.beam2, self.coll = unpackBCIDMask(bmask, self.nb1, self.nb2, self.ncol) + + def setValidity(self, obj): + self.validStartTime = obj.since() + self.validEndTime = obj.until() + + def isValid(self, time): + return (self.validStartTime <= time < self.validEndTime) + +# Utility object to keep track of valid Bunch Group definition +# Bunch group is kept as a list of integers (0-3563) +class BunchGroup(): + + def __init__(self): + + self.clearValidity() + self.bg = [] + + def clearValidity(self): + self.validStartTime = cool.ValidityKeyMax + self.validEndTime = cool.ValidityKeyMin + + def setBG(self, bgObj): + self.setValidity(bgObj) + + blob = bgObj.payload()['BunchCode'] + self.bg = unpackBunchGroup(blob) + self.bg.sort() + + def setValidity(self, obj): + self.validStartTime = obj.since() + self.validEndTime = obj.until() + + def isValid(self, time): + return (self.validStartTime <= time < self.validEndTime) + + +class NtupleHandler: + + def __init__(self): + + self.fileName = 'lumi.root' + self.treeName = 'lumiData' + self.file = None + self.tree = None + + self.nBCID = 3564 + + # Control channel lists + self.chan2011 = True + self.chan2012 = False + + # Control ntuple content + self.fibers = False + self.oldBCM = False + + def open(self): + print 'NtupleHandler.open() called' + + self.file = TFile(self.fileName, 'recreate') + self.tree = TTree(self.treeName, self.treeName) + + def close(self): + print 'ScanNtupleHandler.close() called' + + self.file.Write() + self.file.Close() + + def init(self): + print 'ScanNtupleHandler.init() called' + + self.initLBData() + self.initBCIDData() + + # Information about the general lumi block + def initLBData(self): + + self.lbDataStruct = self.getLBDataStruct() + + # l = 64 bit unsigned int, L = 64 bit signed int + self.tree.Branch('LBDATA', self.lbDataStruct, 'StartTime/l:EndTime/l:Run/i:LB/i:stable/i') + + self.tree.Branch('AvgBeam1', AddressOf(self.lbDataStruct, 'fAvgBeam1'), 'AvgBeam1/F') + self.tree.Branch('AvgBeam2', AddressOf(self.lbDataStruct, 'fAvgBeam2'), 'AvgBeam2/F') + self.tree.Branch('pmtA', AddressOf(self.lbDataStruct, 'fPmtA'), 'pmtA/F') + self.tree.Branch('pmtC', AddressOf(self.lbDataStruct, 'fPmtC'), 'pmtC/F') + self.tree.Branch('fibA', AddressOf(self.lbDataStruct, 'fFibA'), 'fibA/F') + self.tree.Branch('fibC', AddressOf(self.lbDataStruct, 'fFibC'), 'fibC/F') + + # Pass an IObject object for a single ntuple entry + def fillLBData(self, obj): + self.lbDataStruct.fStartTime = obj.since() # Time in ns + self.lbDataStruct.fEndTime = obj.until() # Time in ns + self.lbDataStruct.fRun = obj.payload()['RunLB'] >> 32 + self.lbDataStruct.fLB = obj.payload()['RunLB']&0xFFFFFFFF + self.lbDataStruct.fAvgBeam1 = 0. + self.lbDataStruct.fAvgBeam2 = 0. + self.lbDataStruct.fPmtA = 0. + self.lbDataStruct.fPmtC = 0. + self.lbDataStruct.fFibA = 0. + self.lbDataStruct.fFibC = 0. + + # Return LBData struct + def getLBDataStruct(self): + + # + # Define LBDATA tree + # Time is in ms + structStr = "struct LBDataStruct {\ + ULong64_t fStartTime;\ + ULong64_t fEndTime;\ + UInt_t fRun;\ + UInt_t fLB;\ + UInt_t fStable;\ + Float_t fAvgBeam1;\ + Float_t fAvgBeam2;\ + Float_t fPmtA;\ + Float_t fPmtC;\ + Float_t fFibA;\ + Float_t fFibC;\ + };" + + # Replace sizes if needed + gROOT.ProcessLine(structStr) + from ROOT import LBDataStruct + return LBDataStruct() + + def getMuDataStruct(self): + # Keep track of collisions in Status + gROOT.ProcessLine("struct MuStruct {\ + Float_t fMuToLumi;\ + UInt_t fStatus[3564];\ + Float_t fMuLucOR[3564];\ + Float_t fMuLucAND[3564];\ + Float_t fMuLucHitOR[3564];\ + Float_t fMuLucHitAND[3564];\ + Float_t fMuLucA[3564];\ + Float_t fMuLucC[3564];\ + \ + Float_t fMuLFiOR[3564];\ + Float_t fMuLFiAND[3564];\ + Float_t fMuLFiHitOR[3564];\ + Float_t fMuLFiHitAND[3564];\ + Float_t fMuLFiA[3564];\ + Float_t fMuLFiC[3564];\ + \ + Float_t fMuBcmHOR[3564];\ + Float_t fMuBcmHAND[3564];\ + Float_t fMuBcmHXORA[3564];\ + Float_t fMuBcmHXORC[3564];\ + Float_t fMuBcmHORA[3564];\ + Float_t fMuBcmHORC[3564];\ + Float_t fMuBcmHAND25[3564];\ + \ + Float_t fMuBcmVOR[3564];\ + Float_t fMuBcmVAND[3564];\ + Float_t fMuBcmVXORA[3564];\ + Float_t fMuBcmVXORC[3564];\ + Float_t fMuBcmVORA[3564];\ + Float_t fMuBcmVORC[3564];\ + Float_t fMuBcmVAND25[3564];\ + \ + Float_t fMuBcmTOR[3564];\ + Float_t fMuBcmTAND[3564];\ + Float_t fMuBcmTORC[3564];\ + \ + Float_t fMuBcm11HOR[3564];\ + Float_t fMuBcm11HAND[3564];\ + Float_t fMuBcm11HXORC[3564];\ + \ + Float_t fMuBcm11VOR[3564];\ + Float_t fMuBcm11VAND[3564];\ + Float_t fMuBcm11VXORC[3564];\ + \ + Float_t fMuZdcAND[3564];\ + Float_t fMuZdcOR[3564];\ + Float_t fMuZdcORA[3564];\ + Float_t fMuZdcORC[3564];\ + Float_t fBeam1[3564];\ + Float_t fBeam2[3564];\ + };") + + from ROOT import MuStruct + return MuStruct() + + def getRawDataStruct(self): + + # Store all BCIDs + gROOT.ProcessLine("struct RawStruct {\ + Float_t fRawLucOR[3564];\ + Float_t fRawLucAND[3564];\ + Float_t fRawLucHitOR[3564];\ + Float_t fRawLucHitAND[3564];\ + Float_t fRawLucA[3564];\ + Float_t fRawLucC[3564];\ + \ + Float_t fRawLFiOR[3564];\ + Float_t fRawLFiAND[3564];\ + Float_t fRawLFiHitOR[3564];\ + Float_t fRawLFiHitAND[3564];\ + Float_t fRawLFiA[3564];\ + Float_t fRawLFiC[3564];\ + \ + Float_t fRawBcmHOR[3564];\ + Float_t fRawBcmHAND[3564];\ + Float_t fRawBcmHXORA[3564];\ + Float_t fRawBcmHXORC[3564];\ + Float_t fRawBcmHORA[3564];\ + Float_t fRawBcmHORC[3564];\ + Float_t fRawBcmHAND25[3564];\ + \ + Float_t fRawBcmVOR[3564];\ + Float_t fRawBcmVAND[3564];\ + Float_t fRawBcmVXORA[3564];\ + Float_t fRawBcmVXORC[3564];\ + Float_t fRawBcmVORA[3564];\ + Float_t fRawBcmVORC[3564];\ + Float_t fRawBcmVAND25[3564];\ + \ + Float_t fRawBcmTOR[3564];\ + Float_t fRawBcmTAND[3564];\ + Float_t fRawBcmTORC[3564];\ + \ + Float_t fRawBcm11HOR[3564];\ + Float_t fRawBcm11HAND[3564];\ + Float_t fRawBcm11HXORC[3564];\ + \ + Float_t fRawBcm11VOR[3564];\ + Float_t fRawBcm11VAND[3564];\ + Float_t fRawBcm11VXORC[3564];\ + \ + Float_t fRawZdcAND[3564];\ + Float_t fRawZdcOR[3564];\ + Float_t fRawZdcORA[3564];\ + Float_t fRawZdcORC[3564];\ + };") + + from ROOT import RawStruct + return RawStruct() + + # All BCID-dependent quantities + def initBCIDData(self): + + + self.bcidStruct = self.getMuDataStruct() + self.rawStruct = self.getRawDataStruct() + + self.tree.Branch('muToLumi', AddressOf(self.bcidStruct, 'fMuToLumi'), 'muToLumi/F') + self.tree.Branch('Status', AddressOf(self.bcidStruct, 'fStatus'), 'Status[3564]/i') + + self.tree.Branch('RawLucOR', AddressOf(self.rawStruct, 'fRawLucOR'), 'RawLucOR[3564]/F') + self.tree.Branch('RawLucA', AddressOf(self.rawStruct, 'fRawLucA'), 'RawLucA[3564]/F') + self.tree.Branch('RawLucC', AddressOf(self.rawStruct, 'fRawLucC'), 'RawLucC[3564]/F') + self.tree.Branch('RawLucAND', AddressOf(self.rawStruct, 'fRawLucAND'), 'RawLucAND[3564]/F') + self.tree.Branch('RawLucHitOR', AddressOf(self.rawStruct, 'fRawLucHitOR'), 'RawLucHitOR[3564]/F') + self.tree.Branch('RawLucHitAND', AddressOf(self.rawStruct, 'fRawLucHitAND'), 'RawLucHitAND[3564]/F') + + if self.fibers: + self.tree.Branch('RawLFiOR', AddressOf(self.rawStruct, 'fRawLFiOR'), 'RawLFiOR[3564]/F') + self.tree.Branch('RawLFiA', AddressOf(self.rawStruct, 'fRawLFiA'), 'RawLFiA[3564]/F') + self.tree.Branch('RawLFiC', AddressOf(self.rawStruct, 'fRawLFiC'), 'RawLFiC[3564]/F') + self.tree.Branch('RawLFiAND', AddressOf(self.rawStruct, 'fRawLFiAND'), 'RawLFiAND[3564]/F') + self.tree.Branch('RawLFiHitOR', AddressOf(self.rawStruct, 'fRawLFiHitOR'), 'RawLFiHitOR[3564]/F') + self.tree.Branch('RawLFiHitAND', AddressOf(self.rawStruct, 'fRawLFiHitAND'), 'RawLFiHitAND[3564]/F') + + self.tree.Branch('RawBcmHOR', AddressOf(self.rawStruct, 'fRawBcmHOR'), 'RawBcmHOR[3564]/F') + self.tree.Branch('RawBcmHAND', AddressOf(self.rawStruct, 'fRawBcmHAND'), 'RawBcmHAND[3564]/F') + if self.chan2011: + self.tree.Branch('RawBcmHXORA', AddressOf(self.rawStruct, 'fRawBcmHXORA'), 'RawBcmHXORA[3564]/F') + self.tree.Branch('RawBcmHXORC', AddressOf(self.rawStruct, 'fRawBcmHXORC'), 'RawBcmHXORC[3564]/F') + if self.chan2012: + # self.tree.Branch('RawBcmHORA', AddressOf(self.rawStruct, 'fRawBcmHORA'), 'RawBcmHORA[3564]/F') + self.tree.Branch('RawBcmHORC', AddressOf(self.rawStruct, 'fRawBcmHORC'), 'RawBcmHORC[3564]/F') + self.tree.Branch('RawBcmHAND25', AddressOf(self.rawStruct, 'fRawBcmHAND25'), 'RawBcmHAND25[3564]/F') + + self.tree.Branch('RawBcmVOR', AddressOf(self.rawStruct, 'fRawBcmVOR'), 'RawBcmVOR[3564]/F') + self.tree.Branch('RawBcmVAND', AddressOf(self.rawStruct, 'fRawBcmVAND'), 'RawBcmVAND[3564]/F') + if self.chan2011: + self.tree.Branch('RawBcmVXORA', AddressOf(self.rawStruct, 'fRawBcmVXORA'), 'RawBcmVXORA[3564]/F') + self.tree.Branch('RawBcmVXORC', AddressOf(self.rawStruct, 'fRawBcmVXORC'), 'RawBcmVXORC[3564]/F') + if self.chan2012: + # self.tree.Branch('RawBcmVORA', AddressOf(self.rawStruct, 'fRawBcmVORA'), 'RawBcmVORA[3564]/F') + self.tree.Branch('RawBcmVORC', AddressOf(self.rawStruct, 'fRawBcmVORC'), 'RawBcmVORC[3564]/F') + self.tree.Branch('RawBcmVAND25', AddressOf(self.rawStruct, 'fRawBcmVAND25'), 'RawBcmVAND25[3564]/F') + + if self.chan2012: + self.tree.Branch('RawBcmTOR', AddressOf(self.rawStruct, 'fRawBcmTOR'), 'RawBcmTOR[3564]/F') + self.tree.Branch('RawBcmTAND', AddressOf(self.rawStruct, 'fRawBcmTAND'), 'RawBcmTAND[3564]/F') + self.tree.Branch('RawBcmTORC', AddressOf(self.rawStruct, 'fRawBcmTORC'), 'RawBcmTORC[3564]/F') + + if self.oldBCM: + self.tree.Branch('RawBcm11HOR', AddressOf(self.rawStruct, 'fRawBcm11HOR'), 'RawBcm11HOR[3564]/F') + self.tree.Branch('RawBcm11HAND', AddressOf(self.rawStruct, 'fRawBcm11HAND'), 'RawBcm11HAND[3564]/F') + self.tree.Branch('RawBcm11HXORC', AddressOf(self.rawStruct, 'fRawBcm11HXORC'), 'RawBcm11HXORC[3564]/F') + + self.tree.Branch('RawBcm11VOR', AddressOf(self.rawStruct, 'fRawBcm11VOR'), 'RawBcm11VOR[3564]/F') + self.tree.Branch('RawBcm11VAND', AddressOf(self.rawStruct, 'fRawBcm11VAND'), 'RawBcm11VAND[3564]/F') + self.tree.Branch('RawBcm11VXORC', AddressOf(self.rawStruct, 'fRawBcm11VXORC'), 'RawBcm11VXORC[3564]/F') + + if self.chan2011: + self.tree.Branch('RawZdcOR', AddressOf(self.rawStruct, 'fRawZdcOR'), 'RawZdcOR[3564]/F') + self.tree.Branch('RawZdcORA', AddressOf(self.rawStruct, 'fRawZdcORA'), 'RawZdcORA[3564]/F') + self.tree.Branch('RawZdcORC', AddressOf(self.rawStruct, 'fRawZdcORC'), 'RawZdcORC[3564]/F') + self.tree.Branch('RawZdcAND', AddressOf(self.rawStruct, 'fRawZdcAND'), 'RawZdcAND[3564]/F') + + self.tree.Branch('MuLucOR', AddressOf(self.bcidStruct, 'fMuLucOR'), 'MuLucOR[3564]/F') + self.tree.Branch('MuLucA', AddressOf(self.bcidStruct, 'fMuLucA'), 'MuLucA[3564]/F') + self.tree.Branch('MuLucC', AddressOf(self.bcidStruct, 'fMuLucC'), 'MuLucC[3564]/F') + self.tree.Branch('MuLucAND', AddressOf(self.bcidStruct, 'fMuLucAND'), 'MuLucAND[3564]/F') + self.tree.Branch('MuLucHitOR', AddressOf(self.bcidStruct, 'fMuLucHitOR'), 'MuLucHitOR[3564]/F') + self.tree.Branch('MuLucHitAND', AddressOf(self.bcidStruct, 'fMuLucHitAND'), 'MuLucHitAND[3564]/F') + + if self.fibers: + self.tree.Branch('MuLFiOR', AddressOf(self.bcidStruct, 'fMuLFiOR'), 'MuLFiOR[3564]/F') + self.tree.Branch('MuLFiA', AddressOf(self.bcidStruct, 'fMuLFiA'), 'MuLFiA[3564]/F') + self.tree.Branch('MuLFiC', AddressOf(self.bcidStruct, 'fMuLFiC'), 'MuLFiC[3564]/F') + self.tree.Branch('MuLFiAND', AddressOf(self.bcidStruct, 'fMuLFiAND'), 'MuLFiAND[3564]/F') + self.tree.Branch('MuLFiHitOR', AddressOf(self.bcidStruct, 'fMuLFiHitOR'), 'MuLFiHitOR[3564]/F') + self.tree.Branch('MuLFiHitAND', AddressOf(self.bcidStruct, 'fMuLFiHitAND'), 'MuLFiHitAND[3564]/F') + + self.tree.Branch('MuBcmHOR', AddressOf(self.bcidStruct, 'fMuBcmHOR'), 'MuBcmHOR[3564]/F') + self.tree.Branch('MuBcmHAND', AddressOf(self.bcidStruct, 'fMuBcmHAND'), 'MuBcmHAND[3564]/F') + if self.chan2011: + self.tree.Branch('MuBcmHXORA', AddressOf(self.bcidStruct, 'fMuBcmHXORA'), 'MuBcmHXORA[3564]/F') + self.tree.Branch('MuBcmHXORC', AddressOf(self.bcidStruct, 'fMuBcmHXORC'), 'MuBcmHXORC[3564]/F') + if self.chan2012: + # self.tree.Branch('MuBcmHORA', AddressOf(self.bcidStruct, 'fMuBcmHORA'), 'MuBcmHORA[3564]/F') + self.tree.Branch('MuBcmHORC', AddressOf(self.bcidStruct, 'fMuBcmHORC'), 'MuBcmHORC[3564]/F') + self.tree.Branch('MuBcmHAND25', AddressOf(self.bcidStruct, 'fMuBcmHAND25'), 'MuBcmHAND25[3564]/F') + + self.tree.Branch('MuBcmVOR', AddressOf(self.bcidStruct, 'fMuBcmVOR'), 'MuBcmVOR[3564]/F') + self.tree.Branch('MuBcmVAND', AddressOf(self.bcidStruct, 'fMuBcmVAND'), 'MuBcmVAND[3564]/F') + if self.chan2011: + self.tree.Branch('MuBcmVXORA', AddressOf(self.bcidStruct, 'fMuBcmVXORA'), 'MuBcmVXORA[3564]/F') + self.tree.Branch('MuBcmVXORC', AddressOf(self.bcidStruct, 'fMuBcmVXORC'), 'MuBcmVXORC[3564]/F') + if self.chan2012: + # self.tree.Branch('MuBcmVORA', AddressOf(self.bcidStruct, 'fMuBcmVORA'), 'MuBcmVORA[3564]/F') + self.tree.Branch('MuBcmVORC', AddressOf(self.bcidStruct, 'fMuBcmVORC'), 'MuBcmVORC[3564]/F') + self.tree.Branch('MuBcmVAND25', AddressOf(self.bcidStruct, 'fMuBcmVAND25'), 'MuBcmVAND25[3564]/F') + + if self.chan2012: + self.tree.Branch('MuBcmTOR', AddressOf(self.bcidStruct, 'fMuBcmTOR'), 'MuBcmTOR[3564]/F') + self.tree.Branch('MuBcmTAND', AddressOf(self.bcidStruct, 'fMuBcmTAND'), 'MuBcmTAND[3564]/F') + self.tree.Branch('MuBcmTORC', AddressOf(self.bcidStruct, 'fMuBcmTORC'), 'MuBcmTORC[3564]/F') + + if self.oldBCM: + self.tree.Branch('MuBcm11HOR', AddressOf(self.bcidStruct, 'fMuBcm11HOR'), 'MuBcm11HOR[3564]/F') + self.tree.Branch('MuBcm11HAND', AddressOf(self.bcidStruct, 'fMuBcm11HAND'), 'MuBcm11HAND[3564]/F') + self.tree.Branch('MuBcm11HXORC', AddressOf(self.bcidStruct, 'fMuBcm11HXORC'), 'MuBcm11HXORC[3564]/F') + + self.tree.Branch('MuBcm11VOR', AddressOf(self.bcidStruct, 'fMuBcm11VOR'), 'MuBcm11VOR[3564]/F') + self.tree.Branch('MuBcm11VAND', AddressOf(self.bcidStruct, 'fMuBcm11VAND'), 'MuBcm11VAND[3564]/F') + self.tree.Branch('MuBcm11VXORC', AddressOf(self.bcidStruct, 'fMuBcm11VXORC'), 'MuBcm11VXORC[3564]/F') + + if self.chan2011: + self.tree.Branch('MuZdcOR', AddressOf(self.bcidStruct, 'fMuZdcOR'), 'MuZdcOR[3564]/F') + self.tree.Branch('MuZdcORA', AddressOf(self.bcidStruct, 'fMuZdcORA'), 'MuZdcORA[3564]/F') + self.tree.Branch('MuZdcORC', AddressOf(self.bcidStruct, 'fMuZdcORC'), 'MuZdcORC[3564]/F') + self.tree.Branch('MuZdcAND', AddressOf(self.bcidStruct, 'fMuZdcAND'), 'MuZdcAND[3564]/F') + + self.tree.Branch('Beam1', AddressOf(self.bcidStruct, 'fBeam1'), 'Beam1[3564]/F') + self.tree.Branch('Beam2', AddressOf(self.bcidStruct, 'fBeam2'), 'Beam2[3564]/F') + + def clearBCIDData(self): + + for i in range(self.nBCID): + self.rawStruct.fRawLucAND[i] = 0. # 101 + self.bcidStruct.fMuLucAND[i] = 0. + self.rawStruct.fRawLucOR[i] = 0. # 102 + self.bcidStruct.fMuLucOR[i] = 0. + + self.rawStruct.fRawLucHitOR[i] = 0. # 103 + self.bcidStruct.fMuLucHitOR[i] = 0. + self.rawStruct.fRawLucHitAND[i] = 0. # 104 + self.bcidStruct.fMuLucHitAND[i] = 0. + + self.rawStruct.fRawLucA[i] = 0. # 105 + self.bcidStruct.fMuLucA[i] = 0. + self.rawStruct.fRawLucC[i] = 0. # 106 + self.bcidStruct.fMuLucC[i] = 0. + + # Lucid Fiber channels + self.rawStruct.fRawLFiAND[i] = 0. # 111 + self.bcidStruct.fMuLFiAND[i] = 0. + self.rawStruct.fRawLFiOR[i] = 0. # 112 + self.bcidStruct.fMuLFiOR[i] = 0. + + self.rawStruct.fRawLFiHitOR[i] = 0. # 113 + self.bcidStruct.fMuLFiHitOR[i] = 0. + self.rawStruct.fRawLFiHitAND[i] = 0. # 114 + self.bcidStruct.fMuLFiHitAND[i] = 0. + + self.rawStruct.fRawLFiA[i] = 0. # 115 + self.bcidStruct.fMuLFiA[i] = 0. + self.rawStruct.fRawLFiC[i] = 0. # 116 + self.bcidStruct.fMuLFiC[i] = 0. + + self.rawStruct.fRawBcmHAND[i] = 0. # 201 + self.bcidStruct.fMuBcmHAND[i] = 0. + self.rawStruct.fRawBcmHOR[i] = 0. # 202 + self.bcidStruct.fMuBcmHOR[i] = 0. + self.rawStruct.fRawBcmHXORA[i] = 0. # 203 + self.bcidStruct.fMuBcmHXORA[i] = 0. + self.rawStruct.fRawBcmHXORC[i] = 0. # 204 + self.bcidStruct.fMuBcmHXORC[i] = 0. + self.rawStruct.fRawBcmHORA[i] = 0. # 205 + self.bcidStruct.fMuBcmHORA[i] = 0. + self.rawStruct.fRawBcmHORC[i] = 0. # 206 + self.bcidStruct.fMuBcmHORC[i] = 0. + self.rawStruct.fRawBcmHAND25[i] = 0. # 207 + self.bcidStruct.fMuBcmHAND25[i] = 0. + + self.rawStruct.fRawBcmVAND[i] = 0. # 211 + self.bcidStruct.fMuBcmVAND[i] = 0. + self.rawStruct.fRawBcmVOR[i] = 0. # 212 + self.bcidStruct.fMuBcmVOR[i] = 0. + self.rawStruct.fRawBcmVXORA[i] = 0. # 213 + self.bcidStruct.fMuBcmVXORA[i] = 0. + self.rawStruct.fRawBcmVXORC[i] = 0. # 214 + self.bcidStruct.fMuBcmVXORC[i] = 0. + self.rawStruct.fRawBcmVORA[i] = 0. # 215 + self.bcidStruct.fMuBcmVORA[i] = 0. + self.rawStruct.fRawBcmVORC[i] = 0. # 216 + self.bcidStruct.fMuBcmVORC[i] = 0. + self.rawStruct.fRawBcmVAND25[i] = 0. # 217 + self.bcidStruct.fMuBcmVAND25[i] = 0. + + self.rawStruct.fRawBcmTAND[i] = 0. # 221 + self.bcidStruct.fMuBcmTAND[i] = 0. + self.rawStruct.fRawBcmTOR[i] = 0. # 222 + self.bcidStruct.fMuBcmTOR[i] = 0. + self.rawStruct.fRawBcmTORC[i] = 0. # 226 + self.bcidStruct.fMuBcmTORC[i] = 0. + + self.rawStruct.fRawZdcAND[i] = 0. # 411 + self.bcidStruct.fMuZdcAND[i] = 0. + self.rawStruct.fRawZdcOR[i] = 0. # 412 + self.bcidStruct.fMuZdcOR[i] = 0. + self.rawStruct.fRawZdcORA[i] = 0. # 413 + self.bcidStruct.fMuZdcORA[i] = 0. + self.rawStruct.fRawZdcORC[i] = 0. # 414 + self.bcidStruct.fMuZdcORC[i] = 0. + + self.rawStruct.fRawBcm11HAND[i] = 0. # 1001 + self.bcidStruct.fMuBcm11HAND[i] = 0. + self.rawStruct.fRawBcm11HOR[i] = 0. # 1002 + self.bcidStruct.fMuBcm11HOR[i] = 0. + self.rawStruct.fRawBcm11HXORC[i] = 0. # 1004 + self.bcidStruct.fMuBcm11HXORC[i] = 0. + + self.rawStruct.fRawBcm11VAND[i] = 0. # 1011 + self.bcidStruct.fMuBcm11VAND[i] = 0. + self.rawStruct.fRawBcm11VOR[i] = 0. # 1012 + self.bcidStruct.fMuBcm11VOR[i] = 0. + self.rawStruct.fRawBcm11VXORC[i] = 0. # 1014 + self.bcidStruct.fMuBcm11VXORC[i] = 0. + + self.bcidStruct.fBeam1[i] = 0. + self.bcidStruct.fBeam2[i] = 0. + + def fillBCIDData(self, chan, bcid, lraw, muval): + + if chan == 101: + self.rawStruct.fRawLucAND[bcid] = lraw + self.bcidStruct.fMuLucAND[bcid] = muval + + elif chan == 102: + self.rawStruct.fRawLucOR[bcid] = lraw + self.bcidStruct.fMuLucOR[bcid] = muval + + elif chan == 103: + self.rawStruct.fRawLucHitOR[bcid] = lraw + self.bcidStruct.fMuLucHitOR[bcid] = muval + + elif chan == 104: + self.rawStruct.fRawLucHitAND[bcid] = lraw + self.bcidStruct.fMuLucHitAND[bcid] = muval + + elif chan == 105: + self.rawStruct.fRawLucA[bcid] = lraw + self.bcidStruct.fMuLucA[bcid] = muval + + elif chan == 106: + self.rawStruct.fRawLucC[bcid] = lraw + self.bcidStruct.fMuLucC[bcid] = muval + + elif chan == 111: + self.rawStruct.fRawLFiAND[bcid] = lraw + self.bcidStruct.fMuLFiAND[bcid] = muval + + elif chan == 112: + self.rawStruct.fRawLFiOR[bcid] = lraw + self.bcidStruct.fMuLFiOR[bcid] = muval + + elif chan == 113: + self.rawStruct.fRawLFiHitOR[bcid] = lraw + self.bcidStruct.fMuLFiHitOR[bcid] = muval + + elif chan == 114: + self.rawStruct.fRawLFiHitAND[bcid] = lraw + self.bcidStruct.fMuLFiHitAND[bcid] = muval + + elif chan == 115: + self.rawStruct.fRawLFiA[bcid] = lraw + self.bcidStruct.fMuLFiA[bcid] = muval + + elif chan == 116: + self.rawStruct.fRawLFiC[bcid] = lraw + self.bcidStruct.fMuLFiC[bcid] = muval + + elif chan == 201: + self.rawStruct.fRawBcmHOR[bcid] = lraw + self.bcidStruct.fMuBcmHOR[bcid] = muval + + elif chan == 202: + self.rawStruct.fRawBcmHAND[bcid] = lraw + self.bcidStruct.fMuBcmHAND[bcid] = muval + + elif chan == 203: + self.rawStruct.fRawBcmHXORA[bcid] = lraw + self.bcidStruct.fMuBcmHXORA[bcid] = muval + + elif chan == 204: + self.rawStruct.fRawBcmHXORC[bcid] = lraw + self.bcidStruct.fMuBcmHXORC[bcid] = muval + + elif chan == 205: + self.rawStruct.fRawBcmHORA[bcid] = lraw + self.bcidStruct.fMuBcmHORA[bcid] = muval + + elif chan == 206: + self.rawStruct.fRawBcmHORC[bcid] = lraw + self.bcidStruct.fMuBcmHORC[bcid] = muval + + elif chan == 207: + self.rawStruct.fRawBcmHAND25[bcid] = lraw + self.bcidStruct.fMuBcmHAND25[bcid] = muval + + elif chan == 211: + self.rawStruct.fRawBcmVOR[bcid] = lraw + self.bcidStruct.fMuBcmVOR[bcid] = muval + + elif chan == 212: + self.rawStruct.fRawBcmVAND[bcid] = lraw + self.bcidStruct.fMuBcmVAND[bcid] = muval + + elif chan == 213: + self.rawStruct.fRawBcmVXORA[bcid] = lraw + self.bcidStruct.fMuBcmVXORA[bcid] = muval + + elif chan == 214: + self.rawStruct.fRawBcmVXORC[bcid] = lraw + self.bcidStruct.fMuBcmVXORC[bcid] = muval + + elif chan == 215: + self.rawStruct.fRawBcmVORA[bcid] = lraw + self.bcidStruct.fMuBcmVORA[bcid] = muval + + elif chan == 216: + self.rawStruct.fRawBcmVORC[bcid] = lraw + self.bcidStruct.fMuBcmVORC[bcid] = muval + + elif chan == 217: + self.rawStruct.fRawBcmVAND25[bcid] = lraw + self.bcidStruct.fMuBcmVAND25[bcid] = muval + + elif chan == 221: + self.rawStruct.fRawBcmTOR[bcid] = lraw + self.bcidStruct.fMuBcmTOR[bcid] = muval + + elif chan == 222: + self.rawStruct.fRawBcmTAND[bcid] = lraw + self.bcidStruct.fMuBcmTAND[bcid] = muval + + elif chan == 226: + self.rawStruct.fRawBcmTORC[bcid] = lraw + self.bcidStruct.fMuBcmTORC[bcid] = muval + + elif chan == 411: + self.rawStruct.fRawZdcAND[bcid] = lraw + self.bcidStruct.fMuZdcAND[bcid] = muval + + elif chan == 412: + self.rawStruct.fRawZdcOR[bcid] = lraw + self.bcidStruct.fMuZdcOR[bcid] = muval + + elif chan == 413: + self.rawStruct.fRawZdcORA[bcid] = lraw + self.bcidStruct.fMuZdcORA[bcid] = muval + + elif chan == 414: + self.rawStruct.fRawZdcORC[bcid] = lraw + self.bcidStruct.fMuZdcORC[bcid] = muval + + elif chan == 1001: + self.rawStruct.fRawBcm11HOR[bcid] = lraw + self.bcidStruct.fMuBcm11HOR[bcid] = muval + + elif chan == 1002: + self.rawStruct.fRawBcm11HAND[bcid] = lraw + self.bcidStruct.fMuBcm11HAND[bcid] = muval + + elif chan == 1004: + self.rawStruct.fRawBcm11HXORC[bcid] = lraw + self.bcidStruct.fMuBcm11HXORC[bcid] = muval + + elif chan == 1011: + self.rawStruct.fRawBcm11VOR[bcid] = lraw + self.bcidStruct.fMuBcm11VOR[bcid] = muval + + elif chan == 1012: + self.rawStruct.fRawBcm11VAND[bcid] = lraw + self.bcidStruct.fMuBcm11VAND[bcid] = muval + + elif chan == 1014: + self.rawStruct.fRawBcm11VXORC[bcid] = lraw + self.bcidStruct.fMuBcm11VXORC[bcid] = muval + + else: + print 'Channel %d unknown for bcid %d!' % (chan, bcid) + + # Pass an IObject object for a single BUNCHDATA entry, and a MaskObj instance + def fillCurrentData(self, obj, mask): + self.lbDataStruct.fAvgBeam1 = obj.payload()['B1BunchAverage'] + self.lbDataStruct.fAvgBeam2 = obj.payload()['B2BunchAverage'] + blob1 = obj.payload()['B1BunchIntensities'] + blob2 = obj.payload()['B2BunchIntensities'] + + if blob1.size() != 0: + bcidVec, bcidVal = unpackBCIDValues(blob1, mask.beam1, self.lbDataStruct.fAvgBeam1) + + for i in range(len(bcidVal)): + + bcid = bcidVec[i] + + # Protect against weird values + if bcid >= self.nBCID: + print 'BCID %d found in beam 1 current data!' % bcid + continue + + self.bcidStruct.fBeam1[bcid] = bcidVal[i] + + if blob2.size() != 0: + bcidVec, bcidVal = unpackBCIDValues(blob2, mask.beam2, self.lbDataStruct.fAvgBeam2) + + for i in range(len(bcidVal)): + + bcid = bcidVec[i] + + # Protect against weird values + if bcid >= self.nBCID: + print 'BCID %d found in beam 2 current data!' % bcid + continue + + self.bcidStruct.fBeam2[bcid] = bcidVal[i] + + + +# Executed from the command line +if __name__ == '__main__': + olm = OflLumiMaker() + olm.execute() + + diff --git a/Database/CoolLumiUtilities/share/calibNtupleMaker15.py b/Database/CoolLumiUtilities/share/calibNtupleMaker15.py new file mode 100755 index 0000000000000000000000000000000000000000..00deb70c49cb82f9e751dc8fb45503ad59d07d7b --- /dev/null +++ b/Database/CoolLumiUtilities/share/calibNtupleMaker15.py @@ -0,0 +1,857 @@ +#!/usr/bin/env python +# +# calibNtupleMaker.py +# +# Produce an ntuple of per-bcid luminosities using the raw lumi data +# 23 May 2011 Modified to write out all BCID +# +# Updated for use in 2012. Removed historical stuff from 2011 +# Updated again for 2015, don't bother calibrating anything now +# +# Eric Torrence - 27 April 2011 +# +import sys +import array +import string + +from optparse import OptionParser + +# Get our global DB handler object +from CoolLumiUtilities.LumiDBHandler import LumiDBHandler +from CoolLumiUtilities.CoolDataReader import CoolDataReader + +from CoolLumiUtilities.LumiBlobConversion import unpackBCIDMask, unpackBCIDValues +from CoolLumiUtilities.LumiBlobConversion import unpackLiveFraction, unpackBunchGroup + +from PyCool import cool +from CoolConvUtilities.AtlCoolLib import forceOpen,ensureFolder,athenaDesc + +from ROOT import TFile, TH1D, TTree, gROOT, AddressOf + +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() + +# Utility object to keep track of valid BCID mask +class BCIDMask(): + + def __init__(self): + + self.clearValidity() + + self.nb1 = 0 + self.nb2 = 0 + self.ncol = 0 + + self.beam1 = [] + self.beam2 = [] + self.coll = [] + + def clearValidity(self): + self.validStartTime = cool.ValidityKeyMax + self.validEndTime = cool.ValidityKeyMin + + def setMask(self, maskObj): + self.setValidity(maskObj) + + self.nb1 = maskObj.payload()['Beam1Bunches'] + self.nb2 = maskObj.payload()['Beam2Bunches'] + self.ncol = maskObj.payload()['LuminousBunches'] + bmask = maskObj.payload()['BCIDmasks'] + + self.beam1, self.beam2, self.coll = unpackBCIDMask(bmask, self.nb1, self.nb2, self.ncol) + + def setValidity(self, obj): + self.validStartTime = obj.since() + self.validEndTime = obj.until() + + def isValid(self, time): + return (self.validStartTime <= time < self.validEndTime) + +# Utility object to keep track of valid Bunch Group definition +# Bunch group is kept as a list of integers (0-3563) +class BunchGroup(): + + def __init__(self): + + self.clearValidity() + self.bg = [] + + def clearValidity(self): + self.validStartTime = cool.ValidityKeyMax + self.validEndTime = cool.ValidityKeyMin + + def setBG(self, bgObj): + self.setValidity(bgObj) + + blob = bgObj.payload()['BunchCode'] + self.bg = unpackBunchGroup(blob) + self.bg.sort() + + def setValidity(self, obj): + self.validStartTime = obj.since() + self.validEndTime = obj.until() + + def isValid(self, time): + return (self.validStartTime <= time < self.validEndTime) + + +class NtupleHandler: + + def __init__(self): + + self.fileName = 'lumi.root' + self.treeName = 'lumiData' + self.file = None + self.tree = None + + self.nBCID = 3564 + + # Map of channel names keyed by (int) channel number + self.chanMap = dict() + + def open(self): + print 'NtupleHandler.open() called' + + self.file = TFile(self.fileName, 'recreate') + self.tree = TTree(self.treeName, self.treeName) + + def close(self): + print 'ScanNtupleHandler.close() called' + + self.file.Write() + self.file.Close() + + def init(self): + print 'ScanNtupleHandler.init() called' + + self.initLBData() + self.initBCIDData() + + # Information about the general lumi block + def initLBData(self): + + self.lbDataStruct = self.getLBDataStruct() + + # l = 64 bit unsigned int, L = 64 bit signed int + self.tree.Branch('LBDATA', self.lbDataStruct, 'StartTime/l:EndTime/l:Run/i:LB/i:stable/i') + + self.tree.Branch('BPTXBeam1All', AddressOf(self.lbDataStruct, 'fBPTXBeam1'), 'BPTXBeam1All/F') + self.tree.Branch('BPTXBeam2All', AddressOf(self.lbDataStruct, 'fBPTXBeam2'), 'BPTXBeam2All/F') + self.tree.Branch('BCTBeam1All', AddressOf(self.lbDataStruct, 'fBCTBeam1'), 'BCTBeam1All/F') + self.tree.Branch('BCTBeam2All', AddressOf(self.lbDataStruct, 'fBCTBeam2'), 'BCTBeam2All/F') + self.tree.Branch('DCCTBeam1All', AddressOf(self.lbDataStruct, 'fDCCTBeam1'), 'DCCTBeam1All/F') + self.tree.Branch('DCCTBeam2All', AddressOf(self.lbDataStruct, 'fDCCTBeam2'), 'DCCTBeam2All/F') + self.tree.Branch('DCCT24Beam1All', AddressOf(self.lbDataStruct, 'fDCCT24Beam1'), 'DCCT24Beam1All/F') + self.tree.Branch('DCCT24Beam2All', AddressOf(self.lbDataStruct, 'fDCCT24Beam2'), 'DCCT24Beam2All/F') + + # Pass an IObject object for a single ntuple entry + def fillLBData(self, obj): + self.lbDataStruct.fStartTime = obj.since() # Time in ns + self.lbDataStruct.fEndTime = obj.until() # Time in ns + self.lbDataStruct.fRun = obj.payload()['RunLB'] >> 32 + self.lbDataStruct.fLB = obj.payload()['RunLB']&0xFFFFFFFF + self.lbDataStruct.fBPTXBeam1 = 0. + self.lbDataStruct.fBPTXBeam2 = 0. + self.lbDataStruct.fBCTBeam1 = 0. + self.lbDataStruct.fBCTBeam2 = 0. + self.lbDataStruct.fDCCTBeam1 = 0. + self.lbDataStruct.fDCCTBeam2 = 0. + self.lbDataStruct.fDCCT24Beam1 = 0. + self.lbDataStruct.fDCCT24Beam2 = 0. + + # Return LBData struct + def getLBDataStruct(self): + + # + # Define LBDATA tree + # Time is in ms + structStr = "struct LBDataStruct {\ + ULong64_t fStartTime;\ + ULong64_t fEndTime;\ + UInt_t fRun;\ + UInt_t fLB;\ + UInt_t fStable;\ + Float_t fBPTXBeam1;\ + Float_t fBPTXBeam2;\ + Float_t fBCTBeam1;\ + Float_t fBCTBeam2;\ + Float_t fDCCTBeam1;\ + Float_t fDCCTBeam2;\ + Float_t fDCCT24Beam1;\ + Float_t fDCCT24Beam2;\ + };" + + # Replace sizes if needed + gROOT.ProcessLine(structStr) + from ROOT import LBDataStruct + return LBDataStruct() + + # All BCID-dependent quantities + def initBCIDData(self): + + # Try this a different way + self.bcidArray = dict() + + # First get channel numbers from map + chanList = sorted(self.chanMap.keys()) + for chan in chanList: + + # First create some memory for this + self.bcidArray[chan] = array.array('f', self.nBCID*[0.]) + + # Next, create the branch + name = self.chanMap[chan] + format = '%s[%d]/F' % (name, self.nBCID) + self.tree.Branch(name, self.bcidArray[chan], format) + + # Do a few special extras also + self.bcidArray['Status'] = array.array('i', self.nBCID*[0]) + self.bcidArray['Beam1'] = array.array('f', self.nBCID*[0.]) + self.bcidArray['Beam2'] = array.array('f', self.nBCID*[0.]) + self.tree.Branch('Status', self.bcidArray['Status'], 'Status[3564]/I') + self.tree.Branch('Beam1', self.bcidArray['Beam1'], 'Beam1[3564]/F') + self.tree.Branch('Beam2', self.bcidArray['Beam2'], 'Beam2[3564]/F') + + if self.writeExtraCurrents: + self.bcidArray['BPTXBeam1'] = array.array('f', self.nBCID*[0.]) + self.bcidArray['BPTXBeam2'] = array.array('f', self.nBCID*[0.]) + self.tree.Branch('BPTXBeam1', self.bcidArray['BPTXBeam1'], 'BPTXBeam1[3564]/F') + self.tree.Branch('BPTXBeam2', self.bcidArray['BPTXBeam2'], 'BPTXBeam2[3564]/F') + + + def clearBCIDData(self): + + # Must use [:] to specify original location of array + # Without this, the memory location would change. + # Hope this is quicker than iterating and assigning each value to zero + for chan in self.bcidArray: + if chan == 'Status': + self.bcidArray[chan][:] = array.array('i', self.nBCID*[0]) + else: + self.bcidArray[chan][:] = array.array('f', self.nBCID*[0.]) + + + def fillBCIDData(self, chan, bcid, lraw): + + if chan not in self.chanMap.keys(): + print 'Unknown channel', chan + + # Fill our storage + self.bcidArray[chan][bcid] = lraw + + + def fillMoreCurrentData(self, obj): + + if 0 in obj: + self.lbDataStruct.fBPTXBeam1 = obj[0].payload()['Beam1IntensityAll'] + self.lbDataStruct.fBPTXBeam2 = obj[0].payload()['Beam2IntensityAll'] + + if 1 in obj: + self.lbDataStruct.fBCTBeam1 = obj[1].payload()['Beam1IntensityAll'] + self.lbDataStruct.fBCTBeam2 = obj[1].payload()['Beam2IntensityAll'] + + if 2 in obj: + self.lbDataStruct.fDCCTBeam1 = obj[2].payload()['Beam1IntensityAll'] + self.lbDataStruct.fDCCTBeam2 = obj[2].payload()['Beam2IntensityAll'] + + if 3 in obj: + self.lbDataStruct.fDCCT24Beam1 = obj[3].payload()['Beam1IntensityAll'] + self.lbDataStruct.fDCCT24Beam2 = obj[3].payload()['Beam2IntensityAll'] + + # Pass an IObject object for a single BUNCHDATA entry, and a MaskObj instance + def fillCurrentData(self, obj, mask, chan=1): + + blob1 = obj[chan].payload()['B1BunchIntensities'] + blob2 = obj[chan].payload()['B2BunchIntensities'] + + if blob1.size() != 0: + bcidVec, bcidVal = unpackBCIDValues(blob1, mask.beam1, obj[chan].payload()['B1BunchAverage']) + + for i in range(len(bcidVal)): + + bcid = bcidVec[i] + + # Protect against weird values + if bcid >= self.nBCID: + print 'BCID %d found in beam 1 current data!' % bcid + continue + + if chan==1: + self.bcidArray['Beam1'][bcid] = bcidVal[i] + elif chan==0: + self.bcidArray['BPTXBeam1'][bcid] = bcidVal[i] + + if blob2.size() != 0: + bcidVec, bcidVal = unpackBCIDValues(blob2, mask.beam2, obj[chan].payload()['B2BunchAverage']) + + for i in range(len(bcidVal)): + + bcid = bcidVec[i] + + # Protect against weird values + if bcid >= self.nBCID: + print 'BCID %d found in beam 2 current data!' % bcid + continue + + if chan==1: + self.bcidArray['Beam2'][bcid] = bcidVal[i] + elif chan==0: + self.bcidArray['BPTXBeam2'][bcid] = bcidVal[i] + +# Executed from the command line +if __name__ == '__main__': + mhm = CalibNtupleMaker() + mhm.execute() + + diff --git a/Database/CoolLumiUtilities/share/trigNtupleMaker.py b/Database/CoolLumiUtilities/share/trigNtupleMaker.py new file mode 100755 index 0000000000000000000000000000000000000000..3efefdbc0944c73a7c62f172a8ef34ace391a1ba --- /dev/null +++ b/Database/CoolLumiUtilities/share/trigNtupleMaker.py @@ -0,0 +1,297 @@ +#!/usr/bin/env python +# +# trigNtupleMaker.py +# +# Test application to make ntuple of trigger rates vs. luminosity. +# This assumes a proper ATLAS release has been set up. +# Script should be called in the main production directory. +# The needed directory structure will be set up if it doesn't already exist +# + +import os +import sys +import glob +import shutil +import filecmp +import datetime + +from optparse import OptionParser + +from CoolLumiUtilities.TriggerHandler import TriggerHandler, runLBString +from CoolLumiUtilities.TrigNtupleHandler import TrigNtupleHandler + +from CoolLumiUtilities.LumiDBHandler import LumiDBHandler +from CoolLumiUtilities.CoolDataReader import CoolDataReader +from CoolLumiUtilities.LumiDBCache import LumiDBCache + +from PyCool import cool + +class trigNtupleMaker: + + def __init__(self): + + # + # Steering booleans to control execution + # + + # Only ntuple atlasReady + self.ready = True + self.lumiChannel = 0 + self.lumiTag = 'OflLumi-8TeV-003' + + # Run helpers in verbose mode + self.verbose = True + + # List of specific fills or runs to update (only) + self.runList = [] + + # Utlity routine for handling COOL connections + self.dbHandler = LumiDBHandler() + + # Output directory for ntuple + self.outdir = '.' + + # For diagnostic output only + self.trigChan = 'L1_EM30' + + # Explicitly clean up our DB connections + def __del__(self): + self.dbHandler.closeAllDB() + + 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() + + 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="update specific run, or comma separated list.") + + parser.add_option("--notReady", + action="store_false", default=self.ready, dest="ready", + help="turn off AtlasReady requirement") + + parser.add_option("--lumiChan", + dest="lumichan", metavar="CHANNEL", default=self.lumiChannel, + help="specify luminosity channel (default %d)" % self.lumiChannel) + + parser.add_option("--lumiTag", + dest="lumitag", metavar="TAG", default=self.lumiTag, + help="specify luminosity tag (default %s)" % self.lumiTag) + + parser.add_option("-o", "--outputDirectory", + dest="outdir", metavar="DIR", default=self.outdir, + help="specify output directory (default %s)" % self.outdir) + + + parser.add_option("--trigChan", + dest="trigchan", metavar="CHAN", default=self.trigChan, + help="specify trigger channel for diagnostic output (default %s)" % self.trigChan) + + (options, args) = parser.parse_args() + + if options.help: + parser.print_help() + sys.exit() + + self.ready = options.ready + self.lumiChannel = int(options.lumichan) + self.lumiTag = options.lumitag + self.outdir = options.outdir + self.trigChan = options.trigchan + + if options.runList != None: + + # Parse list and enter into fill list + self.runList = self.parseRunString(options.runList) + + if len(self.runList) == 0: + print 'Invalid run list specified: %s!' % options.runList + sys.exit() + + print 'Processing runs:', self.runList + + # Parse any list of numbers including comma-separated values and ranges + def parseRunString(self, liststr): + + retlist = [] + tokenlist = liststr.split(',') + if len(tokenlist) == 0: + print 'Invalid list found:', liststr + return [] + + for valstr in tokenlist: + subvallist = valstr.split('-') + + if len(subvallist) == 1: # Single value + retlist.append(int(subvallist[0])) + + elif len(subvallist) == 2: # Range of values + for val in range(int(subvallist[0]), int(subvallist[1])+1): + retlist.append(val) + + else: # Too many parameters + print 'Invalid list segment found:', valstr + return [] + + # Make sure this is sorted + retlist.sort() + return retlist + + +# Executed from the command line +if __name__ == '__main__': + tnm = trigNtupleMaker() + tnm.execute() + + diff --git a/Database/CoolLumiUtilities/share/vdMScanMaker15.py b/Database/CoolLumiUtilities/share/vdMScanMaker15.py new file mode 100755 index 0000000000000000000000000000000000000000..1261d8f6d31569f6d10acfc51676de3120479095 --- /dev/null +++ b/Database/CoolLumiUtilities/share/vdMScanMaker15.py @@ -0,0 +1,269 @@ +#!/usr/bin/env python +# +# vdMScanMaker.py +# +# Main application script to generate ntuples of vdM scan data +# +import os +import sys +import shutil +import array +import time, calendar + +from optparse import OptionParser + +# Utility to unpack BCID blobs +from AtlDataSummary.AtlDataSumLumiData import LumiBCIDData + +# General COOL reader object +from CoolLumiUtilities.CoolDataReader import CoolDataReader + +# Get our global DB handler object +from CoolLumiUtilities.LumiDBHandler import LumiDBHandler + +# Ntuple definition +from CoolLumiUtilities.ScanNtupleHandler import ScanNtupleHandler + +from PyCool import cool + +from ROOT import TFile, TTree, gROOT, AddressOf + +# Simple utility for converting time strings +def timeVal(val): + "Convert argument to time in seconds, treating as a literal or date" + try: + a=int(val) + return a + + except ValueError: + try: + ts=time.strptime(val,'%Y-%m-%d:%H:%M:%S/%Z') + return int(calendar.timegm(ts))*1000000000L + + # Try again with UTC attached + except ValueError: + try: + ts=time.strptime(val+'/UTC', '%Y-%m-%d:%H:%M:%S/%Z') + return int(calendar.timegm(ts))*1000000000L + + except ValueError,e: + print "ERROR in time specification:",val,"- use e.g. 2007-05-25:14:01:00/UTC" + return None + +def timeString(iovkey): + # Convert the IOVkey (63 bit) to a string representing time stamp + if (iovkey == cool.ValidityKeyMin): + return 'ValidityKeyMin' + elif (iovkey == cool.ValidityKeyMax): + return 'ValidityKeyMax' + else: + stime=int(round(iovkey/1000000000L)) + return time.strftime('%Y-%m-%d:%H:%M:%S/UTC', time.gmtime(stime)) + + +class OflLumiMaker: + + def __init__(self): + + # Control output level + self.verbose = False + + # Output root file name + self.fileName = 'scan.root' + + # Location of scan data + self.tdaqDB = 'COOLONL_TDAQ/CONDBR2' + + 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 + + # 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() + + 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!)") + + (options, args) = parser.parse_args() + + if options.help: + parser.print_help() + sys.exit() + + self.verbose = options.verbose + self.ions = options.ions + + # 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() + + if self.verbose or True: + for obj in self.scanData.data: + run = obj.payload()['RunLB'] >> 32 + lb = obj.payload()['RunLB'] & 0xFFFFFFFF + print timeString(obj.since()), run, lb, (obj.until()-obj.since())/1E9, obj.payload()['StepProgress'], obj.payload()['ScanningIP'], obj.payload()['AcquisitionFlag'], obj.payload()['NominalSeparation'], 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 + self.bunchData = CoolDataReader(self.tdaqDB, self.bunchFolder) + + self.bunchData.setIOVRange(self.startTimeIOV, self.endTimeIOV) + 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 + 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() + +# Executed from the command line +if __name__ == '__main__': + olm = OflLumiMaker() + olm.execute() + + diff --git a/Database/CoolLumiUtilities/src/BunchDescription.cxx b/Database/CoolLumiUtilities/src/BunchDescription.cxx index 3c432e93ec99ad0021c7e434c5c8a026106a75b9..dd61cfe1ad38a03ffc4828757629d9ddd3017e99 100644 --- a/Database/CoolLumiUtilities/src/BunchDescription.cxx +++ b/Database/CoolLumiUtilities/src/BunchDescription.cxx @@ -76,7 +76,7 @@ BunchDescription::setValue(const coral::AttributeList& attrList) { // Decode beam1 list for (unsigned int i = 0; i < blobBC.size(); i++, p++) { - unsigned int tmp = *p; + //unsigned int tmp = *p; // std::cout << "The Data of BunchGroupContent is " << tmp << std::endl ; // std::cout << "BGC " << tmp << std::endl; m_bunchD.push_back(*p);