diff --git a/Control/AthenaMonitoring/python/AthenaMonitoringCfg.py b/Control/AthenaMonitoring/python/AthenaMonitoringCfg.py
index de779c0d90647464e3ea69513e106b8ee8409560..df758b81ca21c07a17fcfece931949079348c4e2 100644
--- a/Control/AthenaMonitoring/python/AthenaMonitoringCfg.py
+++ b/Control/AthenaMonitoring/python/AthenaMonitoringCfg.py
@@ -82,5 +82,10 @@ def AthenaMonitoringCfg(flags):
         info('Set up AFP monitoring')
         from Run3AFPMonitoring.Run3AFPExampleMonitorAlgorithm import Run3AFPExampleMonitoringConfig
         result.merge(Run3AFPExampleMonitoringConfig(flags))
+
+    if flags.DQ.Steering.doLVL1CaloMon:
+        info('Set up LVL1Calo monitoring')
+        from TrigT1CaloMonitoring.LVL1CaloMonitoringConfig import LVL1CaloMonitoringConfig
+        result.merge(LVL1CaloMonitoringConfig(flags))
         
     return result
diff --git a/Control/AthenaMonitoring/python/DQConfigFlags.py b/Control/AthenaMonitoring/python/DQConfigFlags.py
index 24db04e8f0d51e3bfd92332b2152e905b0575126..bf7157de5b3573bc0c4f0522827401d79a61101b 100644
--- a/Control/AthenaMonitoring/python/DQConfigFlags.py
+++ b/Control/AthenaMonitoring/python/DQConfigFlags.py
@@ -4,7 +4,7 @@
 
 from AthenaConfiguration.AthConfigFlags import AthConfigFlags
 
-_steeringFlags = [ 'doGlobalMon', 'LVL1CaloMon', 'doCTPMon', 'doHLTMon',
+_steeringFlags = [ 'doGlobalMon', 'doLVL1CaloMon', 'doCTPMon', 'doHLTMon',
                    'doPixelMon', 'doSCTMon', 'doTRTMon', 'doInDetMon',
                    'doLArMon', 'doTileMon',
                    'doCaloGlobalMon', 'doMuonMon',
diff --git a/Trigger/TrigT1/TrigT1CaloMonitoring/CMakeLists.txt b/Trigger/TrigT1/TrigT1CaloMonitoring/CMakeLists.txt
index 07d356ecaf64cf428ad7af2098692dadd2f0b2e2..dde39bcc376450bacb5116b1faeaf3c3e0dfaa06 100644
--- a/Trigger/TrigT1/TrigT1CaloMonitoring/CMakeLists.txt
+++ b/Trigger/TrigT1/TrigT1CaloMonitoring/CMakeLists.txt
@@ -53,4 +53,5 @@ atlas_add_component( TrigT1CaloMonitoring
 
 # Install files from the package:
 atlas_install_joboptions( share/*.py )
-
+# required for Run 3 monitoring
+atlas_install_python_modules( python/*.py )
diff --git a/Trigger/TrigT1/TrigT1CaloMonitoring/python/CpmMonitorAlgorithm.py b/Trigger/TrigT1/TrigT1CaloMonitoring/python/CpmMonitorAlgorithm.py
new file mode 100644
index 0000000000000000000000000000000000000000..a8e51a91664706ca133de2f8ba265f03f02a415f
--- /dev/null
+++ b/Trigger/TrigT1/TrigT1CaloMonitoring/python/CpmMonitorAlgorithm.py
@@ -0,0 +1,255 @@
+#
+#  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+#
+def CpmMonitoringConfig(inputFlags):
+    '''Function to configure LVL1 Cpm algorithm in the monitoring system.'''
+
+    import math 
+    # get the component factory - used for getting the algorithms
+    from AthenaConfiguration.ComponentFactory import CompFactory
+    from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
+    result = ComponentAccumulator()
+
+    # make the athena monitoring helper
+    from AthenaMonitoring import AthMonitorCfgHelper
+    helper = AthMonitorCfgHelper(inputFlags,'CpmMonitoringCfg')
+
+    # get any algorithms
+    CpmMonAlg = helper.addAlgorithm(CompFactory.CpmMonitorAlgorithm,'CpmMonAlg')
+
+    # add any steering
+    groupName = 'CpmMonitor' # the monitoring group name is also used for the package name
+    CpmMonAlg.PackageName = groupName
+    crates = 4
+    CpmMonAlg.s_crates = crates
+    maxSlices = 5
+    CpmMonAlg.s_maxSlices = maxSlices
+    isolBits = 4
+    CpmMonAlg.s_isolBits = isolBits
+    tobsPerCPM = 5
+    CpmMonAlg.s_tobsPerCPM = tobsPerCPM
+    maxTobsPerCmx = 70
+    CpmMonAlg.MaxTOBsPerCMX = maxTobsPerCmx
+
+    # set up the directory structure
+    mainDir = 'L1Calo'
+    trigPath = 'CPM' # replaces m_rootDir
+    errorDir=trigPath+"/Errors/Hardware"
+    monDetailPath=errorDir+"/Detail/"
+    monCPMinputPath=trigPath+"/Input/"
+    monRoIPath=trigPath+"/Output/"
+    #monCMXPath=trigPath+"_CMX/Errors/Hardware/"
+    monCMXinPath=trigPath+"_CMX/Input/"
+    #monCMXoutPath=trigPath+"_CMX/Output/"
+
+    # add monitoring algorithm to group, with group name and main directory 
+    myGroup = helper.addGroup(CpmMonAlg, groupName , mainDir)
+
+    #
+    #   CPM Towers - monCPMinputPath
+    #
+    # Trigger Tower plots - for binning see TrigT1CaloLWHistogramTool::bookPPMEmEtaVsPhi
+    etabins_2d=66
+    etamin_2d=-3.3
+    etamax_2d=3.3
+    phibins_2d=64
+    phimin_2d=0.0
+    phimax_2d=64.0    
+    # for 2D histograms x,y;histogram alias
+    myGroup.defineHistogram('etaTT,phiTT;ppm_em_2d_etaPhi_tt_Hitmap',title='PPM Trigger Tower EM eta/phi;Tower #eta; Tower #phi',type='TH2F',
+                            cutmask='mask_em_TT',path=monCPMinputPath,
+                            xbins=etabins_2d,xmin=etamin_2d,xmax=etamax_2d,ybins=phibins_2d,ymin=phimin_2d,ymax=phimax_2d)
+    myGroup.defineHistogram('etaTT,phiTT;ppm_had_2d_etaPhi_tt_Hitmap',title='PPM Trigger Tower HAD eta/phi;Tower #eta; Tower #phi',type='TH2F',
+                            cutmask='mask_had_TT',path=monCPMinputPath,
+                            xbins=etabins_2d,xmin=etamin_2d,xmax=etamax_2d,ybins=phibins_2d,ymin=phimin_2d,ymax=phimax_2d)
+    
+    # CPMTower plots
+    maxEnergyRange = 256 # Maximum energy plotted
+    # EM 1d
+    myGroup.defineHistogram('etCpmTT_em;cpm_em_1d_tt_Et', title='CPM Tower EM Et;CPM Tower EM Energy;',
+                            cutmask='',path=monCPMinputPath,xbins=maxEnergyRange,xmin=0,xmax=maxEnergyRange)
+    myGroup.defineHistogram('etaCpmTT_em;cpm_em_1d_tt_Eta', title='CPM Tower EM eta;CPM Tower EM #eta;',
+                            cutmask='',path=monCPMinputPath,xbins=50,xmin=-2.5,xmax=2.5)
+    myGroup.defineHistogram('phiCpmTT_em;cpm_em_1d_tt_Phi', title='CPM Tower EM phi;CPM Tower EM #phi;',
+                            cutmask='',path=monCPMinputPath,xbins=64,xmin=0,xmax=2*math.pi)
+    # EM 2d
+    myGroup.defineHistogram('etaCpmTT_em,phiScaledCpmTT_em;cpm_em_2d_etaPhi_tt_Hitmap',
+                            title='CPM Tower EM eta/phi;Tower #eta; Tower #phi',type='TH2F',
+                            cutmask='',path=monCPMinputPath,
+                            xbins=etabins_2d,xmin=etamin_2d,xmax=etamax_2d,ybins=phibins_2d,ymin=phimin_2d,ymax=phimax_2d)
+    myGroup.defineHistogram('etaCpmTT_em,phiScaledCpmTT_em;cpm_em_2d_etaPhi_tt_EtWeighted',
+                            title='CPM Tower EM eta/phi weighted;Tower #eta; Tower #phi',type='TH2F',
+                            cutmask='',path=monCPMinputPath,
+                            xbins=etabins_2d,xmin=etamin_2d,xmax=etamax_2d,ybins=phibins_2d,ymin=phimin_2d,ymax=phimax_2d, weight="etCpmTT_em")
+
+    
+    # HAD 1d
+    myGroup.defineHistogram('etCpmTT_had;cpm_had_1d_tt_Et', title='CPM Tower HAD Et;CPM Tower HAD Energy;',
+                            cutmask='',path=monCPMinputPath,xbins=maxEnergyRange,xmin=0,xmax=maxEnergyRange)
+    myGroup.defineHistogram('etaCpmTT_had;cpm_had_1d_tt_Eta', title='CPM Tower HAD eta;CPM Tower HAD #eta;',
+                            cutmask='',path=monCPMinputPath,xbins=50,xmin=-2.5,xmax=2.5)
+    myGroup.defineHistogram('phiCpmTT_had;cpm_had_1d_tt_Phi', title='CPM Tower HAD phi;CPM Tower HAD #phi;',
+                            cutmask='',path=monCPMinputPath,xbins=64,xmin=0,xmax=2*math.pi)
+    # HAD 2d
+    myGroup.defineHistogram('etaCpmTT_had,phiScaledCpmTT_had;cpm_had_2d_etaPhi_tt_Hitmap',
+                            title='CPM Tower HAD eta/phi;Tower #eta; Tower #phi',type='TH2F',
+                            cutmask='',path=monCPMinputPath,
+                            xbins=etabins_2d,xmin=etamin_2d,xmax=etamax_2d,ybins=phibins_2d,ymin=phimin_2d,ymax=phimax_2d)
+    myGroup.defineHistogram('etaCpmTT_had,phiScaledCpmTT_had;cpm_had_2d_etaPhi_tt_EtWeighted'
+                            ,title='CPM Tower HAD eta/phi weighted;Tower #eta; Tower #phi',type='TH2F',
+                            cutmask='',path=monCPMinputPath,
+                            xbins=etabins_2d,xmin=etamin_2d,xmax=etamax_2d,ybins=phibins_2d,ymin=phimin_2d,ymax=phimax_2d, weight="etCpmTT_had")
+
+    xbinshist = int(crates * maxSlices)
+    myGroup.defineHistogram('sliceCpmTT_tot,peakCpmTT_tot;cpm_2d_tt_Slices'
+                            ,title='CPM Slices and Triggered Slice;Crate/Number of Slices;Triggered Slice',type='TH2F',
+                            cutmask='',path=monCPMinputPath,
+                            xbins=xbinshist,xmin=0,xmax=xbinshist,ybins=maxSlices,ymin=0,ymax=maxSlices)
+
+
+    #
+    # Errors - monDetailPath
+    #
+    # em - tot means addition of CPM and Overlap containers
+    myGroup.defineHistogram('etaCpmTT_em_tot,phiScaledCpmTT_em_tot;cpm_em_2d_etaPhi_tt_Parity'
+                            ,title='CPM Tower EM Parity Errors;Tower #eta; Tower #phi',type='TH2F',
+                            cutmask='parityErrorCpmTT_em',path=monDetailPath,
+                            xbins=etabins_2d,xmin=etamin_2d,xmax=etamax_2d,ybins=phibins_2d,ymin=phimin_2d,ymax=phimax_2d)
+    myGroup.defineHistogram('etaCpmTT_em_tot,phiScaledCpmTT_em_tot;cpm_em_2d_etaPhi_tt_LinkDown',
+                            title='CPM Tower EM Link Down Errors;Tower #eta; Tower #phi',type='TH2F',
+                            cutmask='linkDownErrorCpmTT_em',path=monDetailPath,
+                            xbins=etabins_2d,xmin=etamin_2d,xmax=etamax_2d,ybins=phibins_2d,ymin=phimin_2d,ymax=phimax_2d)
+
+    # had
+    myGroup.defineHistogram('etaCpmTT_had_tot,phiScaledCpmTT_had_tot;cpm_had_2d_etaPhi_tt_Parity',
+                            title='CPM Tower HAD Parity Errors;Tower #eta; Tower #phi',type='TH2F',
+                            cutmask='parityErrorCpmTT_had',path=monDetailPath,
+                            xbins=etabins_2d,xmin=etamin_2d,xmax=etamax_2d,ybins=phibins_2d,ymin=phimin_2d,ymax=phimax_2d)
+    myGroup.defineHistogram('etaCpmTT_had_tot,phiScaledCpmTT_had_tot;cpm_had_2d_etaPhi_tt_LinkDown',
+                            title='CPM Tower HAD Link Down Errors;Tower #eta; Tower #phi',type='TH2F',
+                            cutmask='linkDownErrorCpmTT_had',path=monDetailPath,
+                            xbins=etabins_2d,xmin=etamin_2d,xmax=etamax_2d,ybins=phibins_2d,ymin=phimin_2d,ymax=phimax_2d)
+
+
+    #
+    #  CPM TOB RoIs - monRoIPath
+    #
+    isolRange=32 # Maximum range for encoded isolation
+    myGroup.defineHistogram('energyTobRoIsEner;cpm_1d_roi_EnergyEm', title='CPM TOB RoI Cluster Energy EM;Cluster Energy;',
+                            cutmask='mask_tobroi_ener_em',path=monRoIPath,
+                            xbins=maxEnergyRange,xmin=0,xmax=maxEnergyRange)
+    myGroup.defineHistogram('energyTobRoIsEner;cpm_1d_roi_EnergyTau', title='CPM TOB RoI Cluster Energy Tau;Cluster Energy;',
+                            cutmask='mask_tobroi_ener_tau',path=monRoIPath,
+                            xbins=maxEnergyRange,xmin=0,xmax=maxEnergyRange)
+
+    myGroup.defineHistogram('energyTobRoIsIsol;cpm_1d_roi_IsolationEm', title='CPM TOB RoI Encoded Isolation Value EM;;',
+                            cutmask='mask_tobroi_isol_em',path=monRoIPath,
+                            xbins=isolRange,xmin=0,xmax=isolRange)
+    myGroup.defineHistogram('energyTobRoIsIsol;cpm_1d_roi_IsolationTau', title='CPM TOB RoI Encoded Isolation Value Tau;;',
+                            cutmask='mask_tobroi_isol_tau',path=monRoIPath,
+                            xbins=isolRange,xmin=0,xmax=isolRange)
+
+
+    # bit masks to be done
+    #myGroup.defineHistogram('bitsTobRoIsIsol;cpm_1d_roi_IsolationBitsEm', title='CPM TOB RoI Encoded Isolation Bits EM;;',
+    #                        cutmask='mask_tobroi_isol_em',path=monRoIPath,
+    #                        xbins=isolBits,xmin=0,xmax=isolBits)
+
+    # 2D
+    # For binning see TrigT1CaloLWHistogramTool::bookCPMRoIEtaVsPhi,fillCPMRoIEtaVsPhi m_shrinkEtaBins=true
+    # isolation
+    myGroup.defineHistogram('etaTobRoIsIsol,phiTobRoIsIsol;cpm_2d_etaPhi_roi_HitmapIsolEm',
+                            title='CPM TOB RoIs EM Non-zero Isolation Hit Map;Tower #eta; Tower #phi',type='TH2F',
+                            cutmask='mask_tobroi_isol_em',path=monRoIPath,
+                            xbins=etabins_2d,xmin=etamin_2d,xmax=etamax_2d,ybins=phibins_2d,ymin=phimin_2d,ymax=phimax_2d)
+    myGroup.defineHistogram('etaTobRoIsIsol,phiTobRoIsIsol;cpm_2d_etaPhi_roi_HitmapIsolTau',
+                            title='CPM TOB RoIs Tau Non-zero Isolation Hit Map;Tower #eta; Tower #phi',type='TH2F',
+                            cutmask='mask_tobroi_isol_tau',path=monRoIPath,
+                            xbins=etabins_2d,xmin=etamin_2d,xmax=etamax_2d,ybins=phibins_2d,ymin=phimin_2d,ymax=phimax_2d)
+
+    # energy
+    myGroup.defineHistogram('etaTobRoIsEner,phiTobRoIsEner;cpm_2d_etaPhi_roi_HitmapEm',
+                            title='CPM TOB RoIs EM Hit Map;Tower #eta; Tower #phi',type='TH2F',
+                            cutmask='mask_tobroi_ener_em',path=monRoIPath,
+                            xbins=etabins_2d,xmin=etamin_2d,xmax=etamax_2d,ybins=phibins_2d,ymin=phimin_2d,ymax=phimax_2d)
+    myGroup.defineHistogram('etaTobRoIsEner,phiTobRoIsEner;cpm_2d_etaPhi_roi_EtWeightedEm',
+                            title='CPM TOB RoIs EM Weighted by Energy;Tower #eta; Tower #phi',type='TH2F',
+                            cutmask='mask_tobroi_ener_em',path=monRoIPath,
+                            xbins=etabins_2d,xmin=etamin_2d,xmax=etamax_2d,ybins=phibins_2d,ymin=phimin_2d,ymax=phimax_2d, weight="energyTobRoIsEner")
+
+    myGroup.defineHistogram('etaTobRoIsEner,phiTobRoIsEner;cpm_2d_etaPhi_roi_HitmapTau',
+                            title='CPM TOB RoIs Tau Hit Map;Tower #eta; Tower #phi',type='TH2F',
+                            cutmask='mask_tobroi_ener_tau',path=monRoIPath,
+                            xbins=etabins_2d,xmin=etamin_2d,xmax=etamax_2d,ybins=phibins_2d,ymin=phimin_2d,ymax=phimax_2d)
+    myGroup.defineHistogram('etaTobRoIsEner,phiTobRoIsEner;cpm_2d_etaPhi_roi_EtWeightedTau',
+                            title='CPM TOB RoIs Tau Weighted by Energy;Tower #eta; Tower #phi',type='TH2F',
+                            cutmask='mask_tobroi_ener_tau',path=monRoIPath,
+                            xbins=etabins_2d,xmin=etamin_2d,xmax=etamax_2d,ybins=phibins_2d,ymin=phimin_2d,ymax=phimax_2d, weight="energyTobRoIsEner")
+
+    # TOBs per CPM 
+    myGroup.defineHistogram('tobPerCPMEm;cpm_1d_roi_TOBsPerCPMEm', title='CPM TOB RoI TOBs per CPM EM;Number of TOBs;',
+                            cutmask='',path=monRoIPath,
+                            xbins=tobsPerCPM+1,xmin=1,xmax=tobsPerCPM+2)
+    myGroup.defineHistogram('tobPerCPMTau;cpm_1d_roi_TOBsPerCPMTau', title='CPM TOB RoI TOBs per CPM Tau;Number of TOBs;',
+                            cutmask='',path=monRoIPath,
+                            xbins=tobsPerCPM+1,xmin=1,xmax=tobsPerCPM+2)
+    # How to set labels e.g.
+    # m_h_cpm_1d_roi_TOBsPerCPMEm->GetXaxis()->SetBinLabel(s_tobsPerCPM + 1, "More");
+
+    #
+    #  CMX-CP TOBs - monCMXinPath
+    #
+    myGroup.defineHistogram('enerTobCmxEner;cmx_1d_tob_TOBsPerCMXLeft', title='CMX-CP TOBs per CMX Left;Number of TOBs;',
+                            cutmask='',path=monCMXinPath,
+                            xbins=maxTobsPerCmx,xmin=0,xmax=maxTobsPerCmx)
+
+
+    acc = helper.result()
+    result.merge(acc)
+    return result
+
+
+if __name__=='__main__':
+    # For direct tests
+    from AthenaCommon.Configurable import Configurable
+    Configurable.configurableRun3Behavior = 1
+
+    # set debug level for whole job
+    from AthenaCommon.Logging import log
+    from AthenaCommon.Constants import INFO #DEBUG
+    log.setLevel(INFO)
+
+    # set input file and config options
+    from AthenaConfiguration.AllConfigFlags import ConfigFlags
+    import glob
+
+    inputs = glob.glob('/eos/atlas/atlascerngroupdisk/data-art/build-output/master/Athena/x86_64-centos7-gcc8-opt/2020-04-06T2139/TrigP1Test/test_trigP1_v1PhysP1_T0Mon_build/ESD.pool.root')
+
+    ConfigFlags.Input.Files = inputs
+    ConfigFlags.Output.HISTFileName = 'ExampleMonitorOutput_LVL1.root'
+
+    ConfigFlags.lock()
+    ConfigFlags.dump() # print all the configs
+
+    from AthenaCommon.AppMgr import ServiceMgr
+    ServiceMgr.Dump = False
+
+    from AthenaConfiguration.MainServicesConfig import MainServicesSerialCfg 
+    from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg
+    cfg = MainServicesSerialCfg()
+    cfg.merge(PoolReadCfg(ConfigFlags))
+
+    CpmMonitorCfg = CpmMonitoringConfig(ConfigFlags)
+    cfg.merge(CpmMonitorCfg)
+
+    # message level for algorithm
+    CpmMonitorCfg.getEventAlgo('CpmMonAlg').OutputLevel = 2 # 1/2 INFO/DEBUG
+    # options - print all details of algorithms, very short summary 
+    cfg.printConfig(withDetails=False, summariseProps = True)
+
+    nevents=-1
+    cfg.run(nevents)
+
+
+
+
diff --git a/Trigger/TrigT1/TrigT1CaloMonitoring/python/LVL1CaloMonitoringConfig.py b/Trigger/TrigT1/TrigT1CaloMonitoring/python/LVL1CaloMonitoringConfig.py
new file mode 100644
index 0000000000000000000000000000000000000000..04d66e715e0bce43ad098956e782a229950dad5b
--- /dev/null
+++ b/Trigger/TrigT1/TrigT1CaloMonitoring/python/LVL1CaloMonitoringConfig.py
@@ -0,0 +1,24 @@
+#
+#  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+#
+
+def LVL1CaloMonitoringConfig(flags):
+    '''Function to call l1calo DQ monitoring algorithms'''
+    from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
+    import logging
+
+    # local printing
+    local_logger = logging.getLogger('AthenaMonitoringCfg')
+    info = local_logger.info
+    info('In LVL1CaloMonitoringConfig')
+
+    result = ComponentAccumulator()
+
+    # monitoring algorithm configs
+    # do not run in RAW->ESD, or AOD-only
+    if flags.DQ.Environment not in ('tier0Raw', 'AOD'):
+        from TrigT1CaloMonitoring.CpmMonitorAlgorithm import CpmMonitoringConfig
+        result.merge(CpmMonitoringConfig(flags))
+
+
+    return result
diff --git a/Trigger/TrigT1/TrigT1CaloMonitoring/src/CpmMonitorAlgorithm.cxx b/Trigger/TrigT1/TrigT1CaloMonitoring/src/CpmMonitorAlgorithm.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..08fdefa3fa3fa094658b8d6d4362aa480ed8ab48
--- /dev/null
+++ b/Trigger/TrigT1/TrigT1CaloMonitoring/src/CpmMonitorAlgorithm.cxx
@@ -0,0 +1,479 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "CpmMonitorAlgorithm.h"
+#include "TrigT1CaloUtils/CoordToHardware.h"
+#include "TrigT1CaloUtils/DataError.h"
+#include "TrigT1Interfaces/CPRoIDecoder.h"
+
+CpmMonitorAlgorithm::CpmMonitorAlgorithm( const std::string& name, ISvcLocator* pSvcLocator )
+  : AthMonitorAlgorithm(name,pSvcLocator),
+    m_phiScaleTT(32./M_PI), m_phiScaleJE(16./M_PI)
+{
+}
+
+StatusCode CpmMonitorAlgorithm::initialize() {
+
+  ATH_MSG_DEBUG("CpmMonitorAlgorith::initialize");
+  ATH_MSG_DEBUG("Package Name "<< m_packageName);
+  // container names
+  ATH_MSG_DEBUG("m_xAODTriggerTowerContainerName"<< m_xAODTriggerTowerContainerName); 
+  ATH_MSG_DEBUG("m_cpmTowerLocation"<< m_cpmTowerLocation); 
+  ATH_MSG_DEBUG("m_cpmTowerLocationOverlap"<< m_cpmTowerLocationOverlap); 
+
+  // steering parameters
+  ATH_MSG_DEBUG("m_crates"<<m_crates ); 
+  ATH_MSG_DEBUG("m_modules"<<m_modules ); 
+  ATH_MSG_DEBUG("m_maxSlices"<<m_maxSlices );
+  ATH_MSG_DEBUG("m_tobsPerCPM"<<m_tobsPerCPM );  
+  ATH_MSG_DEBUG("m_isolBits"<<m_isolBits ); 
+  ATH_MSG_DEBUG("m_maxTobsPerCmx"<<m_maxTobsPerCmx ); 
+
+  // initialise all the containers that we need
+  ATH_CHECK(m_xAODTriggerTowerContainerName.initialize());
+  ATH_CHECK(m_cpmTowerLocation.initialize());
+  ATH_CHECK(m_cpmTowerLocationOverlap.initialize());
+  ATH_CHECK( m_cpmTobRoiLocation.initialize());
+  ATH_CHECK( m_cmxCpTobLocation.initialize());
+  ATH_CHECK( m_cmxCpHitsLocation.initialize());
+
+  return AthMonitorAlgorithm::initialize();
+}
+
+StatusCode CpmMonitorAlgorithm::fillHistograms( const EventContext& ctx ) const {
+
+  ATH_MSG_DEBUG("CpmMonitorAlgorithm::fillHistograms");
+
+  // Retrieve Trigger Towers from SG
+  SG::ReadHandle<xAOD::TriggerTowerContainer> triggerTowerTES(m_xAODTriggerTowerContainerName, ctx);
+  ATH_CHECK(triggerTowerTES.isValid());
+
+  // Retrieve Core CPM Towers from SG
+  SG::ReadHandle<xAOD::CPMTowerContainer> cpmTowerTES(m_cpmTowerLocation, ctx);
+  ATH_CHECK(cpmTowerTES.isValid());
+  
+  // Retrieve Overlap CPM Towers from SG
+  SG::ReadHandle<xAOD::CPMTowerContainer> cpmTowerOverlapTES(m_cpmTowerLocationOverlap, ctx);
+  ATH_CHECK(cpmTowerOverlapTES.isValid());
+
+  //Retrieve CPM TOB RoIs from SG
+  SG::ReadHandle<xAOD::CPMTobRoIContainer> cpmTobRoiTES(m_cpmTobRoiLocation, ctx);
+  ATH_CHECK(cpmTobRoiTES.isValid());
+
+  //Retrieve CMX-CP TOBs from SG
+  SG::ReadHandle<xAOD::CMXCPTobContainer> cmxCpTobTES(m_cmxCpTobLocation, ctx);
+  ATH_CHECK(cmxCpTobTES.isValid());
+
+  //Retrieve CMX-CP Hits from SG
+  SG::ReadHandle<xAOD::CMXCPHitsContainer> cmxCpHitsTES(m_cmxCpHitsLocation, ctx);
+  ATH_CHECK(cmxCpHitsTES.isValid());
+
+  //
+  // array of monitored items
+  std::vector<std::reference_wrapper<Monitored::IMonitoredVariable>> variables;
+
+  // Global plots
+  // Create a vector of towers we want to monitor 
+  std::vector<MonitorTT> monTTs;
+  xAOD::TriggerTowerContainer::const_iterator ttIterator = (*triggerTowerTES).begin();
+  xAOD::TriggerTowerContainer::const_iterator ttIteratorEnd = (*triggerTowerTES).end();
+  for (; ttIterator != ttIteratorEnd; ++ttIterator) {
+    const int layer = (*ttIterator)->layer();
+    const xAOD::TriggerTower_v2* tt = *ttIterator; 
+    const double eta = (*ttIterator)->eta();
+    if ( std::abs(eta) > 2.5) continue;
+      
+    if (!tt->cpET()) continue; 
+    //check if the TriggerTower is in EM or HAD layer
+    if (layer == 0) { //EM
+      const int em = int(tt->cpET()); 
+      if (em) { 
+	MonitorTT monTT; 
+	monTT.ttower=(*ttIterator);
+	monTT.phi_scaled=(*ttIterator)->phi()*m_phiScaleTT;
+	monTTs.push_back(monTT);
+      }
+    }
+    if (layer == 1) { //HAD
+      const int had = int(tt->cpET()); 
+      if (had)  {
+	MonitorTT monTT; 
+	monTT.ttower=(*ttIterator);
+	monTT.phi_scaled=(*ttIterator)->phi()*m_phiScaleTT;
+	monTTs.push_back(monTT);
+      }
+    }      
+  } //ttIterator
+
+  // setup cutmasks to select the em and had TTs
+  auto mask_em_TT = Monitored::Collection("mask_em_TT", monTTs, []( const auto &tower ) {return ( tower.ttower->layer()==0); } );  variables.push_back( mask_em_TT );
+  auto mask_had_TT = Monitored::Collection("mask_had_TT", monTTs, []( const auto &tower ){return ( tower.ttower->layer()==1); } ); variables.push_back( mask_had_TT );
+
+  // the variables to monitor
+  auto etaTT = Monitored::Collection("etaTT", monTTs, []( const auto &tower ){return tower.ttower->eta();} );  variables.push_back( etaTT );
+  auto phiTT = Monitored::Collection("phiTT", monTTs, []( const auto &tower ){return tower.phi_scaled;} );  variables.push_back( phiTT );
+
+  // CPM Global maps
+
+  // Vectors for error overview bits;
+  std::vector<int> errorsCPM(m_crates * m_modules);
+  std::vector<int> errorsCMX(m_crates * 2); // L/R
+  //cpmTowerTES
+  std::vector<MonitorCpmTT> monCpmTTs_em;
+  std::vector<MonitorCpmTT> monCpmTTs_had;
+  bool core=true;
+  ATH_CHECK(fillCpmTowerVectors(cpmTowerTES, monCpmTTs_em, monCpmTTs_had, errorsCPM, core));
+  std::vector<MonitorCpmTT> monCpmOverlapTTs_em;
+  std::vector<MonitorCpmTT> monCpmOverlapTTs_had;
+  core=false;
+  ATH_CHECK(fillCpmTowerVectors(cpmTowerOverlapTES, monCpmOverlapTTs_em, monCpmOverlapTTs_had, errorsCPM, core));
+
+  // add the CPM global variables to be monitored - exclude Overlap
+  auto etCpmTT_em = Monitored::Collection("etCpmTT_em", monCpmTTs_em, []( const auto &tt ){return tt.ttower->emEnergy();} ); variables.push_back( etCpmTT_em );
+  auto etaCpmTT_em = Monitored::Collection("etaCpmTT_em", monCpmTTs_em, []( const auto &tt ){return tt.ttower->eta();} ); variables.push_back( etaCpmTT_em );
+  auto phiCpmTT_em = Monitored::Collection("phiCpmTT_em", monCpmTTs_em, []( const auto &tt ){return tt.ttower->phi();} ); variables.push_back( phiCpmTT_em );
+  auto phiScaledCpmTT_em = Monitored::Collection("phiScaledCpmTT_em", monCpmTTs_em, []( const auto &tt ){return tt.phi_scaled;} ); 
+  variables.push_back( phiScaledCpmTT_em );
+  auto etCpmTT_had = Monitored::Collection("etCpmTT_had", monCpmTTs_had, []( const auto &tt ){return tt.ttower->hadEnergy();} ); variables.push_back( etCpmTT_had );
+  auto etaCpmTT_had = Monitored::Collection("etaCpmTT_had", monCpmTTs_had, []( const auto &tt ){return tt.ttower->eta();} ); variables.push_back( etaCpmTT_had );
+  auto phiCpmTT_had = Monitored::Collection("phiCpmTT_had", monCpmTTs_had, []( const auto &tt ){return tt.ttower->phi();} ); variables.push_back( phiCpmTT_had );
+  auto phiScaledCpmTT_had = Monitored::Collection("phiScaledCpmTT_had", monCpmTTs_had, []( const auto &tt ){return tt.phi_scaled;} ); 
+  variables.push_back( phiScaledCpmTT_had );
+
+  // errors and slices are filled for sum of Core and Overlap
+  std::vector<MonitorCpmTT> monCpmTTs_em_tot(monCpmTTs_em.begin(),monCpmTTs_em.end());
+  monCpmTTs_em_tot.insert(monCpmTTs_em_tot.end(), monCpmOverlapTTs_em.begin(),monCpmOverlapTTs_em.end());
+  std::vector<MonitorCpmTT> monCpmTTs_had_tot(monCpmTTs_had.begin(),monCpmTTs_had.end());
+  monCpmTTs_had_tot.insert(monCpmTTs_had_tot.end(), monCpmOverlapTTs_had.begin(),monCpmOverlapTTs_had.end());
+  // the variables
+  auto etaCpmTT_em_tot = Monitored::Collection("etaCpmTT_em_tot", monCpmTTs_em_tot, []( const auto &tt ){return tt.ttower->eta();} ); 
+  variables.push_back( etaCpmTT_em_tot) ;
+  auto phiScaledCpmTT_em_tot = Monitored::Collection("phiScaledCpmTT_em_tot", monCpmTTs_em_tot, []( const auto &tt ){return tt.phi_scaled;} ); 
+  variables.push_back( phiScaledCpmTT_em_tot );
+  auto etaCpmTT_had_tot = Monitored::Collection("etaCpmTT_had_tot", monCpmTTs_had_tot, []( const auto &tt ){return tt.ttower->eta();} ); 
+  variables.push_back( etaCpmTT_had_tot) ;
+  auto phiScaledCpmTT_had_tot = Monitored::Collection("phiScaledCpmTT_had_tot", monCpmTTs_had_tot, []( const auto &tt ){return tt.phi_scaled;} ); 
+  variables.push_back( phiScaledCpmTT_had_tot );
+
+
+  // the masks
+  auto parityErrorCpmTT_em = Monitored::Collection("parityErrorCpmTT_em", monCpmTTs_em_tot, []( const auto &tt ){return tt.emParityError;} ); 
+  variables.push_back( parityErrorCpmTT_em );
+  auto linkDownErrorCpmTT_em = Monitored::Collection("linkDownErrorCpmTT_em", monCpmTTs_em_tot, []( const auto &tt ){return tt.emLinkDownError;} ); 
+  variables.push_back( linkDownErrorCpmTT_em );
+  auto parityErrorCpmTT_had = Monitored::Collection("parityErrorCpmTT_had", monCpmTTs_had_tot, []( const auto &tt ){return tt.hadParityError;} ); 
+  variables.push_back( parityErrorCpmTT_had );
+  auto linkDownErrorCpmTT_had = Monitored::Collection("linkDownErrorCpmTT_had", monCpmTTs_had_tot, []( const auto &tt ){return tt.hadLinkDownError;} ); 
+  variables.push_back( linkDownErrorCpmTT_had );
+
+  // and the sum of the Core and Overlap for EM and HAD
+  std::vector<MonitorCpmTT> monCpmTTs_tot(monCpmTTs_em_tot.begin(),monCpmTTs_em_tot.end());
+  monCpmTTs_tot.insert(monCpmTTs_tot.end(), monCpmTTs_had_tot.begin(),monCpmTTs_had_tot.end());
+
+  auto peakCpmTT_tot = Monitored::Collection("peakCpmTT_tot", monCpmTTs_tot, []( const auto &tt ){return tt.ttower->peak();} ); 
+  variables.push_back( peakCpmTT_tot );
+  auto sliceCpmTT_tot = Monitored::Collection("sliceCpmTT_tot", monCpmTTs_tot, []( const auto &tt ){return tt.slice;} ); 
+  variables.push_back( sliceCpmTT_tot );
+
+  //=============================================
+  //  CPM TOB RoIs
+  //=============================================
+
+  std::vector<MonitorTobRoI> monTobRoIsEner;
+  std::vector<MonitorTobRoI> monTobRoIsIsol;
+
+  const int vecSize = m_crates * m_modules * 2;
+  std::vector<int> tobCount(vecSize);
+  LVL1::CPRoIDecoder decoder;
+  xAOD::CPMTobRoIContainer::const_iterator crIterator    = (*cpmTobRoiTES).begin();
+  xAOD::CPMTobRoIContainer::const_iterator crIteratorEnd = (*cpmTobRoiTES).end();
+  for (; crIterator != crIteratorEnd; ++crIterator) {
+    const int type      = (*crIterator)->type();  // 0=EM, 1=Tau
+    const int energy    = (*crIterator)->energy();
+    const int isolation = (*crIterator)->isolation();
+    const LVL1::CoordinateRange coord(decoder.coordinate((*crIterator)->roiWord())); 
+    const double eta = coord.eta();
+    const double phi = coord.phi();
+    const double phiMod = phi * m_phiScaleTT - 0.5;
+    const double etaMod = eta - 0.05;
+    if (energy) {
+      MonitorTobRoI monTobRoI;
+      monTobRoI.tobroi=(*crIterator);
+      monTobRoI.etaMod=etaMod;
+      monTobRoI.phiMod=phiMod;
+      monTobRoIsEner.push_back(monTobRoI);
+    }
+    if (isolation) {
+      // have a go at isolation bits
+      int * isolbits=getIsolationBits(isolation, m_isolBits, 1);
+      bool isolationBits[4]={false}; //cannot use Gaudi::Property<int> so set size
+
+      bool isolationBitSet=false;
+      for (int thr = 0; thr < m_isolBits; ++thr) {
+	isolationBits[thr]=isolbits[thr];
+	if (isolationBits[thr])
+	  isolationBitSet=true;
+      }
+      //
+      MonitorTobRoI monTobRoI;
+      monTobRoI.tobroi=(*crIterator);
+      monTobRoI.etaMod=etaMod;
+      monTobRoI.phiMod=phiMod;
+      memcpy(monTobRoI.isolationBits, isolationBits , sizeof(isolationBits));
+      monTobRoI.isolationBitSet=isolationBitSet;
+      monTobRoIsIsol.push_back(monTobRoI);
+    }
+    const int crate = (*crIterator)->crate();
+    const int cpm   = (*crIterator)->cpm();
+    ++tobCount[(crate * m_modules + cpm - 1) * 2 + type];
+  }
+  // Energy
+  auto etaTobRoIsEner = Monitored::Collection("etaTobRoIsEner", monTobRoIsEner, []( const auto &roi ){return roi.etaMod;} ); 
+  variables.push_back(etaTobRoIsEner);
+  auto phiTobRoIsEner = Monitored::Collection("phiTobRoIsEner", monTobRoIsEner, []( const auto &roi ){return roi.phiMod;} );
+  variables.push_back(phiTobRoIsEner);
+  auto energyTobRoIsEner = Monitored::Collection("energyTobRoIsEner", monTobRoIsEner, []( const auto &roi ){return roi.tobroi->energy();} ); 
+  variables.push_back(energyTobRoIsEner);
+  auto typeTobRoIsEner = Monitored::Collection("typeTobRoIsEner", monTobRoIsEner, []( const auto &roi ){return roi.tobroi->type();} ); 
+  variables.push_back(typeTobRoIsEner);
+
+  // setup cutmasks to select EM or Tau
+  auto mask_tobroi_ener_em = Monitored::Collection("mask_tobroi_ener_em", monTobRoIsEner, []( const auto &roi ) {return ( roi.tobroi->type()==0); } );  
+  variables.push_back( mask_tobroi_ener_em );
+  auto mask_tobroi_ener_tau = Monitored::Collection("mask_tobroi_ener_tau", monTobRoIsEner, []( const auto &roi ){return ( roi.tobroi->type()==1); } ); 
+  variables.push_back( mask_tobroi_ener_tau );
+
+  // Isol
+  auto etaTobRoIsIsol = Monitored::Collection("etaTobRoIsIsol", monTobRoIsIsol, []( const auto &roi ){return roi.etaMod;} ); 
+  variables.push_back(etaTobRoIsIsol);
+  auto phiTobRoIsIsol = Monitored::Collection("phiTobRoIsIsol", monTobRoIsIsol, []( const auto &roi ){return roi.phiMod;} );
+  variables.push_back(phiTobRoIsIsol);
+  auto energyTobRoIsIsol = Monitored::Collection("energyTobRoIsIsol", monTobRoIsIsol, []( const auto &roi ){return roi.tobroi->isolation();} ); 
+  variables.push_back(energyTobRoIsIsol);
+
+  auto mask_tobroi_isol_em = Monitored::Collection("mask_tobroi_isol_em", monTobRoIsIsol, []( const auto &roi ) {return ( roi.tobroi->type()==0); } );  
+  variables.push_back( mask_tobroi_isol_em );
+  auto mask_tobroi_isol_tau = Monitored::Collection("mask_tobroi_isol_tau", monTobRoIsIsol, []( const auto &roi ){return ( roi.tobroi->type()==1); } ); 
+  variables.push_back( mask_tobroi_isol_tau );
+
+
+  // count ToBs
+  std::vector<int> tobCountEm;
+  std::vector<int> tobCountTau;
+  for (int crate = 0; crate < m_crates; ++crate) {
+    for (int cpm = 1; cpm <= m_modules; ++cpm) {
+      for (int type = 0; type < 2; ++type) {
+	int val = tobCount[(crate * m_modules + cpm - 1) * 2 + type];
+	if (val) {
+	  if (val > m_tobsPerCPM) val = m_tobsPerCPM + 1;
+	  if (type == 0) {
+	    tobCountEm.push_back(val);
+	  } else {
+	    tobCountTau.push_back(val);
+	  }
+	}
+      }
+    }
+  }
+  auto tobEm = Monitored::Collection("tobPerCPMEm", tobCountEm, []( const auto &tob ){return tob;} );  variables.push_back( tobEm );
+  auto tobTau = Monitored::Collection("tobPerCPMTau", tobCountTau, []( const auto &tob ){return tob;} );  variables.push_back( tobTau );
+
+
+  //=============================================
+  //  CMX-CP TOBs
+  //=============================================
+
+  std::vector<MonitorCmxCpTob> monCmxCpTobEner;
+  std::vector<MonitorCmxCpTob> monCmxCpTobIsol;
+  std::vector<MonitorCmxCpTob> monCmxCpTobError;
+
+  tobCount.assign(vecSize, 0);
+  std::vector<int> cmxCount(m_crates * 2);
+  xAOD::CMXCPTobContainer::const_iterator cmxCpTobIter    = (*cmxCpTobTES).begin();
+  xAOD::CMXCPTobContainer::const_iterator cmxCpTobIterEnd = (*cmxCpTobTES).end();
+  for (; cmxCpTobIter != cmxCpTobIterEnd; ++cmxCpTobIter) {
+    const uint8_t crate     = (*cmxCpTobIter)->crate();
+    const uint8_t cpm       = (*cmxCpTobIter)->cpm();     // 1-14
+    const uint8_t cmx       = (*cmxCpTobIter)->cmx();     // 0=Left, 1=Right  (Assumed in Sim to be Left Tau, Right EM)
+    const uint8_t chip      = (*cmxCpTobIter)->chip();    // 4 bits
+    const uint8_t location  = (*cmxCpTobIter)->location();// 2 bits
+    const uint8_t energy    = (*cmxCpTobIter)->energy();
+    const uint8_t isolation = (*cmxCpTobIter)->isolation();
+    const uint32_t error     = (*cmxCpTobIter)->error();
+    const uint8_t x = crate * m_modules + cpm - 1;
+    const uint8_t y = chip * 4 + location;
+    if (energy) {
+      MonitorCmxCpTob monCmxCpTob;
+      monCmxCpTob.tob=(*cmxCpTobIter);
+      monCmxCpTob.x=x;
+      monCmxCpTob.y=y;
+      monCmxCpTobEner.push_back(monCmxCpTob);
+
+    }
+    if (isolation) {
+      MonitorCmxCpTob monCmxCpTob;
+      monCmxCpTob.tob=(*cmxCpTobIter);
+      monCmxCpTob.x=x;
+      monCmxCpTob.y=y;
+      monCmxCpTobIsol.push_back(monCmxCpTob);
+    }
+    if (error) {
+      const LVL1::DataError err(error);
+      if (err.get(LVL1::DataError::Overflow)) {
+	tobCount[x * 2 + cmx] = m_tobsPerCPM + 1;
+      }
+      const int ybase = cmx * 5;
+      bool parity = false;
+      if (err.get(LVL1::DataError::ParityMerge)) {
+	parity = true;
+      }
+      if (err.get(LVL1::DataError::ParityPhase0)) {
+	parity = true;
+      }
+      if (err.get(LVL1::DataError::ParityPhase1)) {
+	parity = true;
+      }
+      if (err.get(LVL1::DataError::ParityPhase2)) {
+	parity = true;
+      }
+      if (err.get(LVL1::DataError::ParityPhase3)) {
+	parity = true;
+      }
+      if (parity) errorsCMX[crate * 2 + cmx] |= (1 << TOBParity);
+
+      MonitorCmxCpTob monCmxCpTob;
+      monCmxCpTob.tob=(*cmxCpTobIter);
+      monCmxCpTob.x=x;
+      monCmxCpTob.ybase=ybase;
+      monCmxCpTobEner.push_back(monCmxCpTob);
+    }
+    if (energy || isolation || error) {
+      ++tobCount[x * 2 + cmx];
+      ++cmxCount[crate * 2 + cmx];
+    }
+  }
+  
+
+  fill(m_packageName,variables);
+  variables.clear();
+  return StatusCode::SUCCESS;
+}
+
+
+int* CpmMonitorAlgorithm::getIsolationBits(int val, int nThresh, int nBits, int offset) const
+{
+  // return array of threshold bits
+  // 
+  static int nthres[20]={0};
+  for (int thr = 0; thr < 20; ++thr) {
+    nthres[thr]=0;
+  }
+  if (val) {
+    const int mask = (1 << nBits) - 1;
+    for (int thr = 0; thr < nThresh; ++thr) {
+      const int hit = (val >> (nBits*thr)) & mask;
+      if (hit) {
+	nthres[thr+offset]=hit;
+      }  
+    }
+  } else {
+    ATH_MSG_WARNING("getIsolationBits: no input word supplied" ); 
+  }
+  return nthres;
+
+}
+
+StatusCode CpmMonitorAlgorithm::fillCpmTowerVectors(SG::ReadHandle<xAOD::CPMTowerContainer> &cpmTower,
+						    std::vector<MonitorCpmTT> &monCpmTTs_em, std::vector<MonitorCpmTT> &monCpmTTs_had,
+						    std::vector<int> &errorsCPM,
+						    bool core
+						    ) const
+{
+  //   
+  xAOD::CPMTowerContainer::const_iterator ctIterator    = (*cpmTower).begin();
+  xAOD::CPMTowerContainer::const_iterator ctIteratorEnd = (*cpmTower).end();      
+  for (; ctIterator != ctIteratorEnd; ++ctIterator) {
+    const xAOD::CPMTower* ct = *ctIterator;
+    const uint8_t    em  = ct->emEnergy();
+    const uint8_t    had = ct->hadEnergy();
+    const double eta = ct->eta();
+    const double phi = ct->phi();
+    const LVL1::Coordinate coord(phi, eta);
+    LVL1::CoordToHardware converter;
+    const int crate  = (core) ? converter.cpCrate(coord)
+      : converter.cpCrateOverlap(coord);
+    const int cpm    = (core) ? converter.cpModule(coord)
+      : converter.cpModuleOverlap(coord);
+    const int loc    = crate * m_modules + cpm - 1;
+    const int slices = (ct->emEnergyVec()).size();
+    const int slice = crate * m_maxSlices + slices - 1;
+    if (crate==999) {
+      ATH_MSG_DEBUG("Crate number is 999, "<< crate << " eta " << eta << " phi " << phi <<       
+ 		    " cpm " << cpm << " slices " << slices <<
+		    " max slices " << m_maxSlices << " m_modules " << m_modules <<
+		    " slice " << slice);
+    }
+
+    // Errors    
+    bool emParityError=true;
+    bool emLinkDownError=true;
+    bool emGLinkParityError[8]={false};
+    uint32_t error = ct->emError(); // uint8_t
+    if (error) {
+      const LVL1::DataError emError(error);
+      if (emError.get(LVL1::DataError::Parity)) {
+	emParityError=true;
+        errorsCPM[loc] |= (1 << EMParity);
+      }
+      if (emError.get(LVL1::DataError::LinkDown)) {
+	emLinkDownError=true;
+        errorsCPM[loc] |= (1 << EMLink);
+      }
+      const int status = (error >> LVL1::DataError::GLinkParity) & 0xff;
+      if (status) {
+        for (int bit = 0; bit < 8; ++bit) {
+          if ((status >> bit) & 0x1) emGLinkParityError[bit]=true; 
+        }
+        errorsCPM[loc] |= (1 << CPMStatus);
+      }
+    }
+
+    bool hadParityError=true;
+    bool hadLinkDownError=true;
+    error = ct->hadError();
+    if (error) {
+      const LVL1::DataError hadError(error);
+      if (hadError.get(LVL1::DataError::Parity)) {
+	hadParityError=true;
+        errorsCPM[loc] |= (1 << HadParity);
+      }
+      if (hadError.get(LVL1::DataError::LinkDown)) {
+	hadLinkDownError=true;
+        errorsCPM[loc] |= (1 << HadLink);
+      }
+    }
+    // fill tower vector for plots
+    MonitorCpmTT monTT; 
+    monTT.ttower=ct;
+    monTT.phi_scaled=ct->phi()*m_phiScaleTT;
+    monTT.slice=slice;
+    monTT.emParityError=emParityError;
+    monTT.emLinkDownError=emLinkDownError;
+    memcpy(monTT.emGLinkParityError, emGLinkParityError, sizeof(emGLinkParityError));
+    monTT.hadParityError=hadParityError;
+    monTT.hadLinkDownError=hadLinkDownError;
+    if (em) {
+      monCpmTTs_em.push_back(monTT);
+    }
+    if (had) {
+      monCpmTTs_had.push_back(monTT);
+    }
+
+  } // iterator
+
+
+  return StatusCode::SUCCESS;
+}
+
+
diff --git a/Trigger/TrigT1/TrigT1CaloMonitoring/src/CpmMonitorAlgorithm.h b/Trigger/TrigT1/TrigT1CaloMonitoring/src/CpmMonitorAlgorithm.h
new file mode 100644
index 0000000000000000000000000000000000000000..42033d2e5c41df3bb4413679d5de515fe0a412a6
--- /dev/null
+++ b/Trigger/TrigT1/TrigT1CaloMonitoring/src/CpmMonitorAlgorithm.h
@@ -0,0 +1,110 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+#ifndef TRIGT1CALOMONITORING_CPMMONITORALGORITHM_H
+#define TRIGT1CALOMONITORING_CPMMONITORALGORITHM_H
+
+#include "AthenaMonitoring/AthMonitorAlgorithm.h"
+#include "AthenaMonitoringKernel/Monitored.h"
+#include "StoreGate/ReadHandleKey.h"
+#include "xAODTrigL1Calo/CPMTowerContainer.h" 
+#include "xAODTrigL1Calo/CPMTobRoIContainer.h"
+#include "xAODTrigL1Calo/CMXCPTobContainer.h"
+#include "xAODTrigL1Calo/CMXCPHitsContainer.h"
+#include "TrigT1Interfaces/TrigT1CaloDefs.h"
+
+
+class CpmMonitorAlgorithm : public AthMonitorAlgorithm {
+ public:CpmMonitorAlgorithm( const std::string& name, ISvcLocator* pSvcLocator );
+  virtual ~CpmMonitorAlgorithm()=default;
+  virtual StatusCode initialize() override;
+  virtual StatusCode fillHistograms( const EventContext& ctx ) const override;
+
+  // monitoring trigger tower structs for various towers
+  struct MonitorTT{
+    const xAOD::TriggerTower_v2* ttower;
+    double phi_scaled; // rescaled for 2D plots
+  };
+  struct MonitorCpmTT{
+    const xAOD::CPMTower_v2* ttower;
+    // some modified/derived information 
+    double phi_scaled; // rescaled for 2D plots
+    int slice; // crate * m_maxSlices + emEnergyVec()).size() - 1;
+    // errors
+    bool emParityError;
+    bool emLinkDownError;
+    bool emGLinkParityError[8]; 
+    bool hadParityError;
+    bool hadLinkDownError;   
+  };
+
+  struct MonitorTobRoI{
+    const xAOD::CPMTobRoI_v1* tobroi;
+    //xAOD::CPMTower_v2
+    // some modified/derived information 
+    double etaMod; 
+    double phiMod; 
+    bool isolationBits[4]; 
+    bool isolationBitSet; // set to true if at least one bit set 
+  };
+
+
+  struct MonitorCmxCpTob{
+    const xAOD::CMXCPTob_v1* tob;
+    // some modified/derived information 
+    uint8_t x; // crate * m_modules + cpm - 1;
+    uint8_t y; // chip * 4 + location;
+    int ybase; // cmx * 5;
+  };
+
+
+
+
+private:
+
+  // Phi scale for trigger tower eta/phi plots
+  double m_phiScaleTT;
+  // Phi scale for jet element eta/phi plots
+  double m_phiScaleJE;
+
+  StringProperty m_packageName{this,"PackageName","CpmMonitor","group name for histograming"};
+
+  // The following enums are set in the python in order to get consistent histogram bins
+  // only add here if they are used in the .cxx
+  Gaudi::Property<int> m_crates{this,"s_crates", 4,  "Number of CPM crates"};
+  Gaudi::Property<int> m_modules{this,"s_modules", 14, "Number of modules per crate (modules numbered 1-14)"};
+  Gaudi::Property<int> m_maxSlices{this,"s_maxSlices", 5,  "Maximum number of slices"};
+  Gaudi::Property<int> m_tobsPerCPM{this,"s_tobsPerCPM", 5,  "Maximum number of TOBs per CPM sent to CMX"};
+  Gaudi::Property<int> m_isolBits{this,"s_isolBits", 4,  "Number of bits for encoded isolation"};
+  // see fillXVsThresholds
+  Gaudi::Property<int> m_threshBits{this,"s_threshBits", 3,  "Number of bits per threshold for hit sums"};
+  Gaudi::Property<int> m_thresholds{this,"s_thresholds", 16, "Number of EM/Tau threshold bits"};
+
+  // previously declared in .cxx
+  Gaudi::Property<int> m_maxTobsPerCmx{this,"MaxTOBsPerCMX", 70,  "Maximum number of TOBs per CMX plotted"};
+
+  /// Error summary plot bins
+  enum SummaryErrors { EMParity, EMLink, HadParity, HadLink, CPMStatus,
+                       TOBParity, SumParity, CMXStatus, NumberOfSummaryBins };
+
+
+  // container keys including steering parameter and description
+  SG::ReadHandleKey<xAOD::TriggerTowerContainer> m_xAODTriggerTowerContainerName{this, "BS_xAODTriggerTowerContainer",LVL1::TrigT1CaloDefs::xAODTriggerTowerLocation,"Trigger Tower Container"};
+  SG::ReadHandleKey<xAOD::CPMTowerContainer> m_cpmTowerLocation{this, "CPMTowerLocation", LVL1::TrigT1CaloDefs::CPMTowerLocation, "CPM container"};
+  SG::ReadHandleKey<xAOD::CPMTowerContainer> m_cpmTowerLocationOverlap{this, "CPMTowerLocationOverlap",LVL1::TrigT1CaloDefs::CPMTowerLocation + "Overlap", "CPM Overlap container"};
+  SG::ReadHandleKey<xAOD::CPMTobRoIContainer> m_cpmTobRoiLocation{this, "CPMTobRoILocation", LVL1::TrigT1CaloDefs::CPMTobRoILocation, "CPMTobRoI container"};
+  SG::ReadHandleKey<xAOD::CMXCPTobContainer> m_cmxCpTobLocation{this, "CMXCPTobLocation", LVL1::TrigT1CaloDefs::CMXCPTobLocation, "CMXCPTob container"};
+  SG::ReadHandleKey<xAOD::CMXCPHitsContainer> m_cmxCpHitsLocation{this, "CMXCPHitsLocation", LVL1::TrigT1CaloDefs::CMXCPHitsLocation, "CMXCPHits container"};
+
+  int * getIsolationBits(int val, int nThresh, int nBits, int offset=0) const;
+
+
+  StatusCode fillCpmTowerVectors(SG::ReadHandle<xAOD::CPMTowerContainer> &cpmTower,
+				 std::vector<MonitorCpmTT> &monCpmTTs_em, std::vector<MonitorCpmTT> &monCpmTTs_had,
+				 std::vector<int> &errorsCPM, 
+				 bool core
+				 ) const;
+
+
+};
+#endif
diff --git a/Trigger/TrigT1/TrigT1CaloMonitoring/src/components/TrigT1CaloMonitoring_entries.cxx b/Trigger/TrigT1/TrigT1CaloMonitoring/src/components/TrigT1CaloMonitoring_entries.cxx
index 6656b9ccd8da4327c88604be8fc2af55042316de..22a5bd4ca7d188b0dd987abf1bad225ba17b6bfd 100644
--- a/Trigger/TrigT1/TrigT1CaloMonitoring/src/components/TrigT1CaloMonitoring_entries.cxx
+++ b/Trigger/TrigT1/TrigT1CaloMonitoring/src/components/TrigT1CaloMonitoring_entries.cxx
@@ -1,3 +1,12 @@
+// Run 3
+#include "../CpmMonitorAlgorithm.h"
+//#include "../CpmSimMonitorAlgorithm.h"
+//#include "../PpmSimBsMonitorAlgorithm.h"
+//#include "../PprMonitorAlgorithm.h"
+//#include "../PprSpareMonitorAlgorithm.h"
+//#include "../PprStabilityMonitorAlgorithm.h"
+
+// Run 2
 #include "../CPMon.h"
 #include "../CPSimMon.h"
 #include "../JEPJEMMon.h"
@@ -24,7 +33,15 @@
 #include "../JetEfficienciesMonTool.h"
 #include "../RODMonV1.h"
 
+// Run 3
+DECLARE_COMPONENT( CpmMonitorAlgorithm )
+//DECLARE_COMPONENT( CpmSimMonitorAlgorithm )
+//DECLARE_COMPONENT( PpmSimBsMonitorAlgorithm )
+//DECLARE_COMPONENT( PprMonitorAlgorithm )
+//DECLARE_COMPONENT( PprSpareMonitorAlgorithm )
+//DECLARE_COMPONENT( PprStabilityMonitorAlgorithm )
 
+// Run 2
 DECLARE_COMPONENT( LVL1::OverviewMon )
 DECLARE_COMPONENT( LVL1::CPMon )
 DECLARE_COMPONENT( LVL1::CPSimMon )