diff --git a/TileCalorimeter/TileMonitoring/CMakeLists.txt b/TileCalorimeter/TileMonitoring/CMakeLists.txt
index 63fa307b2d3212f157038132d79a917f295de7fb..c2ef7632ef60f0c1a6a7098c86642cbf36a4f19d 100644
--- a/TileCalorimeter/TileMonitoring/CMakeLists.txt
+++ b/TileCalorimeter/TileMonitoring/CMakeLists.txt
@@ -89,6 +89,11 @@ atlas_add_test( TileMuonFitMonitorAlgorithm_test
                 PROPERTIES TIMEOUT 600
                 POST_EXEC_SCRIPT nopost.sh)
 
+atlas_add_test( TileRODMonitorAlgorithm_test
+                SCRIPT python -m TileMonitoring.TileRODMonitorAlgorithm
+                PROPERTIES TIMEOUT 600
+                POST_EXEC_SCRIPT nopost.sh)
+
 atlas_add_test( TileMonitoringConfig_test
                 SCRIPT python -m TileMonitoring.TileMonitoringConfig
                 PROPERTIES TIMEOUT 300
diff --git a/TileCalorimeter/TileMonitoring/python/TileMuIdMonitorAlgorithm.py b/TileCalorimeter/TileMonitoring/python/TileMuIdMonitorAlgorithm.py
index e63686d0163f1f106c0974aec14d1c0ef69eef1e..ed69925e3d4c6dc85cf81a57b89308132eecfdda 100644
--- a/TileCalorimeter/TileMonitoring/python/TileMuIdMonitorAlgorithm.py
+++ b/TileCalorimeter/TileMonitoring/python/TileMuIdMonitorAlgorithm.py
@@ -1,5 +1,5 @@
 #
-#  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+#  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
 #
 '''
 @file TileMuIdMonitorAlgorithm.py
@@ -14,6 +14,12 @@ def TileMuIdMonitoringConfig(flags, **kwargs):
     from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
     result = ComponentAccumulator()
 
+    from TileGeoModel.TileGMConfig import TileGMCfg
+    result.merge(TileGMCfg(flags))
+
+    from LArGeoAlgsNV.LArGMConfig import LArGMCfg
+    result.merge(LArGMCfg(flags))
+
     # The following class will make a sequence, configure algorithms, and link
     # them to GenericMonitoringTools
     from AthenaMonitoring import AthMonitorCfgHelper
diff --git a/TileCalorimeter/TileMonitoring/python/TileRODMonitorAlgorithm.py b/TileCalorimeter/TileMonitoring/python/TileRODMonitorAlgorithm.py
new file mode 100644
index 0000000000000000000000000000000000000000..fcaf3497604c8d0a7da837072fdea1c9b99b60b9
--- /dev/null
+++ b/TileCalorimeter/TileMonitoring/python/TileRODMonitorAlgorithm.py
@@ -0,0 +1,215 @@
+#
+#  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+#
+'''
+@file TileRODMonitorAlgorithm.py
+@brief Python configuration of TileRODMonitorAlgorithm algorithm for the Run III
+'''
+
+def TileRODMonitoringConfig(flags, **kwargs):
+    ''' Function to configure TileRODMonitorAlgorithm algorithm in the monitoring system.'''
+
+    # Define one top-level monitoring algorithm. The new configuration
+    # framework uses a component accumulator.
+    from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
+    result = ComponentAccumulator()
+
+    from TileRecUtils.TileDQstatusConfig import TileDQstatusAlgCfg
+    result.merge( TileDQstatusAlgCfg(flags) )
+
+    from TileGeoModel.TileGMConfig import TileGMCfg
+    result.merge(TileGMCfg(flags))
+
+    from TileConditions.TileCablingSvcConfig import TileCablingSvcCfg
+    result.merge( TileCablingSvcCfg(flags) )
+
+    from TileConditions.TileBadChannelsConfig import TileBadChannelsCondAlgCfg
+    result.merge( TileBadChannelsCondAlgCfg(flags, **kwargs) )
+
+    kwargs.setdefault('CheckDCS', flags.Tile.useDCS)
+    if kwargs['CheckDCS']:
+        from TileConditions.TileDCSConfig import TileDCSCondAlgCfg
+        result.merge( TileDCSCondAlgCfg(flags) )
+
+    from AthenaConfiguration.ComponentFactory import CompFactory
+
+    kwargs.setdefault('fillRODFragmentSizeHistograms', True)
+    fillRODFragmentSizeHistograms = kwargs['fillRODFragmentSizeHistograms']
+    if fillRODFragmentSizeHistograms:
+        result.addService(CompFactory.ROBDataProviderSvc())
+
+    # The following class will make a sequence, configure algorithms, and link
+    # them to GenericMonitoringTools
+    from AthenaMonitoring import AthMonitorCfgHelper
+    helper = AthMonitorCfgHelper(flags,'TileRODMonitoring')
+
+    # Adding an TileRODMonitorAlgorithm algorithm to the helper
+    tileRODMonAlg = helper.addAlgorithm(CompFactory.TileRODMonitorAlgorithm, 'TileRODMonAlg')
+
+    # L1Trigger Type Bits:
+    #     bit0_RNDM, bit1_ZeroBias, bit2_L1Cal, bit3_Muon,
+    #     bit4_RPC, bit5_FTK, bit6_CTP, bit7_Calib, AnyPhysTrig
+    kwargs.setdefault('fillHistogramsForL1Triggers', ['AnyPhysTrig', 'bit7_Calib'])
+    l1Triggers = kwargs['fillHistogramsForL1Triggers']
+
+    kwargs.setdefault('EnergyThreshold', 300.)
+    energyThreshold = kwargs['EnergyThreshold']
+
+    kwargs.setdefault('TileRawChannelContainer', flags.Tile.RawChannelContainer)
+    kwargs.setdefault('NumberOfROBFragmets', 32)
+    nROBs = kwargs['NumberOfROBFragmets']
+
+    for k, v in kwargs.items():
+        setattr(tileRODMonAlg, k, v)
+
+    run = str(flags.Input.RunNumber[0])
+
+    # Configure histogram with TileRODMonAlg algorithm execution time
+    executeTimeGroup = helper.addGroup(tileRODMonAlg, 'TileRODMonExecuteTime', 'Tile/')
+    executeTimeGroup.defineHistogram('TIME_execute', path = 'ROD', type='TH1F',
+                                     title = 'Time for execute TileRODMonAlg algorithm;time [#ms]',
+                                     xbins = 100, xmin = 0, xmax = 100000)
+
+
+    from TileMonitoring.TileMonitoringCfgHelper import addTile1DHistogramsArray
+
+    # Configure histograms with relative difference between Tile DSP and offline energies
+    titleEnergyDiff = 'Relative difference between E_{DSP} and E_{OFFLINE}'
+    titleEnergyDiff += ';(E_{DSP}- E_{OFFLINE})/E_{OFFLINE}'
+    addTile1DHistogramsArray(helper, tileRODMonAlg, name = 'TileDspEnergyDiff',
+                             xvalue = 'energyDiff', title = titleEnergyDiff, path = 'Tile/ROD',
+                             xbins = 41, xmin = -0.205, xmax = 0.205, type = 'TH1D', run = run,
+                             triggers = l1Triggers, perPartition = True)
+
+    # Configure histograms with difference between Tile DSP and offline times
+    titleTimeDiff = 'Difference between t_{DSP} and t_{OFFLINE}'
+    titleTimeDiff += ';t_{DSP}- t_{OFFLINE} [ns]'
+    addTile1DHistogramsArray(helper, tileRODMonAlg, name = 'TileDspTimeDiff',
+                             xvalue = 'timeDiff', title = titleTimeDiff, path = 'Tile/ROD',
+                             xbins = 101, xmin = -50.5, xmax = 50.5, type = 'TH1D', run = run,
+                             triggers = l1Triggers, perPartition = True)
+
+    # Configure histograms with difference between Tile DSP and offline times vs offline time
+    titleTimeDiffVsTime = 'Difference between t_{DSP} and t_{OFFLINE}'
+    titleTimeDiffVsTime += ';t_{OFFLINE} [ns];t_{DSP}- t_{OFFLINE} [ns]'
+    addTile1DHistogramsArray(helper, tileRODMonAlg, name = 'TileDspTimeDiffVsTime',
+                             xvalue = 'time', value = 'timeDiff', title = titleTimeDiffVsTime,
+                             path = 'Tile/ROD', xbins = 51, xmin = -25.5, xmax = 25.5,
+                             type = 'TProfile', run = run, triggers = l1Triggers, perPartition = True)
+
+    # Configure histograms with difference between Tile DSP and offline times vs offline energy
+    titleTimeDiffVsEnergy = 'Difference between t_{DSP} and t_{OFFLINE}'
+    titleTimeDiffVsEnergy += ';E_{OFFLINE} [MeV];t_{DSP}- t_{OFFLINE}'
+    addTile1DHistogramsArray(helper, tileRODMonAlg, name = 'TileDspTimeDiffVsEnergy',
+                             xvalue = 'energy', value = 'timeDiff', title = titleTimeDiffVsEnergy,
+                             path = 'Tile/ROD', xbins = 75, xmin = energyThreshold, xmax = 15000.,
+                             type = 'TProfile', run = run, triggers = l1Triggers, perPartition = True)
+
+
+    from TileMonitoring.TileMonitoringCfgHelper import addTile2DHistogramsArray
+
+    # Configure histograms with relative difference between Tile DSP and offline energies vs offline time
+    titleEnergyDiffVsTime = 'Relative difference between E_{DSP} and E_{OFFLINE}'
+    titleEnergyDiffVsTime += ';t_{DSP} [ns];(E_{DSP}- E_{OFFLINE})/E_{OFFLINE}'
+    addTile2DHistogramsArray(helper, tileRODMonAlg, name = 'TileDspEnergyDiffVsTime',
+                             xvalue = 'time', yvalue = 'energyDiff',
+                             title = titleEnergyDiffVsTime, path = 'Tile/ROD',
+                             xbins = 51, xmin = -25.5, xmax = 25.5,
+                             ybins = 30, ymin = -0.35, ymax = 0.1,
+                             type = 'TH2D', run = run, triggers = l1Triggers, perPartition = True)
+
+    # Configure histograms with relative difference between Tile DSP and offline energies vs offline energy
+    titleEnergyDiffVsEnergy = 'Relative difference between E_{DSP} and E_{OFFLINE}'
+    titleEnergyDiffVsEnergy += ';E_{OFFLINE} [MeV];(E_{DSP}- E_{OFFLINE})/E_{OFFLINE}'
+    addTile2DHistogramsArray(helper, tileRODMonAlg, name = 'TileDspEnergyDiffVsEnergy',
+                             xvalue = 'energy', yvalue = 'energyDiff',
+                             title = titleEnergyDiffVsEnergy, path = 'Tile/ROD',
+                             xbins = 75, xmin = energyThreshold, xmax = 15000.,
+                             ybins = 82, ymin = -0.205, ymax = 0.205,
+                             type = 'TH2D', run = run, triggers = l1Triggers, perPartition = True)
+
+
+    from TileMonitoring.TileMonitoringCfgHelper import addTileModuleChannelMapsArray
+
+    # Configure histograms with everagy Tile channel time per partition
+    titleChanTime = ('Tile DSP Channel Time (t_{DSP}) [ns], E_{ch} > %s MeV' % energyThreshold)
+    addTileModuleChannelMapsArray(helper, tileRODMonAlg, name = 'TileDspChannelTime', type = 'TProfile2D',
+                                  value = 'time', title = titleChanTime, path = 'Tile/ROD',
+                                  run = run, triggers = l1Triggers, separator = '_')
+
+
+    if fillRODFragmentSizeHistograms:
+        # Configure histogram with all Tile ROD fragments size vs luminosity block
+        titleAllRodFragSize = 'All Tile ROD fragments size vs luminosity block;LumiBlock;# words'
+        addTile1DHistogramsArray(helper, tileRODMonAlg, name = 'TileRodFragmentSizeLB',
+                                 xvalue = 'lumiBlock', value = 'allRodFragsSize',
+                                 title = titleAllRodFragSize, path = 'Tile/ROD',
+                                 xbins = 1000, xmin = -0.5, xmax = 999.5,
+                                 type = 'TProfile', run = run, triggers = l1Triggers,
+                                 perPartition = False, opt = 'kAddBinsDynamically')
+
+        from TileCalibBlobObjs.Classes import TileCalibUtils as Tile
+        from TileMonitoring.TileMonitoringCfgHelper import getPartitionName
+
+        # Configure histogram with Tile ROD fragment size vs fragment number and partition
+        titleRodFragSize = 'Tile ROD fragment size [word]; Fragment;'
+        partitionLabels = [getPartitionName(ros) for ros in range(1, Tile.MAX_ROS)]
+        addTile2DHistogramsArray(helper, tileRODMonAlg, name = 'TileRodFragmentMapSize',
+                                 xvalue = 'fragment', yvalue = 'partition', value = 'rodFragSize',
+                                 title = titleRodFragSize, path = 'Tile/ROD',
+                                 xbins = nROBs, xmin = -0.5, xmax = nROBs - 0.5,
+                                 ybins = Tile.MAX_ROS - 1, ymin = 0.5, ymax = Tile.MAX_ROS - 0.5,
+                                 type = 'TProfile2D', run = run, triggers = l1Triggers, ylabels = partitionLabels)
+
+
+    accumalator = helper.result()
+    result.merge(accumalator)
+    return result
+
+if __name__=='__main__':
+
+    # Setup the Run III behavior
+    from AthenaCommon.Configurable import Configurable
+    Configurable.configurableRun3Behavior = True
+
+    # Setup logs
+    from AthenaCommon.Logging import log
+    from AthenaCommon.Constants import INFO
+    log.setLevel(INFO)
+
+    # Set the Athena configuration flags
+    from AthenaConfiguration.AllConfigFlags import ConfigFlags
+
+    from AthenaConfiguration.TestDefaults import defaultTestFiles
+    ConfigFlags.Input.Files = defaultTestFiles.RAW
+    ConfigFlags.Output.HISTFileName = 'TileRODMonitorOutput.root'
+    ConfigFlags.DQ.useTrigger = False
+    ConfigFlags.DQ.enableLumiAccess = False
+    ConfigFlags.Tile.doOptATLAS = True
+    ConfigFlags.Exec.MaxEvents = 3
+    ConfigFlags.fillFromArgs()
+    ConfigFlags.lock()
+
+    # Initialize configuration object, add accumulator, merge, and run.
+    from AthenaConfiguration.MainServicesConfig import MainServicesCfg
+    cfg = MainServicesCfg(ConfigFlags)
+
+    from ByteStreamCnvSvc.ByteStreamConfig import ByteStreamReadCfg
+    tileTypeNames = ['TileRawChannelContainer/TileRawChannelCnt', 'TileDigitsContainer/TileDigitsCnt']
+    cfg.merge( ByteStreamReadCfg(ConfigFlags, type_names = tileTypeNames) )
+
+    from TileRecUtils.TileRawChannelMakerConfig import TileRawChannelMakerCfg
+    cfg.merge( TileRawChannelMakerCfg(ConfigFlags) )
+
+    cfg.merge( TileRODMonitoringConfig(ConfigFlags) )
+
+    cfg.printConfig(withDetails = True, summariseProps = True)
+    ConfigFlags.dump()
+
+    cfg.store( open('TileRODMonitorAlgorithm.pkl','wb') )
+
+    sc = cfg.run()
+
+    import sys
+    # Success should be 0
+    sys.exit(not sc.isSuccess())
diff --git a/TileCalorimeter/TileMonitoring/src/TileRODMonitorAlgorithm.cxx b/TileCalorimeter/TileMonitoring/src/TileRODMonitorAlgorithm.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..663ce8b9fe92c2251ab78b491817174e4cff305c
--- /dev/null
+++ b/TileCalorimeter/TileMonitoring/src/TileRODMonitorAlgorithm.cxx
@@ -0,0 +1,333 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "TileRODMonitorAlgorithm.h"
+#include "TileIdentifier/TileHWID.h"
+#include "TileCalibBlobObjs/TileCalibUtils.h"
+
+#include "StoreGate/ReadHandle.h"
+#include "StoreGate/ReadCondHandle.h"
+
+StatusCode TileRODMonitorAlgorithm::initialize() {
+
+  ATH_MSG_DEBUG("in initialize()");
+
+  // initialize superclass
+  ATH_CHECK( TileMonitorAlgorithm::initialize() );
+
+  std::sort(m_fragIDsToIgnoreDMUerrors.begin(), m_fragIDsToIgnoreDMUerrors.end());
+
+  ATH_CHECK( detStore()->retrieve(m_tileHWID) );
+
+  ATH_CHECK( m_cablingSvc.retrieve() );
+  m_cabling = m_cablingSvc->cablingService();
+
+  ATH_CHECK( m_rawChannelContainerKey.initialize() );
+  ATH_CHECK( m_dspRawChannelContainerKey.initialize() );
+  ATH_CHECK( m_DQstatusKey.initialize() );
+  ATH_CHECK( m_badChannelsKey.initialize() );
+  ATH_CHECK( m_emScaleKey.initialize() );
+  ATH_CHECK( m_DCSStateKey.initialize(m_checkDCS) );
+
+  if (m_comparisonUnit <= TileRawChannelUnit::OnlineMegaElectronVolts) {
+    m_finalRawChannelUnit = static_cast<TileRawChannelUnit::UNIT>(m_comparisonUnit.value());
+  }
+
+  if (m_timeRange.size() != 2) {
+    ATH_MSG_FATAL( "Size of TimeRange should be 2 (from,to), but is " << m_timeRange.size() );
+    return StatusCode::FAILURE;
+  }
+
+  using namespace Monitored;
+  using Tile = TileCalibUtils;
+
+  int nL1Triggers = getNumberOfL1Triggers();
+
+  m_energyDiffGroups = buildToolMap<std::vector<int>>(m_tools, "TileDspEnergyDiff",
+                                                      Tile::MAX_ROS - 1, nL1Triggers);
+
+  m_energyDiffVsTimeGroups = buildToolMap<std::vector<int>>(m_tools, "TileDspEnergyDiffVsTime",
+                                                            Tile::MAX_ROS - 1, nL1Triggers);
+
+  m_energyDiffVsEnergyGroups = buildToolMap<std::vector<int>>(m_tools, "TileDspEnergyDiffVsEnergy",
+                                                              Tile::MAX_ROS - 1, nL1Triggers);
+
+  m_timeDiffGroups = buildToolMap<std::vector<int>>(m_tools, "TileDspTimeDiff",
+                                                    Tile::MAX_ROS - 1, nL1Triggers);
+
+  m_timeDiffVsTimeGroups = buildToolMap<std::vector<int>>(m_tools, "TileDspTimeDiffVsTime",
+                                                          Tile::MAX_ROS - 1, nL1Triggers);
+
+  m_timeDiffVsEnergyGroups = buildToolMap<std::vector<int>>(m_tools, "TileDspTimeDiffVsEnergy",
+                                                            Tile::MAX_ROS - 1, nL1Triggers);
+
+  m_dspChanTimeGroups = buildToolMap<std::vector<int>>(m_tools, "TileDspChannelTime",
+                                                       Tile::MAX_ROS - 1, nL1Triggers);
+
+  if (m_fillRODfragSizeHistograms) {
+    ATH_CHECK( m_robSvc.retrieve() );
+
+    if (m_nROBs > MAX_TILE_ROBS) {
+      int nROBsSetUp = m_nROBs;
+      m_nROBs = MAX_TILE_ROBS;
+      ATH_MSG_INFO( "Decreasing number of ROBs from "  << nROBsSetUp << " to " << m_nROBs );
+    }
+
+    m_tileRobIds.reserve((Tile::MAX_ROS - 1) * m_nROBs); // Partitions * fragments
+    for (unsigned int rodId : {0x510000, 0x520000, 0x530000, 0x540000}) {
+      for (unsigned int fragment = 0; fragment < m_nROBs; ++fragment) {
+        m_tileRobIds.push_back(rodId + fragment);
+      }
+    }
+
+    m_rodFragSizeMapGroups = buildToolMap<int>(m_tools, "TileRodFragmentMapSize", nL1Triggers);
+    m_rodFragSizeLBGroups = buildToolMap<int>(m_tools, "TileRodFragmentSizeLB", nL1Triggers);
+  }
+
+  return StatusCode::SUCCESS;
+}
+
+
+StatusCode TileRODMonitorAlgorithm::fillHistograms( const EventContext& ctx ) const {
+
+  using Tile = TileCalibUtils;
+
+  // In case you want to measure the execution time
+  auto timer = Monitored::Timer("TIME_execute");
+
+  const xAOD::EventInfo* eventInfo = GetEventInfo(ctx).get();
+
+  ATH_MSG_DEBUG(*eventInfo);
+
+  const TileDQstatus* dqStatus = SG::makeHandle(m_DQstatusKey, ctx).get();
+  const TileDCSState* dcsState = m_checkDCS ? SG::ReadCondHandle(m_DCSStateKey, ctx).cptr() : nullptr;
+
+  SG::ReadCondHandle<TileBadChannels> badChannels(m_badChannelsKey, ctx);
+  SG::ReadCondHandle<TileEMScale> emScale(m_emScaleKey, ctx);
+
+  SG::ReadHandle<TileRawChannelContainer> rawChannelContainer(m_rawChannelContainerKey, ctx);
+  ATH_CHECK( rawChannelContainer.isValid() );
+
+  TileRawChannelUnit::UNIT rawChannelUnit = rawChannelContainer->get_unit();
+
+  float referenceTimes[Tile::MAX_ROS - 1][Tile::MAX_DRAWER][Tile::MAX_CHAN] = {{{0}}};
+  float referenceEnergies[Tile::MAX_ROS - 1][Tile::MAX_DRAWER][Tile::MAX_CHAN] = {{{0}}};
+
+  for (const TileRawChannelCollection* rawChannelCollection : *rawChannelContainer) {
+    if (rawChannelCollection->empty() ) continue;
+
+    HWIdentifier adc_id = rawChannelCollection->front()->adc_HWID();
+    int ros = m_tileHWID->ros(adc_id);
+    int drawer = m_tileHWID->drawer(adc_id);
+    unsigned int drawerIdx = TileCalibUtils::getDrawerIdx(ros, drawer);
+    int partition = ros - 1;
+
+    bool checkDQ = true;
+
+    int fragId = rawChannelCollection->identify();
+    if (std::binary_search(m_fragIDsToIgnoreDMUerrors.begin(), m_fragIDsToIgnoreDMUerrors.end(), fragId)) {
+      checkDQ = false;
+    }
+
+    for (const TileRawChannel* rawChannel : *rawChannelCollection) {
+
+      adc_id = rawChannel->adc_HWID();
+      int channel = m_tileHWID->channel(adc_id);
+      int adc = m_tileHWID->adc(adc_id);
+
+      if (m_cabling->isDisconnected(ros, drawer, channel)) {
+        ATH_MSG_VERBOSE(m_tileHWID->to_string(adc_id) << ": channlel is disconnected => skipping!");
+        continue;
+      }
+
+      if (checkDQ && !(dqStatus->isAdcDQgood(ros, drawer, channel, adc))) {
+        ATH_MSG_VERBOSE(m_tileHWID->to_string(adc_id) << ": DQ is BAD => skipping!");
+        continue;
+      }
+
+      if (m_checkDCS && dcsState->isStatusBad(ros, drawer, channel)) {
+        ATH_MSG_VERBOSE(m_tileHWID->to_string(adc_id) << ": DCS is Bad => skipping!");
+        continue;
+      }
+
+      if (badChannels->getAdcStatus(adc_id).isBad()) {
+        ATH_MSG_VERBOSE(m_tileHWID->to_string(adc_id) << ": Status is BAD => skipping!");
+        continue;
+      }
+
+      if (ros > 2) { // Check if channel is MBTS, no MBTS in LB
+        int pmt;
+        int index;
+        m_cabling->h2s_cell_id_index(adc_id, index, pmt);
+        if (index < -1) {
+          ATH_MSG_VERBOSE(m_tileHWID->to_string(adc_id) << ": MBTS => skipping!");
+          continue;
+        }
+      }
+
+      float amplitude = rawChannel->amplitude();
+      if (rawChannelUnit != m_comparisonUnit) {
+        amplitude = emScale->calibrateChannel(drawerIdx, channel, adc, amplitude, rawChannelUnit, m_finalRawChannelUnit);
+      }
+
+      float time = rawChannel->uncorrTime();
+      if (amplitude > m_energyThreshold && time > m_timeRange[0] && time < m_timeRange[1]) {
+        referenceEnergies[partition][drawer][channel] = amplitude;
+        referenceTimes[partition][drawer][channel] = time;
+      }
+    }
+  }
+
+  std::vector<float> timeDiffs[Tile::MAX_ROS - 1];
+  std::vector<float> energyDiffs[Tile::MAX_ROS - 1];
+  std::vector<float> offlineEnergies[Tile::MAX_ROS - 1];
+  std::vector<float> offlineTimes[Tile::MAX_ROS - 1];
+
+  std::vector<float> dspTimes[Tile::MAX_ROS - 1];
+  std::vector<float> dspTimesChannels[Tile::MAX_ROS - 1];
+  std::vector<float> dspTimesDrawers[Tile::MAX_ROS - 1];
+
+  SG::ReadHandle<TileRawChannelContainer> dspRawChannelContainer(m_dspRawChannelContainerKey, ctx);
+  ATH_CHECK( dspRawChannelContainer.isValid() );
+
+  TileRawChannelUnit::UNIT dspRawChannelUnit = dspRawChannelContainer->get_unit();
+  for (const TileRawChannelCollection* rawChannelCollection : *dspRawChannelContainer) {
+    if (rawChannelCollection->empty() ) continue;
+
+    HWIdentifier adc_id = rawChannelCollection->front()->adc_HWID();
+    int ros = m_tileHWID->ros(adc_id);
+    int drawer = m_tileHWID->drawer(adc_id);
+    unsigned int drawerIdx = TileCalibUtils::getDrawerIdx(ros, drawer);
+    int partition = ros - 1;
+
+    for (const TileRawChannel* rawChannel : *rawChannelCollection) {
+      adc_id = rawChannel->adc_HWID();
+      int channel = m_tileHWID->channel(adc_id);
+      int adc = m_tileHWID->adc(adc_id);
+
+      float offlineEnergy = referenceEnergies[partition][drawer][channel];
+      if (offlineEnergy > m_energyThreshold) {
+        offlineEnergies[partition].push_back(offlineEnergy);
+
+        float offlineTime = referenceTimes[partition][drawer][channel];
+        offlineTimes[partition].push_back(offlineTime);
+
+        float dspEnergy = rawChannel->amplitude();
+        float dspTime = rawChannel->uncorrTime();
+        dspTimes[partition].push_back(dspTime);
+        dspTimesDrawers[partition].push_back(drawer);
+        dspTimesChannels[partition].push_back(channel);
+
+        if (dspRawChannelUnit != m_finalRawChannelUnit) {
+          dspEnergy = emScale->calibrateChannel(drawerIdx, channel, adc, dspEnergy, dspRawChannelUnit, m_finalRawChannelUnit);
+        }
+
+        float energyDiff = (dspEnergy - offlineEnergy) / offlineEnergy;
+        energyDiffs[partition].push_back(energyDiff);
+
+        float timeDiff = dspTime - offlineTime;
+        timeDiffs[partition].push_back(timeDiff);
+
+        ATH_MSG_VERBOSE(m_tileHWID->to_string(adc_id) << ": (DSP/OFFLINE)"
+                        << ", energy " << dspEnergy << "/" << offlineEnergy
+                        << ", time " << dspTime << "/" << offlineTime);
+      }
+    }
+  }
+
+  // Indices of L1 trigger histograms to be filled in the current event
+  std::vector<int> l1TriggersIndices = getL1TriggerIndices(eventInfo->level1TriggerType());
+
+  for (unsigned int partition = 0; partition < Tile::MAX_ROS - 1; ++partition) {
+    if (!energyDiffs[partition].empty()) {
+      auto monTime = Monitored::Collection("time", offlineTimes[partition]);
+      auto monEnergy = Monitored::Collection("energy", offlineEnergies[partition]);
+      auto monEnergyDiff = Monitored::Collection("energyDiff", energyDiffs[partition]);
+      for (int l1TriggerIdx : l1TriggersIndices) {
+        fill(m_tools[m_energyDiffGroups[partition][l1TriggerIdx]], monEnergyDiff);
+        fill(m_tools[m_energyDiffVsTimeGroups[partition][l1TriggerIdx]], monTime, monEnergyDiff);
+        fill(m_tools[m_energyDiffVsEnergyGroups[partition][l1TriggerIdx]], monEnergy, monEnergyDiff);
+      }
+    }
+
+    if (!timeDiffs[partition].empty()) {
+      auto monTime = Monitored::Collection("time", offlineTimes[partition]);
+      auto monEnergy = Monitored::Collection("energy", offlineEnergies[partition]);
+      auto monTimeDiff = Monitored::Collection("timeDiff", timeDiffs[partition]);
+      for (int l1TriggerIdx : l1TriggersIndices) {
+        fill(m_tools[m_timeDiffGroups[partition][l1TriggerIdx]], monTimeDiff);
+        fill(m_tools[m_timeDiffVsTimeGroups[partition][l1TriggerIdx]], monTime, monTimeDiff);
+        fill(m_tools[m_timeDiffVsEnergyGroups[partition][l1TriggerIdx]], monEnergy, monTimeDiff);
+      }
+    }
+    if (!timeDiffs[partition].empty()) {
+      auto monTime = Monitored::Collection("time", offlineTimes[partition]);
+      auto monEnergy = Monitored::Collection("energy", offlineEnergies[partition]);
+      auto monTimeDiff = Monitored::Collection("timeDiff", timeDiffs[partition]);
+      for (int l1TriggerIdx : l1TriggersIndices) {
+        fill(m_tools[m_timeDiffGroups[partition][l1TriggerIdx]], monTimeDiff);
+        fill(m_tools[m_timeDiffVsTimeGroups[partition][l1TriggerIdx]], monTime, monTimeDiff);
+        fill(m_tools[m_timeDiffVsEnergyGroups[partition][l1TriggerIdx]], monEnergy, monTimeDiff);
+      }
+    }
+
+    if (!dspTimes[partition].empty()) {
+      auto monTime = Monitored::Collection("time", dspTimes[partition]);
+      auto monModule = Monitored::Collection("module", dspTimesDrawers[partition]);
+      auto monChannel = Monitored::Collection("channel", dspTimesChannels[partition]);
+      for (int l1TriggerIdx : l1TriggersIndices) {
+        fill(m_tools[m_dspChanTimeGroups[partition][l1TriggerIdx]], monModule, monChannel, monTime);
+      }
+    }
+
+  }
+
+
+  if (m_fillRODfragSizeHistograms) {
+    int allTileRodFragsSize = 0;
+    std::vector<int> roses;
+    std::vector<int> fragments;
+    std::vector<int> fragmentSizes;
+
+    std::vector<const OFFLINE_FRAGMENTS_NAMESPACE::ROBFragment*> robFragments;
+    m_robSvc->getROBData(m_tileRobIds, robFragments);
+
+    for (const OFFLINE_FRAGMENTS_NAMESPACE::ROBFragment* robFragment : robFragments) {
+      uint32_t rodSourceId = robFragment->rod_source_id();
+      unsigned int ros = (rodSourceId & 0x0F0000) >> 16;
+      unsigned int fragment = rodSourceId & 0x0000FF;
+      int rodFragmentSize = robFragment->rod_fragment_size_word();
+
+      allTileRodFragsSize += rodFragmentSize;
+      if (ros > 0 && ros < Tile::MAX_ROS && fragment < m_nROBs) {
+        roses.push_back(ros);
+        fragments.push_back(fragment);
+        fragmentSizes.push_back(rodFragmentSize);
+        ATH_MSG_VERBOSE("ROS = " << ros << ", ROD fragment = " << fragment << ", size = " << rodFragmentSize);
+      }
+    }
+
+    ATH_MSG_DEBUG( "All Tile ROD fragemsts size: " << allTileRodFragsSize << " in LB " << eventInfo->lumiBlock());
+
+    auto lumiBlock = Monitored::Scalar<int>("lumiBlock", eventInfo->lumiBlock());
+    auto monRodFragsSize = Monitored::Scalar<int>("allRodFragsSize", allTileRodFragsSize);
+    for (int l1TriggerIdx : l1TriggersIndices) {
+      fill(m_tools[m_rodFragSizeLBGroups[l1TriggerIdx]], lumiBlock, monRodFragsSize);
+    }
+
+    if (!fragmentSizes.empty()) {
+      auto monPartition = Monitored::Collection("partition", roses);
+      auto monFragment = Monitored::Collection("fragment", fragments);
+      auto monFragmentSize = Monitored::Collection("rodFragSize", fragmentSizes);
+      for (int l1TriggerIdx : l1TriggersIndices) {
+        fill(m_tools[m_rodFragSizeMapGroups[l1TriggerIdx]], monFragment, monPartition, monFragmentSize);
+      }
+    }
+  }
+
+
+  fill("TileRODMonExecuteTime", timer);
+
+  return StatusCode::SUCCESS;
+}
diff --git a/TileCalorimeter/TileMonitoring/src/TileRODMonitorAlgorithm.h b/TileCalorimeter/TileMonitoring/src/TileRODMonitorAlgorithm.h
new file mode 100644
index 0000000000000000000000000000000000000000..ad0c254dc53ff1af1ecd0dcd89c5482f0fc1d0c6
--- /dev/null
+++ b/TileCalorimeter/TileMonitoring/src/TileRODMonitorAlgorithm.h
@@ -0,0 +1,122 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TILEMONITORING_TILERODMONITORALGORITHM_H
+#define TILEMONITORING_TILERODMONITORALGORITHM_H
+
+#include "TileEvent/TileDQstatus.h"
+#include "TileIdentifier/TileRawChannelUnit.h"
+#include "TileEvent/TileRawChannelContainer.h"
+#include "TileConditions/TileDCSState.h"
+#include "TileConditions/TileBadChannels.h"
+#include "TileConditions/TileEMScale.h"
+#include "TileConditions/TileCablingSvc.h"
+#include "TileMonitorAlgorithm.h"
+
+#include "ByteStreamCnvSvcBase/IROBDataProviderSvc.h"
+#include "AthenaMonitoringKernel/Monitored.h"
+#include "StoreGate/ReadHandleKey.h"
+#include "StoreGate/ReadCondHandleKey.h"
+
+class TileHWID;
+class TileCablingService;
+
+/** @class TileRODMonitorAlgorithm
+ *  @brief Class for Tile digi noise based monitoring
+ */
+
+class TileRODMonitorAlgorithm : public TileMonitorAlgorithm {
+
+  public:
+
+    using TileMonitorAlgorithm::TileMonitorAlgorithm;
+    virtual ~TileRODMonitorAlgorithm() = default;
+    virtual StatusCode initialize() override;
+    virtual StatusCode fillHistograms(const EventContext& ctx) const override;
+
+  private:
+
+    Gaudi::Property<bool> m_checkDCS{this, "CheckDCS", false, "Check Tile DCS status"};
+    Gaudi::Property<std::vector<unsigned int>> m_triggerTypes{this,
+        "TriggerTypes", {}, "Given trigger types only events with these TT will be used, otherwise all"};
+
+    Gaudi::Property<std::vector<int>> m_fragIDsToIgnoreDMUerrors{this,
+        "FragIDsToIgnoreDMUErrors", {}, "List of Tile frag IDs for which ignore DMU errors"};
+
+    Gaudi::Property<unsigned int> m_comparisonUnit{this,
+        "ComparisonUnit", TileRawChannelUnit::MegaElectronVolts, "Units to compare Tile raw channel containers"};
+
+    Gaudi::Property<float> m_energyThreshold{this,
+        "EnergyThreshold", 300.0F, "Energy threshold in MeV"};
+
+    Gaudi::Property<std::vector<float>> m_timeRange{this,
+        "TimeRange", {-65.0F, 65.0F}, "Time range to be monitored, default: (-65,65)"};
+
+    Gaudi::Property<unsigned int> m_nROBs{this,
+        "NumberOfROBFragmets", MAX_TILE_ROBS, "Number of Tile ROB fragments"};
+
+    Gaudi::Property<bool> m_fillRODfragSizeHistograms{this,
+        "fillRODFragmentSizeHistograms", true, "Fill summary histograms with ROD fragment size"};
+
+    SG::ReadHandleKey<TileDQstatus> m_DQstatusKey{this,
+        "TileDQstatus", "TileDQstatus", "Tile DQ status name"};
+
+    /**
+     * @brief Name of TileDCSState object in condition store
+     */
+    SG::ReadCondHandleKey<TileDCSState> m_DCSStateKey{this,
+        "TileDCS", "TileDCS", "Input Tile DCS status"};
+
+    SG::ReadHandleKey<TileRawChannelContainer> m_rawChannelContainerKey{this,
+        "TileRawChannelContainer", "TileRawChannelOpt2", "Input Tile reference raw channel container key"};
+
+    SG::ReadHandleKey<TileRawChannelContainer> m_dspRawChannelContainerKey{this,
+        "TileRawChannelContainerDSP", "TileRawChannelCnt", "Input Tile DSP raw channel container key"};
+
+    /**
+     * @brief Name of TileBadChannels in condition store
+     */
+    SG::ReadCondHandleKey<TileBadChannels> m_badChannelsKey{this,
+        "TileBadChannels", "TileBadChannels", "Input Tile bad channel status"};
+
+    /**
+     * @brief Name of TileEMScale in condition store
+     */
+    SG::ReadCondHandleKey<TileEMScale> m_emScaleKey{this,
+        "TileEMScale", "TileEMScale", "Input Tile EMS calibration constants"};
+
+    /**
+     * @brief Name of Tile cabling service
+     */
+    ServiceHandle<TileCablingSvc> m_cablingSvc{ this,
+        "TileCablingSvc", "TileCablingSvc", "The Tile cabling service"};
+
+    /**
+     * @brief Name of ROB data provider service
+     */
+    ServiceHandle<IROBDataProviderSvc> m_robSvc{this,
+        "ROBDataProviderSvc", "ROBDataProviderSvc", "The ROB data provider service"};
+
+    const TileHWID* m_tileHWID{nullptr};
+    const TileCablingService* m_cabling{nullptr};
+    TileRawChannelUnit::UNIT m_finalRawChannelUnit{TileRawChannelUnit::Invalid};
+
+    std::vector<int> m_rodFragSizeMapGroups;
+    std::vector<int> m_rodFragSizeLBGroups;
+    std::vector<std::vector<std::vector<int>>> m_rodFragSizeGroups;
+
+    std::vector<std::vector<int>> m_energyDiffGroups;
+    std::vector<std::vector<int>> m_energyDiffVsTimeGroups;
+    std::vector<std::vector<int>> m_energyDiffVsEnergyGroups;
+    std::vector<std::vector<int>> m_timeDiffGroups;
+    std::vector<std::vector<int>> m_timeDiffVsTimeGroups;
+    std::vector<std::vector<int>> m_timeDiffVsEnergyGroups;
+    std::vector<std::vector<int>> m_dspChanTimeGroups;
+
+    std::vector<uint32_t> m_tileRobIds;
+    static const int MAX_TILE_ROBS = 32;
+};
+
+
+#endif // TILEMONITORING_TILERODMONITORALGORITHM_H
diff --git a/TileCalorimeter/TileMonitoring/src/components/TileMonitoring_entries.cxx b/TileCalorimeter/TileMonitoring/src/components/TileMonitoring_entries.cxx
index 2570ba2eb2a66e7dc62709d3b07802f8592bec5f..e5df98c9de6cd240502cf4cd2ba9419ca48bf056 100644
--- a/TileCalorimeter/TileMonitoring/src/components/TileMonitoring_entries.cxx
+++ b/TileCalorimeter/TileMonitoring/src/components/TileMonitoring_entries.cxx
@@ -35,6 +35,7 @@
 #include "../TileRawChannelTimeMonitorAlgorithm.h"
 #include "../TileRawChannelNoiseMonitorAlgorithm.h"
 #include "../TileMuonFitMonitorAlgorithm.h"
+#include "../TileRODMonitorAlgorithm.h"
 
 DECLARE_COMPONENT( TileFatherMonTool )
 DECLARE_COMPONENT( TilePaterMonTool )
@@ -73,3 +74,4 @@ DECLARE_COMPONENT( TileDigiNoiseMonitorAlgorithm )
 DECLARE_COMPONENT( TileRawChannelTimeMonitorAlgorithm )
 DECLARE_COMPONENT( TileRawChannelNoiseMonitorAlgorithm )
 DECLARE_COMPONENT( TileMuonFitMonitorAlgorithm )
+DECLARE_COMPONENT( TileRODMonitorAlgorithm )