diff --git a/Calorimeter/CaloRec/CMakeLists.txt b/Calorimeter/CaloRec/CMakeLists.txt
index 5a6e54f39775554cf3e1ba880d31c7647744453a..3eeb4ff05f3bdb2deee57e5fc79f680aa765585c 100644
--- a/Calorimeter/CaloRec/CMakeLists.txt
+++ b/Calorimeter/CaloRec/CMakeLists.txt
@@ -31,8 +31,10 @@ atlas_depends_on_subdirs(
    Calorimeter/CaloIdentifier
    Calorimeter/CaloInterface
    Calorimeter/CaloUtils
+   Calorimeter/CaloLumiConditions
    LArCalorimeter/LArTools
    LArCalorimeter/LArElecCalib
+   LArCalorimeter/LArIdentifier
    LArCalorimeter/LArRawConditions
    LumiBlock/LumiBlockComps
    Control/AthenaMonitoringKernel )
@@ -57,12 +59,13 @@ atlas_add_library( CaloRecLib
    Identifier xAODCaloEvent GaudiKernel CaloDetDescrLib CaloUtilsLib
    StoreGateLib LArToolsLib LumiBlockCompsLib AthenaMonitoringKernelLib
    PRIVATE_LINK_LIBRARIES ${ROOT_LIBRARIES} ${CORAL_LIBRARIES}
-   ${EIGEN_LIBRARIES} AthAllocators IdDictParser EventKernel
+   ${EIGEN_LIBRARIES} AthAllocators IdDictParser EventKernel CaloLumiConditions
+   LArRawConditions
    FourMom NavFourMom )
 
 atlas_add_component( CaloRec
    src/components/*.cxx
-   LINK_LIBRARIES CaloRecLib )
+   LINK_LIBRARIES CaloRecLib CaloLumiConditions )
 
 # Test(s) in the package:
 atlas_add_test( CaloClusterProcessor_test
@@ -80,9 +83,17 @@ atlas_add_test( CaloCellContainerFromClusterTool_test
    LINK_LIBRARIES CaloRecLib 
    ENVIRONMENT "JOBOPTSEARCHPATH=${CMAKE_CURRENT_SOURCE_DIR}/share" )
 
+atlas_add_test( CaloBCIDCoeffsCondAlg_test
+   SOURCES test/CaloBCIDCoeffsCondAlg_test.cxx
+   LINK_LIBRARIES CaloRecLib CaloLumiConditions LArRawConditions IdDictParser TestTools )
+
+atlas_add_test( CaloBCIDLumiCondAlg_test
+   SOURCES test/CaloBCIDLumiCondAlg_test.cxx
+   LINK_LIBRARIES CaloRecLib CaloLumiConditions LArRawConditions IdDictParser TestTools )
+
 # Install files from the package:
 atlas_install_python_modules( python/*.py )
-atlas_install_joboptions( share/*.py )
+atlas_install_joboptions( share/*.py share/*.txt )
 
 
 atlas_add_test( CaloBCIDAvgAlgConfig_test
@@ -90,6 +101,16 @@ atlas_add_test( CaloBCIDAvgAlgConfig_test
                 LOG_SELECT_PATTERN "ComponentAccumulator|^---|^IOVDbSvc" )
 
 
+atlas_add_test( CaloBCIDCoeffsCondAlgConfig_test
+                SCRIPT python -m CaloRec.CaloBCIDCoeffsCondAlgConfig
+                LOG_SELECT_PATTERN "ComponentAccumulator|^---|^IOVDbSvc" )
+
+
+atlas_add_test( CaloBCIDLumiCondAlgConfig_test
+                SCRIPT python -m CaloRec.CaloBCIDLumiCondAlgConfig
+                LOG_SELECT_PATTERN "ComponentAccumulator|^---|^IOVDbSvc" )
+
+
 atlas_add_test( CaloTopoClusterConfig_test
                 SCRIPT python -m CaloRec.CaloTopoClusterConfig
                 PROPERTIES TIMEOUT 300
diff --git a/Calorimeter/CaloRec/python/CaloBCIDAvgAlgDefault.py b/Calorimeter/CaloRec/python/CaloBCIDAvgAlgDefault.py
index 25294e33795945b9b71ef0b5023fb3be208ad8ab..af923f0f7d998d02e1563972097fe8e94bd8a12f 100644
--- a/Calorimeter/CaloRec/python/CaloBCIDAvgAlgDefault.py
+++ b/Calorimeter/CaloRec/python/CaloBCIDAvgAlgDefault.py
@@ -25,10 +25,12 @@ def CaloBCIDAvgAlgDefault():
             #Here we need a 32-sample, symmetrized shape. Therfore the re-key'ing and the dedicated LArPileUpShapeSymCondAlg
 
             from LArRecUtils.LArRecUtilsConf import LArSymConditionsAlg_LArMinBiasAverageMC_LArMinBiasAverageSym_ as LArMinBiasAverageSymAlg
-            condSeq+=LArMinBiasAverageSymAlg("LArPileUpAvgSymCondAlg",ReadKey="LArPileupAverage",WriteKey="LArPileupAverageSym")
+            if not hasattr (condSeq, 'LArPileUpAvgSymCondAlg'):
+                condSeq+=LArMinBiasAverageSymAlg("LArPileUpAvgSymCondAlg",ReadKey="LArPileupAverage",WriteKey="LArPileupAverageSym")
 
             from LArRecUtils.LArRecUtilsConf import LArSymConditionsAlg_LArShape32MC_LArShape32Sym_ as LArShapeSymAlg
-            condSeq+=LArShapeSymAlg("LArPileUpShapeSymCondAlg",ReadKey="LArShape32",WriteKey="LArShape32Sym")
+            if not hasattr (condSeq, 'LArPileUpShapeSymCondAlg'):
+                condSeq+=LArShapeSymAlg("LArPileUpShapeSymCondAlg",ReadKey="LArShape32",WriteKey="LArShape32Sym")
 
             topSequence+=CaloBCIDAvgAlg(isMC=False,
                                         LuminosityCondDataKey = lumiAlg.LuminosityOutputKey,
diff --git a/Calorimeter/CaloRec/python/CaloBCIDCoeffsCondAlgConfig.py b/Calorimeter/CaloRec/python/CaloBCIDCoeffsCondAlgConfig.py
new file mode 100644
index 0000000000000000000000000000000000000000..972582d2d0269b35a4144d18613c15b7a03e240b
--- /dev/null
+++ b/Calorimeter/CaloRec/python/CaloBCIDCoeffsCondAlgConfig.py
@@ -0,0 +1,95 @@
+# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+
+# File: CaloRec/python/CaloBCIDCoeffsCondAlgConfig.py
+# Created: Mar 2020, sss
+# Purpose: Configure CaloBCIDCoeffsCondAlg.
+
+from __future__ import print_function
+
+from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
+from AthenaConfiguration.ComponentFactory import CompFactory
+from IOVDbSvc.IOVDbSvcConfig import addFolderList
+
+
+def CaloBCIDCoeffsCondAlgCfg (flags):
+    result = ComponentAccumulator()
+
+    from LArRecUtils.LArRecUtilsConfig import LArMCSymCondAlgCfg
+    result.merge (LArMCSymCondAlgCfg (flags))
+
+    if flags.Input.isMC is False:
+        #For data, the regular shape is the 4-sample one used to Q-factor computation by LArRawChannelBuilder
+        #Here we need a 32-sample, symmetrized shape. Therfore the re-key'ing and the dedicated LArPileUpShapeSymCondAlg
+
+        if flags.Common.isOnline:
+            result.merge(addFolderList(flags, (('/LAR/LArPileup/LArPileupShape<key>LArShape32</key>', 'LAR_ONL', 'LArShape32MC'),
+                                               ('/LAR/LArPileup/LArPileupAverage','LAR_ONL','LArMinBiasAverageMC')) ))
+        else:
+            result.merge(addFolderList(flags, (('/LAR/ElecCalibOfl/LArPileupShape<key>LArShape32</key>','LAR_OFL','LArShape32MC'),
+                                               ('/LAR/ElecCalibOfl/LArPileupAverage','LAR_OFL','LArMinBiasAverageMC')) ))
+
+        from LArRecUtils.LArRecUtilsConf import LArSymConditionsAlg_LArMinBiasAverageMC_LArMinBiasAverageSym_ as LArMinBiasAverageSymAlg
+        result.addCondAlgo(LArMinBiasAverageSymAlg("LArPileUpAvgSymCondAlg",ReadKey="LArPileupAverage",WriteKey="LArPileupAverageSym"))
+
+        from LArRecUtils.LArRecUtilsConf import LArSymConditionsAlg_LArShape32MC_LArShape32Sym_ as LArShapeSymAlg
+        result.addCondAlgo(LArShapeSymAlg("LArPileUpShapeSymCondAlg",ReadKey="LArShape32",WriteKey="LArShape32Sym"))
+
+        ShapeKey = 'LArShape32Sym'
+    else:
+        from LArRecUtils.LArADC2MeVCondAlgConfig import LArADC2MeVCondAlgCfg
+        from LArRecUtils.LArRecUtilsConfig import LArOFCCondAlgCfg, LArAutoCorrTotalCondAlgCfg
+
+        result.merge (LArADC2MeVCondAlgCfg (flags))
+        result.merge (LArOFCCondAlgCfg (flags))
+        result.merge (LArAutoCorrTotalCondAlgCfg (flags))
+
+        result.merge(addFolderList(flags, (('/LAR/ElecCalibMC/Shape','LAR_OFL','LArShape32MC'), 
+                                           ('/LAR/ElecCalibMC/LArPileupAverage', 'LAR_OFL', 'LArMinBiasAverageMC')) ))
+                               
+
+        from LArRecUtils.LArRecUtilsConf import LArSymConditionsAlg_LArMinBiasAverageMC_LArMinBiasAverageSym_ as LArMinBiasAverageSymAlg
+        result.addCondAlgo(LArMinBiasAverageSymAlg("LArPileUpAvgSymCondAlg",ReadKey="LArPileupAverage",WriteKey="LArPileupAverageSym"))
+
+        ShapeKey = 'LArShapeSym'
+
+
+    CaloBCIDCoeffsCondAlg = CompFactory.CaloBCIDCoeffsCondAlg # CaloRec
+    alg = CaloBCIDCoeffsCondAlg ('CaloBCIDCoeffsCondAlg',
+                                 MCSymKey = 'LArMCSym',
+                                 OFCKey = 'LArOFC',
+                                 ShapeKey = ShapeKey,
+                                 MinBiasAvgKey = 'LArPileupAverageSym',
+                                 OutputCoeffsKey = 'CaloBCIDCoeffs')
+    result.addCondAlgo (alg)
+
+    return result
+
+
+if __name__ == "__main__":
+    from AthenaCommon.Configurable import Configurable
+    Configurable.configurableRun3Behavior = 1
+    from AthenaConfiguration.AllConfigFlags import ConfigFlags
+    from AthenaConfiguration.TestDefaults import defaultTestFiles
+    ConfigFlags.loadAllDynamicFlags()
+
+    only = ['CaloBCIDCoeffsCondAlg',
+            'LArPileUpAvgSymCondAlg',
+            'LArPileUpShapeSymCondAlg']
+
+    print ('--- data')
+    flags1 = ConfigFlags.clone()
+    flags1.Input.Files = defaultTestFiles.RAW
+    flags1.lock()
+    acc1 = CaloBCIDCoeffsCondAlgCfg (flags1)
+    acc1.printConfig(summariseProps=True, onlyComponents=only)
+    print ('IOVDbSvc:', acc1.getService('IOVDbSvc').Folders)
+    acc1.wasMerged()
+
+    print ('--- mc')
+    flags2 = ConfigFlags.clone()
+    flags2.Input.Files = defaultTestFiles.ESD
+    flags2.lock()
+    acc2 = CaloBCIDCoeffsCondAlgCfg (flags2)
+    acc2.printConfig(summariseProps=True, onlyComponents=only)
+    print ('IOVDbSvc:', acc2.getService('IOVDbSvc').Folders)
+    acc2.wasMerged()
diff --git a/Calorimeter/CaloRec/python/CaloBCIDCoeffsCondAlgDefault.py b/Calorimeter/CaloRec/python/CaloBCIDCoeffsCondAlgDefault.py
new file mode 100644
index 0000000000000000000000000000000000000000..c7e900c112fa4ac41bea3a52bd49de7424c1529b
--- /dev/null
+++ b/Calorimeter/CaloRec/python/CaloBCIDCoeffsCondAlgDefault.py
@@ -0,0 +1,70 @@
+# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+
+# File: CaloRec/python/CaloBCIDCoeffsCondAlgDefault.py
+# Created: Mar 2020, sss
+# Purpose: Configure CaloBCIDCoeffsCondAlg.
+
+
+from AthenaCommon.AlgSequence import AthSequencer
+from AthenaConfiguration.ComponentFactory import CompFactory
+
+
+def CaloBCIDCoeffsCondAlgDefault():
+    from AthenaCommon.GlobalFlags import globalflags
+    from IOVDbSvc.CondDB import conddb
+    from AthenaCommon.AthenaCommonFlags import athenaCommonFlags
+
+    name = 'CaloBCIDCoeffsCondAlg'
+    condSeq = AthSequencer ('AthCondSeq')
+
+    if hasattr (condSeq, name):
+        return getattr (condSeq, name)
+
+    from LArRecUtils.LArMCSymCondAlg import LArMCSymCondAlgDefault
+    LArMCSymCondAlgDefault()
+
+    if globalflags.DataSource()=='data':
+        if athenaCommonFlags.isOnline:
+            conddb.addFolder("LAR_ONL","/LAR/LArPileup/LArPileupShape<key>LArShape32</key>",className="LArShape32MC")
+            conddb.addFolder("LAR_ONL","/LAR/LArPileup/LArPileupAverage",className="LArMinBiasAverageMC")
+        else:
+            conddb.addFolder("LAR_OFL","/LAR/ElecCalibOfl/LArPileupShape<key>LArShape32</key>",className="LArShape32MC")
+            conddb.addFolder("LAR_OFL","/LAR/ElecCalibOfl/LArPileupAverage",className="LArMinBiasAverageMC")
+
+        #For data, the regular shape is the 4-sample one used to Q-factor computation by LArRawChannelBuilder
+        #Here we need a 32-sample, symmetrized shape. Therfore the re-key'ing and the dedicated LArPileUpShapeSymCondAlg
+
+        from LArRecUtils.LArRecUtilsConf import LArSymConditionsAlg_LArMinBiasAverageMC_LArMinBiasAverageSym_ as LArMinBiasAverageSymAlg
+        if not hasattr (condSeq, 'LArPileUpAvgSymCondAlg'):
+            condSeq+=LArMinBiasAverageSymAlg("LArPileUpAvgSymCondAlg",ReadKey="LArPileupAverage",WriteKey="LArPileupAverageSym")
+
+        from LArRecUtils.LArRecUtilsConf import LArSymConditionsAlg_LArShape32MC_LArShape32Sym_ as LArShapeSymAlg
+        if not hasattr (condSeq, 'LArPileUpShapeSymCondAlg'):
+            condSeq+=LArShapeSymAlg("LArPileUpShapeSymCondAlg",ReadKey="LArShape32",WriteKey="LArShape32Sym")
+
+        ShapeKey = 'LArShape32Sym'
+    else: #MC case
+        from LArRecUtils.LArOFCCondAlgDefault import LArOFCCondAlgDefault
+        from LArRecUtils.LArAutoCorrTotalCondAlgDefault import  LArAutoCorrTotalCondAlgDefault
+        from LArRecUtils.LArADC2MeVCondAlgDefault import LArADC2MeVCondAlgDefault
+        LArADC2MeVCondAlgDefault()
+        LArAutoCorrTotalCondAlgDefault()
+        LArOFCCondAlgDefault()
+        conddb.addFolder("LAR_OFL","/LAR/ElecCalibMC/LArPileupAverage",className="LArMinBiasAverageMC")
+
+        from LArRecUtils.LArRecUtilsConf import LArSymConditionsAlg_LArMinBiasAverageMC_LArMinBiasAverageSym_ as LArMinBiasAverageSymAlg
+        condSeq+=LArMinBiasAverageSymAlg("LArPileUpAvgSymCondAlg",ReadKey="LArPileupAverage",WriteKey="LArPileupAverageSym")
+
+        ShapeKey = 'LArShapeSym'
+
+    CaloBCIDCoeffsCondAlg = CompFactory.CaloBCIDCoeffsCondAlg # CaloRec
+    alg = CaloBCIDCoeffsCondAlg (name,
+                                 MCSymKey = 'LArMCSym',
+                                 OFCKey = 'LArOFC',
+                                 ShapeKey = ShapeKey,
+                                 MinBiasAvgKey = 'LArPileupAverageSym',
+                                 OutputCoeffsKey = 'CaloBCIDCoeffs')
+    condSeq += alg
+    return alg
+
+    
diff --git a/Calorimeter/CaloRec/python/CaloBCIDLumiCondAlgConfig.py b/Calorimeter/CaloRec/python/CaloBCIDLumiCondAlgConfig.py
new file mode 100644
index 0000000000000000000000000000000000000000..6745a93f43c4715c270f6bf330f8472f81641c5e
--- /dev/null
+++ b/Calorimeter/CaloRec/python/CaloBCIDLumiCondAlgConfig.py
@@ -0,0 +1,68 @@
+# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+
+# File: CaloRec/python/CaloBCIDLumiCondAlgConfig.py
+# Created: Mar 2020, sss
+# Purpose: Configure CaloBCIDLumiCondAlg.
+
+from __future__ import print_function
+
+from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
+from AthenaConfiguration.ComponentFactory import CompFactory
+
+
+def CaloBCIDLumiCondAlgCfg (flags):
+    result = ComponentAccumulator()
+
+    from CaloRec.CaloBCIDCoeffsCondAlgConfig import CaloBCIDCoeffsCondAlgCfg
+    result.merge (CaloBCIDCoeffsCondAlgCfg (flags))
+
+    if flags.Input.isMC is False:
+        from LumiBlockComps.LuminosityCondAlgConfig import LuminosityCondAlgCfg
+        result.merge (LuminosityCondAlgCfg (flags))
+
+    else:
+        from LumiBlockComps.BunchCrossingCondAlgConfig import BunchCrossingCondAlgCfg
+        result.merge (BunchCrossingCondAlgCfg(flags))
+
+
+    CaloBCIDLumiCondAlg = CompFactory.CaloBCIDLumiCondAlg # CaloRec
+    alg = CaloBCIDLumiCondAlg ('CaloBCIDLumiCondAlg',
+                               CoeffsKey = 'CaloBCIDCoeffs',
+                               BunchCrossingCondDataKey = 'BunchCrossingData',
+                               LuminosityCondDataKey = 'LuminosityCondData',
+                               isMC = flags.Input.isMC,
+                               OutputLumiKey = 'CaloBCIDLumi')
+    result.addCondAlgo (alg)
+
+    return result
+
+
+if __name__ == "__main__":
+    from AthenaCommon.Configurable import Configurable
+    Configurable.configurableRun3Behavior = 1
+    from AthenaConfiguration.AllConfigFlags import ConfigFlags
+    from AthenaConfiguration.TestDefaults import defaultTestFiles
+    ConfigFlags.loadAllDynamicFlags()
+
+    only = ['CaloBCIDCoeffsCondAlg',
+            'CaloBCIDLumiCondAlg',
+            'LuminosityCondAlg',
+            'BunchCrossingCondAlg']
+
+    print ('--- data')
+    flags1 = ConfigFlags.clone()
+    flags1.Input.Files = defaultTestFiles.RAW
+    flags1.lock()
+    acc1 = CaloBCIDLumiCondAlgCfg (flags1)
+    acc1.printConfig(summariseProps=True, onlyComponents=only)
+    print ('IOVDbSvc:', acc1.getService('IOVDbSvc').Folders)
+    acc1.wasMerged()
+
+    print ('--- mc')
+    flags2 = ConfigFlags.clone()
+    flags2.Input.Files = defaultTestFiles.ESD
+    flags2.lock()
+    acc2 = CaloBCIDLumiCondAlgCfg (flags2)
+    acc2.printConfig(summariseProps=True, onlyComponents=only)
+    print ('IOVDbSvc:', acc2.getService('IOVDbSvc').Folders)
+    acc2.wasMerged()
diff --git a/Calorimeter/CaloRec/python/CaloBCIDLumiCondAlgDefault.py b/Calorimeter/CaloRec/python/CaloBCIDLumiCondAlgDefault.py
new file mode 100644
index 0000000000000000000000000000000000000000..25485f71b01775e271077b0c406a5610d5003ccb
--- /dev/null
+++ b/Calorimeter/CaloRec/python/CaloBCIDLumiCondAlgDefault.py
@@ -0,0 +1,41 @@
+# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+
+# File: CaloRec/python/CaloBCIDLumiCondAlgDefault.py
+# Created: Mar 2020, sss
+# Purpose: Configure CaloBCIDLumiCondAlg.
+
+
+from AthenaCommon.AlgSequence import AthSequencer
+from AthenaConfiguration.ComponentFactory import CompFactory
+
+
+def CaloBCIDLumiCondAlgDefault():
+    from AthenaCommon.GlobalFlags import globalflags
+
+    name = 'CaloBCIDLumiCondAlg'
+    condSeq = AthSequencer ('AthCondSeq')
+
+    if hasattr (condSeq, name):
+        return getattr (condSeq, name)
+
+    from CaloRec.CaloBCIDCoeffsCondAlgDefault import CaloBCIDCoeffsCondAlgDefault
+    CaloBCIDCoeffsCondAlgDefault()
+
+    if globalflags.DataSource()=='data':
+        from LumiBlockComps.LuminosityCondAlgDefault import LuminosityCondAlgDefault
+        LuminosityCondAlgDefault()
+    else: #MC case
+        from LumiBlockComps.BunchCrossingCondAlgDefault import BunchCrossingCondAlgDefault
+        BunchCrossingCondAlgDefault()
+
+    CaloBCIDLumiCondAlg = CompFactory.CaloBCIDLumiCondAlg # CaloRec
+    alg = CaloBCIDLumiCondAlg (name,
+                               CoeffsKey = 'CaloBCIDCoeffs',
+                               BunchCrossingCondDataKey = 'BunchCrossingData',
+                               LuminosityCondDataKey = 'LuminosityCondData',
+                               isMC = globalflags.DataSource()!='data',
+                               OutputLumiKey = 'CaloBCIDLumi')
+    condSeq += alg
+    return alg
+
+    
diff --git a/Calorimeter/CaloRec/share/CaloBCIDCoeffsCondAlgConfig_test.ref b/Calorimeter/CaloRec/share/CaloBCIDCoeffsCondAlgConfig_test.ref
new file mode 100644
index 0000000000000000000000000000000000000000..3161436ebc66a66bca0d9e89bf8e14d26b9d13de
--- /dev/null
+++ b/Calorimeter/CaloRec/share/CaloBCIDCoeffsCondAlgConfig_test.ref
@@ -0,0 +1,75 @@
+Py:ConfigurableDb    INFO Read module info for 5154 configurables from 2 genConfDb files
+Py:ConfigurableDb    INFO No duplicates have been found: that's good !
+Py:Athena            INFO using release [?-21.0.0] [?] [?/?] -- built on [?]
+--- data
+Py:AutoConfigFlags    INFO Obtaining metadata of auto-configuration by peeking into /home/sss/nobackup/referencefiles/TrigP1Test/data17_13TeV.00327265.physics_EnhancedBias.merge.RAW._lb0100._SFO-1._0001.1
+Py:MetaReader        INFO Current mode used: peeker
+Py:MetaReader        INFO Current filenames: ['/home/sss/nobackup/referencefiles/TrigP1Test/data17_13TeV.00327265.physics_EnhancedBias.merge.RAW._lb0100._SFO-1._0001.1']
+Py:ComponentAccumulator    INFO Event Inputs
+Py:ComponentAccumulator    INFO Event Algorithm Sequences
+Py:ComponentAccumulator    INFO Top sequence 0
+Py:ComponentAccumulator    INFO \__ AthAlgSeq (seq: SEQ AND)
+Py:ComponentAccumulator    INFO Condition Algorithms
+Py:ComponentAccumulator    INFO  \__ LArPileUpAvgSymCondAlg (cond alg)
+Py:ComponentAccumulator    INFO      * ReadKey: LArPileupAverage
+Py:ComponentAccumulator    INFO      * WriteKey: LArPileupAverageSym
+Py:ComponentAccumulator    INFO  \__ LArPileUpShapeSymCondAlg (cond alg)
+Py:ComponentAccumulator    INFO      * ReadKey: LArShape32
+Py:ComponentAccumulator    INFO      * WriteKey: LArShape32Sym
+Py:ComponentAccumulator    INFO  \__ CaloBCIDCoeffsCondAlg (cond alg)
+Py:ComponentAccumulator    INFO      * MCSymKey: LArMCSym
+Py:ComponentAccumulator    INFO      * MinBiasAvgKey: LArPileupAverageSym
+Py:ComponentAccumulator    INFO      * OFCKey: LArOFC
+Py:ComponentAccumulator    INFO      * OutputCoeffsKey: CaloBCIDCoeffs
+Py:ComponentAccumulator    INFO      * ShapeKey: LArShape32Sym
+Py:ComponentAccumulator    INFO Services
+Py:ComponentAccumulator    INFO []
+Py:ComponentAccumulator    INFO Public Tools
+Py:ComponentAccumulator    INFO [
+Py:ComponentAccumulator    INFO ]
+Py:ComponentAccumulator    INFO Private Tools
+Py:ComponentAccumulator    INFO [
+Py:ComponentAccumulator    INFO ]
+Py:ComponentAccumulator    INFO TheApp properties
+IOVDbSvc: ['/LAR/ElecCalibOfl/LArPileupShape<key>LArShape32</key><db>COOLOFL_LAR/CONDBR2</db>', '/LAR/ElecCalibOfl/LArPileupAverage<db>COOLOFL_LAR/CONDBR2</db>']
+--- mc
+Py:AutoConfigFlags    INFO Obtaining metadata of auto-configuration by peeking into /home/sss/nobackup/referencefiles/RecExRecoTest/mc16_13TeV.361022.Pythia8EvtGen_A14NNPDF23LO_jetjet_JZ2W.recon.ESD.e3668_s3170_r10572_homeMade.pool.root
+Py:MetaReader        INFO Current mode used: peeker
+Py:MetaReader        INFO Current filenames: ['/home/sss/nobackup/referencefiles/RecExRecoTest/mc16_13TeV.361022.Pythia8EvtGen_A14NNPDF23LO_jetjet_JZ2W.recon.ESD.e3668_s3170_r10572_homeMade.pool.root']
+Py:MetaReader        INFO MetaReader is called with the parameter "unique_tag_info_values" set to True. This is a workaround to remove all duplicate values from "/TagInfo" key
+Py:LArOFCCondAlgCfg    INFO  entering LArOFCCondAlgCfg
+Py:LArOFCCondAlgCfg    INFO  no pileup optimization
+Py:LArAutoCorrTotalCondAlgCfg    INFO  entering LArAutoCorrTotalCondAlgCfg
+Py:LArAutoCorrTotalCondAlgCfg    INFO Nsamples 5
+Py:LArAutoCorrTotalCondAlgCfg    INFO firstSample 0
+Py:LArAutoCorrTotalCondAlgCfg    INFO DeltaBunch 1 
+Py:LArAutoCorrTotalCondAlgCfg    INFO  no pileup noise in LArAutoCorrTotal 
+Py:LArAutoCorrTotalCondAlgCfg    INFO  entering LArAutoCorrTotalCondAlgCfg
+Py:LArAutoCorrTotalCondAlgCfg    INFO Nsamples 5
+Py:LArAutoCorrTotalCondAlgCfg    INFO firstSample 0
+Py:LArAutoCorrTotalCondAlgCfg    INFO DeltaBunch 1 
+Py:LArAutoCorrTotalCondAlgCfg    INFO  no pileup noise in LArAutoCorrTotal 
+Py:ComponentAccumulator    INFO Event Inputs
+Py:ComponentAccumulator    INFO Event Algorithm Sequences
+Py:ComponentAccumulator    INFO Top sequence 0
+Py:ComponentAccumulator    INFO \__ AthAlgSeq (seq: SEQ AND)
+Py:ComponentAccumulator    INFO Condition Algorithms
+Py:ComponentAccumulator    INFO  \__ LArPileUpAvgSymCondAlg (cond alg)
+Py:ComponentAccumulator    INFO      * ReadKey: LArPileupAverage
+Py:ComponentAccumulator    INFO      * WriteKey: LArPileupAverageSym
+Py:ComponentAccumulator    INFO  \__ CaloBCIDCoeffsCondAlg (cond alg)
+Py:ComponentAccumulator    INFO      * MCSymKey: LArMCSym
+Py:ComponentAccumulator    INFO      * MinBiasAvgKey: LArPileupAverageSym
+Py:ComponentAccumulator    INFO      * OFCKey: LArOFC
+Py:ComponentAccumulator    INFO      * OutputCoeffsKey: CaloBCIDCoeffs
+Py:ComponentAccumulator    INFO      * ShapeKey: LArShapeSym
+Py:ComponentAccumulator    INFO Services
+Py:ComponentAccumulator    INFO []
+Py:ComponentAccumulator    INFO Public Tools
+Py:ComponentAccumulator    INFO [
+Py:ComponentAccumulator    INFO ]
+Py:ComponentAccumulator    INFO Private Tools
+Py:ComponentAccumulator    INFO [
+Py:ComponentAccumulator    INFO ]
+Py:ComponentAccumulator    INFO TheApp properties
+IOVDbSvc: ['/LAR/Identifier/OnOffIdMap<tag>LARIdentifierOnOffIdMap-012</tag><db>COOLOFL_LAR/OFLP200</db>', '/LAR/Align<db>COOLOFL_LAR/OFLP200</db>', '/LAR/LArCellPositionShift<db>COOLOFL_LAR/OFLP200</db>', '/LAR/ElecCalibMC/Ramp<db>COOLOFL_LAR/OFLP200</db>', '/LAR/ElecCalibMC/DAC2uA<db>COOLOFL_LAR/OFLP200</db>', '/LAR/ElecCalibMC/uA2MeV<db>COOLOFL_LAR/OFLP200</db>', '/LAR/ElecCalibMC/MphysOverMcal<db>COOLOFL_LAR/OFLP200</db>', '/LAR/ElecCalibMC/HVScaleCorr<db>COOLOFL_LAR/OFLP200</db>', '/LAR/ElecCalibMC/Shape<db>COOLOFL_LAR/OFLP200</db>', '/LAR/ElecCalibMC/Noise<db>COOLOFL_LAR/OFLP200</db>', '/LAR/ElecCalibMC/Pedestal<db>COOLOFL_LAR/OFLP200</db>', '/LAR/ElecCalibMC/AutoCorr<db>COOLOFL_LAR/OFLP200</db>', '/LAR/ElecCalibMC/fSampl<db>COOLOFL_LAR/OFLP200</db>', '/LAR/ElecCalibMC/MinBias<db>COOLOFL_LAR/OFLP200</db>', '/LAR/ElecCalibMC/LArPileupAverage<db>COOLOFL_LAR/OFLP200</db>']
diff --git a/Calorimeter/CaloRec/share/CaloBCIDCoeffsCondAlg_test.ref b/Calorimeter/CaloRec/share/CaloBCIDCoeffsCondAlg_test.ref
new file mode 100644
index 0000000000000000000000000000000000000000..c2121a95e66ecfa49a0d426e3723e09db927e8ab
--- /dev/null
+++ b/Calorimeter/CaloRec/share/CaloBCIDCoeffsCondAlg_test.ref
@@ -0,0 +1,27 @@
+CaloRec/CaloBCIDCoeffsCondAlg_test
+
+
+Initializing Gaudi ApplicationMgr using job opts /gpfs/mnt/atlasgpfs01/usatlas/data/snyder/atlas-master-acas-c/build-x86_64-centos7-gcc8-opt/x86_64-centos7-gcc8-opt/jobOptions/CaloRec/CaloBCIDTests.txt
+JobOptionsSvc        INFO # =======> /gpfs/mnt/atlasgpfs01/usatlas/data/snyder/atlas-master-acas-c/build-x86_64-centos7-gcc8-opt/x86_64-centos7-gcc8-opt/jobOptions/CaloRec/CaloBCIDTests.txt
+JobOptionsSvc        INFO # (1,1): ApplicationMgr.ExtSvc += ["StoreGateSvc/DetectorStore"]
+JobOptionsSvc        INFO # (2,1): ApplicationMgr.ExtSvc += ["StoreGateSvc/ConditionStore"]
+JobOptionsSvc        INFO # (4,1): CaloBCIDLumiCondAlgMC.isMC = 1
+JobOptionsSvc        INFO # (5,1): CaloBCIDLumiCondAlgMC.OutputLumiKey = "CaloBCIDLumiMC"
+JobOptionsSvc        INFO # (6,1): CaloBCIDLumiCondAlgData.isMC = 0
+JobOptionsSvc        INFO # (7,1): CaloBCIDLumiCondAlgData.OutputLumiKey = "CaloBCIDLumiData"
+JobOptionsSvc        INFO Job options successfully read in from /gpfs/mnt/atlasgpfs01/usatlas/data/snyder/atlas-master-acas-c/build-x86_64-centos7-gcc8-opt/x86_64-centos7-gcc8-opt/jobOptions/CaloRec/CaloBCIDTests.txt
+ApplicationMgr    SUCCESS 
+====================================================================================================================================
+                                                   Welcome to ApplicationMgr (GaudiCoreSvc v33r1)
+                                          running on spar0103.usatlas.bnl.gov on Mon Mar 30 11:20:20 2020
+====================================================================================================================================
+ApplicationMgr       INFO Application Manager Configured successfully
+ClassIDSvc           INFO  getRegistryEntries: read 9577 CLIDRegistry entries for module ALL
+EventLoopMgr      WARNING Unable to locate service "EventSelector" 
+EventLoopMgr      WARNING No events will be processed from external input.
+ApplicationMgr       INFO Application Manager Initialized successfully
+ApplicationMgr Ready
+LArMiniFCAL_ID       INFO  initialize_from_dict - LArCalorimeter dictionary does NOT contain miniFCAL description. Unable to initialize LArMiniFCAL_ID.
+test1
+ClassIDSvc           INFO  getRegistryEntries: read 372 CLIDRegistry entries for module ALL
+CaloBCIDCoeffsC...   INFO recorded new CaloBCIDCoeffs with range {[10,t:0,l:20] - [10,l:75]}
diff --git a/Calorimeter/CaloRec/share/CaloBCIDLumiCondAlgConfig_test.ref b/Calorimeter/CaloRec/share/CaloBCIDLumiCondAlgConfig_test.ref
new file mode 100644
index 0000000000000000000000000000000000000000..46f1bbb288cc9c9b834c09e7e661dd4f8888f77d
--- /dev/null
+++ b/Calorimeter/CaloRec/share/CaloBCIDLumiCondAlgConfig_test.ref
@@ -0,0 +1,91 @@
+Py:ConfigurableDb    INFO Read module info for 5154 configurables from 2 genConfDb files
+Py:ConfigurableDb    INFO No duplicates have been found: that's good !
+Py:Athena            INFO using release [?-21.0.0] [?] [?/?] -- built on [?]
+--- data
+Py:AutoConfigFlags    INFO Obtaining metadata of auto-configuration by peeking into /home/sss/nobackup/referencefiles/TrigP1Test/data17_13TeV.00327265.physics_EnhancedBias.merge.RAW._lb0100._SFO-1._0001.1
+Py:MetaReader        INFO Current mode used: peeker
+Py:MetaReader        INFO Current filenames: ['/home/sss/nobackup/referencefiles/TrigP1Test/data17_13TeV.00327265.physics_EnhancedBias.merge.RAW._lb0100._SFO-1._0001.1']
+Py:LuminosityCondAlg    INFO luminosityCondAlgRun2Config requested /TRIGGER/OFLLUMI/OflPrefLumi
+Py:LuminosityCondAlg    INFO Created Run2 LuminosityCondAlg using folder /TRIGGER/OFLLUMI/OflPrefLumi
+Py:ComponentAccumulator    INFO Event Inputs
+Py:ComponentAccumulator    INFO Event Algorithm Sequences
+Py:ComponentAccumulator    INFO Top sequence 0
+Py:ComponentAccumulator    INFO \__ AthAlgSeq (seq: SEQ AND)
+Py:ComponentAccumulator    INFO Condition Algorithms
+Py:ComponentAccumulator    INFO  \__ CaloBCIDCoeffsCondAlg (cond alg)
+Py:ComponentAccumulator    INFO      * MCSymKey: LArMCSym
+Py:ComponentAccumulator    INFO      * MinBiasAvgKey: LArPileupAverageSym
+Py:ComponentAccumulator    INFO      * OFCKey: LArOFC
+Py:ComponentAccumulator    INFO      * OutputCoeffsKey: CaloBCIDCoeffs
+Py:ComponentAccumulator    INFO      * ShapeKey: LArShape32Sym
+Py:ComponentAccumulator    INFO  \__ LuminosityCondAlg (cond alg)
+Py:ComponentAccumulator    INFO      * BunchGroupInputKey: 
+Py:ComponentAccumulator    INFO      * BunchLumisInputKey: 
+Py:ComponentAccumulator    INFO      * FillParamsInputKey: 
+Py:ComponentAccumulator    INFO      * LuminosityFolderInputKey: /TRIGGER/OFLLUMI/OflPrefLumi
+Py:ComponentAccumulator    INFO      * LuminosityOutputKey: LuminosityCondData
+Py:ComponentAccumulator    INFO      * OnlineLumiCalibrationInputKey: OnlineLumiCalibrationCondData
+Py:ComponentAccumulator    INFO  \__ CaloBCIDLumiCondAlg (cond alg)
+Py:ComponentAccumulator    INFO      * BunchCrossingCondDataKey: BunchCrossingData
+Py:ComponentAccumulator    INFO      * CoeffsKey: CaloBCIDCoeffs
+Py:ComponentAccumulator    INFO      * LuminosityCondDataKey: LuminosityCondData
+Py:ComponentAccumulator    INFO      * OutputLumiKey: CaloBCIDLumi
+Py:ComponentAccumulator    INFO      * isMC: False
+Py:ComponentAccumulator    INFO Services
+Py:ComponentAccumulator    INFO []
+Py:ComponentAccumulator    INFO Public Tools
+Py:ComponentAccumulator    INFO [
+Py:ComponentAccumulator    INFO ]
+Py:ComponentAccumulator    INFO Private Tools
+Py:ComponentAccumulator    INFO [
+Py:ComponentAccumulator    INFO ]
+Py:ComponentAccumulator    INFO TheApp properties
+IOVDbSvc: ['/LAR/ElecCalibOfl/LArPileupShape<key>LArShape32</key><db>COOLOFL_LAR/CONDBR2</db>', '/LAR/ElecCalibOfl/LArPileupAverage<db>COOLOFL_LAR/CONDBR2</db>', '/TRIGGER/OFLLUMI/OflPrefLumi<db>COOLOFL_TRIGGER/CONDBR2</db>', '/TDAQ/OLC/CALIBRATIONS<db>COOLONL_TDAQ/CONDBR2</db>']
+--- mc
+Py:AutoConfigFlags    INFO Obtaining metadata of auto-configuration by peeking into /home/sss/nobackup/referencefiles/RecExRecoTest/mc16_13TeV.361022.Pythia8EvtGen_A14NNPDF23LO_jetjet_JZ2W.recon.ESD.e3668_s3170_r10572_homeMade.pool.root
+Py:MetaReader        INFO Current mode used: peeker
+Py:MetaReader        INFO Current filenames: ['/home/sss/nobackup/referencefiles/RecExRecoTest/mc16_13TeV.361022.Pythia8EvtGen_A14NNPDF23LO_jetjet_JZ2W.recon.ESD.e3668_s3170_r10572_homeMade.pool.root']
+Py:MetaReader        INFO MetaReader is called with the parameter "unique_tag_info_values" set to True. This is a workaround to remove all duplicate values from "/TagInfo" key
+Py:LArOFCCondAlgCfg    INFO  entering LArOFCCondAlgCfg
+Py:LArOFCCondAlgCfg    INFO  no pileup optimization
+Py:LArAutoCorrTotalCondAlgCfg    INFO  entering LArAutoCorrTotalCondAlgCfg
+Py:LArAutoCorrTotalCondAlgCfg    INFO Nsamples 5
+Py:LArAutoCorrTotalCondAlgCfg    INFO firstSample 0
+Py:LArAutoCorrTotalCondAlgCfg    INFO DeltaBunch 1 
+Py:LArAutoCorrTotalCondAlgCfg    INFO  no pileup noise in LArAutoCorrTotal 
+Py:LArAutoCorrTotalCondAlgCfg    INFO  entering LArAutoCorrTotalCondAlgCfg
+Py:LArAutoCorrTotalCondAlgCfg    INFO Nsamples 5
+Py:LArAutoCorrTotalCondAlgCfg    INFO firstSample 0
+Py:LArAutoCorrTotalCondAlgCfg    INFO DeltaBunch 1 
+Py:LArAutoCorrTotalCondAlgCfg    INFO  no pileup noise in LArAutoCorrTotal 
+Py:ComponentAccumulator    INFO Event Inputs
+Py:ComponentAccumulator    INFO Event Algorithm Sequences
+Py:ComponentAccumulator    INFO Top sequence 0
+Py:ComponentAccumulator    INFO \__ AthAlgSeq (seq: SEQ AND)
+Py:ComponentAccumulator    INFO Condition Algorithms
+Py:ComponentAccumulator    INFO  \__ CaloBCIDCoeffsCondAlg (cond alg)
+Py:ComponentAccumulator    INFO      * MCSymKey: LArMCSym
+Py:ComponentAccumulator    INFO      * MinBiasAvgKey: LArPileupAverageSym
+Py:ComponentAccumulator    INFO      * OFCKey: LArOFC
+Py:ComponentAccumulator    INFO      * OutputCoeffsKey: CaloBCIDCoeffs
+Py:ComponentAccumulator    INFO      * ShapeKey: LArShapeSym
+Py:ComponentAccumulator    INFO  \__ BunchCrossingCondAlg (cond alg)
+Py:ComponentAccumulator    INFO      * FillParamsFolderKey: /Digitization/Parameters
+Py:ComponentAccumulator    INFO      * Run1: False
+Py:ComponentAccumulator    INFO      * isMC: True
+Py:ComponentAccumulator    INFO  \__ CaloBCIDLumiCondAlg (cond alg)
+Py:ComponentAccumulator    INFO      * BunchCrossingCondDataKey: BunchCrossingData
+Py:ComponentAccumulator    INFO      * CoeffsKey: CaloBCIDCoeffs
+Py:ComponentAccumulator    INFO      * LuminosityCondDataKey: LuminosityCondData
+Py:ComponentAccumulator    INFO      * OutputLumiKey: CaloBCIDLumi
+Py:ComponentAccumulator    INFO      * isMC: True
+Py:ComponentAccumulator    INFO Services
+Py:ComponentAccumulator    INFO []
+Py:ComponentAccumulator    INFO Public Tools
+Py:ComponentAccumulator    INFO [
+Py:ComponentAccumulator    INFO ]
+Py:ComponentAccumulator    INFO Private Tools
+Py:ComponentAccumulator    INFO [
+Py:ComponentAccumulator    INFO ]
+Py:ComponentAccumulator    INFO TheApp properties
+IOVDbSvc: ['/LAR/Identifier/OnOffIdMap<tag>LARIdentifierOnOffIdMap-012</tag><db>COOLOFL_LAR/OFLP200</db>', '/LAR/Align<db>COOLOFL_LAR/OFLP200</db>', '/LAR/LArCellPositionShift<db>COOLOFL_LAR/OFLP200</db>', '/LAR/ElecCalibMC/Ramp<db>COOLOFL_LAR/OFLP200</db>', '/LAR/ElecCalibMC/DAC2uA<db>COOLOFL_LAR/OFLP200</db>', '/LAR/ElecCalibMC/uA2MeV<db>COOLOFL_LAR/OFLP200</db>', '/LAR/ElecCalibMC/MphysOverMcal<db>COOLOFL_LAR/OFLP200</db>', '/LAR/ElecCalibMC/HVScaleCorr<db>COOLOFL_LAR/OFLP200</db>', '/LAR/ElecCalibMC/Shape<db>COOLOFL_LAR/OFLP200</db>', '/LAR/ElecCalibMC/Noise<db>COOLOFL_LAR/OFLP200</db>', '/LAR/ElecCalibMC/Pedestal<db>COOLOFL_LAR/OFLP200</db>', '/LAR/ElecCalibMC/AutoCorr<db>COOLOFL_LAR/OFLP200</db>', '/LAR/ElecCalibMC/fSampl<db>COOLOFL_LAR/OFLP200</db>', '/LAR/ElecCalibMC/MinBias<db>COOLOFL_LAR/OFLP200</db>', '/LAR/ElecCalibMC/LArPileupAverage<db>COOLOFL_LAR/OFLP200</db>', '/Digitization/Parameters']
diff --git a/Calorimeter/CaloRec/share/CaloBCIDLumiCondAlg_test.ref b/Calorimeter/CaloRec/share/CaloBCIDLumiCondAlg_test.ref
new file mode 100644
index 0000000000000000000000000000000000000000..b739b612d1449c6fa5cbdb53575c399151e3a0d7
--- /dev/null
+++ b/Calorimeter/CaloRec/share/CaloBCIDLumiCondAlg_test.ref
@@ -0,0 +1,28 @@
+CaloRec/CaloBCIDLumiCondAlg_test
+
+
+Initializing Gaudi ApplicationMgr using job opts /gpfs/mnt/atlasgpfs01/usatlas/data/snyder/atlas-master-acas-c/build-x86_64-centos7-gcc8-opt/x86_64-centos7-gcc8-opt/jobOptions/CaloRec/CaloBCIDTests.txt
+JobOptionsSvc        INFO # =======> /gpfs/mnt/atlasgpfs01/usatlas/data/snyder/atlas-master-acas-c/build-x86_64-centos7-gcc8-opt/x86_64-centos7-gcc8-opt/jobOptions/CaloRec/CaloBCIDTests.txt
+JobOptionsSvc        INFO # (1,1): ApplicationMgr.ExtSvc += ["StoreGateSvc/DetectorStore"]
+JobOptionsSvc        INFO # (2,1): ApplicationMgr.ExtSvc += ["StoreGateSvc/ConditionStore"]
+JobOptionsSvc        INFO # (4,1): CaloBCIDLumiCondAlgMC.isMC = 1
+JobOptionsSvc        INFO # (5,1): CaloBCIDLumiCondAlgMC.OutputLumiKey = "CaloBCIDLumiMC"
+JobOptionsSvc        INFO # (6,1): CaloBCIDLumiCondAlgData.isMC = 0
+JobOptionsSvc        INFO # (7,1): CaloBCIDLumiCondAlgData.OutputLumiKey = "CaloBCIDLumiData"
+JobOptionsSvc        INFO Job options successfully read in from /gpfs/mnt/atlasgpfs01/usatlas/data/snyder/atlas-master-acas-c/build-x86_64-centos7-gcc8-opt/x86_64-centos7-gcc8-opt/jobOptions/CaloRec/CaloBCIDTests.txt
+ApplicationMgr    SUCCESS 
+====================================================================================================================================
+                                                   Welcome to ApplicationMgr (GaudiCoreSvc v33r1)
+                                          running on spar0103.usatlas.bnl.gov on Mon Mar 30 11:20:24 2020
+====================================================================================================================================
+ApplicationMgr       INFO Application Manager Configured successfully
+ClassIDSvc           INFO  getRegistryEntries: read 7977 CLIDRegistry entries for module ALL
+EventLoopMgr      WARNING Unable to locate service "EventSelector" 
+EventLoopMgr      WARNING No events will be processed from external input.
+ApplicationMgr       INFO Application Manager Initialized successfully
+ApplicationMgr Ready
+test1
+ClassIDSvc           INFO  getRegistryEntries: read 372 CLIDRegistry entries for module ALL
+ClassIDSvc           INFO  getRegistryEntries: read 2381 CLIDRegistry entries for module ALL
+CaloBCIDLumiCon...   INFO recorded new CaloBCIDLumiMC with range {[10,t:0,l:20] - [10,t:100,l:75]}
+CaloBCIDLumiCon...   INFO recorded new CaloBCIDLumiData with range {[10,t:20,l:20] - [10,t:80,l:75]}
diff --git a/Calorimeter/CaloRec/share/CaloBCIDTests.txt b/Calorimeter/CaloRec/share/CaloBCIDTests.txt
new file mode 100644
index 0000000000000000000000000000000000000000..402677be5a1c80027d1ad199226b3501b6d4972a
--- /dev/null
+++ b/Calorimeter/CaloRec/share/CaloBCIDTests.txt
@@ -0,0 +1,7 @@
+ApplicationMgr.ExtSvc += {"StoreGateSvc/DetectorStore"};
+ApplicationMgr.ExtSvc += {"StoreGateSvc/ConditionStore"};
+
+CaloBCIDLumiCondAlgMC.isMC = true;
+CaloBCIDLumiCondAlgMC.OutputLumiKey = "CaloBCIDLumiMC";
+CaloBCIDLumiCondAlgData.isMC = false;
+CaloBCIDLumiCondAlgData.OutputLumiKey = "CaloBCIDLumiData";
diff --git a/Calorimeter/CaloRec/src/CaloBCIDCoeffsCondAlg.cxx b/Calorimeter/CaloRec/src/CaloBCIDCoeffsCondAlg.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..d528fec4d685788b545142d8cdfe735d371a3936
--- /dev/null
+++ b/Calorimeter/CaloRec/src/CaloBCIDCoeffsCondAlg.cxx
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration.
+ */
+/**
+ * @file CaloRec/src/CaloBCIDCoeffsCondAlg.cxx
+ * @author scott snyder <snyder@bnl.gov>
+ * @date Mar, 2020
+ * @brief Conditions algorithm to create CaloBCIDCoeffs.
+ */
+
+
+#include "CaloBCIDCoeffsCondAlg.h"
+#include "StoreGate/ReadCondHandle.h"
+#include "StoreGate/WriteCondHandle.h"
+#include "GaudiKernel/ICondSvc.h"
+
+
+/**
+ * @brief Gaudi initialize method.
+ */
+StatusCode CaloBCIDCoeffsCondAlg::initialize()
+{
+  ATH_CHECK( m_mcSymKey.initialize() );
+  ATH_CHECK( m_ofcKey.initialize() );
+  ATH_CHECK( m_shapeKey.initialize() );
+  ATH_CHECK( m_minBiasAvgKey.initialize() );
+  ATH_CHECK( m_outputCoeffsKey.initialize() );
+
+  ServiceHandle<ICondSvc> condSvc ("CondSvc", name());
+  ATH_CHECK( condSvc.retrieve() );
+  ATH_CHECK( condSvc->regHandle (this, m_outputCoeffsKey) );
+
+  ATH_CHECK( detStore()->retrieve (m_laronline_id, "LArOnlineID") );
+  return StatusCode::SUCCESS;
+}
+
+
+/**
+ * @brief Execute the algorithm.
+ * @param ctx Event context.
+ */
+StatusCode CaloBCIDCoeffsCondAlg::execute (const EventContext& ctx) const
+{
+  SG::WriteCondHandle<CaloBCIDCoeffs> outputCoeffs (m_outputCoeffsKey, ctx);
+  if (outputCoeffs.isValid()) {
+    ATH_MSG_DEBUG ("Found valid write handle");
+    return StatusCode::SUCCESS;
+  }
+
+  SG::ReadCondHandle<LArMCSym>           mcsym      (m_mcSymKey, ctx);
+  SG::ReadCondHandle<ILArOFC>            ofcs       (m_ofcKey,   ctx);
+  SG::ReadCondHandle<ILArShape>          shapes     (m_shapeKey, ctx);
+  SG::ReadCondHandle<ILArMinBiasAverage> minBiasAvg (m_minBiasAvgKey, ctx);
+
+  auto coeffs = std::make_unique<CaloBCIDCoeffs> (mcsym->symIds(),
+                                                  *m_laronline_id,
+                                                  **ofcs,
+                                                  **shapes,
+                                                  **minBiasAvg);
+
+  outputCoeffs.addDependency (mcsym, ofcs, shapes, minBiasAvg);
+  ATH_CHECK( outputCoeffs.record (std::move (coeffs)) );
+  ATH_MSG_INFO( "recorded new " << outputCoeffs.key() << " with range " << outputCoeffs.getRange() );
+  return StatusCode::SUCCESS;
+}
diff --git a/Calorimeter/CaloRec/src/CaloBCIDCoeffsCondAlg.h b/Calorimeter/CaloRec/src/CaloBCIDCoeffsCondAlg.h
new file mode 100644
index 0000000000000000000000000000000000000000..1abf430faf54dcd93d2c3c7a8868494b6b94f787
--- /dev/null
+++ b/Calorimeter/CaloRec/src/CaloBCIDCoeffsCondAlg.h
@@ -0,0 +1,84 @@
+// This file's extension implies that it's C, but it's really -*- C++ -*-.
+/*
+ * Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration.
+ */
+/**
+ * @file CaloRec/src/CaloBCIDCoeffsCondAlg.h
+ * @author scott snyder <snyder@bnl.gov>
+ * @date Mar, 2020
+ * @brief Conditions algorithm to create CaloBCIDCoeffs.
+ */
+
+
+#ifndef CALOREC_CALOBCIDCOEFFSCONDALG_H
+#define CALOREC_CALOBCIDCOEFFSCONDALG_H
+
+
+#include "CaloLumiConditions/CaloBCIDCoeffs.h"
+#include "LArElecCalib/ILArOFC.h"
+#include "LArElecCalib/ILArShape.h"
+#include "LArElecCalib/ILArMinBiasAverage.h"
+#include "LArRawConditions/LArMCSym.h"
+#include "LArIdentifier/LArOnlineID.h"
+#include "AthenaBaseComps/AthReentrantAlgorithm.h"
+#include "StoreGate/ReadCondHandleKey.h"
+#include "StoreGate/WriteCondHandleKey.h"
+
+
+/**
+ * @brief Conditions algorithm to create CaloBCIDCoeffs.
+ *
+ * This is part of the cell-by-cell bunch-dependent pileup offset correction.
+ * The information needed to do the calculation is stored in two
+ * conditions objects, CaloBCIDCoeffs and CaloBCIDLumi.
+ * The former has calibration-related values, processed to enable
+ * efficient calculation, and the latter has the per-bunch
+ * luminosities.  There are two distinct conditions objects because
+ * the luminosity changes much faster than then calibrations.
+ */
+class CaloBCIDCoeffsCondAlg : public AthReentrantAlgorithm
+{
+public:
+  using AthReentrantAlgorithm::AthReentrantAlgorithm;
+
+
+  /**
+   * @brief Gaudi initialize method.
+   */
+  virtual StatusCode initialize() override;
+
+
+  /**
+   * @brief Execute the algorithm.
+   * @param ctx Event context.
+   */
+  virtual StatusCode execute (const EventContext& ctx) const override;
+
+
+private:
+  /// Property: Symmetrization helper (conditions input).
+  SG::ReadCondHandleKey<LArMCSym> m_mcSymKey
+  {this, "MCSymKey", "LArMCSym", "SG Key of LArMCSym object"};
+
+  /// Property: OFC coefficients (conditions input).
+  SG::ReadCondHandleKey<ILArOFC> m_ofcKey
+  {this, "OFCKey", "LArOFC", "SG Key of OFC conditions object" };
+
+  /// Property: Pulse shape (conditions input).
+  SG::ReadCondHandleKey<ILArShape> m_shapeKey
+  {this, "ShapeKey", "LArShape32", "SG Key of Shape conditions object"};
+
+  /// Property: Min bias offset (conditions input).
+  SG::ReadCondHandleKey<ILArMinBiasAverage> m_minBiasAvgKey
+  {this, "MinBiasAvgKey", "LArPileupAverageSym", "SGKey of LArMinBiasAverage object"};
+
+  /// Property: Offset calculation coefficients (conditions output).
+  SG::WriteCondHandleKey<CaloBCIDCoeffs> m_outputCoeffsKey
+  { this, "OutputCoeffsKey", "CaloBCIDCoeffs", "SG key of output coefficients" };
+
+  /// LAr online ID helper.
+  const LArOnlineID* m_laronline_id = nullptr;
+};
+
+
+#endif // not CALOREC_CALOBCIDCOEFFSCONDALG_H
diff --git a/Calorimeter/CaloRec/src/CaloBCIDLumiCondAlg.cxx b/Calorimeter/CaloRec/src/CaloBCIDLumiCondAlg.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..541eaac2a616409c876dcbff2fea1edff4407d2b
--- /dev/null
+++ b/Calorimeter/CaloRec/src/CaloBCIDLumiCondAlg.cxx
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration.
+ */
+/**
+ * @file CaloRec/src/CaloBCIDLumiCondAlg.cxx
+ * @author scott snyder <snyder@bnl.gov>
+ * @date Mar, 2020
+ * @brief Conditions algorithm to create CaloBCIDLumi.
+ */
+
+
+#include "CaloBCIDLumiCondAlg.h"
+#include "StoreGate/ReadCondHandle.h"
+#include "StoreGate/WriteCondHandle.h"
+#include "GaudiKernel/ICondSvc.h"
+
+
+/**
+ * @brief Gaudi initialize method.
+ */
+StatusCode CaloBCIDLumiCondAlg::initialize()
+{
+  ATH_CHECK( m_coeffsKey.initialize() );
+  ATH_CHECK( m_outputLumiKey.initialize() );
+  ATH_CHECK( m_bcDataKey.initialize(m_isMC) );
+  ATH_CHECK( m_lumiDataKey.initialize(!m_isMC) );
+
+  ServiceHandle<ICondSvc> condSvc ("CondSvc", name());
+  ATH_CHECK( condSvc.retrieve() );
+  ATH_CHECK( condSvc->regHandle (this, m_outputLumiKey) );
+
+  return StatusCode::SUCCESS;
+}
+
+
+/**
+ * @brief Execute the algorithm.
+ * @param ctx Event context.
+ */
+StatusCode CaloBCIDLumiCondAlg::execute (const EventContext& ctx) const
+{
+  SG::WriteCondHandle<CaloBCIDLumi> outputLumi (m_outputLumiKey, ctx);
+  SG::ReadCondHandle<CaloBCIDCoeffs>     coeffs     (m_coeffsKey, ctx);
+
+  std::unique_ptr<CaloBCIDLumi> lumi;
+  if (m_isMC) {
+    if (outputLumi.isValid()) {
+      ATH_MSG_DEBUG ("Found valid write handle");
+      return StatusCode::SUCCESS;
+    }
+
+    SG::ReadCondHandle<BunchCrossingCondData> bccd (m_bcDataKey,ctx);
+    lumi = std::make_unique<CaloBCIDLumi> (**coeffs, **bccd);
+    outputLumi.addDependency (bccd);
+  }
+  else {
+    SG::ReadCondHandle<LuminosityCondData> lcd (m_lumiDataKey,ctx);
+
+    // Need to check start of range, since lumi might be extensible.
+    EventIDRange range;
+    if (outputLumi.isValid(range)) {
+      EventIDBase start = range.start();
+      EventIDBase coeffs_start = coeffs.getRange().start();
+      EventIDBase lcd_start = lcd.getRange().start();
+      if ((start.time_stamp() == coeffs_start.time_stamp() &&
+           start.time_stamp_ns_offset() == coeffs_start.time_stamp_ns_offset()) ||
+          (start.time_stamp() == lcd_start.time_stamp() &&
+           start.time_stamp_ns_offset() == lcd_start.time_stamp_ns_offset()))
+      {
+        ATH_MSG_DEBUG ("Found valid write handle");
+        return StatusCode::SUCCESS;
+      }
+    }
+
+    lumi = std::make_unique<CaloBCIDLumi> (**coeffs, **lcd);
+    outputLumi.addDependency (lcd);
+  }
+
+  outputLumi.addDependency (coeffs);
+
+  ATH_CHECK( outputLumi.record (std::move (lumi)) );
+  ATH_MSG_INFO( "recorded new " << outputLumi.key() << " with range " << outputLumi.getRange() );
+  return StatusCode::SUCCESS;
+}
diff --git a/Calorimeter/CaloRec/src/CaloBCIDLumiCondAlg.h b/Calorimeter/CaloRec/src/CaloBCIDLumiCondAlg.h
new file mode 100644
index 0000000000000000000000000000000000000000..9bd8cd76ff95039255bcdee2926b344e056a6adc
--- /dev/null
+++ b/Calorimeter/CaloRec/src/CaloBCIDLumiCondAlg.h
@@ -0,0 +1,79 @@
+// This file's extension implies that it's C, but it's really -*- C++ -*-.
+/*
+ * Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration.
+ */
+/**
+ * @file CaloRec/src/CaloBCIDLumiCondAlg.h
+ * @author scott snyder <snyder@bnl.gov>
+ * @date Mar, 2020
+ * @brief Conditions algorithm to create CaloBCIDLumi.
+ */
+
+
+#ifndef CALOREC_CALOBCIDLUMICONDALG_H
+#define CALOREC_CALOBCIDLUMICONDALG_H
+
+
+#include "CaloLumiConditions/CaloBCIDLumi.h"
+#include "CaloLumiConditions/CaloBCIDCoeffs.h"
+#include "LumiBlockData/LuminosityCondData.h"
+#include "LumiBlockData/BunchCrossingCondData.h"
+#include "AthenaBaseComps/AthReentrantAlgorithm.h"
+#include "StoreGate/ReadCondHandleKey.h"
+#include "StoreGate/WriteCondHandleKey.h"
+
+
+/**
+ * @brief Conditions algorithm to create CaloBCIDLumi.
+ *
+ * This is part of the cell-by-cell bunch-dependent pileup offset correction.
+ * The information needed to do the calculation is stored in two
+ * conditions objects, CaloBCIDCoeffs and CaloBCIDLumi.
+ * The former has calibration-related values, processed to enable
+ * efficient calculation, and the latter has the per-bunch
+ * luminosities.  There are two distinct conditions objects because
+ * the luminosity changes much faster than then calibrations.
+ */
+class CaloBCIDLumiCondAlg : public AthReentrantAlgorithm
+{
+public:
+  using AthReentrantAlgorithm::AthReentrantAlgorithm;
+
+
+  /**
+   * @brief Gaudi initialize method.
+   */
+  virtual StatusCode initialize() override;
+
+
+  /**
+   * @brief Execute the algorithm.
+   * @param ctx Event context.
+   */
+  virtual StatusCode execute (const EventContext& ctx) const override;
+
+
+private:
+  /// Property: Coefficients object (conditions input).
+  SG::ReadCondHandleKey<CaloBCIDCoeffs> m_coeffsKey
+  {this, "CoeffsKey", "CaloBCIDCoeffs", "SG Key coefficient object"};
+
+  /// Property: Bunch crossing data (MC only) (conditions input).
+  SG::ReadCondHandleKey<BunchCrossingCondData> m_bcDataKey
+  {this, "BunchCrossingCondDataKey", "BunchCrossingData" ,"SG Key of BunchCrossing CDO"};
+
+  /// Property: Per-bunch luminosity data (data only) conditions input).
+  SG::ReadCondHandleKey<LuminosityCondData> m_lumiDataKey
+  {this, "LuminosityCondDataKey", "LuminosityCondData", "SG Key of LuminosityCondData object"};
+
+  /// Property: Offset correction luminosity-dependent conditions object (output).
+  SG::WriteCondHandleKey<CaloBCIDLumi> m_outputLumiKey
+  { this, "OutputLumiKey", "CaloBCIDLumi", "SG key of output luminosity object" };
+
+  /// Property; MC flag.
+  Gaudi::Property<bool> m_isMC
+  {this, "isMC", false, "Real data or MC"};
+};
+
+
+#endif // not CALOREC_CALOBCIDLUMICONDALG_H
diff --git a/Calorimeter/CaloRec/src/components/CaloRec_entries.cxx b/Calorimeter/CaloRec/src/components/CaloRec_entries.cxx
index 203cda1025fe6dfb962c7c4701f148de93f8ca53..cf359eba74306299cbe8ec45ded0fb0f617d4527 100644
--- a/Calorimeter/CaloRec/src/components/CaloRec_entries.cxx
+++ b/Calorimeter/CaloRec/src/components/CaloRec_entries.cxx
@@ -28,6 +28,8 @@
 #include "../CaloTowerxAODFromClusters.h"
 #include "../CaloClusterSnapshot.h"
 #include "../CaloBCIDAvgAlg.h"
+#include "../CaloBCIDCoeffsCondAlg.h"
+#include "../CaloBCIDLumiCondAlg.h"
 #include "../CaloCellDumper.h"
 #include "../CaloThinCellsByClusterAlg.h"
 #include "../CaloThinCellsBySamplingAlg.h"
@@ -68,6 +70,8 @@ DECLARE_COMPONENT( CaloCellFastCopyTool )
 DECLARE_COMPONENT( CaloClusterSnapshot )
 
 DECLARE_COMPONENT( CaloBCIDAvgAlg )
+DECLARE_COMPONENT( CaloBCIDCoeffsCondAlg )
+DECLARE_COMPONENT( CaloBCIDLumiCondAlg )
 
 DECLARE_COMPONENT (CaloCellDumper)
 
diff --git a/Calorimeter/CaloRec/test/CaloBCIDCoeffsCondAlg_test.cxx b/Calorimeter/CaloRec/test/CaloBCIDCoeffsCondAlg_test.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..3e5368b82fd4c362c9d20b9449c11526dc9d0d18
--- /dev/null
+++ b/Calorimeter/CaloRec/test/CaloBCIDCoeffsCondAlg_test.cxx
@@ -0,0 +1,333 @@
+/*
+ * Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration.
+ */
+/**
+ * @file CaloRec/test/CaloBCIDCoeffsCondAlg_test.cxx
+ * @author scott snyder <snyder@bnl.gov>
+ * @date Mar, 2020
+ * @brief Unit test for CaloBCIDCoeffsCondAlg.
+ */
+
+
+#undef NDEBUG
+#include "../src/CaloBCIDCoeffsCondAlg.h"
+#include "LArRawConditions/LArMCSym.h"
+#include "LArElecCalib/ILArOFC.h"
+#include "LArElecCalib/ILArShape.h"
+#include "LArElecCalib/ILArMinBiasAverage.h"
+#include "LArIdentifier/LArOnlineID.h"
+#include "CaloIdentifier/CaloHelpersTest.h"
+#include "IdDictParser/IdDictParser.h"
+#include "StoreGate/StoreGateSvc.h"
+#include "AthenaKernel/DummyRCUSvc.h"
+#include "AthenaKernel/ExtendedEventContext.h"
+#include "TestTools/initGaudi.h"
+#include "TestTools/random.h"
+#include "GaudiKernel/ServiceHandle.h"
+#include <iostream>
+#include <cassert>
+
+
+static constexpr size_t NCELL = 1833;
+
+
+EventIDBase runlbn (int run,
+                    int lbn)
+{
+  return EventIDBase (run,  // run
+                      EventIDBase::UNDEFEVT,  // event
+                      EventIDBase::UNDEFNUM,  // timestamp
+                      0,                      // ns offset
+                      lbn);
+}
+
+
+//************************************************************************
+
+
+class LArOnlineIDTest
+{
+public:
+  LArOnlineIDTest();
+  ~LArOnlineIDTest();
+
+  const LArOnlineID&  onlineID() const { return *m_helper; }
+
+
+private:
+  std::unique_ptr<IdDictParser> m_parser;
+  LArOnlineID*                  m_helper;
+};
+
+
+LArOnlineIDTest::LArOnlineIDTest()
+  : m_parser (std::make_unique<IdDictParser>())
+{
+  m_parser->register_external_entity("LArCalorimeter", "IdDictLArCalorimeter_DC3-05.xml");
+  IdDictMgr& idd = m_parser->parse("IdDictParser/ATLAS_IDS.xml");
+  m_helper = new LArOnlineID;
+  m_helper->set_quiet (true);
+  if (m_helper->initialize_from_dictionary(idd) != 0) {
+    std::abort();
+  }
+
+  ServiceHandle<StoreGateSvc> detStore ("DetectorStore", "test");
+  assert( detStore->record (m_helper, "LArOnlineID").isSuccess() );
+}
+
+
+LArOnlineIDTest::~LArOnlineIDTest()
+{
+}
+
+
+//************************************************************************
+
+
+class TestData
+{
+public:
+  TestData (const uint32_t seed_in,
+            const size_t ndata,
+            const std::vector<HWIdentifier>& hwids,
+            float maxval = 1,
+            float offset = 0);
+  LArVectorProxy data (const HWIdentifier& id) const;
+
+  std::unordered_map<HWIdentifier, std::vector<float> > m_data;
+};
+
+
+TestData::TestData (uint32_t seed_in,
+                    const size_t ndata,
+                    const std::vector<HWIdentifier>& hwids,
+                    float maxval /*= 1*/,
+                    float offset /*= 0*/)
+{
+  for (HWIdentifier id : hwids) {
+    std::vector<float>& data = m_data[id];
+    data.resize (ndata);
+    uint32_t seed = id.get_identifier32().get_compact() + seed_in;
+    for (size_t i = 0; i < ndata; ++i) {
+      data[i] = Athena_test::randf_seed (seed, maxval) - offset;
+    }
+  }
+}
+
+
+LArVectorProxy TestData::data (const HWIdentifier& id) const
+{
+  auto it = m_data.find (id);
+  if (it != m_data.end()) {
+    return LArVectorProxy (it->second.data(), it->second.data()+it->second.size());
+  }
+  return LArVectorProxy();
+}
+
+
+//************************************************************************
+
+
+class TestOFC : public ILArOFC
+{
+public:
+  typedef LArVectorProxy OFCRef_t;
+
+  TestOFC (size_t nofc, const std::vector<HWIdentifier>& hwids)
+    : m_data (1234, nofc, hwids)
+  {
+  }
+
+  virtual OFCRef_t OFC_a (const HWIdentifier& id,
+                          int,
+                          int=0) const override
+  {
+    return m_data.data (id);
+  }
+  
+  virtual OFCRef_t OFC_b(const HWIdentifier&,
+                         int,
+                         int=0) const override
+  { std::abort(); }
+  
+  virtual float timeOffset(const HWIdentifier&, int) const override
+  { std::abort(); }
+
+  virtual unsigned nTimeBins(const HWIdentifier&, int) const override
+  { std::abort(); }
+ 
+  virtual float timeBinWidth(const HWIdentifier&, int) const override
+  { std::abort(); }
+
+  TestData m_data;
+};
+
+
+//************************************************************************
+
+
+// I'm kind of pulling a fast one here.
+// The actual shapes have both positive and negative entries,
+// averaging to zero.  That means that we're summing a series
+// where the terms have varying sign, and so the result will depend
+// on the order in which the sums are done.  Thus, in general, we won't
+// get exactly the same result if we calculate the offset using the
+// original method or the vectorized method.  However, here we choose
+// the entries to be entirely non-negative.  In that case,
+// the order of summation won't matter, so we should get the same result.
+class TestShape : public ILArShape
+{
+public:
+  TestShape (const std::vector<HWIdentifier>& hwids)
+    : m_data (4321, 32, hwids)
+  {
+  }
+
+  virtual ShapeRef_t Shape   (const HWIdentifier& id,
+                              int,
+                              int = 0,
+                              int = 0 )  const override
+  {
+    return m_data.data (id);
+  }
+
+  
+  virtual ShapeRef_t ShapeDer(const HWIdentifier&,
+                              int,
+                              int = 0,
+                              int = 0 )  const override
+  { std::abort(); }
+
+  TestData m_data;
+};
+
+
+//************************************************************************
+
+
+class TestMinBiasAverage : public ILArMinBiasAverage
+{
+public:
+  TestMinBiasAverage (const std::vector<HWIdentifier>& hwids)
+    : m_data (563424, 1, hwids, 100, 10)
+  {
+  }
+
+  virtual const float& minBiasAverage(const HWIdentifier& id)  const override
+  {
+    return *m_data.data(id).data();
+  }
+
+  TestData m_data;
+};
+
+
+//************************************************************************
+
+
+std::vector<HWIdentifier> get_hwids (const LArOnlineID& online_id)
+{
+  std::vector<HWIdentifier> hwids;
+
+  size_t nhec_left = 100;
+  for (HWIdentifier hwid : online_id.channel_range()) {
+    if (hwids.size() == NCELL) {
+      break;
+    }
+    else if (online_id.isHECchannel (hwid) && nhec_left > 0) {
+      hwids.push_back (hwid);
+      --nhec_left;
+    }
+    else if ((NCELL - hwids.size()) > nhec_left) {
+      hwids.push_back (hwid);
+    }
+  }
+  
+  return hwids;
+}
+
+
+//************************************************************************
+
+
+void test1 (ISvcLocator* svcloc,
+            const CaloCell_ID& calo_id,
+            const LArOnlineID& online_id)
+{
+  std::cout << "test1\n";
+
+  EventContext ctx;
+  ctx.setExtension (Atlas::ExtendedEventContext());
+  ctx.setEventID (runlbn (10, 50));
+
+  CaloBCIDCoeffsCondAlg alg ("CaloBCIDCoeffsCondAlg", svcloc);
+  alg.addRef();
+  assert( alg.sysInitialize().isSuccess() );
+
+  Athena_test::DummyRCUSvc rcu;
+  std::vector<HWIdentifier> hwids = get_hwids (online_id);
+
+  ServiceHandle<StoreGateSvc> conditionStore ("ConditionStore", "test");
+
+  DataObjID id_mcsym ("LArMCSym");
+  auto cc_mcsym = std::make_unique<CondCont<LArMCSym> > (rcu, id_mcsym);
+  auto mcsym = std::make_unique<LArMCSym> (&online_id,
+                                           &calo_id,
+                                           std::vector<HWIdentifier>(),
+                                           std::vector<HWIdentifier>(),
+                                           std::vector<HWIdentifier>(hwids));
+  const EventIDRange range_mcsym (runlbn (10, 0), runlbn (10, 100));
+  assert( cc_mcsym->insert (range_mcsym, std::move(mcsym), ctx).isSuccess() );
+  assert( conditionStore->record (std::move (cc_mcsym), id_mcsym.key()) );
+
+  DataObjID id_ofcs ("LArOFC");
+  auto cc_ofcs = std::make_unique<CondCont<ILArOFC> > (rcu, id_ofcs);
+  auto ofcs = std::make_unique<TestOFC> (5, hwids);
+  const EventIDRange range_ofcs (runlbn (10, 20), runlbn (10, 120));
+  assert( cc_ofcs->insert (range_ofcs, std::move(ofcs), ctx).isSuccess() );
+  assert( conditionStore->record (std::move (cc_ofcs), id_ofcs.key()) );
+
+  DataObjID id_shapes ("LArShape32");
+  auto cc_shapes = std::make_unique<CondCont<ILArShape> > (rcu, id_shapes);
+  auto shapes = std::make_unique<TestShape> (hwids);
+  const EventIDRange range_shapes (runlbn (10, 10), runlbn (10, 80));
+  assert( cc_shapes->insert (range_shapes, std::move(shapes), ctx).isSuccess() );
+  assert( conditionStore->record (std::move (cc_shapes), id_shapes.key()) );
+
+  DataObjID id_mb ("LArPileupAverageSym");
+  auto cc_mb = std::make_unique<CondCont<ILArMinBiasAverage> > (rcu, id_mb);
+  auto mb = std::make_unique<TestMinBiasAverage> (hwids);
+  const EventIDRange range_mb (runlbn (10, 15), runlbn (10, 75));
+  assert( cc_mb->insert (range_mb, std::move(mb), ctx).isSuccess() );
+  assert( conditionStore->record (std::move (cc_mb), id_mb.key()) );
+
+  assert( alg.execute (ctx).isSuccess() );
+
+  CondCont<CaloBCIDCoeffs>* cc_coeffs = nullptr;
+  assert( conditionStore->retrieve (cc_coeffs, "CaloBCIDCoeffs").isSuccess() );
+  const CaloBCIDCoeffs* coeffs = 0;
+  const EventIDRange* range_coeffs = nullptr;
+  assert (cc_coeffs->find (runlbn (10, 50), coeffs, &range_coeffs));
+  assert (range_coeffs->start().lumi_block() == 20);
+  assert (range_coeffs->stop().lumi_block() == 75);
+
+  assert (coeffs->nshapes() == 32);
+  assert (coeffs->nsamples_coeff() == 5);
+}
+
+
+int main()
+{
+  std::cout << "CaloRec/CaloBCIDCoeffsCondAlg_test\n";
+
+  ISvcLocator* svcloc = nullptr;
+  if (!Athena_test::initGaudi ("CaloRec/CaloBCIDTests.txt", svcloc)) {
+    return 1;
+  }
+
+  CaloHelpersTest caloHelpers;
+  LArOnlineIDTest larhelpers;
+
+  test1 (svcloc, caloHelpers.caloID(), larhelpers.onlineID());
+  return 0;
+}
diff --git a/Calorimeter/CaloRec/test/CaloBCIDLumiCondAlg_test.cxx b/Calorimeter/CaloRec/test/CaloBCIDLumiCondAlg_test.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..d72b6acda6275f881069216c9c9d42fad9651f66
--- /dev/null
+++ b/Calorimeter/CaloRec/test/CaloBCIDLumiCondAlg_test.cxx
@@ -0,0 +1,414 @@
+/*
+ * Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration.
+ */
+/**
+ * @file CaloRec/test/CaloBCIDLumiCondAlg_test.cxx
+ * @author scott snyder <snyder@bnl.gov>
+ * @date Mar, 2020
+ * @brief Unit test for CaloBCIDLumiCondAlg.
+ */
+
+
+#undef NDEBUG
+#include "../src/CaloBCIDLumiCondAlg.h"
+#include "LArElecCalib/ILArOFC.h"
+#include "LArElecCalib/ILArShape.h"
+#include "LArElecCalib/ILArMinBiasAverage.h"
+#include "LArIdentifier/LArOnlineID.h"
+#include "LumiBlockData/BunchCrossingCondData.h"
+#include "LumiBlockData/LuminosityCondData.h"
+#include "IdDictParser/IdDictParser.h"
+#include "StoreGate/StoreGateSvc.h"
+#include "AthenaKernel/DummyRCUSvc.h"
+#include "AthenaKernel/ExtendedEventContext.h"
+#include "TestTools/initGaudi.h"
+#include "TestTools/random.h"
+#include "TestTools/FLOATassert.h"
+#include "GaudiKernel/ServiceHandle.h"
+#include <iostream>
+#include <cassert>
+
+
+static constexpr size_t NCELL = 1833;
+
+
+EventIDBase timestamp (int t)
+{
+  return EventIDBase (EventIDBase::UNDEFNUM,  // run
+                      EventIDBase::UNDEFEVT,  // event
+                      t);
+}
+
+
+EventIDBase runlbn (int run,
+                    int lbn)
+{
+  return EventIDBase (run,  // run
+                      EventIDBase::UNDEFEVT,  // event
+                      EventIDBase::UNDEFNUM,  // timestamp
+                      0,                      // ns offset
+                      lbn);
+}
+
+
+EventIDBase mixed (int lbn,
+                   int t)
+{
+  return EventIDBase (10,  // run
+                      EventIDBase::UNDEFEVT,  // event
+                      t,                      // timestamp
+                      0,                      // ns offset
+                      lbn);
+}
+
+
+//************************************************************************
+
+
+class LArOnlineIDTest
+{
+public:
+  LArOnlineIDTest();
+  ~LArOnlineIDTest();
+
+  const LArOnlineID&  onlineID() const { return *m_helper; }
+
+
+private:
+  std::unique_ptr<IdDictParser> m_parser;
+  LArOnlineID*                  m_helper;
+};
+
+
+LArOnlineIDTest::LArOnlineIDTest()
+  : m_parser (std::make_unique<IdDictParser>())
+{
+  m_parser->register_external_entity("LArCalorimeter", "IdDictLArCalorimeter_DC3-05.xml");
+  IdDictMgr& idd = m_parser->parse("IdDictParser/ATLAS_IDS.xml");
+  m_helper = new LArOnlineID;
+  m_helper->set_quiet (true);
+  if (m_helper->initialize_from_dictionary(idd) != 0) {
+    std::abort();
+  }
+
+  ServiceHandle<StoreGateSvc> detStore ("DetectorStore", "test");
+  assert( detStore->record (m_helper, "LArOnlineID").isSuccess() );
+}
+
+
+LArOnlineIDTest::~LArOnlineIDTest()
+{
+}
+
+
+//************************************************************************
+
+
+class TestData
+{
+public:
+  TestData (const uint32_t seed_in,
+            const size_t ndata,
+            const std::vector<HWIdentifier>& hwids,
+            float maxval = 1,
+            float offset = 0);
+  LArVectorProxy data (const HWIdentifier& id) const;
+
+  std::unordered_map<HWIdentifier, std::vector<float> > m_data;
+};
+
+
+TestData::TestData (uint32_t seed_in,
+                    const size_t ndata,
+                    const std::vector<HWIdentifier>& hwids,
+                    float maxval /*= 1*/,
+                    float offset /*= 0*/)
+{
+  for (HWIdentifier id : hwids) {
+    std::vector<float>& data = m_data[id];
+    data.resize (ndata);
+    uint32_t seed = id.get_identifier32().get_compact() + seed_in;
+    for (size_t i = 0; i < ndata; ++i) {
+      data[i] = Athena_test::randf_seed (seed, maxval) - offset;
+    }
+  }
+}
+
+
+LArVectorProxy TestData::data (const HWIdentifier& id) const
+{
+  auto it = m_data.find (id);
+  if (it != m_data.end()) {
+    return LArVectorProxy (it->second.data(), it->second.data()+it->second.size());
+  }
+  return LArVectorProxy();
+}
+
+
+//************************************************************************
+
+
+class TestOFC : public ILArOFC
+{
+public:
+  typedef LArVectorProxy OFCRef_t;
+
+  TestOFC (size_t nofc, const std::vector<HWIdentifier>& hwids)
+    : m_data (1234, nofc, hwids)
+  {
+  }
+
+  virtual OFCRef_t OFC_a (const HWIdentifier& id,
+                          int,
+                          int=0) const override
+  {
+    return m_data.data (id);
+  }
+  
+  virtual OFCRef_t OFC_b(const HWIdentifier&,
+                         int,
+                         int=0) const override
+  { std::abort(); }
+  
+  virtual float timeOffset(const HWIdentifier&, int) const override
+  { std::abort(); }
+
+  virtual unsigned nTimeBins(const HWIdentifier&, int) const override
+  { std::abort(); }
+ 
+  virtual float timeBinWidth(const HWIdentifier&, int) const override
+  { std::abort(); }
+
+  TestData m_data;
+};
+
+
+//************************************************************************
+
+
+// I'm kind of pulling a fast one here.
+// The actual shapes have both positive and negative entries,
+// averaging to zero.  That means that we're summing a series
+// where the terms have varying sign, and so the result will depend
+// on the order in which the sums are done.  Thus, in general, we won't
+// get exactly the same result if we calculate the offset using the
+// original method or the vectorized method.  However, here we choose
+// the entries to be entirely non-negative.  In that case,
+// the order of summation won't matter, so we should get the same result.
+class TestShape : public ILArShape
+{
+public:
+  TestShape (const std::vector<HWIdentifier>& hwids)
+    : m_data (4321, 32, hwids)
+  {
+  }
+
+  virtual ShapeRef_t Shape   (const HWIdentifier& id,
+                              int,
+                              int = 0,
+                              int = 0 )  const override
+  {
+    return m_data.data (id);
+  }
+
+  
+  virtual ShapeRef_t ShapeDer(const HWIdentifier&,
+                              int,
+                              int = 0,
+                              int = 0 )  const override
+  { std::abort(); }
+
+  TestData m_data;
+};
+
+
+//************************************************************************
+
+
+class TestMinBiasAverage : public ILArMinBiasAverage
+{
+public:
+  TestMinBiasAverage (const std::vector<HWIdentifier>& hwids)
+    : m_data (563424, 1, hwids, 100, 10)
+  {
+  }
+
+  virtual const float& minBiasAverage(const HWIdentifier& id)  const override
+  {
+    return *m_data.data(id).data();
+  }
+
+  TestData m_data;
+};
+
+
+//************************************************************************
+
+
+class BunchCrossingCondAlg
+{
+public:
+  static void fill (BunchCrossingCondData& bccd);
+};
+
+
+void BunchCrossingCondAlg::fill (BunchCrossingCondData& bccd)
+{
+  static constexpr int MAX_BCID = BunchCrossingCondData::m_MAX_BCID;
+  uint32_t seed = 12734;
+  for (size_t i = 0; i < MAX_BCID; i++) {
+    bccd.m_luminous[i] = Athena_test::rng_seed (seed) & 0x10000;
+  }
+}
+
+
+std::unique_ptr<BunchCrossingCondData> get_bccd()
+{
+  auto bccd = std::make_unique<BunchCrossingCondData>();
+  BunchCrossingCondAlg::fill (*bccd);
+  return bccd;
+}
+
+
+std::vector<float> get_lumivec()
+{
+  static constexpr int MAX_BCID = BunchCrossingCondData::m_MAX_BCID;
+  uint32_t seed = 42345;
+  std::vector<float> lumivec;
+  lumivec.reserve (200);
+  for (size_t i = 0; i < MAX_BCID; i++) {
+    lumivec.push_back (Athena_test::randf_seed (seed, 10));
+  }
+  return lumivec;
+}
+
+
+//************************************************************************
+
+
+std::vector<HWIdentifier> get_hwids (const LArOnlineID& online_id)
+{
+  std::vector<HWIdentifier> hwids;
+
+  size_t nhec_left = 100;
+  for (HWIdentifier hwid : online_id.channel_range()) {
+    if (hwids.size() == NCELL) {
+      break;
+    }
+    else if (online_id.isHECchannel (hwid) && nhec_left > 0) {
+      hwids.push_back (hwid);
+      --nhec_left;
+    }
+    else if ((NCELL - hwids.size()) > nhec_left) {
+      hwids.push_back (hwid);
+    }
+  }
+  
+  return hwids;
+}
+
+
+//************************************************************************
+
+
+void test1 (ISvcLocator* svcloc,
+            const LArOnlineID& online_id)
+{
+  std::cout << "test1\n";
+
+  EventContext ctx;
+  ctx.setExtension (Atlas::ExtendedEventContext());
+  ctx.setEventID (mixed (50, 50));
+
+  CaloBCIDLumiCondAlg alg_mc ("CaloBCIDLumiCondAlgMC", svcloc);
+  alg_mc.addRef();
+  assert( alg_mc.sysInitialize().isSuccess() );
+  CaloBCIDLumiCondAlg alg_data ("CaloBCIDLumiCondAlgData", svcloc);
+  alg_data.addRef();
+  assert( alg_data.sysInitialize().isSuccess() );
+
+  Athena_test::DummyRCUSvc rcu;
+  std::vector<HWIdentifier> hwids = get_hwids (online_id);
+  TestOFC ofcs (5, hwids);
+  TestShape shapes (hwids);
+  TestMinBiasAverage minbias (hwids);
+
+  ServiceHandle<StoreGateSvc> conditionStore ("ConditionStore", "test");
+
+  DataObjID id_coeffs ("CaloBCIDCoeffs");
+  auto cc_coeffs = std::make_unique<CondCont<CaloBCIDCoeffs> > (rcu, id_coeffs);
+  auto coeffs = std::make_unique<CaloBCIDCoeffs> (hwids,
+                                                  online_id,
+                                                  ofcs,
+                                                  shapes,
+                                                  minbias);
+  const EventIDRange range_coeffs (runlbn (10, 20), runlbn (10, 75));
+  assert( cc_coeffs->insert (range_coeffs, std::move(coeffs), ctx).isSuccess() );
+  assert( conditionStore->record (std::move (cc_coeffs), id_coeffs.key()) );
+
+  DataObjID id_bccd ("BunchCrossingData");
+  auto cc_bccd = std::make_unique<CondCont<BunchCrossingCondData> > (rcu, id_bccd);
+  const EventIDRange range_bccd (timestamp (0), timestamp (100));
+  assert( cc_bccd->insert (range_bccd, get_bccd(), ctx).isSuccess() );
+  assert( conditionStore->record (std::move (cc_bccd), id_bccd.key()) );
+
+  DataObjID id_lumi ("LuminosityCondData");
+  auto cc_lumi = std::make_unique<CondCont<LuminosityCondData> > (rcu, id_lumi);
+  auto lumi = std::make_unique<LuminosityCondData>();
+  lumi->setLbLuminosityPerBCIDVector (get_lumivec());
+  const EventIDRange range_lumi (mixed (15, 20), mixed (80, 80));
+  assert( cc_lumi->insert (range_lumi, std::move(lumi), ctx).isSuccess() );
+  assert( conditionStore->record (std::move (cc_lumi), id_lumi.key()) );
+
+  assert( alg_mc.execute (ctx).isSuccess() );
+
+  CondCont<CaloBCIDLumi>* cc_lumimc = nullptr;
+  assert( conditionStore->retrieve (cc_lumimc, "CaloBCIDLumiMC").isSuccess() );
+  const CaloBCIDLumi* lumimc = 0;
+  const EventIDRange* range_lumimc = nullptr;
+  assert (cc_lumimc->find (mixed (50, 50), lumimc, &range_lumimc));
+  assert (range_lumimc->start().lumi_block() == 20);
+  assert (range_lumimc->start().time_stamp() == 0);
+  assert (range_lumimc->stop().lumi_block() == 75);
+  assert (range_lumimc->stop().time_stamp() == 100);
+
+  CxxUtils::vec_aligned_vector<float> out;
+  lumimc->calc (1, 1, out);
+  assert (out.size() == NCELL);
+  assert (Athena_test::isEqual (out[10], 110.33034));
+  assert (Athena_test::isEqual (out[20], 101.59116));
+
+  assert( alg_data.execute (ctx).isSuccess() );
+
+  CondCont<CaloBCIDLumi>* cc_lumidata = nullptr;
+  assert( conditionStore->retrieve (cc_lumidata, "CaloBCIDLumiData").isSuccess() );
+  const CaloBCIDLumi* lumidata = 0;
+  const EventIDRange* range_lumidata = nullptr;
+  assert (cc_lumidata->find (mixed (50, 50), lumidata, &range_lumidata));
+  assert (range_lumidata->start().lumi_block() == 20);
+  assert (range_lumidata->start().time_stamp() == 20);
+  assert (range_lumidata->stop().lumi_block() == 75);
+  assert (range_lumidata->stop().time_stamp() == 80);
+
+  out.clear();
+  lumidata->calc (1, 1, out);
+  assert (out.size() == NCELL);
+  assert (Athena_test::isEqual (out[10], 6697.305));
+  assert (Athena_test::isEqual (out[20], 5756.6152));
+}
+
+
+int main()
+{
+  std::cout << "CaloRec/CaloBCIDLumiCondAlg_test\n";
+
+  ISvcLocator* svcloc = nullptr;
+  if (!Athena_test::initGaudi ("CaloRec/CaloBCIDTests.txt", svcloc)) {
+    return 1;
+  }
+
+  LArOnlineIDTest larhelpers;
+
+  test1 (svcloc, larhelpers.onlineID());
+  return 0;
+}