diff --git a/CMakeLists.txt b/CMakeLists.txt
index e39c8b2068385282b99f14492d1c6b0be3758926..5b33a74c59bb59464203c9c8ce4fc8408d80cccb 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -137,6 +137,7 @@ lhcb_add_subdirectories(
     Phys/FunctorCache
     Utils/CatboostStandaloneEvaluator
     Vis/PhoenixAlgs
+    UT/UTMonitors
 )
 
 gaudi_install(CMAKE
diff --git a/Phys/TrackRefitting/src/UpdateVertexCoordinatesOffline.cpp b/Phys/TrackRefitting/src/UpdateVertexCoordinatesOffline.cpp
index 0dc413eaa2382b8419c3a11c58e6a4314b2c26d5..b3b63dc66320f5391c480ad7bd06bab107185e88 100644
--- a/Phys/TrackRefitting/src/UpdateVertexCoordinatesOffline.cpp
+++ b/Phys/TrackRefitting/src/UpdateVertexCoordinatesOffline.cpp
@@ -148,4 +148,4 @@ namespace LHCb {
   };
 
   DECLARE_COMPONENT_WITH_ID( UpdateVertexCoordinatesOffline, "UpdateVertexCoordinatesOffline" )
-} // namespace LHCb
\ No newline at end of file
+} // namespace LHCb
diff --git a/Tr/TrackMonitors/CMakeLists.txt b/Tr/TrackMonitors/CMakeLists.txt
index fffb741970034c08d70216e182d986be827493e4..f0304ba1e2a148a6b0e88ae699426f29c46c6daa 100644
--- a/Tr/TrackMonitors/CMakeLists.txt
+++ b/Tr/TrackMonitors/CMakeLists.txt
@@ -35,6 +35,8 @@ gaudi_add_module(TrackMonitors
         src/TrackVertexMonitor.cpp
         src/TrackVPOverlapMonitor.cpp
         src/UTTrackMonitor.cpp
+        src/UTTrackMonitor.cpp
+        src/UTGlobalEffMon.cpp
         src/VPTrackMonitor.cpp
         src/VPHitEfficiencyMonitor.cpp
         src/VertexCompare.cpp
diff --git a/Tr/TrackMonitors/src/UTGlobalEffMon.cpp b/Tr/TrackMonitors/src/UTGlobalEffMon.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..476775432d22c421b955235c4957802771f783f7
--- /dev/null
+++ b/Tr/TrackMonitors/src/UTGlobalEffMon.cpp
@@ -0,0 +1,279 @@
+/*****************************************************************************\
+* (c) Copyright 2000-2018 CERN for the benefit of the LHCb Collaboration      *
+*                                                                             *
+* This software is distributed under the terms of the GNU General Public      *
+* Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING".   *
+*                                                                             *
+* In applying this licence, CERN does not waive the privileges and immunities *
+* granted to it by virtue of its status as an Intergovernmental Organization  *
+* or submit itself to any jurisdiction.                                       *
+\*****************************************************************************/
+
+#include "DetDesc/DetectorElement.h"
+#include "Event/FitNode.h"
+#include "Event/PrFitNode.h"
+#include "Event/PrHits.h"
+#include "Event/PrKalmanFitResult.h"
+#include "Event/State.h"
+#include "Event/Track.h"
+#include "Gaudi/Accumulators/Histogram.h"
+#include "GaudiKernel/Algorithm.h"
+#include "GaudiKernel/PhysicalConstants.h"
+#include "Kernel/LHCbID.h"
+#include "Kernel/UTNames.h"
+#include "LHCbAlgs/Consumer.h"
+#include "TrackKernel/TrackFunctors.h"
+#include "TrackMonitorTupleBase.h"
+#include "UTDAQ/UTDAQHelper.h"
+#include "UTDAQ/UTInfo.h"
+#include <algorithm>
+#include <bitset>
+#include <cstdint>
+#include <iomanip>
+#include <string>
+#include <vector>
+
+/** @class UTGlobalEffMon UTGlobalEffMon.h
+ */
+
+using namespace LHCb;
+using namespace Gaudi;
+
+template <typename T>
+class Mutable {
+  mutable T m_t;
+
+public:
+  template <typename... Args>
+    requires std::is_constructible_v<T, Args...>
+  Mutable( Args&&... args ) : m_t{ std::forward<Args>( args )... } {}
+
+  template <typename Arg>
+  decltype( auto ) operator[]( Arg&& arg ) const {
+    return m_t[std::forward<Arg>( arg )];
+  }
+};
+
+namespace {
+  template <class TrackContainer, class Predicate>
+  std::vector<const LHCb::Track*> myselect( const TrackContainer& tracks, Predicate&& selector ) {
+    std::vector<const LHCb::Track*> rc;
+    std::copy_if( tracks.begin(), tracks.end(), std::back_inserter( rc ), std::forward<Predicate>( selector ) );
+    return rc;
+  }
+
+  auto TrackTypePredicate = []( LHCb::Track::Types atype ) {
+    return [=]( const LHCb::Track* track ) { return track->type() == atype; };
+  };
+
+  auto TrackBackwardPredicate = []( const LHCb::Track* track ) { return track->isVeloBackward(); };
+
+  auto TrackForwardPredicate = []() { return [=]( const LHCb::Track* track ) { return !track->isVeloBackward(); }; };
+
+  auto TrackVeloSidePredicate = []( int asign ) {
+    // +1: left side only, 0: overlap track, -1: right side only
+    // for asign > 0 select left-side tracks only, for a < 0 select right-side tracks, reject overlap tracks
+    return [=]( const LHCb::Track* track ) {
+      int  side         = 0;
+      bool allhitsleft  = true;
+      bool allhitsright = true;
+
+      const std::vector<LHCb::LHCbID>& track_ids = track->lhcbIDs();
+      for ( const auto& track_id : track_ids ) {
+        if ( !track_id.isVP() ) continue;
+
+        auto vp_id = track_id.vpID();
+        // 0 should be right, 1 left side
+        bool sidepos = ( vp_id.sidepos() == LHCb::Detector::VPChannelID::Side::A );
+
+        allhitsleft  = allhitsleft && sidepos;
+        allhitsright = allhitsright && !sidepos;
+      }
+      if ( allhitsleft ) side = +1;
+      if ( allhitsright ) side = -1;
+      return side * asign > 0;
+    };
+  };
+
+} // namespace
+
+template <typename OWNER, typename K, typename H, typename A>
+void buildHistogram( OWNER owner, std::map<K, H>& h, K k, std::string name, std::string labels, A axis ) {
+  h.emplace( std::piecewise_construct, std::forward_as_tuple( k ), std::forward_as_tuple( owner, name, labels, axis ) );
+}
+
+template <typename TFitResult, typename TNode>
+class UTGlobalEffMon
+    : public LHCb::Algorithm::Consumer<void( LHCb::Track::Range const&, DetectorElement const& ),
+                                       LHCb::DetDesc::usesBaseAndConditions<TrackMonitorTupleBase, DetectorElement>> {
+
+public:
+  UTGlobalEffMon( const std::string& name, ISvcLocator* pSvcLocator );
+  StatusCode initialize() override;
+  void       operator()( LHCb::Track::Range const& tracks, DetectorElement const& ) const override;
+
+private:
+  mutable Gaudi::Accumulators::Histogram<1> m_h_ntracks{
+      this, "h_ntracks", "Number of long track; Number of long tracks;Events", { 1000, 0, 5000 } };
+  mutable Gaudi::Accumulators::Histogram<1> m_h_nutlay{
+      this, "h_nutlay", "Number of UT layers per long track; Number of UT layers;Number of tracks", { 5, -0.5, 4.5 } };
+  mutable Gaudi::Accumulators::Histogram<1> m_h_nutlay_high_mult{
+      this,
+      "h_nutlay_high_mult",
+      "Number of UT layers per long track high mult ; Number of UT layers;Number of tracks high mult",
+      { 5, -0.5, 4.5 } };
+  //    full-width sensor 2D bins
+  mutable Gaudi::Accumulators::Histogram<2> m_h_all3{ this,
+                                                      "h_all3",
+                                                      "All tracks         Y vs X UTbX-midplane;X [mm];Y [mm]",
+                                                      { { 18, -860.4, +860.4 }, { 14, -669.2, +669.2 } } };
+  mutable Gaudi::Accumulators::Histogram<2> m_h_pass3{ this,
+                                                       "h_pass3",
+                                                       "UT-matched tracks  Y vs X UTbX-midplane;X [mm];Y [mm]",
+                                                       { { 18, -860.4, +860.4 }, { 14, -669.2, +669.2 } } };
+
+  mutable Gaudi::Accumulators::Histogram<2> m_h_pass3_low_mult{
+      this,
+      "h_pass3_low_mult",
+      "UT-matched tracks  Y vs X UTbX-midplane low mult;X [mm];Y [mm]",
+      { { 18, -860.4, +860.4 }, { 14, -669.2, +669.2 } } };
+
+  mutable Gaudi::Accumulators::Histogram<1> m_h_residual_inner{
+      this,
+      "h_residual_inner",
+      "UT track residual - inner detector;residual [mm];number of UT clusters",
+      { 1000, -0.5, 0.5 } };
+  mutable Gaudi::Accumulators::Histogram<1> m_h_residual_outer{
+      this,
+      "h_residual_outer",
+      "UT track residual - outer detector;residual [mm];number of UT clusters",
+      { 1000, -0.5, 0.5 } };
+
+  mutable Gaudi::Accumulators::Histogram<1> m_h_residualpull_inner{
+      this,
+      "h_residualpull_inner",
+      "UT track residual pull - inner detector;pull;number of UT clusters",
+      { 100, -5, 5 } };
+  mutable Gaudi::Accumulators::Histogram<1> m_h_residualpull_outer{
+      this,
+      "h_residualpull_outer",
+      "UT track residual pull - outer detector;pull;number of UT clsuters",
+      { 100, -5, 5 } };
+};
+
+using UTDataTrMonitor          = UTGlobalEffMon<LHCb::TrackFitResult, LHCb::FitNode>;
+using UTDataTrMonitor_PrKalman = UTGlobalEffMon<LHCb::PrKalmanFitResult, LHCb::Pr::Tracks::Fit::Node>;
+DECLARE_COMPONENT_WITH_ID( UTDataTrMonitor, "UTGlobalEffMon" )
+DECLARE_COMPONENT_WITH_ID( UTDataTrMonitor_PrKalman, "UTGlobalEffMon_PrKalman" )
+
+template <typename TFitResult, typename TNode>
+StatusCode UTGlobalEffMon<TFitResult, TNode>::initialize() {
+  return Consumer::initialize().andThen( [&] {} );
+}
+
+template <typename TFitResult, typename TNode>
+UTGlobalEffMon<TFitResult, TNode>::UTGlobalEffMon( const std::string& name, ISvcLocator* pSvcLocator )
+    : Consumer( name, pSvcLocator,
+                { { "TracksInContainer", LHCb::TrackLocation::Default },
+                  { "StandardGeometryTop", LHCb::standard_geometry_top } } ) {}
+
+template <typename TFitResult, typename TNode>
+void UTGlobalEffMon<TFitResult, TNode>::operator()( LHCb::Track::Range const& tracks,
+                                                    const DetectorElement&    lhcb ) const {
+  auto&        geometry        = *lhcb.geometry();
+  const double zutlay3         = 2652.5;
+  const double UT_sensor_width = 95.6; // do not change this because you think this is not correct!
+  int          nTracks         = tracks.size();
+
+  if ( nTracks > 10000 ) { nTracks = 10000; } // saturation
+  ++m_h_ntracks[nTracks];
+
+  for ( const LHCb::Track* track : tracks ) {
+    auto fitResult = dynamic_cast<const TFitResult*>( track->fitResult() );
+    if ( fitResult ) {
+      LHCb::StateVector aState;
+      extrapolator()->propagate( *track, zutlay3, aState, geometry ).ignore();
+      if ( aState.x() < -9990 ) { continue; } // Skip unphysical tracks
+
+      // tracks must be within UT layer 3 acceptance (exclude also generous region around the beam pipe )
+      double tr2utlax3 = aState.x();
+      double tr2utlay3 = aState.y();
+      if ( fabs( tr2utlax3 ) > 9 * UT_sensor_width ) continue;
+      if ( fabs( tr2utlay3 ) > 7 * UT_sensor_width ) continue;
+      if ( sqrt( pow( tr2utlay3, 2 ) + pow( tr2utlax3, 2 ) ) < 45 ) continue;
+
+      // PT cut
+      try {
+
+        auto cState = track->closestToBeamState();
+        if ( cState.pt() < 1000.0 ) continue;
+
+      } catch ( ... ) { continue; }
+
+      // all tracks passing the cuts (for efficiency map denominator)
+      ++m_h_all3[{ tr2utlax3, tr2utlay3 }];
+
+      const double kDummy = 1000.0;
+
+      int    _tr2ut[4]    = { -1, -1, -1, -1 };
+      double _tr2utr[4]   = { kDummy, kDummy, kDummy, kDummy };
+      double _tr2utchi[4] = { 0.0, 0.0, 0.0, 0.0 };
+
+      unsigned int utnode = 0;
+      for ( const auto& node : nodes( *fitResult ) ) {
+        if ( !( node.hasMeasurement() && node.isHitOnTrack() && node.isUT() ) ) continue;
+        if ( node.isOutlier() ) continue;
+        LHCb::LHCbID lhcbID = id( node );
+
+        Detector::UT::ChannelID chan = lhcbID.utID();
+
+        unsigned int chID = static_cast<unsigned int>( chan );
+
+        double       res    = node.residual();
+        double       chi    = res / node.errResidual();
+        double       ares   = fabs( res );
+        unsigned int _layer = ( chID >> 18 ) & 3;
+
+        // Loop over layers
+        if ( ares < fabs( _tr2utr[_layer] ) ) {
+          _tr2utr[_layer]   = res;
+          _tr2utchi[_layer] = chi;
+          _tr2ut[_layer]    = chID;
+        }
+        utnode++;
+
+      } // nodes loop
+
+      unsigned int nlay = 0;
+      for ( int layer = 0; layer < 4; ++layer ) {
+        if ( _tr2ut[layer] != -1 ) {
+          ++nlay;
+          // Extract values from the current layer
+          UInt_t _mo   = ( _tr2ut[layer] >> 10 ) & 7;
+          UInt_t _st   = ( _tr2ut[layer] >> 14 ) & 15;
+          bool   inner = ( _st == 0 ) && ( _mo == 3 || _mo == 4 );
+          if ( inner ) {
+            ++m_h_residual_inner[_tr2utr[layer]];
+            ++m_h_residualpull_inner[_tr2utchi[layer]];
+          } else {
+            ++m_h_residual_outer[_tr2utr[layer]];
+            ++m_h_residualpull_outer[_tr2utchi[layer]];
+          }
+        }
+      }
+
+      // tracks matched to UT hits (for nominator of efficiency map)
+      if ( nlay > 0 ) ++m_h_pass3[{ tr2utlax3, tr2utlay3 }];
+
+      // change it for protons 2025
+      ++m_h_nutlay_high_mult[nlay];
+
+      if ( nTracks > 4 && nTracks <= 100 ) { // you may want to move these limits to be configurable parameters
+
+        // UT layer counting for efficiency and ghost rate estimates
+        ++m_h_nutlay[nlay];
+        if ( nlay > 0 ) ++m_h_pass3_low_mult[{ tr2utlax3, tr2utlay3 }];
+      }
+    }
+  }
+}
diff --git a/UT/UTMonitors/CMakeLists.txt b/UT/UTMonitors/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..b5e97abfb01b6e3b62e7504090be3cbfa7b9f1b5
--- /dev/null
+++ b/UT/UTMonitors/CMakeLists.txt
@@ -0,0 +1,39 @@
+###############################################################################
+# (c) Copyright 2000-2021 CERN for the benefit of the LHCb Collaboration      #
+#                                                                             #
+# This software is distributed under the terms of the GNU General Public      #
+# Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING".   #
+#                                                                             #
+# In applying this licence, CERN does not waive the privileges and immunities #
+# granted to it by virtue of its status as an Intergovernmental Organization  #
+# or submit itself to any jurisdiction.                                       #
+###############################################################################
+#[=======================================================================[.rst:
+UT/UTMonitors
+-------------
+#]=======================================================================]
+
+gaudi_add_module(UTMonitors
+    SOURCES
+    src/UTDigitsMonitor.cpp
+    src/UTTAEMonitor.cpp
+    src/UTSuperTAEMonitor.cpp
+    src/UTErrorMonitor.cpp
+    src/UTNZSMonitor.cpp
+    src/UTBSMonitor.cpp
+    src/UTVeloUTCorrelationsMonitor.cpp
+    LINK
+        Boost::headers
+        Gaudi::GaudiAlgLib
+        Gaudi::GaudiKernel
+        Gaudi::GaudiUtilsLib
+        LHCb::DAQEventLib
+        LHCb::DigiEvent
+        LHCb::LHCbAlgsLib
+        LHCb::LHCbKernel
+        LHCb::RecEvent
+        LHCb::UTDetLib
+        LHCb::UTKernelLib
+        LHCb::UTTELL1Event
+        ROOT::Hist
+)
diff --git a/UT/UTMonitors/src/UTBSMonitor.cpp b/UT/UTMonitors/src/UTBSMonitor.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c6de3a6d6221356058c237f9f39769bd97b40ede
--- /dev/null
+++ b/UT/UTMonitors/src/UTBSMonitor.cpp
@@ -0,0 +1,456 @@
+/***************************************************************************** \
+* (c) Copyright 2000-2018 CERN for the benefit of the LHCb Collaboration      *
+*                                                                             *
+* This software is distributed under the terms of the GNU General Public      *
+* Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING".   *
+*                                                                             *
+* In applying this licence, CERN does not waive the privileges and immunities *
+* granted to it by virtue of its status as an Intergovernmental Organization  *
+* or submit itself to any jurisdiction.                                       *
+\*****************************************************************************/
+
+#include "Event/UTDigit.h"
+#include "GaudiAlg/GaudiHistoAlg.h"
+#include "Kernel/IUTReadoutTool.h"
+#include "Kernel/UTDAQBoard.h"
+#include "Kernel/UTDAQDefinitions.h"
+#include "Kernel/UTDAQID.h"
+#include "LHCbAlgs/Consumer.h"
+#include "LHCbAlgs/Transformer.h"
+#include "UTDAQ/UTCoordinatesMap.h"
+#include "UTDAQ/UTDAQHelper.h"
+#include "UTDAQ/UTInfo.h"
+#include "UTDet/DeUTDetector.h"
+#include <Event/RawBank.h>
+#include <Event/RawEvent.h>
+#include <Gaudi/Accumulators/Histogram.h>
+#include <Gaudi/Accumulators/HistogramArray.h>
+#include <Kernel/IUTReadoutTool.h>
+#include <TMath.h>
+#include <mutex>
+#include <optional>
+#include <string>
+
+/** @class UTBSMonitor UTBSMonitor.cpp
+ * --------------------------------------------------
+ *  Counters for additional monitoring of UT
+ *  The algorithm produces several useful histograms
+ *  @author Wojciech Krupa
+ *  @date   07/06/2024
+ * --------------------------------------------------
+ **/
+
+using namespace LHCb;
+namespace GA = Gaudi::Accumulators;
+
+// Definition of axis
+const GA::Axis<double> AxisADC        = GA::Axis<double>( 64, -32.5, 31.5, "nADC" ); //-32, 31
+const GA::Axis<double> AxisADC_signed = GA::Axis<double>( 32, -0.5, 31.5, "nADC" );  // 0-31
+const GA::Axis<double> AxisDIGIT      = GA::Axis<double>( 101, -0.5, 7000.5, "UTDigits (size of digit container)" );
+const GA::Axis<double> AxisHits       = GA::Axis<double>( 100, -0.5, 1500.5, "Hits" );
+const GA::Axis<double> AxisUAChannels = GA::Axis<double>( 268288, 0, 268288, "GlobalChannel_ID" );
+const GA::Axis<double> AxisUCChannels = GA::Axis<double>( 268288, 268288, 536576, "GlobalChannel_ID" );
+const GA::Axis<double> AxisUAChips    = GA::Axis<double>( 2096, -0.5, 2095.5, "GlobalASIC_ID" );
+const GA::Axis<double> AxisUCChips    = GA::Axis<double>( 2096, 2095.5, 4191.5, "GlobalASIC_ID" );
+const GA::Axis<double> AxisThresholds = GA::Axis<double>( 32, -0.5, 31.5, "Threshold" );
+const GA::Axis<double> AxisChannels   = GA::Axis<double>( 64, -0.5, 63.5, "Channels" );
+const GA::Axis<double> AxisUA_aUChips = GA::Axis<double>( 496, -0.5, 495.5, "GlobalASIC_ID" );
+const GA::Axis<double> AxisUA_aXChips = GA::Axis<double>( 496, 495.5, 991.5, "GlobalASIC_ID" );
+const GA::Axis<double> AxisUA_bVChips = GA::Axis<double>( 552, 991.5, 1543.5, "GlobalASIC_ID" );
+const GA::Axis<double> AxisUA_bXChips = GA::Axis<double>( 552, 1543.5, 2095.5, "GlobalASIC_ID" );
+const GA::Axis<double> AxisUC_aUChips = GA::Axis<double>( 496, 2095.5, 2591.5, "GlobalASIC_ID" );
+const GA::Axis<double> AxisUC_aXChips = GA::Axis<double>( 496, 2591.5, 3087.5, "GlobalASIC_ID" );
+const GA::Axis<double> AxisUC_bVChips = GA::Axis<double>( 552, 3087.5, 3639.5, "GlobalASIC_ID" );
+const GA::Axis<double> AxisUC_bXChips = GA::Axis<double>( 552, 3639.5, 4191.5, "GlobalASIC_ID" );
+
+std::vector<unsigned int>            m_channel_counter( 536577, 0 );
+std::vector<unsigned int>            m_asic_counter( 4192, 0 );
+std::map<unsigned int, unsigned int> m_threshold_counter;
+std::map<unsigned int, unsigned int> m_maxchannel_counter;
+
+// 2D plots
+const double positionasic[4][3] = {
+    { -0.4375, -0.3125, -0.1875 }, // Chip 0
+    { -0.1875, -0.0625, -0.0625 }, // Chip 1
+    { +0.1875, +0.0625, +0.0625 }, // Chip 2
+    { +0.4375, +0.3125, +0.1875 }  // Chip 3
+};
+
+// UT layers
+const std::array<std::string, 4> UT_layers = { "UTaX", "UTaU", "UTbV", "UTbX" };
+
+enum class masks { channel = 0x000001ff, lane = 0x00000e00, board = 0x000ff000 };
+template <masks m>
+[[nodiscard]] static constexpr unsigned int extract( unsigned int i ) {
+  constexpr auto b = std::countr_zero( static_cast<unsigned int>( m ) );
+  return ( i & static_cast<unsigned int>( m ) ) >> b;
+}
+
+// Tools for booking histograms
+namespace Utility {
+  template <typename T, typename OWNER>
+  void map_emplace( T& t, typename T::key_type key, OWNER* owner, std::string const& title,
+                    Gaudi::Accumulators::Axis<typename T::mapped_type::AxisArithmeticType> axis1 ) {
+    t.emplace( std::piecewise_construct, std::forward_as_tuple( key ),
+               std::forward_as_tuple( owner, key, title, axis1 ) );
+  }
+} // namespace Utility
+/** ------------------------------------------------------------------------------------------------------------------------ */
+
+class UTBSMonitor
+    : public LHCb::Algorithm::Consumer<void( UTDigits const&, UTDigits const&, DeUTDetector const& ),
+                                       LHCb::DetDesc::usesBaseAndConditions<GaudiHistoAlg, DeUTDetector>> {
+public:
+  UTBSMonitor( const std::string& name, ISvcLocator* svcloc )
+      : Consumer{ name,
+                  svcloc,
+                  { { "InputData", UTDigitLocation::UTDigits },
+                    { "InputErrorData", UTDigitLocation::UTDigits },
+                    { "UTLocation", DeUTDetLocation::location() } } } {}
+  ToolHandle<IUTReadoutTool> readoutTool{ this, "ReadoutTool", "UTReadoutTool" };
+
+  StatusCode initialize() override {
+    return Consumer::initialize().andThen( [&] {
+      // Set the top directory to UT
+      if ( histoTopDir().empty() ) setHistoTopDir( "" );
+
+      for ( const auto& module : UTMap.getModulesNames() ) {
+        for ( unsigned int i = 0; i < 4; i++ )
+          Utility::map_emplace( m_1d_ADCCounter, module + ".Chip" + std::to_string( i ), this,
+                                module + ".Chip" + std::to_string( i ), { 32, -0.5, 31.5 } );
+      }
+    } );
+  }
+
+  void operator()( const UTDigits& digitsCont, const UTDigits& digitserrCont, DeUTDetector const& det ) const override {
+
+    // General counters
+    const unsigned int nDigits = digitsCont.size() + digitserrCont.size();
+
+    if ( msgLevel( MSG::DEBUG ) ) debug() << "----------  Found nDigits: " << nDigits << endmsg;
+    ++m_nDigits[nDigits];
+
+    // Hitmaps plots and ADC
+    std::fill( m_channel_counter.begin(), m_channel_counter.end(), 0 );
+    std::fill( m_asic_counter.begin(), m_asic_counter.end(), 0 );
+
+    // For maxADC plots
+    unsigned int   prev_channel = 0;
+    unsigned int   prev_adc     = 0;
+    LHCb::UTDigit* aDigit_max;
+
+    // UT bank
+    for ( const auto& d : digitsCont ) {
+
+      fillHeatPlots( d );
+
+      // First event
+      if ( prev_channel == 0 ) {
+        prev_channel = d->strip();
+        prev_adc     = d->depositedCharge();
+        aDigit_max   = d;
+        continue;
+      }
+      // If cluster size >1
+      if ( d->strip() - prev_channel == 1 )
+        if ( d->depositedCharge() > prev_adc ) aDigit_max = d; // if ADC max in claster
+      // End of cluster
+      if ( d->strip() - prev_channel != 1 ) {
+        fillHeatPlots_MAX( aDigit_max );
+        aDigit_max = d;
+      }
+
+      prev_channel = d->strip();
+      prev_adc     = d->depositedCharge();
+    }
+
+    // UTError bank
+    for ( const auto& d : digitserrCont ) {
+
+      fillHeatPlots( d );
+
+      // First event
+      if ( prev_channel == 0 ) {
+        prev_channel = d->strip();
+        prev_adc     = d->depositedCharge();
+        aDigit_max   = d;
+        continue;
+      }
+      // If cluster size >1
+      if ( d->strip() - prev_channel == 1 )
+        if ( d->depositedCharge() > prev_adc ) aDigit_max = d; // if ADC max in claster
+      // End of cluster
+      if ( d->strip() - prev_channel != 1 ) {
+        fillHeatPlots_MAX( aDigit_max );
+        aDigit_max = d;
+      }
+
+      prev_channel = d->strip();
+      prev_adc     = d->depositedCharge();
+    }
+
+    // Channel hit counters
+    for ( size_t i = 0; i < m_channel_counter.size(); ++i ) {
+      if ( i <= 268288 )
+        hitRateChannels_UA[i] += m_channel_counter[i];
+      else
+        hitRateChannels_UC[i] += m_channel_counter[i];
+    }
+
+    // Chip hit counters
+    for ( size_t i = 0; i < m_asic_counter.size(); ++i ) {
+      if ( i <= 495 ) {
+        hitRateChipAverage_UA_aU[i] += m_asic_counter[i];
+        hitRateChipAverage_UA_aU_radial[UTMap.getRadialID( i )] += m_asic_counter[i];
+      } else if ( i <= 991 ) {
+        hitRateChipAverage_UA_aX[i] += m_asic_counter[i];
+        hitRateChipAverage_UA_aX_radial[UTMap.getRadialID( i )] += m_asic_counter[i];
+      } else if ( i <= 1543 ) {
+        hitRateChipAverage_UA_bV[i] += m_asic_counter[i];
+        hitRateChipAverage_UA_bV_radial[UTMap.getRadialID( i )] += m_asic_counter[i];
+      } else if ( i <= 2095 ) {
+        hitRateChipAverage_UA_bX[i] += m_asic_counter[i];
+        hitRateChipAverage_UA_bX_radial[UTMap.getRadialID( i )] += m_asic_counter[i];
+      } else if ( i <= 2591 ) {
+        hitRateChipAverage_UC_aU[i] += m_asic_counter[i];
+        hitRateChipAverage_UC_aU_radial[UTMap.getRadialID( i )] += m_asic_counter[i];
+      } else if ( i <= 3087 ) {
+        hitRateChipAverage_UC_aX[i] += m_asic_counter[i];
+        hitRateChipAverage_UC_aX_radial[UTMap.getRadialID( i )] += m_asic_counter[i];
+      } else if ( i <= 3639 ) {
+        hitRateChipAverage_UC_bV[i] += m_asic_counter[i];
+        hitRateChipAverage_UC_bV_radial[UTMap.getRadialID( i )] += m_asic_counter[i];
+      } else if ( i <= 4191 ) {
+        hitRateChipAverage_UC_bX[i] += m_asic_counter[i];
+        hitRateChipAverage_UC_bX_radial[UTMap.getRadialID( i )] += m_asic_counter[i];
+      }
+    }
+
+    std::map<unsigned int, unsigned int> count_th; // for summary plots
+    std::map<unsigned int, unsigned int> count_ch;
+
+    for ( size_t i = 0; i < m_asic_counter.size(); ++i ) {
+      if ( m_asic_counter[i] > 0 ) {
+        if ( m_asic_counter[i] > m_maxchannel_counter[i] ) {
+          m_maxchannel_counter[i] = m_asic_counter[i];
+        } // for profile histo
+        unsigned int channelID =
+            UTMap.getChannel( UTMap.getASICName( i ).substr( 0, UTMap.getASICName( i ).find( '.' ) ) );
+        fillHeatMap( channelID + 128 * std::atoi( &UTMap.getASICName( i ).back() ), m_threshold_counter[i],
+                     m_maxchannel_counter[i], det );
+
+        ++count_th[m_threshold_counter[i]];
+        ++count_ch[m_maxchannel_counter[i]];
+      }
+    }
+
+    for ( const auto& entry : count_th ) { ZS_thresholds[entry.first] += entry.second; }
+    for ( const auto& entry : count_ch ) { ZS_channels[entry.first] += entry.second; }
+  }
+
+private:
+  mutable UTCoordinatesMap UTMap;
+
+  // General plots
+  // Digits counter
+  mutable GA::Histogram<1> m_nDigits{ this, "nDigits", "Total nDigits", AxisDIGIT };
+  // ADC counter
+  mutable GA::Histogram<1> m_nADC{ this, "nADC", "Total nADC", AxisADC_signed };
+
+  // Hitrate counters - channel
+  mutable GA::ProfileHistogram<1> hitRateChannels_UA{ this, "hitRateChannels_UA", "hitRateChannels_UA",
+                                                      AxisUAChannels };
+  mutable GA::ProfileHistogram<1> hitRateChannels_UC{ this, "hitRateChannels_UC", "hitRateChannels_UC",
+                                                      AxisUCChannels };
+
+  // Hitrate counters - chips
+  mutable GA::ProfileHistogram<1> hitRateChipAverage_UA_aU{ this, "Average_hitRate_UAaU", "Average_hitRate_UAaU",
+                                                            AxisUA_aUChips };
+  mutable GA::ProfileHistogram<1> hitRateChipAverage_UA_aX{ this, "Average_hitRate_UAaX", "Average_hitRate_UAaX",
+                                                            AxisUA_aXChips };
+  mutable GA::ProfileHistogram<1> hitRateChipAverage_UA_bV{ this, "Average_hitRate_UAbV", "Average_hitRate_UAbV",
+                                                            AxisUA_bVChips };
+  mutable GA::ProfileHistogram<1> hitRateChipAverage_UA_bX{ this, "Average_hitRate_UAbX", "Average_AhitRate_UAbX",
+                                                            AxisUA_bXChips };
+  mutable GA::ProfileHistogram<1> hitRateChipAverage_UC_aU{ this, "Average_hitRate_UCaU", "Average_hitRate_UCaU",
+                                                            AxisUC_aUChips };
+  mutable GA::ProfileHistogram<1> hitRateChipAverage_UC_aX{ this, "Average_hitRate_UCaX", "Average_hitRate_UCaX",
+                                                            AxisUC_aXChips };
+  mutable GA::ProfileHistogram<1> hitRateChipAverage_UC_bV{ this, "Average_hitRate_UCbV", "Average_hitRate_UCbV",
+                                                            AxisUC_bVChips };
+  mutable GA::ProfileHistogram<1> hitRateChipAverage_UC_bX{ this, "Average_hitRate_UCbX", "Average_hitRate_UCbX",
+                                                            AxisUC_bXChips };
+
+  // Hitrate counters - chip radial
+  mutable GA::ProfileHistogram<1> hitRateChipAverage_UA_aU_radial{ this, "Average_hitRate_UAaU_radial",
+                                                                   "Average_hitRate_UAaU_radial", AxisUA_aUChips };
+  mutable GA::ProfileHistogram<1> hitRateChipAverage_UA_aX_radial{ this, "Average_hitRate_UAaX_radial",
+                                                                   "Average_hitRate_UAaX_radial", AxisUA_aXChips };
+  mutable GA::ProfileHistogram<1> hitRateChipAverage_UA_bV_radial{ this, "Average_hitRate_UAbV_radial",
+                                                                   "Average_hitRate_UAbV_radial", AxisUA_bVChips };
+  mutable GA::ProfileHistogram<1> hitRateChipAverage_UA_bX_radial{ this, "Average_hitRate_UAbX_radial",
+                                                                   "Average_AhitRate_UAbX_radial", AxisUA_bXChips };
+  mutable GA::ProfileHistogram<1> hitRateChipAverage_UC_aU_radial{ this, "Average_hitRate_UCaU_radial",
+                                                                   "Average_hitRate_UCaU_radial", AxisUC_aUChips };
+  mutable GA::ProfileHistogram<1> hitRateChipAverage_UC_aX_radial{ this, "Average_hitRate_UCaX_radial",
+                                                                   "Average_hitRate_UCaX_radial", AxisUC_aXChips };
+  mutable GA::ProfileHistogram<1> hitRateChipAverage_UC_bV_radial{ this, "Average_hitRate_UCbV_radial",
+                                                                   "Average_hitRate_UCbV_radial", AxisUC_bVChips };
+  mutable GA::ProfileHistogram<1> hitRateChipAverage_UC_bX_radial{ this, "Average_hitRate_UCbX_radial",
+                                                                   "Average_hitRate_UCbX_radial", AxisUC_bXChips };
+
+  // Special ADC counters - average ADC
+  mutable GA::ProfileHistogram<1> ADCChipAverage_UA_aU{ this, "Average_ADC_UAaU", "Average_ADC_UAaU", AxisUA_aUChips };
+  mutable GA::ProfileHistogram<1> ADCChipAverage_UA_aX{ this, "Average_ADC_UAaX", "Average_ADC_UAaX", AxisUA_aXChips };
+  mutable GA::ProfileHistogram<1> ADCChipAverage_UA_bV{ this, "Average_ADC_UAbV", "Average_ADC_UAbV", AxisUA_bVChips };
+  mutable GA::ProfileHistogram<1> ADCChipAverage_UA_bX{ this, "Average_ADC_UAbX", "Average_ADC_UAbX", AxisUA_bXChips };
+  mutable GA::ProfileHistogram<1> ADCChipAverage_UC_aU{ this, "Average_ADC_UCaU", "Average_ADC_UCaU", AxisUC_aUChips };
+  mutable GA::ProfileHistogram<1> ADCChipAverage_UC_aX{ this, "Average_ADC_UCaX", "Average_ADC_UCaX", AxisUC_aXChips };
+  mutable GA::ProfileHistogram<1> ADCChipAverage_UC_bV{ this, "Average_ADC_UCbV", "Average_ADC_UCbV", AxisUC_bVChips };
+  mutable GA::ProfileHistogram<1> ADCChipAverage_UC_bX{ this, "Average_ADC_UCbX", "Average_ADC_UCbX", AxisUC_bXChips };
+
+  // Hitmap - channel limit & zs threshold per ASIC - 1D
+  mutable GA::ProfileHistogram<1> ZS_thresholds{ this, "ZS_thresholds", "ZS_thresholds", AxisThresholds };
+  mutable GA::ProfileHistogram<1> ZS_channels{ this, "ZS_channels", "ZS_channels", AxisChannels };
+
+  // Hitmap - channel limit & zs threshold per ASIC - 2D
+  mutable Gaudi::Accumulators::HistogramArray<Gaudi::Accumulators::ProfileHistogram<2>, 4> m_2d_ZS_th_chips{
+      this,
+      []( int i ) { return fmt::format( "UT_ZS_th_Chips_Layer{}", i ); },
+      []( int i ) { return fmt::format( "zs_th of Layer{}", i ); },
+      { 144, -9, 9, "Staves (ASICs)" },
+      { 28, -7, 7, "Modules" } };
+
+  mutable Gaudi::Accumulators::HistogramArray<Gaudi::Accumulators::ProfileHistogram<2>, 4> m_2d_ZS_ch_chips{
+      this,
+      []( int i ) { return fmt::format( "UT_ZS_ch_Chips_Layer{}", i ); },
+      []( int i ) { return fmt::format( "zs_channel of Layer{}", i ); },
+      { 144, -9, 9, "Staves (ASICs)" },
+      { 28, -7, 7, "Modules" } };
+
+  // The container for pedestal per channel
+  mutable std::map<std::string, GA::Histogram<1>> m_1d_ADCCounter;
+
+  void fillHeatPlots( const LHCb::UTDigit* aDigit ) const {
+
+    // Let's find where we are
+    std::tuple<float, float, float, float, std::string, std::string> tuple =
+        UTMap.getTuple( aDigit->module(), aDigit->face(), aDigit->stave(), aDigit->side(), aDigit->sector() );
+    std::string module_name = std::get<4>( tuple );
+    std::string type        = std::get<5>( tuple );
+
+    // What a beautiful line of code
+    unsigned int globalASIC_ID = UTMap.getASICNumber( UT_layers[aDigit->layer()] + "_" + module_name + ".Chip" +
+                                                      std::to_string( aDigit->strip() / 128 ) );
+    ++m_channel_counter[globalASIC_ID * 128 + aDigit->strip() % 128];
+    ++m_asic_counter[globalASIC_ID];
+
+    if ( globalASIC_ID <= 495 )
+      ADCChipAverage_UA_aU[globalASIC_ID] += aDigit->depositedCharge();
+    else if ( globalASIC_ID <= 991 )
+      ADCChipAverage_UA_aX[globalASIC_ID] += aDigit->depositedCharge();
+    else if ( globalASIC_ID <= 1543 )
+      ADCChipAverage_UA_bV[globalASIC_ID] += aDigit->depositedCharge();
+    else if ( globalASIC_ID <= 2095 )
+      ADCChipAverage_UA_bX[globalASIC_ID] += aDigit->depositedCharge();
+    else if ( globalASIC_ID <= 2591 )
+      ADCChipAverage_UC_aU[globalASIC_ID] += aDigit->depositedCharge();
+    else if ( globalASIC_ID <= 3087 )
+      ADCChipAverage_UC_aX[globalASIC_ID] += aDigit->depositedCharge();
+    else if ( globalASIC_ID <= 3639 )
+      ADCChipAverage_UC_bV[globalASIC_ID] += aDigit->depositedCharge();
+    else if ( globalASIC_ID <= 4191 )
+      ADCChipAverage_UC_bX[globalASIC_ID] += aDigit->depositedCharge();
+
+    if ( m_threshold_counter[globalASIC_ID] == 0 )
+      m_threshold_counter[globalASIC_ID] = 31; // we can't start from zero to minimise and we can't init all asics with
+                                               // 31 because we want keep disabled empty
+
+    if ( aDigit->depositedCharge() < m_threshold_counter[globalASIC_ID] )
+      m_threshold_counter[globalASIC_ID] = aDigit->depositedCharge();
+
+    // ADC counter
+    ++m_nADC[aDigit->depositedCharge()];
+  }
+
+  void fillHeatPlots_MAX( const LHCb::UTDigit* aDigit ) const {
+    // Let's find where we are
+    std::tuple<float, float, float, float, std::string, std::string> tuple =
+        UTMap.getTuple( aDigit->module(), aDigit->face(), aDigit->stave(), aDigit->side(), aDigit->sector() );
+    std::string module_name = std::get<4>( tuple );
+    std::string type        = std::get<5>( tuple );
+    ++m_1d_ADCCounter.at( UT_layers[aDigit->layer()] + "_" + module_name + ".Chip" +
+                          std::to_string( aDigit->strip() / 128 ) )[aDigit->depositedCharge()];
+  }
+
+  void fillHeatMap( unsigned int channel, unsigned int zs_th, unsigned int ch, DeUTDetector const& det ) const {
+    Detector::UT::ChannelID channelID( channel );
+
+    // Let's find where we are
+    auto tuple =
+        UTMap.getTuple( channelID.module(), channelID.face(), channelID.stave(), channelID.side(), channelID.sector() );
+
+    float       x           = std::get<0>( tuple );
+    float       y           = std::get<1>( tuple );
+    std::string module_name = std::get<4>( tuple );
+    std::string type        = std::get<5>( tuple );
+    auto        aSector     = det.findSector( channelID );
+
+#ifdef USE_DD4HEP
+    auto trajStrip0   = aSector.createTraj( 0, 0 );
+    auto trajStrip511 = aSector.createTraj( 511, 0 );
+    auto trajStrip127 = aSector.createTraj( 127, 0 );
+#else
+    auto trajStrip0   = aSector->trajectory( channelID, 0 );
+    auto trajStrip511 = aSector->trajectory( LHCb::Detector::UT::ChannelID{ channelID + 511 }, 0 );
+    auto trajStrip127 = aSector->trajectory( LHCb::Detector::UT::ChannelID{ channelID + 127 }, 0 );
+#endif
+    double stripx0   = -1 * ( trajStrip0.endPoint().x() + trajStrip0.beginPoint().x() ) * 0.5;
+    double stripx511 = -1 * ( trajStrip511.endPoint().x() + trajStrip511.beginPoint().x() ) * 0.5;
+    double stripx127 = -1 * ( trajStrip127.endPoint().x() + trajStrip127.beginPoint().x() ) * 0.5;
+    double stripy    = ( trajStrip0.endPoint().y() + trajStrip0.beginPoint().y() ) * 0.5;
+
+    double stripwidth  = stripx511 - stripx0;
+    double stripwidth2 = stripx127 - stripx0;
+    int    chip;
+
+    if ( stripwidth > 0 )
+      chip = int( channelID.strip() / 128 );
+    else
+      chip = 3 - int( channelID.strip() / 128 );
+
+    double positionasic_one = positionasic[chip][0];
+    double positionasic_two = positionasic[chip][1];
+    double positionasic_thr = positionasic[chip][2];
+
+    // CHIPS Maps //
+    if ( ( channelID.stave() > 1 ) || ( fabs( y ) > 2 ) ) {
+      m_2d_ZS_th_chips[channelID.layer()][{ x + positionasic_one, y + 0.25 }] += zs_th;
+      m_2d_ZS_th_chips[channelID.layer()][{ x + positionasic_one, y - 0.25 }] += zs_th;
+      m_2d_ZS_th_chips[channelID.layer()][{ x + positionasic_two, y + 0.25 }] += zs_th;
+      m_2d_ZS_th_chips[channelID.layer()][{ x + positionasic_two, y - 0.25 }] += zs_th;
+      if ( ch > 0 ) {
+        m_2d_ZS_ch_chips[channelID.layer()][{ x + positionasic_one, y + 0.25 }] += ch;
+        m_2d_ZS_ch_chips[channelID.layer()][{ x + positionasic_one, y - 0.25 }] += ch;
+        m_2d_ZS_ch_chips[channelID.layer()][{ x + positionasic_two, y + 0.25 }] += ch;
+        m_2d_ZS_ch_chips[channelID.layer()][{ x + positionasic_two, y - 0.25 }] += ch;
+      }
+    }
+    if ( ( ( channelID.stave() == 1 ) && ( fabs( y ) < 2 ) ) ||
+         ( ( channelID.stave() == 0 ) && ( fabs( y ) == 1.5 ) ) ) {
+
+      m_2d_ZS_th_chips[channelID.layer()][{ x + positionasic_thr, y + 0.25 }] += zs_th;
+      m_2d_ZS_th_chips[channelID.layer()][{ x + positionasic_thr, y - 0.25 }] += zs_th;
+      if ( ch > 0 ) {
+        m_2d_ZS_ch_chips[channelID.layer()][{ x + positionasic_thr, y + 0.25 }] += ch;
+        m_2d_ZS_ch_chips[channelID.layer()][{ x + positionasic_thr, y - 0.25 }] += ch;
+      }
+    }
+    if ( ( channelID.stave() == 0 ) && ( fabs( y ) < 1 ) ) {
+      m_2d_ZS_th_chips[channelID.layer()][{ x + positionasic_thr, y }] += zs_th;
+      if ( ch > 0 ) m_2d_ZS_ch_chips[channelID.layer()][{ x + positionasic_thr, y }] += ch;
+    }
+  }
+
+}; // End of class UTBSMonitor
+DECLARE_COMPONENT( UTBSMonitor )
diff --git a/UT/UTMonitors/src/UTDigitsMonitor.cpp b/UT/UTMonitors/src/UTDigitsMonitor.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f1bfd7fe03f00ca80cc0e4835a8dbbe5f66f0f73
--- /dev/null
+++ b/UT/UTMonitors/src/UTDigitsMonitor.cpp
@@ -0,0 +1,668 @@
+/***************************************************************************** \
+* (c) Copyright 2000-2018 CERN for the benefit of the LHCb Collaboration      *
+*                                                                             *
+* This software is distributed under the terms of the GNU General Public      *
+* Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING".   *
+*                                                                             *
+* In applying this licence, CERN does not waive the privileges and immunities *
+* granted to it by virtue of its status as an Intergovernmental Organization  *
+* or submit itself to any jurisdiction.                                       *
+\*****************************************************************************/
+
+#include "Event/UTDigit.h"
+#include "GaudiAlg/GaudiHistoAlg.h"
+#include "Kernel/IUTReadoutTool.h"
+#include "Kernel/UTDAQBoard.h"
+#include "Kernel/UTDAQDefinitions.h"
+#include "Kernel/UTDAQID.h"
+#include "LHCbAlgs/Consumer.h"
+#include "LHCbAlgs/Transformer.h"
+#include "UTDAQ/UTCoordinatesMap.h"
+#include "UTDAQ/UTDAQHelper.h"
+#include "UTDAQ/UTInfo.h"
+#include "UTDet/DeUTDetector.h"
+#include <Event/ODIN.h>
+#include <Event/RawBank.h>
+#include <Event/RawEvent.h>
+#include <Gaudi/Accumulators/Histogram.h>
+#include <Gaudi/Accumulators/HistogramArray.h>
+#include <Kernel/IUTReadoutTool.h>
+#include <mutex>
+#include <optional>
+#include <string>
+
+/** @class UTDigitsMonitor UTDigitsMonitor.cpp
+ * --------------------------------------------------
+ *  Counters for Monet online monitoring of the UT
+ *  The algorithm produces several useful histograms
+ *  @author Wojciech Krupa
+ *  @date   2024/03/20
+ * --------------------------------------------------
+ **/
+
+using namespace LHCb;
+namespace GA = Gaudi::Accumulators;
+
+// Definition of axis
+const GA::Axis<double> AxisADC        = GA::Axis<double>( 64, -32.5, 31.5, "nADC" );       //-32, 31
+const GA::Axis<double> AxisADC_signed = GA::Axis<double>( 32, -0.5, 31.5, "nADC" );        // 0-31
+const GA::Axis<double> AxisBCID       = GA::Axis<double>( 3565, -0.5, 3564.5, "BunchID" ); //
+const GA::Axis<double> AxisDIGIT      = GA::Axis<double>( 1000, -0.5, 100000.5, "UTDigits (size of digit container)" );
+const GA::Axis<double> AxisXnaturalunits   = GA::Axis<double>( 36, -9, 9, "Staves (Sectors)" );
+const GA::Axis<double> AxisXnaturalunits4x = GA::Axis<double>( 144, -9, 9, "Staves (ASICs)" );
+const GA::Axis<double> AxisYnaturalunits   = GA::Axis<double>( 28, -7, 7, "Modules" );
+
+// Definition of histogram names
+const std::array<std::string, 4> s_HistNames = { "UTA_Tell_40_vs_ASIC_Flow0", "UTA_Tell_40_vs_ASIC_Flow1",
+                                                 "UTC_Tell_40_vs_ASIC_Flow0", "UTC_Tell_40_vs_ASIC_Flow1" };
+
+const std::array<std::string, 4> s_HistNames_Counter = {
+    "UTA_Tell_40_EventsCounter_Flow0", "UTA_Tell_40_EventsCounter_Flow1", "UTC_Tell_40_EventsCounter_Flow0",
+    "UTC_Tell_40_EventsCounter_Flow1" };
+
+const std::array<std::string, 6> s_HistNames_BXType = { "nADC", "nADC_A", "nADC_B", "nADC_C", "nADC_D" };
+
+const std::array<std::string, 6> s_HistNames_BXType_labels = {
+    "Total nADC", "Total nADC - type A sensors", "Total nADC - type B sensors", "Total nADC - type C sensors",
+    "Total nADC - type D sensors" };
+
+const std::array<std::string, 15> s_HistNames_EventType = { "NoBias",
+                                                            "Lumi",
+                                                            "Isolated",
+                                                            "Leading",
+                                                            "Trailing",
+                                                            "Empty before isolated",
+                                                            "Empty after isolated",
+                                                            "Empty before leading",
+                                                            "Empty after trailing",
+                                                            "Empty after 19 clock from trailling",
+                                                            "NoBias bb",
+                                                            "Lumi bb",
+                                                            "Isolated bb",
+                                                            "Leading bb",
+                                                            "Trailing bb" };
+
+const std::array<std::string, 15> s_HistNames_EventType_labels = { "NoBias",
+                                                                   "Lumi",
+                                                                   "Isolated - ADC",
+                                                                   "Leading - ADC",
+                                                                   "Trailing - ADC",
+                                                                   "Empty before isolated - ADC",
+                                                                   "Empty after isolated - ADC",
+                                                                   "Empty before leading - ADC",
+                                                                   "Empty after trailing -  ADC",
+                                                                   "Empty after 19 clock from trailling - ADC",
+                                                                   "NoBias bb - ADC",
+                                                                   "Lumi bb - ADC",
+                                                                   "Isolated bb - ADC",
+                                                                   "Leading bb - ADC",
+                                                                   "Trailing bb - ADC" };
+
+// UT layers
+const std::array<std::string, 4> UT_layers = { "UTaX", "UTaU", "UTbV", "UTbX" };
+
+// 2D plots
+const double positionasic[4][3] = {
+    { -0.4375, -0.3125, -0.1875 }, // Chip 0
+    { -0.1875, -0.0625, -0.0625 }, // Chip 1
+    { +0.1875, +0.0625, +0.0625 }, // Chip 2
+    { +0.4375, +0.3125, +0.1875 }  // Chip 3
+};
+
+enum class masks { channel = 0x000001ff, lane = 0x00000e00, board = 0x000ff000 };
+
+template <masks m>
+[[nodiscard]] static constexpr unsigned int extract( unsigned int i ) {
+  constexpr auto b = std::countr_zero( static_cast<unsigned int>( m ) );
+  return ( i & static_cast<unsigned int>( m ) ) >> b;
+}
+
+/** ------------------------------------------------------------------------------------------------------------------------ */
+
+class UTDigitsMonitor
+    : public LHCb::Algorithm::Consumer<void( UTDigits const&, UTDigits const&, DeUTDetector const&, LHCb::ODIN const& ),
+                                       LHCb::DetDesc::usesBaseAndConditions<GaudiHistoAlg, DeUTDetector>> {
+public:
+  UTDigitsMonitor( const std::string& name, ISvcLocator* svcloc )
+      : Consumer{ name,
+                  svcloc,
+                  { { "InputData", UTDigitLocation::UTDigits },
+                    { "InputErrorData", UTDigitLocation::UTDigits },
+                    { "UTLocation", DeUTDetLocation::location() },
+                    { "ODINLocation", LHCb::ODINLocation::Default } } } {}
+  ToolHandle<IUTReadoutTool> readoutTool{ this, "ReadoutTool", "UTReadoutTool" };
+
+  StatusCode initialize() override {
+    return Consumer::initialize().andThen( [&] {
+      // Set the top directory to UT
+      if ( histoTopDir().empty() ) setHistoTopDir( "" );
+    } );
+  }
+
+  void operator()( const UTDigits& digitsCont, const UTDigits& errdigitsCont, DeUTDetector const& det,
+                   LHCb::ODIN const& odin ) const override {
+
+    // General counters
+    const unsigned int nDigits = digitsCont.size() + errdigitsCont.size();
+    const unsigned int nBuncId = odin.bunchId();
+
+    if ( msgLevel( MSG::DEBUG ) ) debug() << "----------  Found nDigits: " << nDigits << endmsg;
+    ++m_nDigits[nDigits];
+    ++m_nBuncId[nBuncId];
+    ++m_nDigitsnBuncId[{ nBuncId, nDigits }];
+
+    if ( odin.bunchCrossingType() == LHCb::ODIN::BXTypes::BeamCrossing )
+      ++m_nDigits_bb[nDigits];
+    else if ( odin.bunchCrossingType() == LHCb::ODIN::BXTypes::Beam1 )
+      ++m_nDigits_be[nDigits];
+    else if ( odin.bunchCrossingType() == LHCb::ODIN::BXTypes::Beam2 )
+      ++m_nDigits_eb[nDigits];
+    else if ( odin.bunchCrossingType() == LHCb::ODIN::BXTypes::NoBeam )
+      ++m_nDigits_ee[nDigits];
+
+    // -------------------------------------------------------
+    // Loop on digits
+    // side==1 is Aside (left), side==0 is Cside (right)
+    // -------------------------------------------------------
+    // Hitmaps plots and ADC
+
+    // Commisioning per side histograms
+    unsigned int ua_size       = 0;
+    unsigned int uc_size       = 0;
+    unsigned int ua_error_size = 0;
+    unsigned int uc_error_size = 0;
+
+    // For max ADC plots
+    unsigned int   prev_channel = 0;
+    unsigned int   prev_adc     = 0;
+    LHCb::UTDigit* aDigit_max;
+
+    // UT bank
+    for ( const auto& d : digitsCont ) {
+      fillHeatMap( d, det );
+      fillADC( d, odin );
+
+      if ( d->face() == 0 )
+        uc_size++;
+      else if ( d->face() == 1 )
+        ua_size++;
+
+      UTDAQID      daqID    = readoutTool->channelIDToDAQID( d->channelID() );
+      auto         board_ID = daqID.board();
+      unsigned int sourceID = UTMap.getSourceIDfromBoardNumber( board_ID );
+
+      if ( sourceID != prevSourceID ) { fillBankHistograms( sourceID ); }
+      prevSourceID = sourceID;
+
+      // Cluster max ADC counters
+      // First event
+      if ( prev_channel == 0 ) {
+        prev_channel = d->strip();
+        prev_adc     = d->depositedCharge();
+        aDigit_max   = d;
+        continue;
+      }
+      // If cluster size >1
+      if ( d->strip() - prev_channel == 1 )
+        if ( d->depositedCharge() > prev_adc ) aDigit_max = d; // if ADC max in claster
+      // End of cluster
+      if ( d->strip() - prev_channel != 1 ) {
+        fillADC_clusterMAX( aDigit_max );
+        aDigit_max = d;
+      }
+
+      prev_channel = d->strip();
+      prev_adc     = d->depositedCharge();
+    }
+
+    // UT error bank
+    for ( const auto& d : errdigitsCont ) {
+      fillHeatMap( d, det );
+      fillADC( d, odin );
+
+      if ( d->face() == 0 )
+        uc_error_size++;
+      else if ( d->face() == 1 )
+        ua_error_size++;
+
+      UTDAQID      daqID    = readoutTool->channelIDToDAQID( d->channelID() );
+      auto         board_ID = daqID.board();
+      unsigned int sourceID = UTMap.getSourceIDfromBoardNumber( board_ID );
+
+      if ( sourceID != prevSourceID ) { fillBankHistograms( sourceID ); }
+
+      prevSourceID = sourceID;
+
+      // Cluster max ADC counters
+      // First event
+      if ( prev_channel == 0 ) {
+        prev_channel = d->strip();
+        prev_adc     = d->depositedCharge();
+        aDigit_max   = d;
+        continue;
+      }
+      // If cluster size >1
+      if ( d->strip() - prev_channel == 1 )
+        if ( d->depositedCharge() > prev_adc ) aDigit_max = d; // if ADC max in claster
+      // End of cluster
+      if ( d->strip() - prev_channel != 1 ) {
+        fillADC_clusterMAX( aDigit_max );
+        aDigit_max = d;
+      }
+
+      prev_channel = d->strip();
+      prev_adc     = d->depositedCharge();
+    }
+
+    // Commisioning per side histograms
+    ++m_nDigits_UA[ua_size + ua_error_size];
+    ++m_nDigits_UC[uc_size + uc_error_size];
+  }
+
+private:
+  mutable UTCoordinatesMap UTMap;
+  mutable unsigned int     prevSourceID = 0;
+
+  // General plots
+  mutable GA::Histogram<1> m_nBuncId{ this, "nBuncId", "Bunch IDs", AxisBCID };
+  mutable GA::Histogram<2> m_nDigitsnBuncId{ this, "nDigitsnBuncId", "nBuncId vs BunchIDs", AxisBCID, AxisDIGIT };
+
+  // Digits counters
+  mutable GA::Histogram<1> m_nDigits{ this, "nDigits", "Total nDigits", AxisDIGIT };
+  mutable GA::Histogram<1> m_nDigits_UA{ this, "nDigits_UA", "Total nDigits UA", AxisDIGIT };
+  mutable GA::Histogram<1> m_nDigits_UC{ this, "nDigits_UC", "Total nDigits UC", AxisDIGIT };
+
+  // Split for event type
+  mutable GA::Histogram<1> m_nDigits_bb{ this, "nDigits_bb", "Total nDigits bb", AxisDIGIT };
+  mutable GA::Histogram<1> m_nDigits_be{ this, "nDigits_be", "Total nDigits be", AxisDIGIT };
+  mutable GA::Histogram<1> m_nDigits_eb{ this, "nDigits_eb", "Total nDigits eb", AxisDIGIT };
+  mutable GA::Histogram<1> m_nDigits_ee{ this, "nDigits_ee", "Total nDigits ee", AxisDIGIT };
+
+  // ADC counters
+  mutable GA::Histogram<1> m_nADC{ this, "nADC", "Total nADC", AxisADC_signed };
+  mutable GA::Histogram<1> m_nADC_A{ this, "nADC_A", "Total nADC - type A sensors", AxisADC_signed };
+  mutable GA::Histogram<1> m_nADC_B{ this, "nADC_B", "Total nADC - type B sensors", AxisADC_signed };
+  mutable GA::Histogram<1> m_nADC_C{ this, "nADC_C", "Total nADC - type C sensors", AxisADC_signed };
+  mutable GA::Histogram<1> m_nADC_D{ this, "nADC_D", "Total nADC - type D sensors", AxisADC_signed };
+
+  // Cluster max counters
+  mutable GA::Histogram<1> m_nADC_clusterMAX{ this, "nADC_clusterMAX", "Total nADC", AxisADC_signed };
+  mutable GA::Histogram<1> m_nADC_A_clusterMAX{ this, "nADC_A_clusterMAX", "Total nADC - type A sensors",
+                                                AxisADC_signed };
+  mutable GA::Histogram<1> m_nADC_B_clusterMAX{ this, "nADC_B_clusterMAX", "Total nADC - type B sensors",
+                                                AxisADC_signed };
+  mutable GA::Histogram<1> m_nADC_C_clusterMAX{ this, "nADC_C_clusterMAX", "Total nADC - type C sensors",
+                                                AxisADC_signed };
+  mutable GA::Histogram<1> m_nADC_D_clusterMAX{ this, "nADC_D_clusterMAX", "Total nADC - type D sensors",
+                                                AxisADC_signed };
+
+  // Split for A/C side (comissioning)
+  mutable Gaudi::Accumulators::HistogramArray<Gaudi::Accumulators::Histogram<1>, 5> m_1d_ua{
+      this,
+      []( int i ) { return fmt::format( "{}", "UA_" + s_HistNames_BXType[i] ); },
+      []( int i ) { return fmt::format( "{}", "UA " + s_HistNames_BXType_labels[i] ); },
+      { 32, -0.5, 31.5, "nADC" } };
+
+  mutable Gaudi::Accumulators::HistogramArray<Gaudi::Accumulators::Histogram<1>, 5> m_1d_uc{
+      this,
+      []( int i ) { return fmt::format( "{}", "UC_" + s_HistNames_BXType[i] ); },
+      []( int i ) { return fmt::format( "{}", "UC " + s_HistNames_BXType_labels[i] ); },
+      { 32, -0.5, 31.5, "nADC" } };
+
+  mutable Gaudi::Accumulators::HistogramArray<Gaudi::Accumulators::Histogram<1>, 5> m_1d_bb{
+      this,
+      []( int i ) { return fmt::format( "{}_bb", s_HistNames_BXType[i] ); },
+      []( int i ) { return fmt::format( "{}_bb", s_HistNames_BXType_labels[i] ); },
+      { 32, -0.5, 31.5, "nADC" } };
+
+  mutable Gaudi::Accumulators::HistogramArray<Gaudi::Accumulators::Histogram<1>, 5> m_1d_be{
+      this,
+      []( int i ) { return fmt::format( "{}_be", s_HistNames_BXType[i] ); },
+      []( int i ) { return fmt::format( "{}_be", s_HistNames_BXType_labels[i] ); },
+      { 32, -0.5, 31.5, "nADC" } };
+
+  mutable Gaudi::Accumulators::HistogramArray<Gaudi::Accumulators::Histogram<1>, 5> m_1d_eb{
+      this,
+      []( int i ) { return fmt::format( "{}_eb", s_HistNames_BXType[i] ); },
+      []( int i ) { return fmt::format( "{}_eb", s_HistNames_BXType_labels[i] ); },
+      { 32, -0.5, 31.5, "nADC" } };
+
+  mutable Gaudi::Accumulators::HistogramArray<Gaudi::Accumulators::Histogram<1>, 5> m_1d_ee{
+      this,
+      []( int i ) { return fmt::format( "{}_ee", s_HistNames_BXType[i] ); },
+      []( int i ) { return fmt::format( "{}_ee", s_HistNames_BXType_labels[i] ); },
+      { 32, -0.5, 31.5, "nADC" } };
+
+  mutable Gaudi::Accumulators::HistogramArray<Gaudi::Accumulators::Histogram<1>, 15> m_1d_type{
+      this,
+      []( int i ) { return fmt::format( "{}", s_HistNames_EventType[i] ); },
+      []( int i ) { return fmt::format( "{}", s_HistNames_EventType_labels[i] ); },
+      { 32, -0.5, 31.5, "nADC" } };
+
+  mutable GA::Histogram<2> m_nADCvsBCID{ this, "nADCvsBuncId", "nADC vs BuncId", AxisBCID, AxisADC_signed };
+
+  mutable Gaudi::Accumulators::HistogramArray<Gaudi::Accumulators::Histogram<2>, 4> m_2d_hitmap_sectors{
+      this,
+      []( int i ) { return fmt::format( "UT_HitMap_Sectors_Layer{}", i ); },
+      []( int i ) { return fmt::format( "Sectors of Layer{} (ASICs)", i ); },
+      { 36, -9, 9, "Staves (ASICs)" },
+      { 28, -7, 7, "Modules" } };
+
+  // UT Hitmaps per asic physical position
+  mutable Gaudi::Accumulators::HistogramArray<Gaudi::Accumulators::Histogram<2>, 4> m_2d_hitmap_chips{
+      this,
+      []( int i ) { return fmt::format( "UT_HitMap_Chips_Layer{}", i ); },
+      []( int i ) { return fmt::format( "ASICs of Layer{}", i ); },
+      { 144, -9, 9, "Staves (ASICs)" },
+      { 28, -7, 7, "Modules" } };
+
+  mutable Gaudi::Accumulators::HistogramArray<Gaudi::Accumulators::Histogram<2>, 4> m_2d_hitmap_tell40_eff{
+      this,
+      []( int i ) { return fmt::format( "UT_HitMap_TELL40_Eff_Layer{}", i ); },
+      []( int i ) { return fmt::format( "TELL40 of Layer{} (ASICs)", i ); },
+      { 36, -9, 9, "Staves (ASICs)" },
+      { 28, -7, 7, "Modules" } };
+
+  // TELL40 plots
+  mutable Gaudi::Accumulators::HistogramArray<Gaudi::Accumulators::Histogram<2>, s_HistNames.size()>
+      m_UT_Tell_40_vs_asic{ this,
+                            []( int i ) { return fmt::format( "{}", s_HistNames[i] ); },
+                            []( int i ) { return fmt::format( "{}", s_HistNames[i] ); },
+                            { 54, 0, 54 },
+                            { 24, 0, 24 } };
+
+  // TELL40 plots - counter
+  mutable Gaudi::Accumulators::HistogramArray<Gaudi::Accumulators::Histogram<1>, s_HistNames_Counter.size()>
+      m_UT_Tell_40_events{ this,
+                           []( int i ) { return fmt::format( "{}", s_HistNames_Counter[i] ); },
+                           []( int i ) { return fmt::format( "{}", s_HistNames_Counter[i] ); },
+                           { 54, 0, 54 } };
+
+  void fillBankHistograms( const int sourceID ) const {
+
+    int SourceID_ = sourceID / 1000;
+
+    if ( UTMap.getTELL40( sourceID ).find( "UA" ) != std::string::npos ) {
+      if ( SourceID_ == 10 ) {
+        ++m_UT_Tell_40_events[0][UTMap.getTELL40Bin( sourceID )];
+      } else if ( SourceID_ == 11 ) {
+        ++m_UT_Tell_40_events[1][UTMap.getTELL40Bin( sourceID )];
+      }
+
+    } else if ( UTMap.getTELL40( sourceID ).find( "UC" ) != std::string::npos ) {
+      if ( SourceID_ == 12 ) {
+        ++m_UT_Tell_40_events[2][UTMap.getTELL40Bin( sourceID )];
+      } else if ( SourceID_ == 13 ) {
+        ++m_UT_Tell_40_events[3][UTMap.getTELL40Bin( sourceID )];
+      }
+    }
+
+    auto modules = UTMap.getNamesfromTELL40( UTMap.getTELL40( sourceID ) );
+    for ( const auto& module : modules ) {
+      unsigned int channel = UTMap.getChannel( module );
+
+      Detector::UT::ChannelID channelID( channel );
+
+      // Let's find where we are
+      auto tuple = UTMap.getTuple( channelID.module(), channelID.face(), channelID.stave(), channelID.side(),
+                                   channelID.sector() );
+
+      float       x           = std::get<0>( tuple );
+      float       y           = std::get<1>( tuple );
+      std::string module_name = std::get<4>( tuple );
+      std::string type        = std::get<5>( tuple );
+
+      // SECTORS Maps //
+      if ( ( channelID.stave() > 1 ) || ( fabs( y ) > 2 ) ) {
+        ++m_2d_hitmap_tell40_eff[channelID.layer()][{ x + 0.25, y + 0.25 }];
+        ++m_2d_hitmap_tell40_eff[channelID.layer()][{ x + 0.25, y - 0.25 }];
+        ++m_2d_hitmap_tell40_eff[channelID.layer()][{ x - 0.25, y + 0.25 }];
+        ++m_2d_hitmap_tell40_eff[channelID.layer()][{ x - 0.25, y - 0.25 }];
+      }
+      if ( ( ( channelID.stave() == 1 ) && ( fabs( y ) < 2 ) ) ||
+           ( ( channelID.stave() == 0 ) && ( fabs( y ) == 1.5 ) ) ) {
+        ++m_2d_hitmap_tell40_eff[channelID.layer()][{ x, y + 0.25 }];
+        ++m_2d_hitmap_tell40_eff[channelID.layer()][{ x, y - 0.25 }];
+      }
+      if ( ( channelID.stave() == 0 ) && ( fabs( y ) < 1 ) ) { ++m_2d_hitmap_tell40_eff[channelID.layer()][{ x, y }]; }
+    }
+  }
+
+  void fillADC( const LHCb::UTDigit* aDigit, LHCb::ODIN const& odin ) const {
+
+    ++m_nADCvsBCID[{ odin.bunchId(), aDigit->depositedCharge() }];
+    std::string type = std::get<5>(
+        UTMap.getTuple( aDigit->module(), aDigit->face(), aDigit->stave(), aDigit->side(), aDigit->sector() ) );
+
+    if ( odin.eventTypeBit( LHCb::ODIN::EventTypes::NoBias ) ) ++m_1d_type[0][aDigit->depositedCharge()];
+    if ( odin.eventTypeBit( LHCb::ODIN::EventTypes::Lumi ) ) ++m_1d_type[1][aDigit->depositedCharge()];
+    if ( odin.eventTypeBit( LHCb::ODIN::EventTypes::et_bit_08 ) ) ++m_1d_type[2][aDigit->depositedCharge()];
+    if ( odin.eventTypeBit( LHCb::ODIN::EventTypes::et_bit_09 ) ) ++m_1d_type[3][aDigit->depositedCharge()];
+    if ( odin.eventTypeBit( LHCb::ODIN::EventTypes::et_bit_10 ) ) ++m_1d_type[4][aDigit->depositedCharge()];
+    if ( odin.eventTypeBit( LHCb::ODIN::EventTypes::et_bit_11 ) ) ++m_1d_type[5][aDigit->depositedCharge()];
+    if ( odin.eventTypeBit( LHCb::ODIN::EventTypes::et_bit_12 ) ) ++m_1d_type[6][aDigit->depositedCharge()];
+    if ( odin.eventTypeBit( LHCb::ODIN::EventTypes::et_bit_13 ) ) ++m_1d_type[7][aDigit->depositedCharge()];
+    if ( odin.eventTypeBit( LHCb::ODIN::EventTypes::et_bit_14 ) ) ++m_1d_type[8][aDigit->depositedCharge()];
+    if ( odin.eventTypeBit( LHCb::ODIN::EventTypes::et_bit_15 ) ) ++m_1d_type[9][aDigit->depositedCharge()];
+
+    if ( odin.bunchCrossingType() == LHCb::ODIN::BXTypes::BeamCrossing ) {
+      if ( odin.eventTypeBit( LHCb::ODIN::EventTypes::NoBias ) ) ++m_1d_type[10][aDigit->depositedCharge()];
+      if ( odin.eventTypeBit( LHCb::ODIN::EventTypes::Lumi ) ) ++m_1d_type[11][aDigit->depositedCharge()];
+      if ( odin.eventTypeBit( LHCb::ODIN::EventTypes::et_bit_08 ) ) ++m_1d_type[12][aDigit->depositedCharge()];
+      if ( odin.eventTypeBit( LHCb::ODIN::EventTypes::et_bit_09 ) ) ++m_1d_type[13][aDigit->depositedCharge()];
+      if ( odin.eventTypeBit( LHCb::ODIN::EventTypes::et_bit_10 ) ) ++m_1d_type[14][aDigit->depositedCharge()];
+    }
+
+    ++m_nADC[aDigit->depositedCharge()];
+
+    if ( aDigit->face() == 0 ) {
+      ++m_1d_uc[0][aDigit->depositedCharge()];
+      if ( type == "A" ) ++m_1d_uc[1][aDigit->depositedCharge()];
+      if ( type == "B" ) ++m_1d_uc[2][aDigit->depositedCharge()];
+      if ( type == "C" ) ++m_1d_uc[3][aDigit->depositedCharge()];
+      if ( type == "D" ) ++m_1d_uc[4][aDigit->depositedCharge()];
+    } else if ( aDigit->face() == 1 ) {
+      ++m_1d_ua[0][aDigit->depositedCharge()];
+      if ( type == "A" ) ++m_1d_ua[1][aDigit->depositedCharge()];
+      if ( type == "B" ) ++m_1d_ua[2][aDigit->depositedCharge()];
+      if ( type == "C" ) ++m_1d_ua[3][aDigit->depositedCharge()];
+      if ( type == "D" ) ++m_1d_ua[4][aDigit->depositedCharge()];
+    }
+
+    if ( odin.bunchCrossingType() == LHCb::ODIN::BXTypes::BeamCrossing )
+      ++m_1d_bb[0][aDigit->depositedCharge()];
+    else if ( odin.bunchCrossingType() == LHCb::ODIN::BXTypes::Beam1 )
+      ++m_1d_be[0][aDigit->depositedCharge()];
+    else if ( odin.bunchCrossingType() == LHCb::ODIN::BXTypes::Beam2 )
+      ++m_1d_eb[0][aDigit->depositedCharge()];
+    else if ( odin.bunchCrossingType() == LHCb::ODIN::BXTypes::NoBeam )
+      ++m_1d_ee[0][aDigit->depositedCharge()];
+
+    if ( type == "A" ) {
+      ++m_nADC_A[aDigit->depositedCharge()];
+      if ( odin.bunchCrossingType() == LHCb::ODIN::BXTypes::BeamCrossing )
+        ++m_1d_bb[1][aDigit->depositedCharge()];
+      else if ( odin.bunchCrossingType() == LHCb::ODIN::BXTypes::Beam1 )
+        ++m_1d_be[1][aDigit->depositedCharge()];
+      else if ( odin.bunchCrossingType() == LHCb::ODIN::BXTypes::Beam2 )
+        ++m_1d_eb[1][aDigit->depositedCharge()];
+      else if ( odin.bunchCrossingType() == LHCb::ODIN::BXTypes::NoBeam )
+        ++m_1d_ee[1][aDigit->depositedCharge()];
+    } else if ( type == "B" ) {
+      ++m_nADC_B[aDigit->depositedCharge()];
+      if ( odin.bunchCrossingType() == LHCb::ODIN::BXTypes::BeamCrossing )
+        ++m_1d_bb[2][aDigit->depositedCharge()];
+      else if ( odin.bunchCrossingType() == LHCb::ODIN::BXTypes::Beam1 )
+        ++m_1d_be[2][aDigit->depositedCharge()];
+      else if ( odin.bunchCrossingType() == LHCb::ODIN::BXTypes::Beam2 )
+        ++m_1d_eb[2][aDigit->depositedCharge()];
+      else if ( odin.bunchCrossingType() == LHCb::ODIN::BXTypes::NoBeam )
+        ++m_1d_ee[2][aDigit->depositedCharge()];
+    } else if ( type == "C" ) {
+      ++m_nADC_C[aDigit->depositedCharge()];
+      if ( odin.bunchCrossingType() == LHCb::ODIN::BXTypes::BeamCrossing )
+        ++m_1d_bb[3][aDigit->depositedCharge()];
+      else if ( odin.bunchCrossingType() == LHCb::ODIN::BXTypes::Beam1 )
+        ++m_1d_be[3][aDigit->depositedCharge()];
+      else if ( odin.bunchCrossingType() == LHCb::ODIN::BXTypes::Beam2 )
+        ++m_1d_eb[3][aDigit->depositedCharge()];
+      else if ( odin.bunchCrossingType() == LHCb::ODIN::BXTypes::NoBeam )
+        ++m_1d_ee[3][aDigit->depositedCharge()];
+    } else if ( type == "D" ) {
+      ++m_nADC_D[aDigit->depositedCharge()];
+      if ( odin.bunchCrossingType() == LHCb::ODIN::BXTypes::BeamCrossing )
+        ++m_1d_bb[4][aDigit->depositedCharge()];
+      else if ( odin.bunchCrossingType() == LHCb::ODIN::BXTypes::Beam1 )
+        ++m_1d_be[4][aDigit->depositedCharge()];
+      else if ( odin.bunchCrossingType() == LHCb::ODIN::BXTypes::Beam2 )
+        ++m_1d_eb[4][aDigit->depositedCharge()];
+      else if ( odin.bunchCrossingType() == LHCb::ODIN::BXTypes::NoBeam )
+        ++m_1d_ee[4][aDigit->depositedCharge()];
+    }
+
+    Detector::UT::ChannelID channelID = aDigit->channelID();
+    UTDAQID                 daqID     = readoutTool->channelIDToDAQID( channelID );
+    auto                    board_ID  = daqID.board();
+    unsigned int            sourceID  = UTMap.getSourceIDfromBoardNumber( board_ID );
+    int                     SourceID_ = sourceID / 1000;
+
+    unsigned int asic_times_lane = int( aDigit->strip() / 128 ) + 4 * extract<masks::lane>( aDigit->getdaqID() );
+
+    // Sadly we (I) can't do it better. But at least its ok!
+    if ( UTMap.getTELL40( sourceID ).find( "UA" ) != std::string::npos ) {
+      if ( SourceID_ == 10 ) {
+        if ( UTMap.getFlavour( UTMap.getTELL40( sourceID ) ) == "2x4" ) {
+          ++m_UT_Tell_40_vs_asic[0][{ UTMap.getTELL40Bin( sourceID ), UTMap.get2_4_Flow0_Bin( asic_times_lane ) }];
+        } else if ( UTMap.getFlavour( UTMap.getTELL40( sourceID ) ) == "2x5" ) {
+          ++m_UT_Tell_40_vs_asic[0][{ UTMap.getTELL40Bin( sourceID ), UTMap.get2_5_Flow0_Bin( asic_times_lane ) }];
+        } else if ( UTMap.getFlavour( UTMap.getTELL40( sourceID ) ) == "4x3" ||
+                    UTMap.getFlavour( UTMap.getTELL40( sourceID ) ) == "2x3" ||
+                    UTMap.getFlavour( UTMap.getTELL40( sourceID ) ) == "Jx3" ) {
+          ++m_UT_Tell_40_vs_asic[0][{ UTMap.getTELL40Bin( sourceID ), asic_times_lane }];
+        }
+      } else if ( SourceID_ == 11 ) {
+        if ( UTMap.getFlavour( UTMap.getTELL40( sourceID ) ) == "2x4" ) {
+          if ( asic_times_lane == 16 || asic_times_lane == 17 )
+            ++m_UT_Tell_40_vs_asic[0][{ UTMap.getTELL40Bin( sourceID ), UTMap.get2_4_Flow0_Bin( asic_times_lane ) }];
+          else
+            ++m_UT_Tell_40_vs_asic[1][{ UTMap.getTELL40Bin( sourceID ), UTMap.get2_4_Flow1_Bin( asic_times_lane ) }];
+        } else if ( UTMap.getFlavour( UTMap.getTELL40( sourceID ) ) == "2x5" )
+          ++m_UT_Tell_40_vs_asic[1][{ UTMap.getTELL40Bin( sourceID ), UTMap.get2_5_Flow1_Bin( asic_times_lane ) }];
+        else if ( UTMap.getFlavour( UTMap.getTELL40( sourceID ) ) == "4x3" ||
+                  UTMap.getFlavour( UTMap.getTELL40( sourceID ) ) == "2x3" ||
+                  UTMap.getFlavour( UTMap.getTELL40( sourceID ) ) == "Jx3" )
+          ++m_UT_Tell_40_vs_asic[1][{ UTMap.getTELL40Bin( sourceID ), asic_times_lane }];
+      }
+
+    } else if ( UTMap.getTELL40( sourceID ).find( "UC" ) != std::string::npos ) {
+      if ( SourceID_ == 12 ) {
+        if ( UTMap.getFlavour( UTMap.getTELL40( sourceID ) ) == "2x4" ) {
+          ++m_UT_Tell_40_vs_asic[2][{ UTMap.getTELL40Bin( sourceID ), UTMap.get2_4_Flow0_Bin( asic_times_lane ) }];
+        } else if ( UTMap.getFlavour( UTMap.getTELL40( sourceID ) ) == "2x5" ) {
+          ++m_UT_Tell_40_vs_asic[2][{ UTMap.getTELL40Bin( sourceID ), UTMap.get2_5_Flow0_Bin( asic_times_lane ) }];
+        } else if ( UTMap.getFlavour( UTMap.getTELL40( sourceID ) ) == "4x3" ||
+                    UTMap.getFlavour( UTMap.getTELL40( sourceID ) ) == "2x3" ||
+                    UTMap.getFlavour( UTMap.getTELL40( sourceID ) ) == "Jx3" ) {
+          ++m_UT_Tell_40_vs_asic[2][{ UTMap.getTELL40Bin( sourceID ), asic_times_lane }];
+        }
+      }
+
+      else if ( SourceID_ == 13 ) {
+        if ( UTMap.getFlavour( UTMap.getTELL40( sourceID ) ) == "2x4" ) {
+          if ( asic_times_lane == 16 || asic_times_lane == 17 )
+            ++m_UT_Tell_40_vs_asic[2][{ UTMap.getTELL40Bin( sourceID ), UTMap.get2_4_Flow0_Bin( asic_times_lane ) }];
+          else
+            ++m_UT_Tell_40_vs_asic[3][{ UTMap.getTELL40Bin( sourceID ), UTMap.get2_4_Flow1_Bin( asic_times_lane ) }];
+        } else if ( UTMap.getFlavour( UTMap.getTELL40( sourceID ) ) == "2x5" )
+          ++m_UT_Tell_40_vs_asic[3][{ UTMap.getTELL40Bin( sourceID ), UTMap.get2_5_Flow1_Bin( asic_times_lane ) }];
+        else if ( UTMap.getFlavour( UTMap.getTELL40( sourceID ) ) == "4x3" ||
+                  UTMap.getFlavour( UTMap.getTELL40( sourceID ) ) == "2x3" ||
+                  UTMap.getFlavour( UTMap.getTELL40( sourceID ) ) == "Jx3" )
+          ++m_UT_Tell_40_vs_asic[3][{ UTMap.getTELL40Bin( sourceID ), asic_times_lane }];
+      }
+    }
+  }
+
+  // Fill clusterMAX counters
+  void fillADC_clusterMAX( const LHCb::UTDigit* aDigit ) const {
+
+    std::string type = std::get<5>(
+        UTMap.getTuple( aDigit->module(), aDigit->face(), aDigit->stave(), aDigit->side(), aDigit->sector() ) );
+
+    ++m_nADC_clusterMAX[aDigit->depositedCharge()];
+
+    if ( type == "A" ) {
+      ++m_nADC_A_clusterMAX[aDigit->depositedCharge()];
+    } else if ( type == "B" ) {
+      ++m_nADC_B_clusterMAX[aDigit->depositedCharge()];
+    } else if ( type == "C" ) {
+      ++m_nADC_C_clusterMAX[aDigit->depositedCharge()];
+    } else if ( type == "D" ) {
+      ++m_nADC_D_clusterMAX[aDigit->depositedCharge()];
+    }
+  }
+
+  void fillHeatMap( const LHCb::UTDigit* aDigit, DeUTDetector const& det ) const {
+
+    // Let's find where we are
+    std::tuple<float, float, float, float, std::string, std::string> tuple =
+        UTMap.getTuple( aDigit->module(), aDigit->face(), aDigit->stave(), aDigit->side(), aDigit->sector() );
+    float       x           = std::get<0>( tuple );
+    float       y           = std::get<1>( tuple );
+    std::string module_name = std::get<4>( tuple );
+    std::string type        = std::get<5>( tuple );
+    auto        chanID      = aDigit->channelID();
+    auto        aSector     = det.findSector( chanID );
+
+// This may be useful but allows to get only position of hybrind. It can be used to get ASIC position.
+#ifdef USE_DD4HEP
+    auto trajStrip0   = aSector.createTraj( 0, 0 );
+    auto trajStrip511 = aSector.createTraj( 511, 0 );
+#else
+    auto trajStrip0   = aSector->trajectory( chanID, 0 );
+    auto trajStrip511 = aSector->trajectory( LHCb::Detector::UT::ChannelID{ chanID + 511 }, 0 );
+#endif
+    double stripx0    = -1 * ( trajStrip0.endPoint().x() + trajStrip0.beginPoint().x() ) * 0.5;
+    double stripx511  = -1 * ( trajStrip511.endPoint().x() + trajStrip511.beginPoint().x() ) * 0.5;
+    double stripwidth = stripx511 - stripx0;
+    int    chip;
+
+    if ( stripwidth > 0 )
+      chip = int( aDigit->strip() / 128 );
+    else
+      chip = 3 - int( aDigit->strip() / 128 );
+
+    double positionasic_one = positionasic[chip][0];
+    double positionasic_two = positionasic[chip][1];
+    double positionasic_thr = positionasic[chip][2];
+
+    // Sectors Maps //
+    if ( ( aDigit->stave() > 1 ) || ( fabs( y ) > 2 ) ) {
+      ++m_2d_hitmap_sectors[aDigit->layer()][{ x + 0.25, y + 0.25 }];
+      ++m_2d_hitmap_sectors[aDigit->layer()][{ x + 0.25, y - 0.25 }];
+      ++m_2d_hitmap_sectors[aDigit->layer()][{ x - 0.25, y + 0.25 }];
+      ++m_2d_hitmap_sectors[aDigit->layer()][{ x - 0.25, y - 0.25 }];
+    }
+    if ( ( ( aDigit->stave() == 1 ) && ( fabs( y ) < 2 ) ) || ( ( aDigit->stave() == 0 ) && ( fabs( y ) == 1.5 ) ) ) {
+      ++m_2d_hitmap_sectors[aDigit->layer()][{ x, y + 0.25 }];
+      ++m_2d_hitmap_sectors[aDigit->layer()][{ x, y - 0.25 }];
+    }
+    if ( ( aDigit->stave() == 0 ) && ( fabs( y ) < 1 ) ) { ++m_2d_hitmap_sectors[aDigit->layer()][{ x, y }]; }
+
+    // Chips Maps //
+    if ( ( aDigit->stave() > 1 ) || ( fabs( y ) > 2 ) ) {
+      ++m_2d_hitmap_chips[aDigit->layer()][{ x + positionasic_one, y + 0.25 }];
+      ++m_2d_hitmap_chips[aDigit->layer()][{ x + positionasic_one, y - 0.25 }];
+      ++m_2d_hitmap_chips[aDigit->layer()][{ x + positionasic_two, y + 0.25 }];
+      ++m_2d_hitmap_chips[aDigit->layer()][{ x + positionasic_two, y - 0.25 }];
+    }
+    if ( ( ( aDigit->stave() == 1 ) && ( fabs( y ) < 2 ) ) || ( ( aDigit->stave() == 0 ) && ( fabs( y ) == 1.5 ) ) ) {
+      ++m_2d_hitmap_chips[aDigit->layer()][{ x + positionasic_thr, y + 0.25 }];
+      ++m_2d_hitmap_chips[aDigit->layer()][{ x + positionasic_thr, y - 0.25 }];
+    }
+    if ( ( aDigit->stave() == 0 ) && ( fabs( y ) < 1 ) ) {
+      ++m_2d_hitmap_chips[aDigit->layer()][{ x + positionasic_thr, y }];
+    }
+  }
+}; // End of class UTDigitsMonitor
+DECLARE_COMPONENT( UTDigitsMonitor )
diff --git a/UT/UTMonitors/src/UTErrorMonitor.cpp b/UT/UTMonitors/src/UTErrorMonitor.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..cd315fd0c04320c63584bd334f549f86d5353984
--- /dev/null
+++ b/UT/UTMonitors/src/UTErrorMonitor.cpp
@@ -0,0 +1,351 @@
+/*****************************************************************************\
+* (c) Copyright 2000-2018 CERN for the benefit of the LHCb Collaboration      *
+*                                                                             *
+* This software is distributed under the terms of the GNU General Public      *
+* Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING".   *
+*                                                                             *
+* In applying this licence, CERN does not waive the privileges and immunities *
+* granted to it by virtue of its status as an Intergovernmental Organization  *
+* or submit itself to any jurisdiction.                                       *
+\*****************************************************************************/
+#include "Event/UTErrorASIC.h"
+#include "GaudiAlg/GaudiHistoAlg.h"
+#include "Kernel/IUTReadoutTool.h"
+#include "LHCbAlgs/Consumer.h"
+#include "UTDAQ/UTCoordinatesMap.h"
+#include "UTDet/DeUTDetector.h"
+#include <Gaudi/Accumulators/Histogram.h>
+#include <Gaudi/Accumulators/HistogramArray.h>
+#include <Kernel/UTDAQID.h>
+
+using namespace LHCb;
+
+/** @class UTErrorMonitor UTErrorMonitor.h
+ *  --------------------------------------------------
+ *  Class for monitoring UTError and UTSpecial banks
+ *  @author Wojciech Krupa (wokrupa@cern.ch) based on code by:
+ *  @author C. Hadjivasiliou
+ *  @date   2024/03/20
+ *  --------------------------------------------------
+ */
+
+enum class masks { channel = 0x000001ff, lane = 0x00000e00, board = 0x000ff000 }; /// Enumeration for use in bit packing
+
+// Definition of axis
+namespace GA                               = Gaudi::Accumulators;
+const GA::Axis<double> AxisADC             = GA::Axis<double>( 64, -32.5, 31.5, "nADC" ); //-32, 31
+const GA::Axis<double> AxisCalib           = GA::Axis<double>( 256, -0.5, 256.5, "CalibStep" );
+const GA::Axis<double> AxisBCID            = GA::Axis<double>( 3565, -0.5, 3564.5, "BunchID" );
+const GA::Axis<double> AxisDIGIT           = GA::Axis<double>( 101, -0.5, 100.5, "UTDigits (size of digit container)" );
+const GA::Axis<double> AxisXnaturalunits   = GA::Axis<double>( 36, -9, 9, "Staves (Sectors)" );
+const GA::Axis<double> AxisXnaturalunits4x = GA::Axis<double>( 144, -9, 9, "Staves (ASICs)" );
+const GA::Axis<double> AxisYnaturalunits   = GA::Axis<double>( 28, -7, 7, "Modules" );
+
+// Definition of histogram names
+const std::array<std::string, 4> s_HistBanksNames = { "UTA_BankType_vs_TELL40_Flow0", "UTA_BankType_vs_TELL40_Flow1",
+                                                      "UTC_BankType_vs_TELL40_Flow0", "UTC_BankType_vs_TELL40_Flow1" };
+
+const std::array<std::string, 4> s_HistBanksNames2 = {
+    "UTA_BankType_vs_TELL40_Error_Flow0", "UTA_BankType_vs_TELL40_Error_Flow1", "UTC_BankType_vs_TELL40_Error_Flow0",
+    "UTC_BankType_vs_TELL40_Error_Flow1" };
+
+// UTError Types
+const std::array<std::string, 12> s_SpecialSubtypeMap = {
+    "UTA_BusyEvent_vs_TELL40_Flow0",   "UTA_BusyEvent_vs_TELL40_Flow1",   "UTC_BusyEvent_vs_TELL40_Flow0",
+    "UTC_BusyEvent_vs_TELL40_Flow1",   "UTA_BufferFull_vs_TELL40_Flow0",  "UTA_BufferFull_vs_TELL40_Flow1",
+    "UTC_BufferFull_vs_TELL40_Flow0",  "UTC_BufferFull_vs_TELL40_Flow1",  "UTA_BufferFullN_vs_TELL40_Flow0",
+    "UTA_BufferFullN_vs_TELL40_Flow1", "UTC_BufferFullN_vs_TELL40_Flow0", "UTC_BufferFullN_vs_TELL40_Flow1" };
+
+// 2D plots
+const double positionasic[4][3] = {
+    { -0.4375, -0.3125, -0.1875 }, // Chip 0
+    { -0.1875, -0.0625, -0.0625 }, // Chip 1
+    { +0.1875, +0.0625, +0.0625 }, // Chip 2
+    { +0.4375, +0.3125, +0.1875 }  // Chip 3
+};
+using namespace LHCb;
+
+template <masks m>
+[[nodiscard]] static constexpr unsigned int extract( unsigned int i ) {
+  constexpr auto b = std::countr_zero( static_cast<unsigned int>( m ) );
+  return ( i & static_cast<unsigned int>( m ) ) >> b;
+}
+
+class UTErrorMonitor
+    : public LHCb::Algorithm::Consumer<void( UTErrorASICs const&, DeUTDetector const& ),
+                                       LHCb::DetDesc::usesBaseAndConditions<GaudiHistoAlg, DeUTDetector>> {
+
+public:
+  /// constructer
+  UTErrorMonitor( const std::string& name, ISvcLocator* svcloc )
+      : Consumer{
+            name,
+            svcloc,
+            { { "InputData", UTErrorASICLocation::UTErrorASICs }, { "UTLocation", DeUTDetLocation::location() } } } {}
+
+  ToolHandle<IUTReadoutTool> readoutTool{ this, "ReadoutTool", "UTReadoutTool" };
+
+  // UTCoordinations map
+  mutable UTCoordinatesMap UTMap;
+
+  // TELL40 vs banktype plots
+  mutable Gaudi::Accumulators::HistogramArray<Gaudi::Accumulators::Histogram<2>, s_HistBanksNames.size()>
+      m_UT_Tell_40_vs_banktype{ this,
+                                []( int i ) { return fmt::format( "{}", s_HistBanksNames[i] ); },
+                                []( int i ) { return fmt::format( "{}", s_HistBanksNames[i] ); },
+                                { 54, 0, 54 },
+                                { 19, 0, 19 } };
+
+  // TELL40 vs banktype plots
+  mutable Gaudi::Accumulators::HistogramArray<Gaudi::Accumulators::Histogram<2>, s_HistBanksNames2.size()>
+      m_UT_Tell_40_vs_banktype_error{ this,
+                                      []( int i ) { return fmt::format( "{}", s_HistBanksNames2[i] ); },
+                                      []( int i ) { return fmt::format( "{}", s_HistBanksNames2[i] ); },
+                                      { 54, 0, 54 },
+                                      { 3, 0, 3 } };
+
+  // TELL40 vs packetID (UTError) plots
+  mutable Gaudi::Accumulators::HistogramArray<Gaudi::Accumulators::Histogram<2>, s_SpecialSubtypeMap.size()>
+      m_2d_packetype{ this,
+                      []( int i ) { return fmt::format( "{}", s_SpecialSubtypeMap[i] ); },
+                      []( int i ) { return fmt::format( "{}", s_SpecialSubtypeMap[i] ); },
+                      { 54, 0, 54 },
+                      { 24, 0, 24 } };
+
+  // 2D plot for geometrical pos of UTErrorKnown
+  mutable Gaudi::Accumulators::HistogramArray<Gaudi::Accumulators::Histogram<2>, 4> m_asics_UTError_Known{
+      this,
+      []( int i ) { return fmt::format( "UTError_Known_Layer{}", i ); },
+      []( int i ) { return fmt::format( "UTError_Known_Layer{}", i ); },
+      { 144, -9, 9, "Staves (ASICs)" },
+      { 28, -7, 7, "Modules" } };
+
+  // Error type counters
+  mutable GA::Histogram<1> m_nErrorsTypeCounter{ this, "ErrorsTypeCounter", "ErrorsTypeCounter", { 19, 0, 19 } };
+  // Number of ASICs in error per event - subtype 19
+  mutable GA::Histogram<1> m_ASICs_nErrorsType19{
+      this, "Number_ASICs_Error_19", "Number of ASICs in Error - subtype 19", { 1001, -0.5, 1000.5 } };
+  // Number of ASICs in error per event - subtype 20
+  mutable GA::Histogram<1> m_ASICs_nErrorsType20{
+      this, "Number_ASICs_Error_20", "Number of ASICs in Error - subtype 20", { 1001, -0.5, 1000.5 } };
+  // Number of ASICs in error per event - subtype 21
+  mutable GA::Histogram<1> m_ASICs_nErrorsType21{
+      this, "Number_ASICs_Error_21", "Number of ASICs in Error - subtype 21", { 1001, -0.5, 1000.5 } };
+
+  /// initialize
+  StatusCode initialize() override {
+    return Consumer::initialize().andThen( [&] {
+      // Set the top directory to UT
+      if ( histoTopDir().empty() ) setHistoTopDir( "" );
+    } );
+  }
+
+  /// execute
+  void operator()( const UTErrorASICs& errorsCont, DeUTDetector const& det ) const override {
+    // number of errors
+    unsigned int asic_inError_19 = 0;
+    unsigned int asic_inError_20 = 0;
+    unsigned int asic_inError_21 = 0;
+
+    plot( (double)errorsCont.size(), "nErrors", -0.5, 9999.5, 10000 );
+    // histos per bank type
+    // histos per error
+    for ( const auto& e : errorsCont ) {
+
+      // Handling UTError enocded in strip 1
+      if ( e->strip() % 128 == 1 && e->packetId() == 19 ) asic_inError_19++;
+      if ( e->strip() % 128 == 1 && e->packetId() == 20 ) asic_inError_20++;
+      if ( e->strip() % 128 == 1 && e->packetId() == 21 ) asic_inError_21++;
+
+      fillBankHistograms( e );
+      fillHeatMap_Error( e, det );
+    }
+
+    // Bank type counter
+    if ( asic_inError_19 > 1000 ) asic_inError_19 = 1000; // saturation
+    if ( asic_inError_20 > 1000 ) asic_inError_20 = 1000; // saturation
+    if ( asic_inError_21 > 1000 ) asic_inError_21 = 1000; // saturation
+
+    ++m_ASICs_nErrorsType19[asic_inError_19];
+    ++m_ASICs_nErrorsType20[asic_inError_20];
+    ++m_ASICs_nErrorsType21[asic_inError_21];
+  }
+
+private:
+  void fillBankHistograms( const LHCb::UTErrorASIC* aError ) const {
+    // Channel and source ID
+    auto         chanID          = aError->channelID();
+    UTDAQID      daqID           = readoutTool->channelIDToDAQID( chanID );
+    auto         board_ID        = daqID.board();
+    unsigned int sourceID        = UTMap.getSourceIDfromBoardNumber( board_ID );
+    int          y               = aError->bankType();
+    auto         LaneID          = extract<masks::lane>( aError->getdaqID() );
+    int          SourceID_       = sourceID / 1000;
+    unsigned int asic_times_lane = aError->asic() + 4 * LaneID;
+
+    // Bank type counter
+    ++m_nErrorsTypeCounter[y];
+
+    // Sadly we (I) can't do it better. But at least its ok!
+    // Normal ErrorType
+    if ( ( aError->strip() == 0 && LaneID == 0 ) ||
+         ( UTMap.getFlavour( UTMap.getTELL40( sourceID ) ) == "2x4" && aError->strip() == 256 && LaneID == 0 ) ) {
+      // TELL40 vs Bank Type
+      if ( UTMap.getTELL40( sourceID ).find( "UA" ) != std::string::npos ) {
+        if ( sourceID / 1000 == 10 ) // 10346-10269
+          ++m_UT_Tell_40_vs_banktype[0][{ UTMap.getTELL40Bin( sourceID ), y }];
+        else if ( sourceID / 1000 == 11 ) // 11370-11293
+          ++m_UT_Tell_40_vs_banktype[1][{ UTMap.getTELL40Bin( sourceID ), y }];
+      } else if ( UTMap.getTELL40( sourceID ).find( "UC" ) != std::string::npos ) {
+        if ( sourceID / 1000 == 12 ) // 12366-12291
+          ++m_UT_Tell_40_vs_banktype[2][{ UTMap.getTELL40Bin( sourceID ), y }];
+        else if ( sourceID / 1000 == 13 ) // 13371-13315
+          ++m_UT_Tell_40_vs_banktype[3][{ UTMap.getTELL40Bin( sourceID ), y }];
+      }
+    }
+
+    if ( aError->strip() % 128 == 1 &&
+         ( aError->packetId() == 19 || aError->packetId() == 20 || aError->packetId() == 21 ) ) {
+
+      // TELL40 vs Bank Type
+      if ( UTMap.getTELL40( sourceID ).find( "UA" ) != std::string::npos ) {
+        if ( sourceID / 1000 == 10 ) // 10346-10269
+          ++m_UT_Tell_40_vs_banktype_error[0][{ UTMap.getTELL40Bin( sourceID ), aError->packetId() - 19 }];
+        else if ( sourceID / 1000 == 11 ) // 11370-11293
+          ++m_UT_Tell_40_vs_banktype_error[1][{ UTMap.getTELL40Bin( sourceID ), aError->packetId() - 19 }];
+      } else if ( UTMap.getTELL40( sourceID ).find( "UC" ) != std::string::npos ) {
+        if ( sourceID / 1000 == 12 ) // 12366-12291
+          ++m_UT_Tell_40_vs_banktype_error[2][{ UTMap.getTELL40Bin( sourceID ), aError->packetId() - 19 }];
+        else if ( sourceID / 1000 == 13 ) // 13371-13315
+          ++m_UT_Tell_40_vs_banktype_error[3][{ UTMap.getTELL40Bin( sourceID ), aError->packetId() - 19 }];
+      }
+
+      // Suberror plots
+      if ( UTMap.getTELL40( sourceID ).find( "UA" ) != std::string::npos ) {
+        if ( SourceID_ == 10 ) {
+          if ( UTMap.getFlavour( UTMap.getTELL40( sourceID ) ) == "2x4" ) {
+            ++m_2d_packetype[( aError->packetId() - 19 ) * 4]
+                            [{ UTMap.getTELL40Bin( sourceID ), UTMap.get2_4_Flow0_Bin( asic_times_lane ) }];
+          } else if ( UTMap.getFlavour( UTMap.getTELL40( sourceID ) ) == "2x5" ) {
+            ++m_2d_packetype[( aError->packetId() - 19 ) * 4]
+                            [{ UTMap.getTELL40Bin( sourceID ), UTMap.get2_5_Flow0_Bin( asic_times_lane ) }];
+          } else if ( UTMap.getFlavour( UTMap.getTELL40( sourceID ) ) == "4x3" ||
+                      UTMap.getFlavour( UTMap.getTELL40( sourceID ) ) == "2x3" ||
+                      UTMap.getFlavour( UTMap.getTELL40( sourceID ) ) == "Jx3" ) {
+            ++m_2d_packetype[( aError->packetId() - 19 ) * 4][{ UTMap.getTELL40Bin( sourceID ), asic_times_lane }];
+          }
+        } else if ( SourceID_ == 11 ) {
+          if ( UTMap.getFlavour( UTMap.getTELL40( sourceID ) ) == "2x4" ) {
+            if ( asic_times_lane == 16 || asic_times_lane == 17 )
+              ++m_2d_packetype[( aError->packetId() - 19 ) * 4]
+                              [{ UTMap.getTELL40Bin( sourceID ), UTMap.get2_4_Flow0_Bin( asic_times_lane ) }];
+            else
+              ++m_2d_packetype[( aError->packetId() - 19 ) * 4 + 1]
+                              [{ UTMap.getTELL40Bin( sourceID ), UTMap.get2_4_Flow1_Bin( asic_times_lane ) }];
+          } else if ( UTMap.getFlavour( UTMap.getTELL40( sourceID ) ) == "2x5" )
+            ++m_2d_packetype[( aError->packetId() - 19 ) * 4 + 1]
+                            [{ UTMap.getTELL40Bin( sourceID ), UTMap.get2_5_Flow1_Bin( asic_times_lane ) }];
+          else if ( UTMap.getFlavour( UTMap.getTELL40( sourceID ) ) == "4x3" ||
+                    UTMap.getFlavour( UTMap.getTELL40( sourceID ) ) == "2x3" ||
+                    UTMap.getFlavour( UTMap.getTELL40( sourceID ) ) == "Jx3" )
+            ++m_2d_packetype[( aError->packetId() - 19 ) * 4 + 1][{ UTMap.getTELL40Bin( sourceID ), asic_times_lane }];
+        }
+
+      } else if ( UTMap.getTELL40( sourceID ).find( "UC" ) != std::string::npos ) {
+        if ( SourceID_ == 12 ) {
+          if ( UTMap.getFlavour( UTMap.getTELL40( sourceID ) ) == "2x4" ) {
+            ++m_2d_packetype[( aError->packetId() - 19 ) * 4 + 2]
+                            [{ UTMap.getTELL40Bin( sourceID ), UTMap.get2_4_Flow0_Bin( asic_times_lane ) }];
+          } else if ( UTMap.getFlavour( UTMap.getTELL40( sourceID ) ) == "2x5" ) {
+            ++m_2d_packetype[( aError->packetId() - 19 ) * 4 + +2]
+                            [{ UTMap.getTELL40Bin( sourceID ), UTMap.get2_5_Flow0_Bin( asic_times_lane ) }];
+          } else if ( UTMap.getFlavour( UTMap.getTELL40( sourceID ) ) == "4x3" ||
+                      UTMap.getFlavour( UTMap.getTELL40( sourceID ) ) == "2x3" ||
+                      UTMap.getFlavour( UTMap.getTELL40( sourceID ) ) == "Jx3" ) {
+            ++m_2d_packetype[( aError->packetId() - 19 ) * 4 + 2][{ UTMap.getTELL40Bin( sourceID ), asic_times_lane }];
+          }
+        }
+
+        else if ( SourceID_ == 13 ) {
+          if ( UTMap.getFlavour( UTMap.getTELL40( sourceID ) ) == "2x4" ) {
+            if ( asic_times_lane == 16 || asic_times_lane == 17 )
+              ++m_2d_packetype[( aError->packetId() - 19 ) * 4 + 2]
+                              [{ UTMap.getTELL40Bin( sourceID ), UTMap.get2_4_Flow0_Bin( asic_times_lane ) }];
+            else
+              ++m_2d_packetype[( aError->packetId() - 19 ) * 4 + 3]
+                              [{ UTMap.getTELL40Bin( sourceID ), UTMap.get2_4_Flow1_Bin( asic_times_lane ) }];
+          } else if ( UTMap.getFlavour( UTMap.getTELL40( sourceID ) ) == "2x5" )
+            ++m_2d_packetype[( aError->packetId() - 19 ) * 4 + 3]
+                            [{ UTMap.getTELL40Bin( sourceID ), UTMap.get2_5_Flow1_Bin( asic_times_lane ) }];
+          else if ( UTMap.getFlavour( UTMap.getTELL40( sourceID ) ) == "4x3" ||
+                    UTMap.getFlavour( UTMap.getTELL40( sourceID ) ) == "2x3" ||
+                    UTMap.getFlavour( UTMap.getTELL40( sourceID ) ) == "Jx3" )
+            ++m_2d_packetype[( aError->packetId() - 19 ) * 4 + 3][{ UTMap.getTELL40Bin( sourceID ), asic_times_lane }];
+        }
+      }
+    }
+  }
+
+  void incrementHistogram( GA::Histogram<2>& histogram, double x, double y, double positionasic_one,
+                           double positionasic_two ) const {
+    ++histogram[{ x + positionasic_one, y + 0.25 }];
+    ++histogram[{ x + positionasic_two, y + 0.25 }];
+    ++histogram[{ x + positionasic_one, y - 0.25 }];
+    ++histogram[{ x + positionasic_two, y - 0.25 }];
+  }
+
+  void fillHeatMap_Error( const LHCb::UTErrorASIC* aError, DeUTDetector const& det ) const {
+
+    // Let's find out where we are in the UT, it should be reoptimised in the future
+    // To be checked if it works properly!
+
+    if ( aError->strip() % 128 == 1 ) {
+      std::tuple<float, float, float, float, std::string, std::string> tuple =
+          UTMap.getTuple( aError->module(), aError->face(), aError->stave(), aError->side(), aError->sector() );
+
+      float       x           = std::get<0>( tuple );
+      float       y           = std::get<1>( tuple );
+      std::string module_name = std::get<4>( tuple );
+      std::string type        = std::get<5>( tuple );
+      auto        chanID      = aError->channelID();
+      auto        aSector     = det.findSector( chanID );
+#ifdef USE_DD4HEP
+      auto trajStrip0   = aSector.createTraj( 0, 0 );
+      auto trajStrip511 = aSector.createTraj( 511, 0 );
+#else
+      auto trajStrip0   = aSector->trajectory( chanID, 0 );
+      auto trajStrip511 = aSector->trajectory( LHCb::Detector::UT::ChannelID{ chanID + 511 }, 0 );
+#endif
+      double stripx0    = -1 * ( trajStrip0.endPoint().x() + trajStrip0.beginPoint().x() ) * 0.5;
+      double stripx511  = -1 * ( trajStrip511.endPoint().x() + trajStrip511.beginPoint().x() ) * 0.5;
+      double stripwidth = stripx511 - stripx0;
+      int    chip;
+
+      if ( stripwidth > 0 )
+        chip = int( aError->strip() / 128 );
+      else
+        chip = 3 - int( aError->strip() / 128 );
+
+      double positionasic_one = positionasic[chip][0];
+      double positionasic_two = positionasic[chip][1];
+      double positionasic_thr = positionasic[chip][2];
+
+      // Chip is in its correct geometrical order
+      // Sector map //
+      if ( ( aError->stave() > 1 ) || ( fabs( y ) > 2 ) ) {
+        assert( aError->layer() >= 0 && aError->layer() <= 3 );
+        incrementHistogram( m_asics_UTError_Known[aError->layer()], x, y, positionasic_one, positionasic_two );
+      }
+
+      if ( ( ( aError->stave() == 1 ) && ( fabs( y ) < 2 ) ) || ( ( aError->stave() == 0 ) && ( fabs( y ) == 1.5 ) ) ) {
+        ++m_asics_UTError_Known[aError->layer() == 0][{ x + positionasic_thr, y + 0.25 }];
+        ++m_asics_UTError_Known[aError->layer() == 0][{ x + positionasic_thr, y - 0.25 }];
+      }
+      if ( ( aError->stave() == 0 ) && ( fabs( y ) < 1 ) ) {
+        ++m_asics_UTError_Known[aError->layer()][{ x + positionasic_thr, y }];
+      }
+    }
+  }
+};
+
+DECLARE_COMPONENT( UTErrorMonitor )
diff --git a/UT/UTMonitors/src/UTNZSMonitor.cpp b/UT/UTMonitors/src/UTNZSMonitor.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c24ffae4793c9f51f2b80ceb509c3e9bd3625025
--- /dev/null
+++ b/UT/UTMonitors/src/UTNZSMonitor.cpp
@@ -0,0 +1,372 @@
+/***************************************************************************** \
+* (c) Copyright 2000-2018 CERN for the benefit of the LHCb Collaboration      *
+*                                                                             *
+* This software is distributed under the teRMS_ADC of the GNU General Public      *
+* Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING".   *
+*                                                                             *
+* In applying this licence, CERN does not waive the privileges and immunities *
+* granted to it by virtue of its status as an Intergovernmental Organization  *
+* or submit itself to any jurisdiction.                                       *
+\*****************************************************************************/
+
+#include "Event/UTDigit.h"
+#include "GaudiAlg/GaudiHistoAlg.h"
+#include "Kernel/IUTReadoutTool.h"
+#include "Kernel/UTDAQBoard.h"
+#include "Kernel/UTDAQDefinitions.h"
+#include "Kernel/UTDAQID.h"
+#include "LHCbAlgs/Consumer.h"
+#include "LHCbAlgs/Transformer.h"
+#include "UTDAQ/UTCoordinatesMap.h"
+#include "UTDAQ/UTDAQHelper.h"
+#include "UTDAQ/UTInfo.h"
+#include "UTDet/DeUTDetector.h"
+#include <Event/ODIN.h>
+#include <Event/RawBank.h>
+#include <Event/RawEvent.h>
+#include <Gaudi/Accumulators/Histogram.h>
+#include <Gaudi/Accumulators/HistogramArray.h>
+#include <Kernel/IUTReadoutTool.h>
+#include <algorithm>
+#include <mutex>
+#include <optional>
+#include <string>
+
+/** @class UTNZSMonitor UTNZSMonitor.cpp
+ * --------------------------------------------------
+ *  Class for monitoring UTNZS banks
+ *    @author Wojciech Krupa (wokrupa@cern.ch):
+ *    @date   2024/02/10
+ * --------------------------------------------------
+ */
+using namespace LHCb;
+namespace GA = Gaudi::Accumulators;
+
+// Definition of axis
+const GA::Axis<double> AxisADC             = GA::Axis<double>( 64, -32.5, 31.5, "nADC" ); //-32, 31
+const GA::Axis<double> AxisCalib           = GA::Axis<double>( 257, -0.5, 256.5, "CalibStep" );
+const GA::Axis<double> AxisBCID            = GA::Axis<double>( 3565, -0.5, 3564.5, "BunchID" );
+const GA::Axis<double> AxisDIGIT           = GA::Axis<double>( 101, -0.5, 100.5, "UTDigits (size of digit container)" );
+const GA::Axis<double> AxisXnaturalunits   = GA::Axis<double>( 36, -9, 9, "Staves (Sectors)" );
+const GA::Axis<double> AxisXnaturalunits4x = GA::Axis<double>( 144, -9, 9, "Staves (ASICs)" );
+const GA::Axis<double> AxisYnaturalunits   = GA::Axis<double>( 28, -7, 7, "Modules" );
+const GA::Axis<double> AxisModule          = GA::Axis<double>( 512, 0, 512, "Strips" );
+
+enum class masks { channel = 0x000001ff, lane = 0x00000e00, board = 0x000ff000 };
+
+const std::array<std::string, 4> s_HistNames = { "UTA_Tell_40_vs_ASIC_Flow0", "UTA_Tell_40_vs_ASIC_Flow1",
+                                                 "UTC_Tell_40_vs_ASIC_Flow0", "UTC_Tell_40_vs_ASIC_Flow1" };
+
+const std::array<std::string, 4> s_HistBanksNames = { "UTA_BankType_vs_TELL40_Flow0", "UTA_BankType_vs_TELL40_Flow1",
+                                                      "UTC_BankType_vs_TELL40_Flow0", "UTC_BankType_vs_TELL40_Flow1" };
+
+// UT layers
+const std::array<std::string, 4> UT_layers = { "UTaX", "UTaU", "UTbV", "UTbX" };
+
+// 2D plots
+const double positionasic[4][3] = {
+    { -0.4375, -0.3125, -0.1875 }, // Chip 0
+    { -0.1875, -0.0625, -0.0625 }, // Chip 1
+    { +0.1875, +0.0625, +0.0625 }, // Chip 2
+    { +0.4375, +0.3125, +0.1875 }  // Chip 3
+};
+
+template <masks m>
+[[nodiscard]] static constexpr unsigned int extract( unsigned int i ) {
+  constexpr auto b = std::countr_zero( static_cast<unsigned int>( m ) );
+  return ( i & static_cast<unsigned int>( m ) ) >> b;
+}
+
+// Tools for booking histograms
+namespace Utility {
+  template <typename T, typename OWNER>
+  void map_emplace( T& t, typename T::key_type key, OWNER* owner, std::string const& title,
+                    Gaudi::Accumulators::Axis<typename T::mapped_type::AxisArithmeticType> axis1 ) {
+    t.emplace( std::piecewise_construct, std::forward_as_tuple( key ),
+               std::forward_as_tuple( owner, key, title, axis1 ) );
+  }
+  template <typename T, typename OWNER>
+  void map_emplace( T& t, typename T::key_type key, OWNER* owner, std::string const& title,
+                    Gaudi::Accumulators::Axis<typename T::mapped_type::AxisArithmeticType> axis1,
+                    Gaudi::Accumulators::Axis<typename T::mapped_type::AxisArithmeticType> axis2 ) {
+    t.emplace( std::piecewise_construct, std::forward_as_tuple( key ),
+               std::forward_as_tuple( owner, key, title, axis1, axis2 ) );
+  }
+
+} // namespace Utility
+
+/** ------------------------------------------------------------------------------------------------------------------------ */
+class UTNZSMonitor
+    : public LHCb::Algorithm::Consumer<void( UTDigits const&, UTDigits const&, DeUTDetector const&, LHCb::ODIN const& ),
+                                       LHCb::DetDesc::usesBaseAndConditions<GaudiHistoAlg, DeUTDetector>> {
+public:
+  UTNZSMonitor( const std::string& name, ISvcLocator* svcloc )
+      : Consumer{ name,
+                  svcloc,
+                  { { "InputData", UTDigitLocation::UTDigits },
+                    { "InputErrData", UTDigitLocation::UTDigits },
+                    { "UTLocation", DeUTDetLocation::location() },
+                    { "ODINLocation", LHCb::ODINLocation::Default } } } {}
+  ToolHandle<IUTReadoutTool> readoutTool{ this, "ReadoutTool", "UTReadoutTool" };
+
+  StatusCode initialize() override;
+  void       operator()( const UTDigits&, const UTDigits&, DeUTDetector const&, LHCb::ODIN const& ) const override;
+  void       fillADC( const LHCb::UTDigit*, LHCb::ODIN const& ) const;
+  void       fillFlow( const LHCb::UTDigit* ) const;
+  void       incrementHistogram( GA::ProfileHistogram<2>&, double, double, double, double, float ) const;
+  void       fillHeatMap_naturalunits( const LHCb::UTDigit*, DeUTDetector const& ) const;
+
+private:
+  mutable UTCoordinatesMap UTMap;
+
+  // TELL40 plots
+  mutable Gaudi::Accumulators::HistogramArray<Gaudi::Accumulators::Histogram<2>, s_HistNames.size()>
+      m_UT_Tell_40_vs_asic{ this,
+                            []( int i ) { return fmt::format( "{}", s_HistNames[i] ); },
+                            []( int i ) { return fmt::format( "{}", s_HistNames[i] ); },
+                            { 54, 0, 54 },
+                            { 24, 0, 24 } };
+
+  // The container for Mean_ADC per channel
+  mutable std::map<std::string, GA::ProfileHistogram<1>> m_2d_Mean_ADCCounter;
+  mutable std::map<std::string, GA::ProfileHistogram<1>> m_2d_RMS_ADCCounter;
+  mutable std::map<std::string, GA::Histogram<2>>        m_2d_ADCCounter;
+
+  // 2D plots with MCMS value per chip
+  mutable Gaudi::Accumulators::HistogramArray<Gaudi::Accumulators::ProfileHistogram<2>, 4> m_UT_mcm_strip{
+      this,
+      []( int i ) { return fmt::format( "MCM_strip_Layer{}", i ); },
+      []( int i ) { return fmt::format( "MCM_strip_Layer{} (ASICs)", i ); },
+      { 144, -9, 9, "Staves (ASICs)" },
+      { 28, -7, 7, "Modules" } };
+
+  // 2D plots with MCMS strip per chip
+  mutable Gaudi::Accumulators::HistogramArray<Gaudi::Accumulators::ProfileHistogram<2>, 4> m_UT_mcm_mu{
+      this,
+      []( int i ) { return fmt::format( "MCM_mu_Layer{}", i ); },
+      []( int i ) { return fmt::format( "MCM_mu_Layer{} (ASICs)", i ); },
+      { 144, -9, 9, "Staves (ASICs)" },
+      { 28, -7, 7, "Modules" } };
+
+  // 2D plots with MCMS strip per chip
+  mutable Gaudi::Accumulators::HistogramArray<Gaudi::Accumulators::ProfileHistogram<2>, 4> m_UT_MCM_rms_ADC{
+      this,
+      []( int i ) { return fmt::format( "MCM_rms_Layer{}", i ); },
+      []( int i ) { return fmt::format( "MCM_rms_Layer{} (ASICs)", i ); },
+      { 144, -9, 9, "Staves (ASICs)" },
+      { 28, -7, 7, "Modules" } };
+
+  // 1D plots: ADC
+  mutable GA::Histogram<2> m_nADCvsBCID{ this, "ADCvsBuncId", "ADC vs BuncId", AxisBCID, AxisADC };
+  mutable GA::Histogram<2> m_nADCvsCalibStep{ this, "ADCvsCalibStep", "ADC vs CalibStep", AxisCalib, AxisADC };
+
+  mutable std::map<std::string, Gaudi::Accumulators::SigmaCounter<>> RawADC;
+  mutable std::map<std::string, Gaudi::Accumulators::SigmaCounter<>> mcm;
+
+}; // End of class UTNZSMonitor
+DECLARE_COMPONENT( UTNZSMonitor )
+
+StatusCode UTNZSMonitor::initialize() {
+  return Consumer::initialize().andThen( [&] {
+    // Set the top directory to UT
+    if ( histoTopDir().empty() ) setHistoTopDir( "" );
+
+    for ( const auto& module : UTMap.getModulesNames() ) {
+      Utility::map_emplace( m_2d_Mean_ADCCounter, "Mean_ADC_" + module, this, "Mean_ADC_" + module, { 512, 0, 512 } );
+      Utility::map_emplace( m_2d_RMS_ADCCounter, "RMS_ADC_" + module, this, "RMS_ADC_" + module, { 512, 0, 512 } );
+      Utility::map_emplace( m_2d_ADCCounter, "ADC_" + module, this, "ADC_" + module, { 512, 0, 512 },
+                            { 64, -32.5, 31.5 } );
+    }
+  } );
+}
+
+void UTNZSMonitor::operator()( const UTDigits& digitsCont, const UTDigits& errdigitsCont, DeUTDetector const& det,
+                               LHCb::ODIN const& odin ) const {
+
+  // General counters
+  // -------------------------------------------------------
+  // Loop on digits
+  // side==1 is Aside (left), side==0 is Cside (right)
+  // -------------------------------------------------------
+  for ( const UTDigit* d : digitsCont ) {
+    fillFlow( d );
+    fillADC( d, odin );
+    fillHeatMap_naturalunits( d, det );
+  }
+
+  for ( const UTDigit* d : errdigitsCont ) {
+    fillFlow( d );
+    fillADC( d, odin );
+    fillHeatMap_naturalunits( d, det );
+  }
+  // -------------------------------------------------------
+  // end loop on digits
+  // -------------------------------------------------------
+} // end execute
+
+void UTNZSMonitor::fillADC( const LHCb::UTDigit* aDigit, LHCb::ODIN const& odin ) const {
+
+  // Summary plots
+  ++m_nADCvsBCID[{ odin.bunchId(), aDigit->depositedCharge() }];
+  ++m_nADCvsCalibStep[{ odin.calibrationStep(), aDigit->depositedCharge() }];
+
+  // ADC counter
+  auto tuple = UTMap.getTuple( aDigit->module(), aDigit->face(), aDigit->stave(), aDigit->side(), aDigit->sector() );
+  std::string module_name = std::get<4>( tuple );
+
+  RawADC[UT_layers[aDigit->layer()] + "_" + module_name + "_" + std::to_string( aDigit->strip() )] +=
+      aDigit->depositedCharge();
+
+  m_2d_Mean_ADCCounter.at( "Mean_ADC_" + UT_layers[aDigit->layer()] + "_" + module_name )[aDigit->strip()] +=
+      RawADC[UT_layers[aDigit->layer()] + "_" + module_name + "_" + std::to_string( aDigit->strip() )].mean();
+  m_2d_RMS_ADCCounter.at( "RMS_ADC_" + UT_layers[aDigit->layer()] + "_" + module_name )[aDigit->strip()] +=
+      RawADC[UT_layers[aDigit->layer()] + "_" + module_name + "_" + std::to_string( aDigit->strip() )]
+          .standard_deviation();
+  ++m_2d_ADCCounter.at( "ADC_" + UT_layers[aDigit->layer()] + "_" +
+                        module_name )[{ aDigit->strip(), aDigit->depositedCharge() }];
+}
+
+void UTNZSMonitor::fillFlow( const LHCb::UTDigit* aDigit ) const {
+  Detector::UT::ChannelID channelID = aDigit->channelID();
+  UTDAQID                 daqID     = readoutTool->channelIDToDAQID( channelID );
+  unsigned int            board_ID  = daqID.board();
+  unsigned int            sourceID  = UTMap.getSourceIDfromBoardNumber( board_ID );
+  int                     SourceID_ = sourceID / 1000;
+
+  unsigned int asic_times_lane = aDigit->asic() % 4 + 4 * extract<masks::lane>( aDigit->getdaqID() );
+
+  // Get TELL40 and Flavour only once
+  std::string tell40    = UTMap.getTELL40( sourceID );
+  std::string flavour   = UTMap.getFlavour( tell40 );
+  int         tell40Bin = UTMap.getTELL40Bin( sourceID );
+
+  // Check if the strip is aligned for filling
+  if ( aDigit->strip() % 128 == 0 ) {
+    if ( tell40.find( "UA" ) != std::string::npos ) {
+      // Handle UA sourceID_ == 10 and 11
+      if ( SourceID_ == 10 ) {
+        if ( flavour == "2x4" ) {
+          ++m_UT_Tell_40_vs_asic[0][{ tell40Bin, UTMap.get2_4_Flow0_Bin( asic_times_lane ) }];
+        } else if ( flavour == "2x5" ) {
+          ++m_UT_Tell_40_vs_asic[0][{ tell40Bin, UTMap.get2_5_Flow0_Bin( asic_times_lane ) }];
+        } else if ( flavour == "4x3" || flavour == "2x3" || flavour == "Jx3" ) {
+          ++m_UT_Tell_40_vs_asic[0][{ tell40Bin, asic_times_lane }];
+        }
+      } else if ( SourceID_ == 11 ) {
+        if ( flavour == "2x4" ) {
+          if ( asic_times_lane == 16 || asic_times_lane == 17 ) {
+            ++m_UT_Tell_40_vs_asic[0][{ tell40Bin, UTMap.get2_4_Flow0_Bin( asic_times_lane ) }];
+          } else {
+            ++m_UT_Tell_40_vs_asic[1][{ tell40Bin, UTMap.get2_4_Flow1_Bin( asic_times_lane ) }];
+          }
+        } else if ( flavour == "2x5" ) {
+          ++m_UT_Tell_40_vs_asic[1][{ tell40Bin, UTMap.get2_5_Flow1_Bin( asic_times_lane ) }];
+        } else if ( flavour == "4x3" || flavour == "2x3" || flavour == "Jx3" ) {
+          ++m_UT_Tell_40_vs_asic[1][{ tell40Bin, asic_times_lane }];
+        }
+      }
+    } else if ( tell40.find( "UC" ) != std::string::npos ) {
+      // Handle UC sourceID_ == 12 and 13
+      if ( SourceID_ == 12 ) {
+        if ( flavour == "2x4" ) {
+          ++m_UT_Tell_40_vs_asic[2][{ tell40Bin, UTMap.get2_4_Flow0_Bin( asic_times_lane ) }];
+        } else if ( flavour == "2x5" ) {
+          ++m_UT_Tell_40_vs_asic[2][{ tell40Bin, UTMap.get2_5_Flow0_Bin( asic_times_lane ) }];
+        } else if ( flavour == "4x3" || flavour == "2x3" || flavour == "Jx3" ) {
+          ++m_UT_Tell_40_vs_asic[2][{ tell40Bin, asic_times_lane }];
+        }
+      } else if ( SourceID_ == 13 ) {
+        if ( flavour == "2x4" ) {
+          if ( asic_times_lane == 16 || asic_times_lane == 17 ) {
+            ++m_UT_Tell_40_vs_asic[2][{ tell40Bin, UTMap.get2_4_Flow0_Bin( asic_times_lane ) }];
+          } else {
+            ++m_UT_Tell_40_vs_asic[3][{ tell40Bin, UTMap.get2_4_Flow1_Bin( asic_times_lane ) }];
+          }
+        } else if ( flavour == "2x5" ) {
+          ++m_UT_Tell_40_vs_asic[3][{ tell40Bin, UTMap.get2_5_Flow1_Bin( asic_times_lane ) }];
+        } else if ( flavour == "4x3" || flavour == "2x3" || flavour == "Jx3" ) {
+          ++m_UT_Tell_40_vs_asic[3][{ tell40Bin, asic_times_lane }];
+        }
+      }
+    }
+  }
+}
+
+void UTNZSMonitor::incrementHistogram( GA::ProfileHistogram<2>& histogram, double x, double y, double positionasic_one,
+                                       double positionasic_two, float val ) const {
+
+  histogram[{ x + positionasic_one, y + 0.25 }] += val;
+  histogram[{ x + positionasic_two, y + 0.25 }] += val;
+  histogram[{ x + positionasic_one, y - 0.25 }] += val;
+  histogram[{ x + positionasic_two, y - 0.25 }] += val;
+}
+
+void UTNZSMonitor::fillHeatMap_naturalunits( const LHCb::UTDigit* aDigit, DeUTDetector const& det ) const {
+
+  if ( aDigit->strip() % 128 == 0 ) {
+
+    std::tuple<float, float, float, float, std::string, std::string> tuple =
+        UTMap.getTuple( aDigit->module(), aDigit->face(), aDigit->stave(), aDigit->side(), aDigit->sector() );
+
+    // Let's find out where we are
+    float       x           = std::get<0>( tuple );
+    float       y           = std::get<1>( tuple );
+    std::string module_name = std::get<4>( tuple );
+    std::string type        = std::get<5>( tuple );
+    auto        chanID      = aDigit->channelID();
+    auto        aSector     = det.findSector( chanID );
+#ifdef USE_DD4HEP
+    auto trajStrip0   = aSector.createTraj( 0, 0 );
+    auto trajStrip511 = aSector.createTraj( 511, 0 );
+#else
+    auto trajStrip0   = aSector->trajectory( chanID, 0 );
+    auto trajStrip511 = aSector->trajectory( LHCb::Detector::UT::ChannelID{ chanID + 511 }, 0 );
+#endif
+    double stripx0    = -1 * ( trajStrip0.endPoint().x() + trajStrip0.beginPoint().x() ) * 0.5;
+    double stripx511  = -1 * ( trajStrip511.endPoint().x() + trajStrip511.beginPoint().x() ) * 0.5;
+    double stripwidth = stripx511 - stripx0;
+    int    chip;
+
+    if ( stripwidth > 0 )
+      chip = int( aDigit->strip() / 128 );
+    else
+      chip = 3 - int( aDigit->strip() / 128 );
+
+    double positionasic_one = positionasic[chip][0];
+    double positionasic_two = positionasic[chip][1];
+    double positionasic_thr = positionasic[chip][2];
+
+    float mcm_val = aDigit->mcmVal() + 0.0001; // protection against 0 value in bin which caused problem in displaying
+                                               // histogram sometimes even bigger statistic the average is 0. Monet
+                                               // interpret it as empty bin what is not true.  won't process more
+                                               // than O(4) NMZS events per run so it wont be a problem
+
+    mcm[UT_layers[aDigit->layer()] + "_" + module_name + "_" + std::to_string( chip )] += mcm_val;
+    float mcm_mu = mcm[UT_layers[aDigit->layer()] + "_" + module_name + "_" + std::to_string( chip )].mean() + 0.0001;
+    float MCM_rms_ADC =
+        mcm[UT_layers[aDigit->layer()] + "_" + module_name + "_" + std::to_string( chip )].standard_deviation() + 0.001;
+
+    // Sector map //
+    if ( ( aDigit->stave() > 1 ) || ( fabs( y ) > 2 ) ) {
+      incrementHistogram( m_UT_mcm_strip[aDigit->layer()], x, y, positionasic_one, positionasic_two,
+                          aDigit->mcmStrip() );
+      incrementHistogram( m_UT_mcm_mu[aDigit->layer()], x, y, positionasic_one, positionasic_two, mcm_mu );
+      incrementHistogram( m_UT_MCM_rms_ADC[aDigit->layer()], x, y, positionasic_one, positionasic_two, MCM_rms_ADC );
+    }
+
+    if ( ( ( aDigit->stave() == 1 ) && ( fabs( y ) < 2 ) ) || ( ( aDigit->stave() == 0 ) && ( fabs( y ) == 1.5 ) ) ) {
+      m_UT_mcm_strip[aDigit->layer()][{ x + positionasic_thr, y + 0.25 }] += aDigit->mcmStrip();
+      m_UT_mcm_strip[aDigit->layer()][{ x + positionasic_thr, y - 0.25 }] += aDigit->mcmStrip();
+      m_UT_mcm_mu[aDigit->layer()][{ x + positionasic_thr, y + 0.25 }] += mcm_mu;
+      m_UT_mcm_mu[aDigit->layer()][{ x + positionasic_thr, y - 0.25 }] += mcm_mu;
+      m_UT_MCM_rms_ADC[aDigit->layer()][{ x + positionasic_thr, y + 0.25 }] += MCM_rms_ADC;
+      m_UT_MCM_rms_ADC[aDigit->layer()][{ x + positionasic_thr, y - 0.25 }] += MCM_rms_ADC;
+    }
+
+    if ( ( aDigit->stave() == 0 ) && ( fabs( y ) < 1 ) ) {
+      { m_UT_mcm_strip[aDigit->layer()][{ x + positionasic_thr, y }] += aDigit->mcmStrip(); }
+      { m_UT_mcm_mu[aDigit->layer()][{ x + positionasic_thr, y }] += mcm_mu; }
+      { m_UT_MCM_rms_ADC[aDigit->layer()][{ x + positionasic_thr, y }] += MCM_rms_ADC; }
+    }
+  }
+}
diff --git a/UT/UTMonitors/src/UTSuperTAEMonitor.cpp b/UT/UTMonitors/src/UTSuperTAEMonitor.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b22c76ed5fc63353095e074ec3178bf98ad39455
--- /dev/null
+++ b/UT/UTMonitors/src/UTSuperTAEMonitor.cpp
@@ -0,0 +1,179 @@
+/*****************************************************************************\
+* (c) Copyright 2020 CERN for the benefit of the LHCb Collaboration           *
+*                                                                             *
+* This software is distributed under the terms of the GNU General Public      *
+* Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING".   *
+*                                                                             *
+* In applying this licence, CERN does not waive the privileges and immunities *
+* granted to it by virtue of its status as an Intergovernmental Organization  *
+* or submit itself to any jurisdiction.                                       *
+\*****************************************************************************/
+
+#include "Event/ODIN.h"
+#include "Event/TAEUtils.h"
+#include "Event/UTDigit.h"
+#include "Gaudi/Accumulators/Histogram.h"
+#include "GaudiAlg/GaudiHistoAlg.h"
+#include "GaudiKernel/GaudiException.h"
+#include "GaudiKernel/PhysicalConstants.h"
+#include "GaudiKernel/SystemOfUnits.h"
+#include "Kernel/IUTReadoutTool.h"
+#include "Kernel/STLExtensions.h"
+#include "Kernel/UTDAQID.h"
+#include "LHCbAlgs/Consumer.h"
+#include "LHCbAlgs/MergingTransformer.h"
+#include "UTDAQ/UTCoordinatesMap.h"
+#include "UTDet/DeUTDetector.h"
+
+/** @class UTSuperTAEMonitor UTSuperTAEMonitor.cpp
+ * --------------------------------------------------
+ *  Counters for additional monitoring of UT (UT in global)
+ *  The algorithm produces several useful histograms
+ *  @author Wojciech Krupa
+ *  @date   2024/10/07
+ * --------------------------------------------------
+ **/
+
+using ODIN        = LHCb::ODIN;
+using ODINVector  = Gaudi::Functional::vector_of_const_<ODIN const*>;
+using InputVector = Gaudi::Functional::vector_of_const_<LHCb::UTDigits const*>;
+using BXTypes     = LHCb::ODIN::BXTypes;
+using EventTypes  = LHCb::ODIN::EventTypes;
+using namespace LHCb;
+namespace GA = Gaudi::Accumulators;
+
+// Tools for booking histograms
+namespace Utility {
+  template <typename T, typename OWNER>
+  void map_emplace( T& t, typename T::key_type key, OWNER* owner, std::string const& title,
+                    Gaudi::Accumulators::Axis<typename T::mapped_type::AxisArithmeticType> axis1,
+                    Gaudi::Accumulators::Axis<typename T::mapped_type::AxisArithmeticType> axis2 ) {
+    t.emplace( std::piecewise_construct, std::forward_as_tuple( key ),
+               std::forward_as_tuple( owner, key, title, axis1, axis2 ) );
+  }
+} // namespace Utility
+
+class UTSuperTAEMonitor final : public LHCb::Algorithm::MergingConsumer<void( ODINVector const&, InputVector const& )> {
+
+public:
+  UTSuperTAEMonitor( const std::string&, ISvcLocator* );
+  StatusCode initialize() override;
+  void       operator()( ODINVector const&, InputVector const& ) const override;
+  void       fillHistograms( const LHCb::UTDigit*, LHCb::ODIN const&, int ) const;
+
+private:
+  LHCb::TAE::Handler          m_taeHandler{ this };
+  mutable UTCoordinatesMap    UTMap;
+  Gaudi::Property<signed int> m_HalfWindow{ this, "HalfWindow", 3 };
+
+  using Histogram1D        = GA::Histogram<1, GA::atomicity::full, float>;
+  using Histogram2D        = GA::Histogram<2, GA::atomicity::full, float>;
+  using ProfileHistogram   = GA::ProfileHistogram<1, GA::atomicity::full, float>;
+  using ProfileHistogram2D = GA::ProfileHistogram<2, GA::atomicity::full, float>;
+  using Axis               = GA::Axis<float>;
+
+  // Definition of axis
+  const GA::Axis<double> AxisADC        = GA::Axis<double>( 64, -32.5, 31.5, "nADC" );       //-32-31
+  const GA::Axis<double> AxisADC_signed = GA::Axis<double>( 32, -0.5, 31.5, "nADC" );        // 0-31
+  const GA::Axis<double> AxisBCID       = GA::Axis<double>( 3565, -0.5, 3564.5, "BunchID" ); //
+  const GA::Axis<double> AxisDIGIT      = GA::Axis<double>( 101, -0.5, 100.5, "UTDigits (size of digit container)" );
+  const GA::Axis<double> AxisTAE =
+      GA::Axis<double>( 2 * m_HalfWindow + 1, -1 * m_HalfWindow - 0.5, m_HalfWindow + 0.5, "TAE index" );
+
+  const std::array<std::string, 4> UT_layers = { "UTaX", "UTaU", "UTbV", "UTbX" };
+
+  // General TAE counters
+  mutable Gaudi::Accumulators::Histogram<1> m_bxtype{ this, "BXType", "BXType", { 4, -0.5, 3.5 } };
+  mutable Gaudi::Accumulators::Histogram<1> m_trgtype{ this, "TrgType", "TrgType", { 16, -0.5, 15.5 } };
+  mutable Gaudi::Accumulators::Histogram<2> m_bcid_bxtype{
+      this, "BXTypeVsBXID", "BXTypeVsBXID", AxisBCID, { 4, -0.5, 3.5 } };
+  mutable Gaudi::Accumulators::Histogram<2> m_bcid_trgtype{
+      this, "TrgTypeVsBXID", "TrgTypeVsBXID", AxisBCID, { 16, -0.5, 15.5 } };
+  mutable Gaudi::Accumulators::WeightedHistogram<2> m_bcid_taesummary{
+      this, "TAESummary", "TAE summary", AxisBCID, { 14, -0.5, -0.5 + 14 } };
+  mutable Gaudi::Accumulators::Histogram<2> m_bcid_taeindex{
+      this, "TAEIndex", "TAE index", AxisBCID, { 64, -0.5, -0.5 + 64 } };
+
+  // Counters TAE step vs ADC per DCB or per quadrant or UT
+  mutable std::map<std::string, GA::Histogram<2>> m_2d_DCB_tae_adc;
+  mutable std::map<std::string, GA::Histogram<2>> m_2d_DCBQuadrant_tae_adc;
+  mutable Gaudi::Accumulators::Histogram<2>       m_2d_UT_tae_adc{ this, "UTTAE", "UTTAE", AxisTAE, AxisADC_signed };
+};
+
+// Declaration of the Algorithm Factory
+DECLARE_COMPONENT( UTSuperTAEMonitor )
+
+UTSuperTAEMonitor::UTSuperTAEMonitor( const std::string& name, ISvcLocator* pSvcLocator )
+    : LHCb::Algorithm::MergingConsumer<void( ODINVector const&, InputVector const& )>(
+          name, pSvcLocator, { KeyValues{ "ODINVector", {} }, KeyValues{ "InputVector", {} } } ){};
+
+StatusCode UTSuperTAEMonitor::initialize() {
+  return base_class::initialize().andThen( [&] {
+    // Set the top directory to UT
+    // Initialise counters
+    for ( const auto& DCB : UTMap.getDCBsAside() ) {
+      Utility::map_emplace( m_2d_DCB_tae_adc, DCB, this, DCB, AxisTAE, AxisADC_signed );
+    }
+    for ( const auto& DCB : UTMap.getDCBsCside() ) {
+      Utility::map_emplace( m_2d_DCB_tae_adc, DCB, this, DCB, AxisTAE, AxisADC_signed );
+    }
+    for ( const auto& DCBQuadrant : UTMap.getDCBQuadrants() ) {
+      Utility::map_emplace( m_2d_DCBQuadrant_tae_adc, DCBQuadrant, this, DCBQuadrant, AxisTAE, AxisADC_signed );
+    }
+  } );
+}
+
+void UTSuperTAEMonitor::operator()( ODINVector const& odinVector, InputVector const& inputVector ) const {
+
+  auto taeEvents = m_taeHandler.arrangeTAE( odinVector, inputVector, 3 );
+
+  if ( taeEvents.empty() ) { return; }
+
+  for ( auto it = taeEvents.begin(); it != taeEvents.end(); ++it ) {
+    int                   offset     = it->first; // 0 is central, negative for Prev, positive for Next
+    const LHCb::ODIN&     odin       = it->second.first;
+    const LHCb::UTDigits& digitsCont = it->second.second;
+
+    for ( auto d_it = digitsCont.begin(); d_it != digitsCont.end(); ++d_it ) { fillHistograms( *d_it, odin, offset ); }
+  }
+}
+
+void UTSuperTAEMonitor::fillHistograms( const LHCb::UTDigit* aDigit, LHCb::ODIN const& odin, int offset ) const {
+
+  // Let's find where we are in UT
+  auto tuple = UTMap.getTuple( aDigit->module(), aDigit->face(), aDigit->stave(), aDigit->side(), aDigit->sector() );
+  std::string                module_name = std::get<4>( tuple );
+  auto                       y_p         = std::get<1>( tuple );
+  std::string                position    = ( y_p > 0 ) ? "T" : "B";
+  std::string                side        = ( aDigit->side() == 0 ) ? "C" : "A";
+  std::array<std::string, 4> layer       = { "UTaX", "UTaU", "UTbV", "UTbX" };
+  std::string                station     = ( aDigit->layer() < 2 ) ? "a" : "b";
+  std::string                dcb_name    = UTMap.getDCB( layer[aDigit->layer()] + "_" + module_name );
+  int                        TAEindex    = offset; //
+
+  // Let's find where we are in the LHCb
+  auto bcid    = odin.bunchId();
+  auto bx      = static_cast<uint8_t>( odin.bunchCrossingType() );
+  auto trgtype = odin.triggerType();
+
+  // simple counters
+  ++m_bxtype[bx];
+  ++m_trgtype[trgtype];
+  ++m_bcid_bxtype[{ bcid, bx }];
+  ++m_bcid_trgtype[{ bcid, trgtype }];
+
+  // summary plots this should be replaced by odin.eventType soon as below
+  double weight  = 1;
+  int    offset2 = 0;
+  m_bcid_taesummary[{ bcid, offset2 + bx }] += weight;
+  offset2 += 4;
+  m_bcid_taesummary[{ bcid, offset2++ }] += weight * odin.isTAE();
+  m_bcid_taesummary[{ bcid, offset2++ }] += weight * odin.timeAlignmentEventCentral();
+  m_bcid_taesummary[{ bcid, offset2++ }] += weight * odin.timeAlignmentEventFirst();
+
+  ++m_bcid_taeindex[{ bcid, odin.timeAlignmentEventIndex() }];
+  ++m_2d_UT_tae_adc[{ TAEindex, aDigit->depositedCharge() }];
+  ++m_2d_DCB_tae_adc.at( dcb_name )[{ TAEindex, aDigit->depositedCharge() }];
+  ++m_2d_DCBQuadrant_tae_adc.at(
+      UTMap.getDCBQuadrant( layer[aDigit->layer()] + "_" + module_name ) )[{ TAEindex, aDigit->depositedCharge() }];
+};
diff --git a/UT/UTMonitors/src/UTTAEMonitor.cpp b/UT/UTMonitors/src/UTTAEMonitor.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8d64c8f747f4f829a8b070df30330a19f4748c0a
--- /dev/null
+++ b/UT/UTMonitors/src/UTTAEMonitor.cpp
@@ -0,0 +1,165 @@
+/*****************************************************************************\
+* (c) Copyright 2000-2018 CERN for the benefit of the LHCb Collaboration      *
+*                                                                             *
+* This software is distributed under the terms of the GNU General Public      *
+* Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING".   *
+*                                                                             *
+* In applying this licence, CERN does not waive the privileges and immunities *
+* granted to it by virtue of its status as an Intergovernmental Organization  *
+* or submit itself to any jurisdiction.                                       *
+\*****************************************************************************/
+
+#include "Event/ODIN.h"
+#include "Event/UTDigit.h"
+#include "Gaudi/Accumulators/Histogram.h"
+#include "GaudiAlg/GaudiHistoAlg.h"
+#include "Kernel/IUTReadoutTool.h"
+#include "Kernel/STLExtensions.h"
+#include "Kernel/UTDAQID.h"
+#include "LHCbAlgs/Consumer.h"
+#include "UTDAQ/UTCoordinatesMap.h"
+
+/** @class UTTAEMonitor UTTAEMonitor.h
+ * --------------------------------------------------
+ *  Class for monitoring TAE in Monet (UT in local)
+ *  @author W. Krupa
+ *  @author C. Hadjivasiliou
+ *  @date   2024/03/19
+ * --------------------------------------------------
+ **/
+
+namespace GA = Gaudi::Accumulators;
+using namespace LHCb;
+using EventTypes = LHCb::ODIN::EventTypes;
+
+// Tools for booking histograms
+namespace Utility {
+  template <typename T, typename OWNER>
+  void map_emplace( T& t, typename T::key_type key, OWNER* owner, std::string const& title,
+                    Gaudi::Accumulators::Axis<typename T::mapped_type::AxisArithmeticType> axis1,
+                    Gaudi::Accumulators::Axis<typename T::mapped_type::AxisArithmeticType> axis2 ) {
+    t.emplace( std::piecewise_construct, std::forward_as_tuple( key ),
+               std::forward_as_tuple( owner, key, title, axis1, axis2 ) );
+  }
+} // namespace Utility
+
+const std::array<std::string, 4> UT_layers = { "UTaX", "UTaU", "UTbV", "UTbX" };
+
+class UTTAEMonitor : public LHCb::Algorithm::Consumer<void( UTDigits const&, UTDigits const&, LHCb::ODIN const& ),
+                                                      LHCb::DetDesc::usesBaseAndConditions<GaudiHistoAlg>> {
+
+public:
+  UTTAEMonitor( const std::string&, ISvcLocator* );
+  StatusCode initialize() override;
+  void       operator()( const UTDigits&, const UTDigits&, LHCb::ODIN const& ) const override;
+  void       fillHistograms( const LHCb::UTDigit*, LHCb::ODIN const& ) const;
+
+  ToolHandle<IUTReadoutTool>  readoutTool{ this, "ReadoutTool", "UTReadoutTool" };
+  mutable UTCoordinatesMap    UTMap;
+  Gaudi::Property<signed int> m_HalfWindow{ this, "HalfWindow", 3 };
+
+  // Definition of axis
+  const GA::Axis<double> AxisADC        = GA::Axis<double>( 64, -32.5, 31.5, "nADC" );       //-32-31
+  const GA::Axis<double> AxisADC_signed = GA::Axis<double>( 32, -0.5, 31.5, "nADC" );        // 0-31
+  const GA::Axis<double> AxisBCID       = GA::Axis<double>( 3565, -0.5, 3564.5, "BunchID" ); //
+  const GA::Axis<double> AxisDIGIT      = GA::Axis<double>( 101, -0.5, 100.5, "UTDigits (size of digit container)" );
+  const GA::Axis<double> AxisTAE = GA::Axis<double>( 2 * m_HalfWindow + 1, -1 * m_HalfWindow - 0.5, m_HalfWindow + 0.5,
+                                                     "TAE index" ); // for windows 3 - central is 4
+private:
+  // General counters
+  mutable Gaudi::Accumulators::Histogram<1> m_bxtype{ this, "BXType", "BXType", { 4, -0.5, 3.5 } };
+  mutable Gaudi::Accumulators::Histogram<1> m_trgtype{ this, "TrgType", "TrgType", { 16, -0.5, 15.5 } };
+  mutable Gaudi::Accumulators::Histogram<2> m_bcid_bxtype{
+      this, "BXTypeVsBXID", "BXTypeVsBXID", AxisBCID, { 4, -0.5, 3.5 } };
+  mutable Gaudi::Accumulators::Histogram<2> m_bcid_trgtype{
+      this, "TrgTypeVsBXID", "TrgTypeVsBXID", AxisBCID, { 16, -0.5, 15.5 } };
+  mutable Gaudi::Accumulators::WeightedHistogram<2> m_bcid_taesummary{
+      this, "TAESummary", "TAE summary", AxisBCID, { 14, -0.5, -0.5 + 14 } };
+  mutable Gaudi::Accumulators::Histogram<2> m_bcid_taeindex{
+      this, "TAEIndex", "TAE index", AxisBCID, { 64, -0.5, -0.5 + 64 } };
+
+  // Counters TAE step vs ADC per DCB or per quadrant or UT
+  mutable std::map<std::string, GA::Histogram<2>> m_2d_DCB_tae_adc;
+  mutable std::map<std::string, GA::Histogram<2>> m_2d_DCBQuadrant_tae_adc;
+  mutable Gaudi::Accumulators::Histogram<2>       m_2d_UT_tae_adc{ this, "UTTAE", "UTTAE", AxisTAE, AxisADC_signed };
+};
+DECLARE_COMPONENT( UTTAEMonitor )
+
+UTTAEMonitor::UTTAEMonitor( const std::string& name, ISvcLocator* svcloc )
+    : Consumer{ name,
+                svcloc,
+                { { "InputData", UTDigitLocation::UTDigits },
+                  { "InputErrorData", UTDigitLocation::UTDigits },
+                  { "ODINLocation", LHCb::ODINLocation::Default } } } {}
+
+StatusCode UTTAEMonitor::initialize() {
+  return Consumer::initialize().andThen( [&] {
+    // Set the top directory to UT
+    if ( histoTopDir().empty() ) setHistoTopDir( "UT/" );
+    for ( const auto& DCB : UTMap.getDCBsAside() ) {
+      Utility::map_emplace( m_2d_DCB_tae_adc, DCB, this, DCB, AxisTAE, AxisADC_signed );
+    }
+    for ( const auto& DCB : UTMap.getDCBsCside() ) {
+      Utility::map_emplace( m_2d_DCB_tae_adc, DCB, this, DCB, AxisTAE, AxisADC_signed );
+    }
+    for ( const auto& DCBQuadrant : UTMap.getDCBQuadrants() ) {
+      Utility::map_emplace( m_2d_DCBQuadrant_tae_adc, DCBQuadrant, this, DCBQuadrant, AxisTAE, AxisADC_signed );
+    }
+  } );
+}
+
+void UTTAEMonitor::operator()( const UTDigits& digitsCont, const UTDigits& errdigitsCont,
+                               LHCb::ODIN const& odin ) const {
+
+  // Loop over UTDigits
+  for ( const auto& d : digitsCont ) { fillHistograms( d, odin ); }
+  // Loop over UTErrDigits
+  for ( const auto& d : errdigitsCont ) { fillHistograms( d, odin ); }
+}
+
+void UTTAEMonitor::fillHistograms( const LHCb::UTDigit* aDigit, LHCb::ODIN const& odin ) const {
+
+  // Let's find where we are in UT
+  auto tuple = UTMap.getTuple( aDigit->module(), aDigit->face(), aDigit->stave(), aDigit->side(), aDigit->sector() );
+  std::string                module_name = std::get<4>( tuple );
+  auto                       y_p         = std::get<1>( tuple );
+  std::string                position    = ( y_p > 0 ) ? "T" : "B";
+  std::string                side        = ( aDigit->side() == 0 ) ? "C" : "A";
+  std::array<std::string, 4> layer       = { "UTaX", "UTaU", "UTbV", "UTbX" };
+  std::string                station     = ( aDigit->layer() < 2 ) ? "a" : "b";
+  std::string                dcb_name    = UTMap.getDCB( layer[aDigit->layer()] + "_" + module_name );
+  unsigned int               TAEindex    = odin.timeAlignmentEventIndex();
+
+  // Let's find where we are in the LHCb
+  auto bcid    = odin.bunchId();
+  auto bx      = static_cast<uint8_t>( odin.bunchCrossingType() );
+  auto trgtype = odin.triggerType();
+
+  // simple counters
+  ++m_bxtype[bx];
+  ++m_trgtype[trgtype];
+  ++m_bcid_bxtype[{ bcid, bx }];
+  ++m_bcid_trgtype[{ bcid, trgtype }];
+
+  // summary plots this should be replace by odin.eventType soon as below
+  double weight = 1;
+  int    offset = 0;
+  m_bcid_taesummary[{ bcid, offset + bx }] += weight;
+  offset += 4;
+  m_bcid_taesummary[{ bcid, offset++ }] += weight * odin.isTAE();
+  m_bcid_taesummary[{ bcid, offset++ }] += weight * odin.timeAlignmentEventCentral();
+  m_bcid_taesummary[{ bcid, offset++ }] += weight * odin.timeAlignmentEventFirst();
+
+  // for ( auto const& et : TAEEventTypes ) { m_bcid_taesummary[{bcid, offset++}] += weight * odin.eventTypeBit( et
+  // );}
+
+  ++m_bcid_taeindex[{ bcid, odin.timeAlignmentEventIndex() }];
+
+  if ( TAEindex != 0 ) {
+    int offset = TAEindex - m_HalfWindow - 1; // let's alligne that with superTAE
+    ++m_2d_UT_tae_adc[{ offset, aDigit->depositedCharge() }];
+    ++m_2d_DCB_tae_adc.at( dcb_name )[{ offset, aDigit->depositedCharge() }];
+    ++m_2d_DCBQuadrant_tae_adc.at(
+        UTMap.getDCBQuadrant( layer[aDigit->layer()] + "_" + module_name ) )[{ offset, aDigit->depositedCharge() }];
+  }
+};
diff --git a/UT/UTMonitors/src/UTVeloUTCorrelationsMonitor.cpp b/UT/UTMonitors/src/UTVeloUTCorrelationsMonitor.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..eb9a0ad0f69b2be9c172d767ca3a06f889d45ac9
--- /dev/null
+++ b/UT/UTMonitors/src/UTVeloUTCorrelationsMonitor.cpp
@@ -0,0 +1,134 @@
+/***************************************************************************** \
+* (c) Copyright 2000-2018 CERN for the benefit of the LHCb Collaboration      *
+*                                                                             *
+* This software is distributed under the terms of the GNU General Public      *
+* Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING".   *
+*                                                                             *
+* In applying this licence, CERN does not waive the privileges and immunities *
+* granted to it by virtue of its status as an Intergovernmental Organization  *
+* or submit itself to any jurisdiction.                                       *
+\*****************************************************************************/
+
+#include "Event/ODIN.h"
+#include "Event/RawBank.h"
+#include "Event/RawEvent.h"
+#include "Event/UTDigit.h"
+#include "Gaudi/Accumulators/Histogram.h"
+#include "Gaudi/Accumulators/HistogramArray.h"
+#include "GaudiAlg/GaudiHistoAlg.h"
+#include "Kernel/IUTReadoutTool.h"
+#include "Kernel/UTDAQBoard.h"
+#include "Kernel/UTDAQDefinitions.h"
+#include "Kernel/UTDAQID.h"
+#include "LHCbAlgs/Consumer.h"
+#include "LHCbAlgs/Transformer.h"
+#include "UTDAQ/UTCoordinatesMap.h"
+#include "UTDAQ/UTDAQHelper.h"
+#include "UTDAQ/UTInfo.h"
+
+// Needed for VELO
+#include "Event/VPFullCluster.h"
+#include "Kernel/VPConstants.h"
+
+/** @class UTVeloUTCorrelationsMonitor UTVeloUTCorrelationsMonitor.cpp
+ * --------------------------------------------------
+ *  Counters for Monet: correlation monitors
+ *  The algorithm produces correlation plots for hits
+ *  @author Paolo Gandini
+ *  @author Wojciech Krupa
+ *  @date  2024/04/20
+ * --------------------------------------------------
+ **/
+
+using namespace LHCb;
+namespace GA = Gaudi::Accumulators;
+
+// Definition of axis
+const GA::Axis<double> AxisADC        = GA::Axis<double>( 64, -32.5, 31.5, "nADC" );       //-32, 31
+const GA::Axis<double> AxisADC_signed = GA::Axis<double>( 31, -0.5, 31.5, "nADC" );        // 0-31
+const GA::Axis<double> AxisBCID       = GA::Axis<double>( 3565, -0.5, 3564.5, "BunchID" ); //
+const GA::Axis<double> AxisDIGIT      = GA::Axis<double>( 1001, -0.5, 10000.5, "# UT" );
+const GA::Axis<double> AxisVeloDIGIT  = GA::Axis<double>( 1001, -0.5, 10000.5, "# Velo" );
+
+// UT layers
+const std::array<std::string, 4> UT_layers = { "UTaX", "UTaU", "UTbV", "UTbX" };
+
+enum class masks { channel = 0x000001ff, lane = 0x00000e00, board = 0x000ff000 };
+template <masks m>
+[[nodiscard]] static constexpr unsigned int extract( unsigned int i ) {
+  constexpr auto b = std::countr_zero( static_cast<unsigned int>( m ) );
+  return ( i & static_cast<unsigned int>( m ) ) >> b;
+}
+
+/** ------------------------------------------------------------------------------------------------------------------------ */
+class UTVeloUTCorrelationsMonitor
+    : public LHCb::Algorithm::Consumer<void( UTDigits const&, UTDigits const&, LHCb::ODIN const&,
+                                             std::vector<VPFullCluster> const& ),
+                                       LHCb::DetDesc::usesBaseAndConditions<GaudiHistoAlg>> {
+public:
+  UTVeloUTCorrelationsMonitor( const std::string& name, ISvcLocator* svcloc )
+      : Consumer{ name,
+                  svcloc,
+                  {
+                      { "InputData", UTDigitLocation::UTDigits },
+                      { "InputErrorData", UTDigitLocation::UTDigits },
+                      { "ODINLocation", LHCb::ODINLocation::Default },
+                      { "VeloClusterLocation", LHCb::VPFullClusterLocation::Default },
+                  } } {}
+  ToolHandle<IUTReadoutTool> readoutTool{ this, "ReadoutTool", "UTReadoutTool" };
+
+  void operator()( const UTDigits&, const UTDigits&, LHCb::ODIN const&,
+                   const std::vector<LHCb::VPFullCluster>& ) const override;
+
+  StatusCode initialize() override {
+    return Consumer::initialize().andThen( [&] {
+      // Set the top directory to UT
+      if ( histoTopDir().empty() ) setHistoTopDir( "" );
+    } );
+  }
+
+private:
+  // General plots
+  mutable GA::Histogram<1> m_nUTDigits{ this, "nUTDigits", "Total UT Digits", AxisDIGIT };
+  mutable GA::Histogram<1> m_nVeloDigits{ this, "nVeloDigits", "Total Velo Digits", AxisVeloDIGIT };
+  mutable GA::Histogram<2> m_nUTnVeloDigits{ this, "nUTnVeloDigits", "nUT vs nVELO", AxisDIGIT, AxisVeloDIGIT };
+  mutable GA::Histogram<2> m_nUTnVeloDigits_bb{ this, "nUTnVeloDigits_bb", "nUT vs nVELO - bb", AxisDIGIT,
+                                                AxisVeloDIGIT };
+  mutable GA::Histogram<2> m_nUTnVeloDigits_be{ this, "nUTnVeloDigits_be", "nUT vs nVELO - be", AxisDIGIT,
+                                                AxisVeloDIGIT };
+  mutable GA::Histogram<2> m_nUTnVeloDigits_eb{ this, "nUTnVeloDigits_eb", "nUT vs nVELO - eb", AxisDIGIT,
+                                                AxisVeloDIGIT };
+  mutable GA::Histogram<2> m_nUTnVeloDigits_ee{ this, "nUTnVeloDigits_ee", "nUT vs nVELO - ee", AxisDIGIT,
+                                                AxisVeloDIGIT };
+
+  mutable GA::HistogramArray<GA::Histogram<2>, 4> m_nUTnVeloDigits_bx{
+      this,
+      []( int i ) { return fmt::format( "nUTnVeloDigits_bx{}", i ); },
+      []( int i ) { return fmt::format( "nUTnVeloDigits BXID{}", i ); },
+      { 201, -0.5, 400.5, "# UT" },
+      { 201, -0.5, 400.5, "# Velo" } };
+
+}; // End of class UTVeloUTCorrelationsMonitor
+DECLARE_COMPONENT( UTVeloUTCorrelationsMonitor )
+
+void UTVeloUTCorrelationsMonitor::operator()( const UTDigits& digitsCont, const UTDigits& errdigitsCont,
+                                              LHCb::ODIN const&                       odin,
+                                              const std::vector<LHCb::VPFullCluster>& vpClusters ) const {
+
+  // General counters
+  const unsigned int nBuncId           = odin.bunchId();
+  const int          bunchCrossingType = (int)odin.bunchCrossingType();
+  ++m_nUTDigits[digitsCont.size() + errdigitsCont.size()];
+  ++m_nVeloDigits[vpClusters.size()];
+  ++m_nUTnVeloDigits[{ digitsCont.size() + errdigitsCont.size(), vpClusters.size() }];
+  ++m_nUTnVeloDigits_bx[bunchCrossingType][{ digitsCont.size() + errdigitsCont.size(), vpClusters.size() }];
+
+  if ( odin.bunchCrossingType() == LHCb::ODIN::BXTypes::BeamCrossing )
+    ++m_nUTnVeloDigits_bb[{ digitsCont.size() + errdigitsCont.size(), vpClusters.size() }];
+  else if ( odin.bunchCrossingType() == LHCb::ODIN::BXTypes::Beam1 )
+    ++m_nUTnVeloDigits_be[{ digitsCont.size() + errdigitsCont.size(), vpClusters.size() }];
+  else if ( odin.bunchCrossingType() == LHCb::ODIN::BXTypes::Beam2 )
+    ++m_nUTnVeloDigits_eb[{ digitsCont.size() + errdigitsCont.size(), vpClusters.size() }];
+  else if ( odin.bunchCrossingType() == LHCb::ODIN::BXTypes::NoBeam )
+    ++m_nUTnVeloDigits_ee[{ digitsCont.size() + errdigitsCont.size(), vpClusters.size() }];
+}