diff --git a/CaloFuture/CaloFutureMoniDst/src/CaloHistogramSink.cpp b/CaloFuture/CaloFutureMoniDst/src/CaloHistogramSink.cpp
index 5a9634acd8fe68c7b1c47fd46d96954540db74b9..31af8adf5af2eb97ef719d1caea717bd1ec05fd6 100644
--- a/CaloFuture/CaloFutureMoniDst/src/CaloHistogramSink.cpp
+++ b/CaloFuture/CaloFutureMoniDst/src/CaloHistogramSink.cpp
@@ -9,208 +9,12 @@
 * or submit itself to any jurisdiction.                                             *
 \***********************************************************************************/
 
-#include <CaloFutureUtils/CellIDHistogram.h>
-#include <Detector/Calo/CaloCellID.h>
+#include <CaloFutureUtils/CellIDHistogramUtils.h>
 
 #include <HistogramPersistencySvc/RootHistogramSinkBase.h>
-#include <HistogramPersistencySvc/RootHistogramUtils.h>
-
-#include <TH2D.h>
-#include <TH3D.h>
-#include <TProfile2D.h>
-#include <TProfile3D.h>
 
 namespace GHSink = Gaudi::Histograming::Sink;
 
-namespace {
-
-  /// description of Calorimeter geometry -- FIXME: READ FROM GEOMETRY
-  struct CaloParams {
-    int   centre;       // centre of the Calorimeter in nb rows/cols
-    int   reg;          // nb divisions of biggest cell used in the histogram
-    int   firstRow;     // nb empty rows at the top/bottom, as the calorimeters are not squares
-    float maxCellSizes; // size in mm of the biggest cell
-  };
-  constexpr CaloParams   EcalParams        = {32, 6, 6, 121.2};
-  constexpr CaloParams   HcalParams        = {16, 2, 3, 262.6};
-  constexpr unsigned int NEcalRootHistBins = ( EcalParams.centre * 2 * EcalParams.reg + 2 ) *
-                                             ( ( EcalParams.centre - EcalParams.firstRow ) * 2 * EcalParams.reg + 2 );
-
-  /// Small enum for the different type of histos a Trait can deal with
-  enum class HistoFlavour {
-    Regular,     // plain, regular histogram, meaning non profile
-    Profile,     // profile histogram, to be kept as such
-    ProfileMean, // profile histogram, to be converted to a regular one hosting the mean values
-    ProfileRMS   // profile histogram, to be converted to a regular one hosting the RMS values
-  };
-
-  /// patches a name depending on the flavour
-  template <HistoFlavour flavour>
-  std::string patchName( std::string& name ) {
-    if constexpr ( flavour == HistoFlavour::ProfileMean ) return name + "_Mean";
-    if constexpr ( flavour == HistoFlavour::ProfileRMS ) return name + "_RMS";
-    return name;
-  }
-
-  /// update a histogram bin, according to the given flavour
-  template <HistoFlavour flavour, typename Histo, typename WeightType>
-  void updateHistoBin( Histo& histo, int bin, WeightType weight ) {
-    if constexpr ( flavour == HistoFlavour::Regular ) {
-      histo.SetBinContent( bin, weight );
-    } else {
-      auto [c, sumWeight2]       = weight;
-      auto [nEntries, sumWeight] = c;
-      if constexpr ( flavour == HistoFlavour::ProfileRMS ) {
-        auto rms = 0;
-        if ( nEntries > 0 ) {
-          auto variance = ( sumWeight2 - sumWeight * ( sumWeight / nEntries ) ) / nEntries;
-          rms           = ( variance > 0 ) ? sqrt( variance ) : 0;
-        }
-        histo.SetBinContent( bin, rms );
-      } else if constexpr ( flavour == HistoFlavour::ProfileMean ) {
-        histo.SetBinContent( bin, nEntries > 0 ? sumWeight / nEntries : 0 );
-      } else if constexpr ( flavour == HistoFlavour::Profile ) {
-        histo.setBinNEntries( bin, nEntries );
-        histo.SetBinContent( bin, sumWeight );
-        histo.setBinW2( bin, sumWeight2 );
-      }
-    }
-  }
-
-  /// Traits handling 1D CellID based histograms, all flavours
-  template <HistoFlavour flavour = HistoFlavour::Regular>
-  struct Traits1D {
-    static constexpr unsigned int Dimension{1};
-    using Histo =
-        std::conditional_t<flavour == HistoFlavour::Profile, GHSink::details::ProfileWrapper<TProfile2D>, TH2D>;
-    using WeightType = std::conditional_t<flavour != HistoFlavour::Regular,
-                                          std::tuple<std::tuple<unsigned int, double>, double>, double>;
-
-    template <typename Axis>
-    static Histo create( std::string& name, std::string& title, Axis& axis ) {
-      auto const& cp    = axis.minValue == 0 ? EcalParams : HcalParams;
-      int         nbCol = cp.centre * 2;
-      int         nbRow = ( cp.centre - cp.firstRow ) * 2;
-      auto        xmax  = cp.maxCellSizes * nbCol / 2.;
-      auto        ymax  = cp.maxCellSizes * nbRow / 2.;
-      return Histo{
-          patchName<flavour>( name ).c_str(), title.c_str(), nbCol * cp.reg, -xmax, xmax, nbRow * cp.reg, -ymax, ymax};
-    }
-
-    static auto fill( Histo& histo, unsigned int i, const WeightType& weight ) {
-      bool               isEcal = histo.GetNcells() == NEcalRootHistBins;
-      auto const&        cp     = isEcal ? EcalParams : HcalParams;
-      unsigned int const nbCells =
-          isEcal ? LHCb::Detector::Calo::Index::nbEcalCells() : LHCb::Detector::Calo::Index::nbHcalCells();
-      // ignore under / overflow bin, they are not used by construction
-      if ( i == 0 || i == nbCells ) return;
-      int                          cellNumber = i - 1 + ( isEcal ? 0 : LHCb::Detector::Calo::Index::nbEcalCells() );
-      LHCb::Detector::Calo::CellID id         = LHCb::Detector::Calo::DenseIndex::details::toCellID( cellNumber );
-      // loop over cell area ( ibox * ibox bins depending on CaloFuture/Area)
-      const unsigned int ibox     = cp.reg / ( id.area() + 1 );
-      auto               cellSize = cp.maxCellSizes / cp.reg;
-      for ( unsigned int ir = 0; ir < ibox; ir++ ) {
-        int    iir = ( id.row() - cp.centre ) * ibox + ir;
-        double y   = cellSize * ( iir + 0.5 );
-        for ( unsigned int ic = 0; ic < ibox; ic++ ) {
-          int    iic = ( id.col() - cp.centre ) * ibox + ic;
-          double x   = cellSize * ( iic + 0.5 );
-          auto   bin = histo.FindBin( x, y );
-          updateHistoBin<flavour>( histo, bin, weight );
-        }
-      }
-    }
-
-    static void fillMetaData( Histo& histo, nlohmann::json const&, unsigned int nentries ) {
-      auto const& cp = histo.GetNcells() == NEcalRootHistBins ? EcalParams : HcalParams;
-      histo.SetEntries( nentries * cp.reg * cp.reg );
-    }
-  };
-
-  /// Traits handling 2D CellID based histograms, all flavours
-  template <HistoFlavour flavour = HistoFlavour::Regular>
-  struct Traits2D {
-    static constexpr unsigned int Dimension{2};
-    using Histo =
-        std::conditional_t<flavour == HistoFlavour::Profile, GHSink::details::ProfileWrapper<TProfile3D>, TH3D>;
-    using WeightType = std::conditional_t<flavour != HistoFlavour::Regular,
-                                          std::tuple<std::tuple<unsigned int, double>, double>, double>;
-
-    template <typename Axis0, typename Axis1>
-    static Histo create( std::string& name, std::string& title, Axis0& axis0, Axis1& axis1 ) {
-      auto const& cp    = axis0.minValue == 0 ? EcalParams : HcalParams;
-      int         nbCol = cp.centre * 2;
-      int         nbRow = ( cp.centre - cp.firstRow ) * 2;
-      auto        xmax  = cp.maxCellSizes * nbCol / 2.;
-      auto        ymax  = cp.maxCellSizes * nbRow / 2.;
-      return Histo{patchName<flavour>( name ).c_str(),
-                   title.c_str(),
-                   nbCol * cp.reg,
-                   -xmax,
-                   xmax,
-                   nbRow * cp.reg,
-                   -ymax,
-                   ymax,
-                   (int)axis1.nBins,
-                   axis1.minValue,
-                   axis1.maxValue};
-    }
-
-    static auto fill( Histo& histo, unsigned int i, const WeightType& weight ) {
-      bool               isEcal = histo.GetNcells() == NEcalRootHistBins;
-      unsigned int const nbCells =
-          isEcal ? LHCb::Detector::Calo::Index::nbEcalCells() : LHCb::Detector::Calo::Index::nbHcalCells();
-      // first extract value in the non CellID dimension (so 3rd dimension of the resulting histo)
-      auto index3rdD = i / ( nbCells + 2 );
-      // then extract value for the cellID dimension
-      i = i % ( nbCells + 2 );
-      // ignore under / overflow bin, they are not used by construction for cellIDs
-      if ( i == 0 || i == nbCells ) return;
-      int                          cellNumber = i - 1 + ( isEcal ? 0 : LHCb::Detector::Calo::Index::nbEcalCells() );
-      LHCb::Detector::Calo::CellID id         = LHCb::Detector::Calo::DenseIndex::details::toCellID( cellNumber );
-      // loop over cell area ( ibox * ibox bins depending on CaloFuture/Area)
-      auto const&        cp       = isEcal ? EcalParams : HcalParams;
-      const unsigned int ibox     = cp.reg / ( id.area() + 1 );
-      auto               cellSize = cp.maxCellSizes / cp.reg;
-      for ( unsigned int ir = 0; ir < ibox; ir++ ) {
-        int    iir    = ( id.row() - cp.centre ) * ibox + ir;
-        double y      = cellSize * ( iir + 0.5 );
-        int    yIndex = histo.GetYaxis()->FindBin( y );
-        for ( unsigned int ic = 0; ic < ibox; ic++ ) {
-          int    iic    = ( id.col() - cp.centre ) * ibox + ic;
-          double x      = cellSize * ( iic + 0.5 );
-          int    xIndex = histo.GetXaxis()->FindBin( x );
-          auto   bin    = histo.GetBin( xIndex, yIndex, index3rdD );
-          updateHistoBin<flavour>( histo, bin, weight );
-        }
-      }
-    }
-
-    static void fillMetaData( Histo& histo, nlohmann::json const&, unsigned int nentries ) {
-      auto const& cp = histo.GetNcells() == NEcalRootHistBins ? EcalParams : HcalParams;
-      histo.SetEntries( nentries * cp.reg * cp.reg );
-    }
-  };
-
-  /// Dedicated handler for Profile Histograms, respecting conversion to standard ones when required
-  template <int ND>
-  void saveProfileRootHisto( TFile& file, std::string dir, std::string name, nlohmann::json const& j,
-                             bool convertProfiles ) {
-    if ( convertProfiles ) {
-      // when converting, we save 2 histograms, one for mean, one for RMS
-      using TrMean =
-          std::conditional_t<ND == 1, Traits1D<HistoFlavour::ProfileMean>, Traits2D<HistoFlavour::ProfileMean>>;
-      using TrRMS = std::conditional_t<ND == 1, Traits1D<HistoFlavour::ProfileRMS>, Traits2D<HistoFlavour::ProfileRMS>>;
-      GHSink::saveRootHisto<TrMean>( file, dir, name, j );
-      GHSink::saveRootHisto<TrRMS>( file, dir, name, j );
-    } else {
-      using Tr = std::conditional_t<ND == 1, Traits1D<HistoFlavour::Profile>, Traits2D<HistoFlavour::Profile>>;
-      GHSink::saveRootHisto<Tr>( file, dir, name, j );
-    }
-  }
-
-} // namespace
-
 namespace LHCb::Calo::Histograming::Sink {
 
   using namespace std::string_literals;