diff --git a/Control/CalypsoExample/Reconstruction/scripts/faser_reco.py b/Control/CalypsoExample/Reconstruction/scripts/faser_reco.py
index 1e9bdefaaf48eeaf9b8326dcb1d0d60499530644..72235c1f2bb0d6f1167e4b12350ecb5214ecd580 100755
--- a/Control/CalypsoExample/Reconstruction/scripts/faser_reco.py
+++ b/Control/CalypsoExample/Reconstruction/scripts/faser_reco.py
@@ -101,7 +101,11 @@ else:
 ConfigFlags.Input.ProjectName = "data20"
 ConfigFlags.GeoModel.Align.Dynamic    = False
 
+# Flags for later
 useCKF = True
+useCal = False
+useLHC = False
+
 # Enable ACTS material corrections, this crashes testbeam geometries
 ConfigFlags.TrackingGeometry.MaterialSource = "/cvmfs/faser.cern.ch/repo/sw/database/DBRelease/current/acts/material-maps.json"
 
@@ -115,6 +119,7 @@ elif runtype == "TestBeamData" or runtype == "TestBeamMC":
     ConfigFlags.GeoModel.FaserVersion = "FASER-TB00" 
     ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-TB00"
     useCKF = False
+    useCal = True
 
 # New TI12 geometry (ugh)
 elif runtype == "TI12Data02":
@@ -127,6 +132,8 @@ elif runtype == "TI12Data03":
     # ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-02"
     # Use the updated field map
     ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-03"
+    useCal = True
+    useLHC = True
 
 else:
     print("Invalid run type found:", runtype)
@@ -178,6 +185,10 @@ else:
 from FaserGeoModel.FaserGeoModelConfig import FaserGeometryCfg
 acc.merge(FaserGeometryCfg(ConfigFlags))
 
+if useLHC:
+    from LHCDataAlgs.LHCDataAlgConfig import LHCDataAlgCfg
+    acc.merge(LHCDataAlgCfg(ConfigFlags))
+
 # Set up algorithms
 from WaveRecAlgs.WaveRecAlgsConfig import WaveformReconstructionCfg    
 acc.merge(WaveformReconstructionCfg(ConfigFlags))
@@ -186,7 +197,7 @@ acc.merge(WaveformReconstructionCfg(ConfigFlags))
 if args.isMC:
     # Not ready for MC quite yet
     pass
-else:
+elif useCal:
     from CaloRecAlgs.CaloRecAlgsConfig import CalorimeterReconstructionCfg
     acc.merge(CalorimeterReconstructionCfg(ConfigFlags))
 
@@ -236,6 +247,9 @@ itemList = [ "xAOD::EventInfo#*"
              , "TrackCollection#*"
 ]
 #
+if useLHC:
+    itemList.extend( ["xAOD::FaserLHCData#*", "xAOD::FaserLHCDataAux#*"] )
+
 if args.isMC:
     # Make xAOD versions of truth
     from Reconstruction.xAODTruthCnvAlgConfig import xAODTruthCnvAlgCfg
diff --git a/Database/ConnectionManagement/FaserAuthentication/CMakeLists.txt b/Database/ConnectionManagement/FaserAuthentication/CMakeLists.txt
index ecf7b9bb3985ff15c82df3794cf93b627ccbb915..eb1c72ae4cfdfd5b7a8a8da914da78a154f9446d 100644
--- a/Database/ConnectionManagement/FaserAuthentication/CMakeLists.txt
+++ b/Database/ConnectionManagement/FaserAuthentication/CMakeLists.txt
@@ -39,6 +39,7 @@ set( FaserAuthentication_home
 # Apparently not needed, because we don't have it...
 #atlas_install_xmls( ${FaserAuthentication_home}/authentication.xml )
 
+
 # Configure the environment setup module:
 configure_file(
    ${CMAKE_CURRENT_SOURCE_DIR}/FaserAuthenticationEnvironmentConfig.cmake.in
diff --git a/Database/ConnectionManagement/FaserAuthentication/data/dblookup.xml b/Database/ConnectionManagement/FaserAuthentication/data/dblookup.xml
index 958fb2ba600c0384381a06460487cb5e83efac98..1518267eeab17bed6f96f3673f6e309c01401dad 100644
--- a/Database/ConnectionManagement/FaserAuthentication/data/dblookup.xml
+++ b/Database/ConnectionManagement/FaserAuthentication/data/dblookup.xml
@@ -26,14 +26,24 @@
   <service name="sqlite_file:///cvmfs/faser.cern.ch/repo/sw/database/DBRelease/current/sqlite200/CABP200.db" accessMode="read" />
  </logicalservice>
 
+ <logicalservice name="COOLOFL_DIGITIZER">
+  <service name="sqlite_file:data/sqlite200/ALLP200.db" accessMode="read" />
+  <service name="sqlite_file:///cvmfs/faser.cern.ch/repo/sw/database/DBRelease/current/sqlite200/ALLP200.db" accessMode="read" />
+ </logicalservice>
+
  <logicalservice name="COOLOFL_INDET">
   <service name="sqlite_file:data/sqlite200/ALLP200.db" accessMode="read" />
   <service name="sqlite_file:///cvmfs/faser.cern.ch/repo/sw/database/DBRelease/current/sqlite200/ALLP200.db" accessMode="read" />
  </logicalservice>
 
 <logicalservice name="COOLOFL_TRIGGER">
-   <service name="sqlite_file:data/sqlite200/ALLP200.db" accessMode="read" />
-   <service name="sqlite_file:///cvmfs/faser.cern.ch/repo/sw/database/DBRelease/current/sqlite200/ALLP200.db" accessMode="read" />   
+  <service name="sqlite_file:data/sqlite200/ALLP200.db" accessMode="read" />
+  <service name="sqlite_file:///cvmfs/faser.cern.ch/repo/sw/database/DBRelease/current/sqlite200/ALLP200.db" accessMode="read" />   
+</logicalservice>
+
+<logicalservice name="COOLOFL_LHC">
+ <service name="sqlite_file:data/sqlite200/ALLP200.db" accessMode="read" />
+  <service name="sqlite_file:///cvmfs/faser.cern.ch/repo/sw/database/DBRelease/current/sqlite200/ALLP200.db" accessMode="read" />   
 </logicalservice>
 
 </servicelist>
diff --git a/LHCData/LHCDataAlgs/CMakeLists.txt b/LHCData/LHCDataAlgs/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..17abef2b21c0be98b310d45ed210fba0c52421db
--- /dev/null
+++ b/LHCData/LHCDataAlgs/CMakeLists.txt
@@ -0,0 +1,19 @@
+###############################################################################
+# Package: LHCDataAlgs
+################################################################################
+
+# Declare the package name:
+atlas_subdir( LHCDataAlgs )
+
+# External dependencies:
+find_package( Boost COMPONENTS filesystem thread system )
+
+# Component(s) in the package:
+atlas_add_component( LHCDataAlgs
+                     src/*.h
+                     src/*.cxx
+                     src/components/*.cxx
+                     LINK_LIBRARIES AthenaBaseComps StoreGateLib xAODFaserLHC LHCDataToolsLib )
+
+# Install files from the package:
+atlas_install_python_modules( python/*.py )
diff --git a/LHCData/LHCDataAlgs/python/LHCDataAlgConfig.py b/LHCData/LHCDataAlgs/python/LHCDataAlgConfig.py
new file mode 100644
index 0000000000000000000000000000000000000000..195fbbd12fe448c71e544bc619d503b7a468eae6
--- /dev/null
+++ b/LHCData/LHCDataAlgs/python/LHCDataAlgConfig.py
@@ -0,0 +1,20 @@
+# Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
+from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
+from AthenaConfiguration.ComponentFactory import CompFactory
+
+from LHCDataTools.LHCDataToolsConfig import LHCDataCfg
+
+#LHCDataTool = CompFactory.LHCDataTool
+
+def LHCDataAlgCfg(flags, name="LHCDataAlg", **kwargs):
+
+    acc = ComponentAccumulator()
+
+    tool = CompFactory.LHCDataTool(name="LHCDataTool")
+    alg = CompFactory.LHCDataAlg(name, **kwargs)
+    alg.LHCDataTool = tool
+
+    acc.addEventAlgo(alg)
+    acc.merge(LHCDataCfg(flags))
+
+    return acc
diff --git a/LHCData/LHCDataAlgs/src/LHCDataAlg.cxx b/LHCData/LHCDataAlgs/src/LHCDataAlg.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..de22698589abfbbbfc2ea9aa6d54feacd4661610
--- /dev/null
+++ b/LHCData/LHCDataAlgs/src/LHCDataAlg.cxx
@@ -0,0 +1,237 @@
+#include "LHCDataAlg.h"
+
+#include "xAODFaserLHC/FaserLHCDataAux.h"
+
+LHCDataAlg::LHCDataAlg(const std::string& name, ISvcLocator* pSvcLocator)
+  : AthReentrantAlgorithm(name, pSvcLocator) { 
+}
+
+StatusCode
+LHCDataAlg::initialize() {
+  ATH_MSG_INFO(name() << "::initalize()" );
+
+  // Initalize tools
+  ATH_CHECK( m_lhcTool.retrieve() );
+
+  // Read handle
+  ATH_CHECK( m_eventInfo.initialize() );
+
+  // Write handle
+  ATH_CHECK( m_lhcDataKey.initialize() );
+
+  return StatusCode::SUCCESS;
+}
+
+StatusCode
+LHCDataAlg::finalize() {
+  return StatusCode::SUCCESS;
+}
+
+StatusCode
+LHCDataAlg::execute(const EventContext& ctx) const {
+
+  ATH_MSG_DEBUG("Executing");
+
+  SG::WriteHandle<xAOD::FaserLHCData> lhcDataHandle(m_lhcDataKey, ctx);
+  ATH_CHECK( lhcDataHandle.record( std::make_unique<xAOD::FaserLHCData>(),
+				   std::make_unique<xAOD::FaserLHCDataAux>() ) );
+
+  ATH_MSG_DEBUG("FaserLHCData " << lhcDataHandle.name() << " initialized");
+
+  lhcDataHandle->set_fillNumber(m_lhcTool->getFillNumber(ctx));
+  lhcDataHandle->set_machineMode(m_lhcTool->getMachineMode(ctx));
+  lhcDataHandle->set_beamMode(m_lhcTool->getBeamMode(ctx));
+  lhcDataHandle->set_beamType1(m_lhcTool->getBeamType1(ctx));
+  lhcDataHandle->set_beamType2(m_lhcTool->getBeamType2(ctx));
+
+  lhcDataHandle->set_betaStar(m_lhcTool->getBetaStar(ctx));
+  lhcDataHandle->set_crossingAngle(m_lhcTool->getCrossingAngle(ctx));
+
+  lhcDataHandle->set_stableBeams(m_lhcTool->getStableBeams(ctx));
+  lhcDataHandle->set_injectionScheme(m_lhcTool->getInjectionScheme(ctx));
+
+  // Slight naming mismatch here, but oh well
+  lhcDataHandle->set_numBunchBeam1(m_lhcTool->getBeam1Bunches(ctx));
+  lhcDataHandle->set_numBunchBeam2(m_lhcTool->getBeam2Bunches(ctx));
+  lhcDataHandle->set_numBunchColliding(m_lhcTool->getCollidingBunches(ctx));
+
+  // Fill BCID information
+
+  // Get the BCID mask
+  std::vector<unsigned char> bcid_mask = m_lhcTool->getBCIDMasks(ctx);
+
+  // Get the event bcid value
+  SG::ReadHandle<xAOD::EventInfo> xevt(m_eventInfo, ctx);
+  unsigned int bcid = xevt->bcid();
+
+  int nearest = findNearest(bcid, bcid_mask, 3);  // Colliding beams
+  lhcDataHandle->set_distanceToCollidingBCID(nearest);
+  ATH_MSG_DEBUG("Found distance of " << nearest << " from BCID " << bcid 
+		<< " to the nearest colliding BCID ");
+
+  nearest = findNearest(bcid, bcid_mask, 1);  // Beam1 unpaired
+  lhcDataHandle->set_distanceToUnpairedB1(nearest);
+  ATH_MSG_DEBUG("Found distance of " << nearest << " from BCID " << bcid 
+		<< " to the nearest unpaired B1 ");
+
+  nearest = findNearest(bcid, bcid_mask, 2);  // Beam2 unpaired
+  lhcDataHandle->set_distanceToUnpairedB2(nearest);
+  ATH_MSG_DEBUG("Found distance of " << nearest << " from BCID " << bcid 
+		<< " to the nearest unpaired B2 ");
+
+  // Add 127 to current BCID to check if inbound B1 is nearby FASER
+  int offset_bcid = (bcid + 127) % 3564;
+  nearest = findNearest(offset_bcid, bcid_mask, 1);  // Inbound B1
+  int nearest2 = findNearest(offset_bcid, bcid_mask, 3);  // Inbound B1
+  if (abs(nearest2) < abs(nearest)) nearest = nearest2;
+  lhcDataHandle->set_distanceToInboundB1(nearest);
+  ATH_MSG_DEBUG("Found distance of " << nearest << " from BCID " << bcid 
+  		<< " to the nearest inbound B1 ");
+
+  unsigned int previous;
+  previous = previousColliding(bcid, bcid_mask);
+  lhcDataHandle->set_distanceToPreviousColliding(previous);
+  ATH_MSG_DEBUG("Found distance of " << previous << " from BCID " << bcid 
+		<< " to the previous colliding bunch ");
+
+  previous = previousTrain(bcid, bcid_mask);
+  lhcDataHandle->set_distanceToTrainStart(previous);
+  ATH_MSG_DEBUG("Found distance of " << previous << " from BCID " << bcid 
+		<< " to the start of the previous train ");
+
+  return StatusCode::SUCCESS;
+}
+
+// Function to find distance to nearest BCID
+// mask indicates the condition: 1 - unpaired B1, 2 - unpaired B2, 3 - colliding
+int
+LHCDataAlg::findNearest(unsigned int bcid, const std::vector<unsigned char>& bcid_mask, unsigned char mask) const {
+
+  // Does the BCID make sense?
+  if ((bcid > 3564) || (bcid <= 0)) {
+    ATH_MSG_WARNING("Requested distance from invalid BCID " << bcid << "!");
+    return -3565;
+  }
+
+  unsigned int test_bcid;
+
+  // Move outwards from the bcid (starting at offset of 0)
+  for (unsigned int i=0; i < 3564/2; i++) {
+
+    // Try positive offsets
+    test_bcid = (bcid + i) % 3564;
+
+    // BCID 0 doesn't exist in the real machine
+    // BCID 3564 doesn't exist in our array (but will always be empty in real machine)
+    // So avoid these pathologies
+    if (test_bcid != 0) 
+      if (mask == bcid_mask[test_bcid]) return i;
+
+    if(i == 0) continue;  // No need to check -0
+
+    // Try negative offsets
+    test_bcid = (bcid - i) % 3564;
+
+    // BCID 0 doesn't exist in the real machine
+    // BCID 3564 doesn't exist in our array (but will always be empty)
+    // So avoid these pathologies
+    if (test_bcid != 0) 
+      if (mask == bcid_mask[test_bcid]) return -i;
+
+  }
+
+  // If we got to here, there was no match
+  // Does the BCID make sense?
+  ATH_MSG_WARNING("Couldn't find distance from BCID " << bcid << " and pattern " << mask << "!");
+  ATH_MSG_WARNING(bcid_mask);
+  return -3565;
+
+}
+
+// Function to find previous colliding BCID
+unsigned int
+LHCDataAlg::previousColliding(unsigned int bcid, const std::vector<unsigned char>& bcid_mask) const {
+
+  // Does the BCID make sense?
+  if ((bcid > 3564) || (bcid <= 0)) {
+    ATH_MSG_WARNING("Requested distance from invalid BCID " << bcid << "!");
+    return 9999;
+  }
+
+  unsigned int test_bcid;
+
+  // Move backwards from the bcid (starting at offset of 0)
+  for (unsigned int i=0; i < 3564; i++) {
+
+    // Try positive offsets
+    test_bcid = (bcid - i) % 3564;
+
+    // BCID 3564 doesn't exist in our array (but will always be empty)
+    // So avoid these pathologies
+    if (test_bcid != 0) 
+      if (0x03 == bcid_mask[test_bcid]) return i;
+
+  }
+
+  // If we got to here, there was no match
+  // Does the BCID make sense?
+  ATH_MSG_WARNING("Couldn't find colliding from BCID " << bcid << "!");
+  ATH_MSG_WARNING(bcid_mask);
+  return 9999;
+
+}
+
+unsigned int
+LHCDataAlg::previousTrain(unsigned int bcid, const std::vector<unsigned char>& bcid_mask) const {
+
+  // Does the BCID make sense?
+  if ((bcid > 3564) || (bcid <= 0)) {
+    ATH_MSG_WARNING("Requested distance from invalid BCID " << bcid << "!");
+    return 9999;
+  }
+
+  unsigned int test_bcid;
+
+  bool in_train = false;
+  // Move backwards from the bcid (starting at offset of 0)
+  for (unsigned int i=0; i < 3564; i++) {
+
+    // BCID to test
+    test_bcid = (bcid - i) % 3564;
+
+    // BCID 3564 doesn't exist in our array (but will always be empty)
+    // So avoid these pathologies
+    ATH_MSG_DEBUG("Test " << test_bcid << " In train: " << in_train << " mask[test_bcid]");
+
+    // If we are not in a train before, lets see if we are in a train now
+    if (!in_train) {
+
+      // If we found a colliding bunch, set in_train, otherwise we are still not in a train
+      if ((test_bcid != 0) && (0x03 == bcid_mask[test_bcid]))
+	in_train = true;
+
+      // Either way, move to next BCID
+      continue;
+
+    } else {
+
+      // Currently in a train, lets see if now we are not
+      if ((test_bcid == 0) || (0x03 != bcid_mask[test_bcid])) {
+	in_train = false;
+	// Previous BCID was first in train
+	return i-1;
+      } else {
+	in_train = true;
+      }
+	
+    }
+
+  }
+
+  // If we got to here, there was no match
+  // Does the BCID make sense?
+  ATH_MSG_WARNING("Couldn't find first in train from BCID " << bcid << "!");
+  ATH_MSG_WARNING(bcid_mask);
+  return 9999;
+
+}
diff --git a/LHCData/LHCDataAlgs/src/LHCDataAlg.h b/LHCData/LHCDataAlgs/src/LHCDataAlg.h
new file mode 100644
index 0000000000000000000000000000000000000000..a8785725aad2eec117a51e87ba54b83e5bd5ef4f
--- /dev/null
+++ b/LHCData/LHCDataAlgs/src/LHCDataAlg.h
@@ -0,0 +1,47 @@
+#ifndef LHCDATAALG_H
+#define LHCDATAALG_H
+
+#include "AthenaBaseComps/AthReentrantAlgorithm.h"
+
+#include "StoreGate/ReadCondHandleKey.h"
+#include "StoreGate/WriteCondHandleKey.h"
+
+#include "GaudiKernel/ToolHandle.h"
+#include "GaudiKernel/ICondSvc.h"
+#include "GaudiKernel/ServiceHandle.h"
+
+#include "xAODFaserLHC/FaserLHCData.h"
+#include "xAODEventInfo/EventInfo.h"
+
+#include "LHCDataTools/ILHCDataTool.h"
+
+class LHCDataAlg : public AthReentrantAlgorithm {
+ public:
+  LHCDataAlg(const std::string& name, ISvcLocator* pSvcLocator);
+  virtual ~LHCDataAlg() = default;
+
+  virtual StatusCode initialize() override;
+  virtual StatusCode execute(const EventContext& ctx) const override;
+  virtual StatusCode finalize() override;
+  virtual bool isClonable() const override { return true; };
+
+ private:
+  ToolHandle<ILHCDataTool> m_lhcTool{this, "LHCDataTool", "LHCDataTool"};
+  SG::ReadHandleKey<xAOD::EventInfo> m_eventInfo{ this, "EventInfoKey", "EventInfo", "ReadHandleKey for xAOD::EventInfo"};
+  SG::WriteHandleKey<xAOD::FaserLHCData> m_lhcDataKey
+    {this, "FaserLHCDataKey", "FaserLHCData"};
+
+  // Utility function to find nearest BCID
+  int findNearest(unsigned int bcid, const std::vector<unsigned char>& bcid_mask, 
+		  unsigned char mask) const;
+
+  unsigned int 
+    previousColliding(unsigned int bcid, const std::vector<unsigned char>& bcid_mask) const;
+
+  // Find the distance to the first BCID of the previous train
+  unsigned int 
+    previousTrain(unsigned int bcid, const std::vector<unsigned char>& bcid_mask) const;
+
+};
+
+#endif // LHCDATAALG_H
diff --git a/LHCData/LHCDataAlgs/src/components/LHCDataAlgs_entries.cxx b/LHCData/LHCDataAlgs/src/components/LHCDataAlgs_entries.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..1620e8dcfc1af5dc0ae3f2bc4af406684b120896
--- /dev/null
+++ b/LHCData/LHCDataAlgs/src/components/LHCDataAlgs_entries.cxx
@@ -0,0 +1,3 @@
+#include "../LHCDataAlg.h"
+
+DECLARE_COMPONENT( LHCDataAlg )
diff --git a/LHCData/LHCDataTools/CMakeLists.txt b/LHCData/LHCDataTools/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..248abc91d58df409f4bc1e65324743c2f66755dd
--- /dev/null
+++ b/LHCData/LHCDataTools/CMakeLists.txt
@@ -0,0 +1,27 @@
+###############################################################################
+# Package: LHCDataTools
+################################################################################
+
+# Declare the package name:
+atlas_subdir( LHCDataTools )
+
+# External dependencies:
+find_package( CLHEP )
+find_package( ROOT COMPONENTS Core Tree MathCore Hist RIO pthread )
+
+# Component(s) in the package:
+atlas_add_component ( LHCDataTools
+                      src/components/*.cxx
+                      INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} ${CLHEP_INCLUDE_DIRS}
+                      LINK_LIBRARIES ${ROOT_LIBRARIES} ${CLHEP_LIBRARIES} AthenaKernel LHCDataToolsLib GaudiKernel AthenaBaseComps AthenaPoolUtilities StoreGateLib xAODEventInfo )
+
+
+atlas_add_library( LHCDataToolsLib
+                  src/*.cxx
+                  PUBLIC_HEADERS LHCDataTools
+                  INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} ${CLHEP_INCLUDE_DIRS}
+                  LINK_LIBRARIES ${ROOT_LIBRARIES} ${CLHEP_LIBRARIES} AthenaKernel  GaudiKernel AthenaBaseComps AthenaPoolUtilities StoreGateLib xAODEventInfo )
+
+# Install files from the package:
+atlas_install_python_modules( python/*.py )
+
diff --git a/LHCData/LHCDataTools/LHCDataTools/ILHCDataTool.h b/LHCData/LHCDataTools/LHCDataTools/ILHCDataTool.h
new file mode 100644
index 0000000000000000000000000000000000000000..6e469d0ebecd41d08333d20eb0778f5bfef5d404
--- /dev/null
+++ b/LHCData/LHCDataTools/LHCDataTools/ILHCDataTool.h
@@ -0,0 +1,75 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS and FAsER collaborations
+*/
+
+/** @file ILHCDataTool.h Interface file for LHCDataTool.
+ */
+
+// Multiple inclusion protection
+#ifndef ILHCDATATOOL
+#define ILHCDATATOOL
+
+//STL includes
+#include <map>
+
+//Gaudi Includes
+#include "GaudiKernel/IAlgTool.h"
+#include "GaudiKernel/EventContext.h"
+
+class ILHCDataTool: virtual public IAlgTool {
+
+ public:
+  
+  //----------Public Member Functions----------//
+  // Structors
+  virtual ~ILHCDataTool() = default; //!< Destructor
+
+  /// Creates the InterfaceID and interfaceID() method
+  DeclareInterfaceID(ILHCDataTool, 1, 0);
+
+  // Methods to return fill data
+  virtual int getFillNumber(const EventContext& ctx) const = 0;
+  virtual int getFillNumber(void) const = 0;
+
+  virtual std::string getMachineMode(const EventContext& ctx) const = 0;
+  virtual std::string getMachineMode(void) const = 0;
+
+  virtual std::string getInjectionScheme(const EventContext& ctx) const = 0;
+  virtual std::string getInjectionScheme(void) const = 0;
+
+  virtual int getBeamType1(const EventContext& ctx) const = 0;
+  virtual int getBeamType1(void) const = 0;
+
+  virtual int getBeamType2(const EventContext& ctx) const = 0;
+  virtual int getBeamType2(void) const = 0;
+
+  // Methods to return beam data
+  virtual std::string getBeamMode(const EventContext& ctx) const = 0;
+  virtual std::string getBeamMode(void) const = 0;
+
+  virtual float getBetaStar(const EventContext& ctx) const = 0;
+  virtual float getBetaStar(void) const = 0;
+
+  virtual float getCrossingAngle(const EventContext& ctx) const = 0;
+  virtual float getCrossingAngle(void) const = 0;
+
+  virtual bool getStableBeams(const EventContext& ctx) const = 0;
+  virtual bool getStableBeams(void) const = 0;
+
+  // Methods to return BCID data
+  virtual unsigned int getBeam1Bunches(const EventContext& ctx) const = 0;
+  virtual unsigned int getBeam1Bunches(void) const = 0;
+
+  virtual unsigned int getBeam2Bunches(const EventContext& ctx) const = 0;
+  virtual unsigned int getBeam2Bunches(void) const = 0;
+
+  virtual unsigned int getCollidingBunches(const EventContext& ctx) const = 0;
+  virtual unsigned int getCollidingBunches(void) const = 0;
+
+  virtual std::vector<unsigned char> getBCIDMasks(const EventContext& ctx) const = 0;
+  virtual std::vector<unsigned char> getBCIDMasks(void) const = 0;
+
+};
+
+//---------------------------------------------------------------------- 
+#endif // LHCDATATOOL
diff --git a/LHCData/LHCDataTools/python/LHCDataToolsConfig.py b/LHCData/LHCDataTools/python/LHCDataToolsConfig.py
new file mode 100644
index 0000000000000000000000000000000000000000..cdd2d267cb63d5ba05378eff252afe4c6d97fe8e
--- /dev/null
+++ b/LHCData/LHCDataTools/python/LHCDataToolsConfig.py
@@ -0,0 +1,19 @@
+# Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
+from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
+from AthenaConfiguration.ComponentFactory import CompFactory
+from IOVDbSvc.IOVDbSvcConfig import addFolders
+
+def LHCDataCfg(flags, **kwargs):
+    acc = ComponentAccumulator()
+    dbInstance = kwargs.get("dbInstance", "COOLOFL_LHC")
+    dbName = flags.IOVDb.DatabaseInstance # e.g. CONDBR3 
+
+    #acc.merge(addFolders(flags, folder_list, dbInstance, className="AthenaAttributeList"))
+    # COOLOFL_LHC is not known to ATLAS IOVDBSvc
+    # Must use non-shorthand folder specification here
+    folder_list = ["/LHC/FillData", "/LHC/BeamData", "/LHC/BCIDData"]
+    for folder_name in folder_list:
+        folder_string = f"<db>{dbInstance}/{dbName}</db> {folder_name}"
+        acc.merge(addFolders(flags, folder_string, className="AthenaAttributeList"))
+    return acc
+
diff --git a/LHCData/LHCDataTools/src/LHCDataTool.cxx b/LHCData/LHCDataTools/src/LHCDataTool.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..7b0fafe00d7137d0d62e81c28f77d812d2501001
--- /dev/null
+++ b/LHCData/LHCDataTools/src/LHCDataTool.cxx
@@ -0,0 +1,237 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS and FASER collaborations
+*/
+
+/** @file LHCDataTool.cxx Implementation file for LHCDataTool.
+    @author Eric Torrence (05/02/22)
+*/
+
+#include "LHCDataTool.h"
+#include "CoralBase/Blob.h"
+
+//----------------------------------------------------------------------
+LHCDataTool::LHCDataTool (const std::string& type, const std::string& name, const IInterface* parent) :
+  base_class(type, name, parent)
+{
+}
+
+//----------------------------------------------------------------------
+StatusCode 
+LHCDataTool::initialize() {
+
+  ATH_MSG_DEBUG("LHCDataTool::initialize()");
+
+  // Read Handles
+  //ATH_CHECK(m_fillDataKey.initialize());
+  ATH_CHECK(m_beamDataKey.initialize());
+  ATH_CHECK(m_bcidDataKey.initialize());
+
+  return StatusCode::SUCCESS;
+}
+
+//----------------------------------------------------------------------
+StatusCode
+LHCDataTool::finalize() {
+  // Print where you are
+  return StatusCode::SUCCESS;
+}
+
+//----------------------------------------------------------------------
+int
+LHCDataTool::getFillNumber(const EventContext& ctx) const {
+  // Read Cond Handle
+  SG::ReadCondHandle<AthenaAttributeList> readHandle{m_beamDataKey, ctx};
+  return (**readHandle)["FillNumber"].data<int>();
+} 
+
+int
+LHCDataTool::getFillNumber(void) const {
+  const EventContext& ctx{Gaudi::Hive::currentContext()};
+  return getFillNumber(ctx);
+}
+
+//----------------------------------------------------------------------
+std::string
+LHCDataTool::getMachineMode(const EventContext& ctx) const {
+  // Read Cond Handle
+  SG::ReadCondHandle<AthenaAttributeList> readHandle{m_beamDataKey, ctx};
+  return (**readHandle)["MachineMode"].data<std::string>();
+} 
+
+std::string
+LHCDataTool::getMachineMode(void) const {
+  const EventContext& ctx{Gaudi::Hive::currentContext()};
+  return getMachineMode(ctx);
+}
+
+//----------------------------------------------------------------------
+std::string
+LHCDataTool::getBeamMode(const EventContext& ctx) const {
+  SG::ReadCondHandle<AthenaAttributeList> readHandle{m_beamDataKey, ctx};
+  return(**readHandle)["BeamMode"].data<std::string>();
+}
+
+std::string
+LHCDataTool::getBeamMode(void) const {
+  const EventContext& ctx{Gaudi::Hive::currentContext()};
+  return getBeamMode(ctx);
+}
+
+//----------------------------------------------------------------------
+int
+LHCDataTool::getBeamType1(const EventContext& ctx) const {
+  // Read Cond Handle
+  SG::ReadCondHandle<AthenaAttributeList> readHandle{m_beamDataKey, ctx};
+  return (**readHandle)["BeamType1"].data<int>();
+} 
+
+int
+LHCDataTool::getBeamType1(void) const {
+  const EventContext& ctx{Gaudi::Hive::currentContext()};
+  return getBeamType1(ctx);
+}
+
+//----------------------------------------------------------------------
+int
+LHCDataTool::getBeamType2(const EventContext& ctx) const {
+  // Read Cond Handle
+  SG::ReadCondHandle<AthenaAttributeList> readHandle{m_beamDataKey, ctx};
+  return (**readHandle)["BeamType2"].data<int>();
+} 
+
+int
+LHCDataTool::getBeamType2(void) const {
+  const EventContext& ctx{Gaudi::Hive::currentContext()};
+  return getBeamType2(ctx);
+}
+
+//----------------------------------------------------------------------
+float
+LHCDataTool::getBetaStar(const EventContext& ctx) const {
+  SG::ReadCondHandle<AthenaAttributeList> readHandle{m_beamDataKey, ctx};
+  return(**readHandle)["BetaStar"].data<float>();
+}
+
+float
+LHCDataTool::getBetaStar(void) const {
+  const EventContext& ctx{Gaudi::Hive::currentContext()};
+  return getBetaStar(ctx);
+}
+
+//----------------------------------------------------------------------
+float
+LHCDataTool::getCrossingAngle(const EventContext& ctx) const {
+  SG::ReadCondHandle<AthenaAttributeList> readHandle{m_beamDataKey, ctx};
+  return(**readHandle)["CrossingAngle"].data<float>();
+}
+
+float
+LHCDataTool::getCrossingAngle(void) const {
+  const EventContext& ctx{Gaudi::Hive::currentContext()};
+  return getCrossingAngle(ctx);
+}
+
+//----------------------------------------------------------------------
+bool
+LHCDataTool::getStableBeams(const EventContext& ctx) const {
+  SG::ReadCondHandle<AthenaAttributeList> readHandle{m_beamDataKey, ctx};
+  return(**readHandle)["StableBeams"].data<bool>();
+}
+
+bool
+LHCDataTool::getStableBeams(void) const {
+  const EventContext& ctx{Gaudi::Hive::currentContext()};
+  return getStableBeams(ctx);
+}
+
+//----------------------------------------------------------------------
+std::string
+LHCDataTool::getInjectionScheme(const EventContext& ctx) const {
+  // Read Cond Handle
+  SG::ReadCondHandle<AthenaAttributeList> readHandle{m_beamDataKey, ctx};
+  return (**readHandle)["InjectionScheme"].data<std::string>();
+} 
+
+std::string
+LHCDataTool::getInjectionScheme(void) const {
+  const EventContext& ctx{Gaudi::Hive::currentContext()};
+  return getInjectionScheme(ctx);
+}
+
+//----------------------------------------------------------------------
+unsigned int
+LHCDataTool::getBeam1Bunches(const EventContext& ctx) const {
+  SG::ReadCondHandle<AthenaAttributeList> readHandle{m_bcidDataKey, ctx};
+  return(**readHandle)["Beam1Bunches"].data<unsigned int>();
+}
+
+unsigned int
+LHCDataTool::getBeam1Bunches(void) const {
+  const EventContext& ctx{Gaudi::Hive::currentContext()};
+  return getBeam1Bunches(ctx);
+}
+
+unsigned int
+LHCDataTool::getBeam2Bunches(const EventContext& ctx) const {
+  SG::ReadCondHandle<AthenaAttributeList> readHandle{m_bcidDataKey, ctx};
+  return(**readHandle)["Beam2Bunches"].data<unsigned int>();
+}
+
+unsigned int
+LHCDataTool::getBeam2Bunches(void) const {
+  const EventContext& ctx{Gaudi::Hive::currentContext()};
+  return getBeam2Bunches(ctx);
+}
+
+unsigned int
+LHCDataTool::getCollidingBunches(const EventContext& ctx) const {
+  SG::ReadCondHandle<AthenaAttributeList> readHandle{m_bcidDataKey, ctx};
+  return(**readHandle)["CollidingBunches"].data<unsigned int>();
+}
+
+unsigned int
+LHCDataTool::getCollidingBunches(void) const {
+  const EventContext& ctx{Gaudi::Hive::currentContext()};
+  return getCollidingBunches(ctx);
+}
+
+
+//----------------------------------------------------------------------
+// This function unpacks the blob every time this is accesed
+// Should probably cache this using a callback
+std::vector<unsigned char>
+LHCDataTool::getBCIDMasks(const EventContext& ctx) const {
+
+  SG::ReadCondHandle<AthenaAttributeList> bcidHandle{m_bcidDataKey, ctx};
+  const coral::Blob& blob = (**bcidHandle)["BCIDmasks"].data<coral::Blob>();
+  const unsigned char* p = static_cast<const unsigned char*>(blob.startingAddress());
+
+  // Should always be 3564 BCIDs
+  if (blob.size() != 3564) {
+    ATH_MSG_WARNING("Found BCID blob with size " << blob.size() << "!");
+  }
+
+  std::vector<unsigned char> bcid_vector(3564);
+
+  bool first = true;
+  for (int i=0; i<blob.size(); i++) {
+    // First BCID is 1, but this is stored at location i=1
+    // So you can index this vector as bcid_vector[bcid_number]
+    bcid_vector[i] = *p++;  
+    if (first && (bcid_vector[i] == 3)) {
+      first = false;
+      ATH_MSG_DEBUG("Found first colliding BCID at " << i);
+    }
+  }
+
+  return bcid_vector;
+}
+
+std::vector<unsigned char>
+LHCDataTool::getBCIDMasks(void) const {
+  const EventContext& ctx{Gaudi::Hive::currentContext()};
+  return getBCIDMasks(ctx);
+}
+
+
+
diff --git a/LHCData/LHCDataTools/src/LHCDataTool.h b/LHCData/LHCDataTools/src/LHCDataTool.h
new file mode 100644
index 0000000000000000000000000000000000000000..3acabfb7502ac6b33d5b6d8a918fe8be97582b74
--- /dev/null
+++ b/LHCData/LHCDataTools/src/LHCDataTool.h
@@ -0,0 +1,101 @@
+// -*- C++ -*-
+
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS and CERN collaborations
+*/
+
+/** @file LHCDataTool.h Header file for LHCDataTool.
+    @author Eric Torrence, 20/04/22
+*/
+
+// Multiple inclusion protection
+#ifndef LHCDATA_TOOL
+#define LHCDATA_TOOL
+
+// Include interface class
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "LHCDataTools/ILHCDataTool.h"
+
+// Include Athena stuff
+#include "AthenaPoolUtilities/CondAttrListCollection.h"
+#include "StoreGate/ReadCondHandleKey.h"
+
+#include "GaudiKernel/ICondSvc.h"
+#include "Gaudi/Property.h"
+
+// Include Gaudi classes
+#include "GaudiKernel/EventContext.h"
+
+/** This class contains a Tool that reads Waveform range data and makes it available to 
+    other algorithms. The current implementation reads the data from a COOL database. 
+*/
+
+class LHCDataTool: public extends<AthAlgTool, ILHCDataTool> {
+
+ public:
+  //----------Public Member Functions----------//
+  // Structors
+  LHCDataTool(const std::string& type, const std::string& name, const IInterface* parent); //!< Constructor
+  virtual ~LHCDataTool() = default; //!< Destructor
+
+  // Standard Gaudi functions
+  virtual StatusCode initialize() override; //!< Gaudi initialiser
+  virtual StatusCode finalize() override; //!< Gaudi finaliser
+
+  // Methods to return fill data
+  // Methods to return beam data
+  virtual int getFillNumber(const EventContext& ctx) const override;
+  virtual int getFillNumber(void) const override;
+
+  virtual std::string getMachineMode(const EventContext& ctx) const override;
+  virtual std::string getMachineMode(void) const override;
+
+  virtual std::string getBeamMode(const EventContext& ctx) const override;
+  virtual std::string getBeamMode(void) const override;
+
+  virtual int getBeamType1(const EventContext& ctx) const override;
+  virtual int getBeamType1(void) const override;
+
+  virtual int getBeamType2(const EventContext& ctx) const override;
+  virtual int getBeamType2(void) const override;
+
+  virtual float getBetaStar(const EventContext& ctx) const override;
+  virtual float getBetaStar(void) const override;
+
+  virtual float getCrossingAngle(const EventContext& ctx) const override;
+  virtual float getCrossingAngle(void) const override;
+
+  virtual bool getStableBeams(const EventContext& ctx) const override;
+  virtual bool getStableBeams(void) const override;
+
+  virtual std::string getInjectionScheme(const EventContext& ctx) const override;
+  virtual std::string getInjectionScheme(void) const override;
+
+  // Methods to return BCID data
+  virtual unsigned int getBeam1Bunches(const EventContext& ctx) const override;
+  virtual unsigned int getBeam1Bunches(void) const override;
+
+  virtual unsigned int getBeam2Bunches(const EventContext& ctx) const override;
+  virtual unsigned int getBeam2Bunches(void) const override;
+
+  virtual unsigned int getCollidingBunches(const EventContext& ctx) const override;
+  virtual unsigned int getCollidingBunches(void) const override;
+
+  // This returns a char for each BCID encoding beam1/beam2
+  // A colliding BCID will have value 3
+  // BCIDs always count starting at 1
+  virtual std::vector<unsigned char> getBCIDMasks(const EventContext& ctx) const override;
+  virtual std::vector<unsigned char> getBCIDMasks(void) const override;
+
+ private:
+  // Read Cond Handles
+  //SG::ReadCondHandleKey<AthenaAttributeList> m_fillDataKey{this, "FillDataKey", "/LHC/FillData", "Key of fill data folder"};
+  SG::ReadCondHandleKey<AthenaAttributeList> m_beamDataKey{this, "BeamDataKey", "/LHC/BeamData", "Key of fill data folder"};
+  SG::ReadCondHandleKey<AthenaAttributeList> m_bcidDataKey{this, "BcidDataKey", "/LHC/BCIDData", "Key of fill data folder"};
+
+  ServiceHandle<ICondSvc> m_condSvc{this, "CondSvc", "CondSvc"};
+
+};
+
+//---------------------------------------------------------------------- 
+#endif // LHCDATA_TOOL
diff --git a/LHCData/LHCDataTools/src/components/LHCDataTools_entries.cxx b/LHCData/LHCDataTools/src/components/LHCDataTools_entries.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..1f44bf0909b4a2be2b03f8e276baab0c5ed58cf9
--- /dev/null
+++ b/LHCData/LHCDataTools/src/components/LHCDataTools_entries.cxx
@@ -0,0 +1,3 @@
+#include "../LHCDataTool.h"
+
+DECLARE_COMPONENT( LHCDataTool )
diff --git a/Waveform/WaveformConditions/WaveformConditionsTools/python/WaveformRangeConfig.py b/Waveform/WaveformConditions/WaveformConditionsTools/python/WaveformRangeConfig.py
index 6450bcec88b3cb8c7194b01edeb59aa6b97e242f..8ac69d912af498475d443f58b3583fc6fdb614c8 100644
--- a/Waveform/WaveformConditions/WaveformConditionsTools/python/WaveformRangeConfig.py
+++ b/Waveform/WaveformConditions/WaveformConditionsTools/python/WaveformRangeConfig.py
@@ -20,8 +20,14 @@ def WaveformRangeCfg(flags, **kwargs):
     acc = ComponentAccumulator()
     # tool = kwargs.get("WaveformRangeTool", WaveformRangeTool(flags))
     # Probably need to figure this out!
-    dbInstance = kwargs.get("dbInstance", "TDAQ_OFL")
+
+    dbInstance = kwargs.get("dbInstance", "COOLOFL_DIGITIZER")
     dbFolder = kwargs.get("dbFolder", "/WAVE/DAQ/Range")
-    acc.merge(addFolders(flags, dbFolder, dbInstance, className="CondAttrListCollection"))
+    dbName = flags.IOVDb.DatabaseInstance # e.g. CONDBR3 
+
+    # COOLOFL_DIGITIZER is not known to ATLAS IOVDBSvc
+    # Must use non-shorthand folder specification here
+    folder_string = f"<db>{dbInstance}/{dbName}</db> {dbFolder}"
+    acc.merge(addFolders(flags, folder_string, className="CondAttrListCollection"))
     return acc
 
diff --git a/xAOD/xAODFaserLHC/CMakeLists.txt b/xAOD/xAODFaserLHC/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..577da2cc72aa0ecb03a16a9b0b440b2eaf2da3eb
--- /dev/null
+++ b/xAOD/xAODFaserLHC/CMakeLists.txt
@@ -0,0 +1,27 @@
+# Copyright (C) 2020 CERN for the benefit of the FASER collaboration
+
+# Declare the package name.
+atlas_subdir( xAODFaserLHC )
+
+# External dependencies.
+find_package( xAODUtilities )
+
+# Component(s) in the package.
+atlas_add_library( xAODFaserLHC
+   xAODFaserLHC/*.h xAODFaserLHC/versions/*.h Root/*.cxx
+   PUBLIC_HEADERS xAODFaserLHC
+   LINK_LIBRARIES xAODCore )
+
+atlas_add_xaod_smart_pointer_dicts(
+   INPUT xAODFaserLHC/selection.xml
+   OUTPUT _selectionFile
+   OBJECTS "xAOD::FaserLHCData_v1" "xAOD::FaserLHCDataAux_v1")
+
+atlas_add_dictionary( xAODFaserLHCDict
+   xAODFaserLHC/xAODFaserLHCDict.h
+   ${_selectionFile}
+   LINK_LIBRARIES xAODCore xAODFaserLHC
+   EXTRA_FILES Root/dict/*.cxx )
+
+# Understand what this does...
+atlas_generate_cliddb( xAODFaserLHC )
diff --git a/xAOD/xAODFaserLHC/Root/FaserLHCDataAux_v1.cxx b/xAOD/xAODFaserLHC/Root/FaserLHCDataAux_v1.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..e9b981b33b5252b2cd5d627096462468c517e7e3
--- /dev/null
+++ b/xAOD/xAODFaserLHC/Root/FaserLHCDataAux_v1.cxx
@@ -0,0 +1,54 @@
+/*
+  Copyright (C) 2020 CERN for the benefit of the FASER collaboration
+*/
+
+// $Id: $
+
+// Local include(s):
+#include "xAODFaserLHC/versions/FaserLHCDataAux_v1.h"
+
+namespace xAOD {
+
+  FaserLHCDataAux_v1::FaserLHCDataAux_v1()
+    : AuxInfoBase(),
+      fillNumber(0), 
+      machineMode(""),
+      beamMode(""),
+      beamType1(0),
+      beamType2(0),
+      betaStar(0),
+      crossingAngle(0),
+      stableBeams(false),
+      injectionScheme(""),
+      numBunchBeam1(0),
+      numBunchBeam2(0),
+      numBunchColliding(0),
+      distanceToCollidingBCID(0),
+      distanceToUnpairedB1(0),
+      distanceToUnpairedB2(0),
+      distanceToInboundB1(0),
+      distanceToTrainStart(0),
+      distanceToPreviousColliding(0)
+  {
+    AUX_VARIABLE( fillNumber );
+    AUX_VARIABLE( machineMode );
+    AUX_VARIABLE( beamMode );
+    AUX_VARIABLE( beamType1 );
+    AUX_VARIABLE( beamType2 );
+    AUX_VARIABLE( betaStar );
+    AUX_VARIABLE( crossingAngle );
+    AUX_VARIABLE( stableBeams );
+    AUX_VARIABLE( injectionScheme );
+    AUX_VARIABLE( numBunchBeam1 );
+    AUX_VARIABLE( numBunchBeam2 );
+    AUX_VARIABLE( numBunchColliding );
+    AUX_VARIABLE( distanceToCollidingBCID );
+    AUX_VARIABLE( distanceToUnpairedB1 );
+    AUX_VARIABLE( distanceToUnpairedB2 );
+    AUX_VARIABLE( distanceToInboundB1 );
+    AUX_VARIABLE( distanceToTrainStart );
+    AUX_VARIABLE( distanceToPreviousColliding );
+
+  }
+
+} // namespace xAOD
diff --git a/xAOD/xAODFaserLHC/Root/FaserLHCData_v1.cxx b/xAOD/xAODFaserLHC/Root/FaserLHCData_v1.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..b09c8c85dcc0b19ae7fea0120c79a706336d0387
--- /dev/null
+++ b/xAOD/xAODFaserLHC/Root/FaserLHCData_v1.cxx
@@ -0,0 +1,92 @@
+/*
+  Copyright (C) 2020 CERN for the benefit of the FASER collaboration
+*/
+
+// $Id: $
+
+// xAOD include(s):
+#include "xAODCore/AuxStoreAccessorMacros.h"
+
+// Local include(s):
+#include "xAODFaserLHC/versions/FaserLHCData_v1.h"
+
+namespace xAOD {
+
+  FaserLHCData_v1::FaserLHCData_v1() 
+    : SG::AuxElement() {
+  }
+
+  /////////////////////////////////////////////////////////////////////////////
+  //
+  //              Implementation for the start time functions
+  AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( FaserLHCData_v1, unsigned int,
+					fillNumber, set_fillNumber )
+
+  AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( FaserLHCData_v1, std::string,
+					machineMode, set_machineMode )
+
+  AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( FaserLHCData_v1, std::string, 
+					beamMode, set_beamMode )
+
+  AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( FaserLHCData_v1, int,
+					beamType1, set_beamType1 )
+
+  AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( FaserLHCData_v1, int,
+					beamType2, set_beamType2 )
+
+  AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( FaserLHCData_v1, float, 
+					betaStar, set_betaStar )
+
+  AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( FaserLHCData_v1, float, 
+					crossingAngle, set_crossingAngle )
+
+  AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( FaserLHCData_v1, bool, 
+					stableBeams, set_stableBeams )
+
+  AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( FaserLHCData_v1, std::string, 
+					injectionScheme, set_injectionScheme )
+
+  AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( FaserLHCData_v1, unsigned int, 
+					numBunchBeam1, set_numBunchBeam1 )
+
+  AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( FaserLHCData_v1, unsigned int, 
+					numBunchBeam2, set_numBunchBeam2 )
+
+  AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( FaserLHCData_v1, unsigned int, 
+					numBunchColliding, set_numBunchColliding )
+
+  AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( FaserLHCData_v1, int, 
+					distanceToCollidingBCID, set_distanceToCollidingBCID )
+
+  AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( FaserLHCData_v1, int, 
+					distanceToUnpairedB1, set_distanceToUnpairedB1 )
+
+  AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( FaserLHCData_v1, int, 
+					distanceToUnpairedB2, set_distanceToUnpairedB2 )
+
+  AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( FaserLHCData_v1, int, 
+					distanceToInboundB1, set_distanceToInboundB1 )
+
+  AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( FaserLHCData_v1, unsigned int, 
+					distanceToTrainStart, set_distanceToTrainStart )
+
+  AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( FaserLHCData_v1, unsigned int, 
+					distanceToPreviousColliding, set_distanceToPreviousColliding )
+
+
+
+} // namespace xAOD
+
+namespace xAOD {
+
+  std::ostream& operator<<(std::ostream& s, const xAOD::FaserLHCData_v1& td) {
+    s << "xAODFaserLHCData: fill=" << td.fillNumber()
+      << " beamMode=" << td.beamMode()
+      << " betaStar=" << td.betaStar()
+      << " distanceToCollidingBCID=" << td.distanceToCollidingBCID()
+      << std::endl;
+
+    return s;
+  }
+
+} // namespace xAOD
diff --git a/xAOD/xAODFaserLHC/Root/xAODFaserLHCCLIDs.cxx b/xAOD/xAODFaserLHC/Root/xAODFaserLHCCLIDs.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..86811f0c3f95dc6b511ecfb2059561ea2b875c53
--- /dev/null
+++ b/xAOD/xAODFaserLHC/Root/xAODFaserLHCCLIDs.cxx
@@ -0,0 +1,8 @@
+/*
+  Copyright (C) 2020 CERN for the benefit of the FASER collaboration
+*/
+
+//simple includes to force the CLASS_DEF etc to be encountered during compile
+
+#include "xAODFaserLHC/FaserLHCData.h"
+#include "xAODFaserLHC/FaserLHCDataAux.h"
diff --git a/xAOD/xAODFaserLHC/xAODFaserLHC/FaserLHCData.h b/xAOD/xAODFaserLHC/xAODFaserLHC/FaserLHCData.h
new file mode 100644
index 0000000000000000000000000000000000000000..561c8782ca68c12381928815f999d45264d73168
--- /dev/null
+++ b/xAOD/xAODFaserLHC/xAODFaserLHC/FaserLHCData.h
@@ -0,0 +1,22 @@
+// Dear emacs, this is -*- c++ -*-
+
+/*
+  Copyright (C) 2020 CERN for the benefit of the FASER collaboration
+*/
+
+#ifndef XAODFASERLHC_FASERLHCDATA_H
+#define XAODFASERLHC_FASERLHCDATA_H
+
+// Local include(s):
+#include "xAODFaserLHC/versions/FaserLHCData_v1.h"
+
+namespace xAOD {
+  /// Declare the latest version of the class
+  typedef FaserLHCData_v1 FaserLHCData;
+}
+
+// Set up a CLID for the container:
+#include "xAODCore/CLASS_DEF.h"
+CLASS_DEF( xAOD::FaserLHCData, 255278152, 1 )
+
+#endif // XAODFASERLHC_FASERLHCDATA_H
diff --git a/xAOD/xAODFaserLHC/xAODFaserLHC/FaserLHCDataAux.h b/xAOD/xAODFaserLHC/xAODFaserLHC/FaserLHCDataAux.h
new file mode 100644
index 0000000000000000000000000000000000000000..6eeac626679c0e95a000d01f96e436b8ad250eb6
--- /dev/null
+++ b/xAOD/xAODFaserLHC/xAODFaserLHC/FaserLHCDataAux.h
@@ -0,0 +1,22 @@
+// Dear emacs, this is -*- c++ -*-
+
+/*
+  Copyright (C) 2020 CERN for the benefit of the FASER collaboration
+*/
+
+#ifndef XAODFASERLHC_FASERLHCDATAAUX_H
+#define XAODFASERLHC_FASERLHCDATAAUX_H
+
+// Local include(s):
+#include "xAODFaserLHC/versions/FaserLHCDataAux_v1.h"
+
+namespace xAOD {
+  /// Declare the latest version of the class
+  typedef FaserLHCDataAux_v1 FaserLHCDataAux;
+}
+
+// Set up a CLID for the container:
+#include "xAODCore/CLASS_DEF.h"
+CLASS_DEF( xAOD::FaserLHCDataAux, 151779941, 1 )
+
+#endif // XAODFASERLHC_FASERLHCDATAAUX_H
diff --git a/xAOD/xAODFaserLHC/xAODFaserLHC/selection.xml b/xAOD/xAODFaserLHC/xAODFaserLHC/selection.xml
new file mode 100644
index 0000000000000000000000000000000000000000..c4ba39f9a6acad53d40208f74cb387ed89b3c36f
--- /dev/null
+++ b/xAOD/xAODFaserLHC/xAODFaserLHC/selection.xml
@@ -0,0 +1,13 @@
+<!-- Copyright (C) 2020 CERN for the benefit of the FASER collaboration -->
+<!-- Missing id values here, need to figure out where these come from... -->
+<lcgdict>
+
+  <class name="xAOD::FaserLHCData_v1" 
+	 id="6c373036-fad1-476c-9a8b-15591faccf00"/>
+  <typedef name="xAOD::FaserLHCData" />
+
+  <class name="xAOD::FaserLHCDataAux_v1" 
+	 id="484ef174-8efb-426a-888c-827f72ed972a"/>
+  <typedef name="xAOD::FaserLHCDataAux" />
+
+</lcgdict>
diff --git a/xAOD/xAODFaserLHC/xAODFaserLHC/versions/FaserLHCDataAux_v1.h b/xAOD/xAODFaserLHC/xAODFaserLHC/versions/FaserLHCDataAux_v1.h
new file mode 100644
index 0000000000000000000000000000000000000000..bc1034143f4338ba39403ea82a7dde8561c636e7
--- /dev/null
+++ b/xAOD/xAODFaserLHC/xAODFaserLHC/versions/FaserLHCDataAux_v1.h
@@ -0,0 +1,74 @@
+// Dear emacs, this is -*- c++ -*-
+
+/*
+  Copyright (C) 2020 CERN for the benefit of the FASER collaboration
+*/
+
+#ifndef XAODFASERLHC_VERSIONS_FASERLHCDATAAUX_V1_H
+#define XAODFASERLHC_VERSIONS_FASERLHCDATAAUX_V1_H
+
+// System include(s):
+extern "C" {
+#   include "stdint.h"
+}
+
+// xAOD include(s):
+#include "xAODCore/AuxInfoBase.h"
+
+namespace xAOD {
+
+  /// Class holding the data handled by FaserLHCData_v1
+  ///
+  /// This class holds the payload of the TLB raw data
+  ///
+  /// @author Eric Torrence <torrence@uoregon.edu>
+  ///
+  /// $Revision:  $
+  /// $Date: $
+
+  class FaserLHCDataAux_v1 : public AuxInfoBase {
+
+  public:
+    /// Default constructor
+    FaserLHCDataAux_v1();
+
+  private:
+    /// @name LHCData payload
+    /// @{
+    unsigned int fillNumber;
+    std::string machineMode;
+    std::string beamMode;
+    int beamType1;
+    int beamType2;
+
+    float betaStar;
+    float crossingAngle;
+
+    bool stableBeams;
+    std::string injectionScheme;
+
+    unsigned int numBunchBeam1;
+    unsigned int numBunchBeam2;
+    unsigned int numBunchColliding;
+
+    int distanceToCollidingBCID;
+    int distanceToUnpairedB1;
+    int distanceToUnpairedB2;
+    int distanceToInboundB1;
+
+    unsigned int distanceToTrainStart;
+    unsigned int distanceToPreviousColliding;
+
+    /// @}
+
+  }; // class FaserLHCDataAuxContainer_v1
+
+} // namespace xAOD
+
+// Set up the StoreGate inheritance of the class:
+#include "xAODCore/BaseInfo.h"
+SG_BASE( xAOD::FaserLHCDataAux_v1, xAOD::AuxInfoBase );
+
+#endif // XAODFASERLHC_VERSIONS_FASERLHCDATAAUX_V1_H
+
+
diff --git a/xAOD/xAODFaserLHC/xAODFaserLHC/versions/FaserLHCData_v1.h b/xAOD/xAODFaserLHC/xAODFaserLHC/versions/FaserLHCData_v1.h
new file mode 100644
index 0000000000000000000000000000000000000000..fd6c68cc0545bc8e5f06c92fb5abb288d9ce4e9f
--- /dev/null
+++ b/xAOD/xAODFaserLHC/xAODFaserLHC/versions/FaserLHCData_v1.h
@@ -0,0 +1,127 @@
+// Dear emacs, this is -*- c++ -*-
+
+/*
+  Copyright (C) 2020 CERN for the benefit of the FASER collaboration
+*/
+
+#ifndef XAODFASERLHC_VERSIONS_FASERLHCDATA_V1_H
+#define XAODFASERLHC_VERSIONS_FASERLHCDATA_V1_H
+
+// System include(s):
+extern "C" {
+#   include "stdint.h"
+}
+
+// Core EDM include(s):
+#include "AthContainers/AuxElement.h"
+
+namespace xAOD {
+
+  /// Class describing the Faser LHC information
+  ///
+  ///
+  class FaserLHCData_v1 : public SG::AuxElement {
+
+  public:
+    /// Default constructor
+    FaserLHCData_v1();
+
+    /// @name Access LHC elements
+    /// @{
+
+    /// First batch comes from ATLAS /LHC/DCS/FILLSTATE folder
+    /// which is a copy of information sent to ATLAS by LHC over DIP
+    /// This is from the FASER COOL folder /LHC/BeamData
+
+    /// LHC fill number
+    unsigned int fillNumber() const;
+    void set_fillNumber(unsigned int value);
+
+    /// LHC machine mode (i.e. PROTON PHYSICS)
+    std::string machineMode() const; 
+    void set_machineMode(std::string value);
+
+    /// LHC Beam Mode (i.e. STABLE BEAMS)
+    std::string beamMode() const; 
+    void set_beamMode(std::string value);
+
+    /// LHC Beam type (charge of particle, 1-proton, 82-lead)
+    int beamType1() const;
+    void set_beamType1(int value);
+
+    int beamType2() const;
+    void set_beamType2(int value);
+
+    // Beta* at IP1, in cm
+    float betaStar() const;
+    void set_betaStar(float value);
+
+    // Crossing angle at IP1, in uRad
+    float crossingAngle() const;
+    void set_crossingAngle(float value);
+
+    // LHC stable beam flag
+    bool stableBeams() const;
+    void set_stableBeams(bool value);
+
+    // Injection scheme
+    std::string injectionScheme() const;
+    void set_injectionScheme(std::string value);
+
+    // Second batch is information is related to the BCID structure
+    // This comes from the LPC filling scheme (nominal values)
+    // and is stored in /LHC/BCIDData
+
+    /// Nominal bunches (derived from DIP "Circulating Bunch Configuration")
+    unsigned int numBunchBeam1() const;
+    void set_numBunchBeam1(unsigned int value);
+    unsigned int numBunchBeam2() const;
+    void set_numBunchBeam2(unsigned int value);
+    unsigned int numBunchColliding() const;
+    void set_numBunchColliding(unsigned int value);
+
+    // Number of BCIDs difference between current event BCID (from EventInfo)
+    // and a colliding BCID in the nominal bunch pattern
+
+    int distanceToCollidingBCID() const;
+    void set_distanceToCollidingBCID(int value);
+
+    int distanceToUnpairedB1() const;
+    void set_distanceToUnpairedB1(int value);
+
+    int distanceToUnpairedB2() const;
+    void set_distanceToUnpairedB2(int value);
+
+    int distanceToInboundB1() const;
+    void set_distanceToInboundB1(int value);
+
+    /// Distance of current BCID to start of previous bunch train
+    unsigned int distanceToTrainStart() const;
+    void set_distanceToTrainStart(unsigned int value);
+
+    /// Distance of current BCID frmo previous colliding BCID (0 if this is colliding)
+    unsigned int distanceToPreviousColliding() const;
+    void set_distanceToPreviousColliding(unsigned int value);
+
+    /// Simple boolean functions to access useful values
+    /// In most cases, these check that the distance above is zero
+    bool isStable() const { return this->stableBeams(); }
+    bool isColliding() const { return this->distanceToCollidingBCID() == 0; }
+    bool isUnpairedBeam1() const { return this->distanceToUnpairedB1() == 0; }
+    bool isUnpairedBeam2() const { return this->distanceToUnpairedB2() == 0; }
+    bool isInboundBeam1() const { return this->distanceToInboundB1() == 0; }
+
+    /// @}
+
+
+  }; // class FaserLHCData_v1
+
+  std::ostream& operator<<(std::ostream& s, const xAOD::FaserLHCData_v1& td);
+
+} // namespace xAOD
+
+// Declare the inheritance of the type:
+#include "xAODCore/BaseInfo.h"
+SG_BASE( xAOD::FaserLHCData_v1, SG::AuxElement );
+
+#endif // XAODFASERLHC_VERSIONS_FASERLHCDATA_V1_H
diff --git a/xAOD/xAODFaserLHC/xAODFaserLHC/xAODFaserLHCDict.h b/xAOD/xAODFaserLHC/xAODFaserLHC/xAODFaserLHCDict.h
new file mode 100644
index 0000000000000000000000000000000000000000..4715ad862918741fd85966378b821f18229ac66a
--- /dev/null
+++ b/xAOD/xAODFaserLHC/xAODFaserLHC/xAODFaserLHCDict.h
@@ -0,0 +1,27 @@
+/*
+  Copyright (C) 2020 CERN for the benefit of the FASER collaboration
+*/
+
+#ifndef XAODFASERLHC_XAODFASERLHCDICT_H
+#define XAODFASERLHC_XAODFASERLHCDICT_H
+
+// Local include(s):
+#include "xAODFaserLHC/FaserLHCData.h"
+#include "xAODFaserLHC/FaserLHCDataAux.h"
+#include "xAODFaserLHC/versions/FaserLHCData_v1.h"
+#include "xAODFaserLHC/versions/FaserLHCDataAux_v1.h"
+
+// EDM include(s).
+#include "xAODCore/tools/DictHelpers.h"
+
+namespace {
+  struct GCCXML_DUMMY_INSTANTIATION_XAODFASERLHC {
+    // Local type(s).
+    XAOD_INSTANTIATE_NS_OBJECT_TYPES( xAOD, FaserLHCData_v1 );
+
+  };
+}
+
+
+#endif // XAODFASERLHC_XAODFASERLHCDICT_H
+
diff --git a/xAOD/xAODFaserLHCAthenaPool/CMakeLists.txt b/xAOD/xAODFaserLHCAthenaPool/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..d15a49ccdcaeb1312417a6b0834eadb395296169
--- /dev/null
+++ b/xAOD/xAODFaserLHCAthenaPool/CMakeLists.txt
@@ -0,0 +1,14 @@
+# Copyright (C) 2020 CERN for the benefit of the FASER collaboration
+
+# Declare the package name.
+atlas_subdir( xAODFaserLHCAthenaPool )
+
+# Component(s) in the package:
+atlas_add_poolcnv_library( xAODFaserLHCAthenaPoolPoolCnv
+   src/*.h src/*.cxx
+   FILES xAODFaserLHC/FaserLHCData.h xAODFaserLHC/FaserLHCDataAux.h
+   TYPES_WITH_NAMESPACE xAOD::FaserLHCData xAOD::FaserLHCDataAux
+   CNV_PFX xAOD
+   LINK_LIBRARIES AthenaPoolCnvSvcLib AthenaPoolUtilities xAODFaserLHC )
+
+
diff --git a/xAOD/xAODFaserLHCAthenaPool/src/xAODFaserLHCDataAuxCnv.cxx b/xAOD/xAODFaserLHCAthenaPool/src/xAODFaserLHCDataAuxCnv.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..2ae9467033ddabd5b6c0e0fab94a5fb20c9c99de
--- /dev/null
+++ b/xAOD/xAODFaserLHCAthenaPool/src/xAODFaserLHCDataAuxCnv.cxx
@@ -0,0 +1,5 @@
+/*
+  Copyright (C) 2020 CERN for the benefit of the FASER collaboration
+*/
+
+// Dummy source file so that cmake will know this is a custom converter.
diff --git a/xAOD/xAODFaserLHCAthenaPool/src/xAODFaserLHCDataAuxCnv.h b/xAOD/xAODFaserLHCAthenaPool/src/xAODFaserLHCDataAuxCnv.h
new file mode 100644
index 0000000000000000000000000000000000000000..dc3f3f9afc0e6cf99a6348eef0dc5bc3b1764501
--- /dev/null
+++ b/xAOD/xAODFaserLHCAthenaPool/src/xAODFaserLHCDataAuxCnv.h
@@ -0,0 +1,16 @@
+// Dear emacs, this is -*- c++ -*-
+
+/*
+  Copyright (C) 2020 CERN for the benefit of the FASER collaboration
+*/
+
+#ifndef XAODFASERLHCDATAATHENAPOOL_XAODFASERLHCDATAAUXCNV_H
+#define XAODFASERLHCDATAATHENAPOOL_XAODFASERLHCDATAAUXCNV_H
+
+#include "xAODFaserLHC/FaserLHCDataAux.h"
+#include "AthenaPoolCnvSvc/T_AthenaPoolAuxContainerCnv.h"
+
+typedef T_AthenaPoolAuxContainerCnv<xAOD::FaserLHCDataAux> xAODFaserLHCDataAuxCnv;
+
+
+#endif // XAODFASERLHCDATAATHENAPOOL_XAODFASERLHCDATAAUXCNV_H
diff --git a/xAOD/xAODFaserLHCAthenaPool/src/xAODFaserLHCDataCnv.cxx b/xAOD/xAODFaserLHCAthenaPool/src/xAODFaserLHCDataCnv.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..2ae9467033ddabd5b6c0e0fab94a5fb20c9c99de
--- /dev/null
+++ b/xAOD/xAODFaserLHCAthenaPool/src/xAODFaserLHCDataCnv.cxx
@@ -0,0 +1,5 @@
+/*
+  Copyright (C) 2020 CERN for the benefit of the FASER collaboration
+*/
+
+// Dummy source file so that cmake will know this is a custom converter.
diff --git a/xAOD/xAODFaserLHCAthenaPool/src/xAODFaserLHCDataCnv.h b/xAOD/xAODFaserLHCAthenaPool/src/xAODFaserLHCDataCnv.h
new file mode 100644
index 0000000000000000000000000000000000000000..a73c439c688c0ef5879a84cd300ab15622d45c5e
--- /dev/null
+++ b/xAOD/xAODFaserLHCAthenaPool/src/xAODFaserLHCDataCnv.h
@@ -0,0 +1,17 @@
+// Dear emacs, this is -*- c++ -*-
+
+/*
+  Copyright (C) 2020 CERN for the benefit of the FASER collaboration
+*/
+
+#ifndef XAODFASERLHCDATAATHENAPOOL_XAODFASERLHCDATACNV_H
+#define XAODFASERLHCDATAATHENAPOOL_XAODFASERLHCDATACNV_H
+
+#include "xAODFaserLHC/FaserLHCData.h"
+#include "AthenaPoolCnvSvc/T_AthenaPoolxAODCnv.h"
+
+
+typedef T_AthenaPoolxAODCnv<xAOD::FaserLHCData> xAODFaserLHCDataCnv;
+
+
+#endif // XAODFASERLHCDATAATHENAPOOL_XAODFASERLHCDATACNV_H