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);