diff --git a/CaloFuture/CaloFutureMoniDst/CMakeLists.txt b/CaloFuture/CaloFutureMoniDst/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..b36c5af5a4f92372a9ca1169f3f54d73309fcfd4
--- /dev/null
+++ b/CaloFuture/CaloFutureMoniDst/CMakeLists.txt
@@ -0,0 +1,33 @@
+################################################################################
+# Package: CaloFutureMoniDst
+################################################################################
+gaudi_subdir(CaloFutureMoniDst v5r21)
+
+gaudi_depends_on_subdirs(Associators/MCAssociators
+                         CaloFuture/CaloFutureInterfaces
+                         Calo/CaloKernel
+                         CaloFuture/CaloFutureUtils
+                         Event/DAQEvent
+                         Event/L0Event
+                         Event/LinkerEvent
+                         Event/PhysEvent
+                         Event/TrackEvent
+                         Kernel/Relations
+                         Tr/TrackInterfaces)
+
+find_package(AIDA)
+find_package(Boost)
+find_package(GSL)
+find_package(ROOT)
+
+include_directories(SYSTEM ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS})
+
+gaudi_add_module(CaloFutureMoniDst
+                 src/*.cpp
+                 INCLUDE_DIRS ROOT AIDA Boost GSL AIDA Associators/MCAssociators Calo/CaloKernel Tr/TrackInterfaces
+                 LINK_LIBRARIES ROOT Boost GSL AIDA CaloFutureUtils DAQEventLib L0Event LinkerEvent PhysEvent TrackEvent RelationsLib)
+
+gaudi_install_python_modules()
+
+gaudi_env(SET CALOFUTUREMONIDSTOPTS \${CALOFUTUREMONIDSTROOT}/options)
+
diff --git a/CaloFuture/CaloFutureMoniDst/doc/release.notes b/CaloFuture/CaloFutureMoniDst/doc/release.notes
new file mode 100755
index 0000000000000000000000000000000000000000..ba432fa316dbe9013ff978322b09f7614a4999b3
--- /dev/null
+++ b/CaloFuture/CaloFutureMoniDst/doc/release.notes
@@ -0,0 +1,470 @@
+! -----------------------------------------------------------------------------
+! Package     : CaloFuture/CaloFutureMoniDst
+! Responsible : Olivier Deschamps odescham@in2p3.fr
+! Purpose     : CaloFuture monitoring of Dst tape 
+! -----------------------------------------------------------------------------
+
+! 2016-08-16 - Olivier Deschamps
+  - implement counter() switch based on FutureCounterLevel tool 
+
+! 2016-06-11 - Deschamps Olivier for J.-F. Marchand
+ - ResolvedPi0Monitor : add 2d histo for pi0 mass versus cell index
+
+!========================= CaloFutureMoniDst v5r21 2016-01-28 =========================
+! 2015-12-08 - Marco Cattaneo
+ - Fix untested StatusCodes exposed by previous fix
+
+! 2015-12-06 - Gerhard Raven
+ - replace explicit boost::assign::list_of with implicit std::initializer_list
+
+!========================= CaloFutureMoniDst v5r20 2015-11-23 =========================
+! 2015-11-06 - O. Deschamps
+  -fix clang warnings
+
+! 2015-10-22 - O. Deschamps
+  -initialize base-class (CaloFutureMoniAlg) everywhere 
+
+!========================= CaloFutureMoniDst v5r19 2015-10-13 =========================
+! 2015-08-30 - Gerhard Raven
+ - remove DECLARE_ALGORITHM_FACTORY( CaloFutureMoniAlg ) and DECLARE_ALGORITHM_FACTORY( CaloFutureNtpBase )
+   as these are not 'concrete' algorithms, but base classes from which one first must inherit
+   and implement execute before they are useful. 
+
+! 2015-08-12 - Gerhard Raven
+ - remove #include of obsolete Gaudi headers
+
+!========================= CaloFutureMoniDst v5r18 2015-05-26 =========================
+! 2015-05-12 - Olivier Deschamps
+  - fix property naming in CaloFutureHypoMonitor
+  - update CaloFuturePi0Ntp & CaloFutureElectronNtp
+
+!========================= CaloFutureMoniDst v5r17 2014-05-13 =======================
+! 2014-05-06 - Marco Cattaneo
+ - CaloFutureMoniAlg.cpp: use setHistoTopDir in initialize() instead of
+   setProperty("HistoTopDir") in constructor. Removes need for debug() in 
+   constructor
+ - CaloFutureEFlowAlg.cpp: remove unnecessary debug() in constructor
+ - Above two changes fix unprotected debug() warnings
+
+!========================= CaloFutureMoniDst v5r16 2014-03-18 =======================
+! 2014-03-06 - Olivier Deschamps
+ -  python/Configuration.py : propagate OutputLevel value to calo sequences only when the property is explicity set
+
+!========================= CaloFutureMoniDst v5r15 2013-10-24 =======================
+! 2013-10-09 - Olivier Deschamps
+ -  python/CaloFutureDAQ/Monitors.py & Configuration.py :  possibility to set-up a configuration without active Spd/Prs  (NoSpdPrs = <False> flag)
+ -  src/  :  protect monitoring algorithms against the upgrade configuration with no Spd/Prs
+
+!========================= CaloFutureMoniDst v5r14 2013-07-18 =======================
+! 2013-06-12 - Marco Cattaneo
+ - Fix gcc48 warning
+ - Change a global variable to local, fixes UNINIT_CTOR warning
+ - Remove empty finalize methods
+
+!========================= CaloFutureMoniDst v5r13 2012-11-28 =======================
+! 2012-11-22 - Marco Clemencic
+ - Added CMake configuration file.
+ - Modified requirements to simplify auto conversion to CMake.
+
+! 2012-10-08 - Marco Cattaneo
+ - In Configuration.py, remove setting of MeasureTime=true in sequencers,
+   should not be the default, and should in any case use TimingAuditor.
+ - Fix UNINIT_CTOR defects
+ - Fix trivial icc remarks
+
+! 2012-10-08 - Olivier Deschamps
+ - Fix coverity problems
+
+!========================= CaloFutureMoniDst v5r12 2012-06-25 =======================
+! 2012-05-13 - Olivier Deschamps
+ - fix CaloFutureAlignmentNtp
+ - update L0CaloFutureScale
+
+!========================= CaloFutureMoniDst v5r11 2012-05-02 =======================
+! 2012-04-17 - Olivier Deschamps
+ - new algorithm : L0CaloFutureScale to compare CaloFutureCluster/CaloFutureHypo/L0Cluster transverse
+   energy
+
+!========================= CaloFutureMoniDst v5r10 2012-04-13 =======================
+! 2012-04-05 - Olivier Deschamps
+ - Add eta->gg monitoring (re-use resolvedPi0 algorithm)
+ - SpdMonitor : set splitArea=true as the default for CaloFuture2Dview histos 
+
+!========================= CaloFutureMoniDst v5r9 2011-09-06 ========================
+! 2011-09-03 - Olivier Deschamps
+ - fix CaloFutureAlignment.cpp
+
+!========================= CaloFutureMoniDst v5r8 2011-07-27 ========================
+! 2011-07-22 - Marco Cattaneo
+ - Create debug() messages only when output level requires it,
+   also using UNLIKELY macro
+ - Replace all endreq by endmsg
+
+!========================= CaloFutureMoniDst v5r7 2011-02-25 ========================
+! 2011-02-07 - Olivier Deschamps
+ - update tupling algorithms
+
+!========================= CaloFutureMoniDst v5r6 2011-01-17 ========================
+! 2010-10-07 - Olivier Deschamps
+ - New base class : CaloFutureNtpBase for tupling algorithms
+ - CaloFutureAlignmentNtp now inherits from CaloFutureNtpBase
+ @TODO : make other XXNtp algorithm to inherit from the base class
+
+!========================= CaloFutureMoniDst v5r5 2010-10-28 ========================
+! 2010-10-07 - Olivier Deschamps
+ - Fix windows warning
+
+! 2010-10-01 - Rob Lambert
+ - Fix windows warning, converting double to int
+
+! 2010-09-30 - Marco Cattaneo
+ - Undo part of previous fix, which was causing a relations table to not be 
+   loaded, causing the algorithm to throw ane exception. This was masking the
+   finalization crash, that is still there....
+
+! 2010-09-30 - Olivier Deschamps 
+  - CaloFuturePhotonChecker : fix finalization crash
+
+! 2010-09-30 - Olivier Deschamps 
+  - Improve CaloFuturePi0Ntp & CaloFutureElectronNtp
+  - add new ntp algorithm : CaloFutureAlignmentNtp
+
+
+!========================== CaloFutureMoniDst v5r4 2010-09-29 =======================
+! 2010-09-27 - Marco Cattaneo
+ - Fix uninitialised member variables in CaloFuturePhotonChecker
+
+! 2010-09-01 - Olivier Deschamps
+  - fix compilation warning on windows
+  - improve CaloFutureHypoNtp
+
+! 2010-08-31 - Olivier Deschamps
+  - fix compilation warning on slc4
+
+! 2010-08-27 - Olivier Deschamps
+  - new algorithm : CaloFutureHypoNtp
+  - CaloFutureHypoMonitor : new monitoring histogram Nhypo/Nclusters
+
+!========================== CaloFutureMoniDst v5r3 2010-06-22 =======================
+! 2010-06-05 - Rob Lambert
+ - Fixes for mistake in yesterday's commit
+
+! 2010-06-04 - Rob Lambert
+ - Fixes for windows warnings savannah 15808
+
+!========================== CaloFutureMoniDst v5r2 2010-05-24 =======================
+
+! 2010-05-24 - Rob Lambert
+ - fix for typo in CaloFuturePi0Ntp
+
+
+! 2010-05-17 - Olivier Deschamps
+  - python/Monitor.py : activate missing monitoring histo for ResolvedPi0 monitoring
+
+!========================== CaloFutureMoniDst v5r1 2010-04-26 =======================
+! 2010-04-12 - Dmitry GOLUBKOV
+ - doc/release.notes : corrected the place of the second comment from 2010-04-12
+ - Monitor.py : check if properties were already set before setting them
+ - cmt/requirements: version incremented to v5r1 
+
+!========================== CaloFutureMoniDst v5r0 2010-04-12 =======================
+! 2010-04-12 - Dmitry GOLUBKOV
+ - CaloFutureEMuPIDMon.cpp: fixed an unchecked StatusCode in the finalize() method
+
+! 2010-04-09 - Rob Lambert
+ - Fixed windows warnings in CaloFutureEMuPIDMon.cpp and CaloFuturePi0Checker.cpp
+
+! 2010-04-02 - Dmitry Golubkov
+ - CaloFutureEMuPIDMon.cpp: fixed an SLC5 warning: type qualifiers ignored on function return type 
+
+! 2010-03-31 - Dmitry Golubkov
+  - following Vanya's suggestion remove completely CaloFutureEMuMonitor, CaloFutureEMuChecker
+
+! 2010-03-31 - Olivier Deschamps
+  - fix typo in CaloFuturePi0Monitor.cpp
+
+! 2010-03-29 - Dmitry Golubkov
+ - CaloFutureMoniDstConf : introduced Histograms slot and passed it to pidsMoni(),
+   test the value of Histograms in CaloFutureMoniDstConf.checkConfiguration()
+ - Monitor.py : add 'CaloFutureEMuMonitor/CaloFuturePIDMon' to the monitoring sequence only
+     if Histograms in ['OfflineFull', 'Expert']
+
+! 2010-03-26 - Dmitry GOLUBKOV
+ - CaloFutureEMuPIDMon.{h,cpp}: a new simplified PID monitoring algorithm
+ - Monitor.py: added CaloFutureEMuPIDMon{Uncut,Soft,Hard} to the monitoring sequence
+ - CaloFuturePIDsMonitor.opts: added CaloFutureEMuPIDMon to the CaloFuturePIDsMon sequence (?)
+ - cmt/requirements: version increment to v4r6
+
+!========================== CaloFutureMoniDst v4r5 2010-03-19 =======================
+! 2010-03-22 - Rob Lambert
+ - Fixed some windows warnings savannah 64668
+
+! 2010-03-08 - Olivier Deschamps
+  - adapt CaloFuturePhotonChecker to change in CaloFuturePIDs
+  
+  @TODO : review checkers (use CaloFutureMCTools ...)
+
+! 2010-03-08 - Olivier Deschamps
+ - make use of CaloFutureAlgUtils to define context-dependent TES inputs
+ - add control counters
+ - CaloFutureMoniDstConf 
+    - add missing ProtoElectronMonitor
+    - delegate the TES I/O to CaloFutureAlgUtils
+ 
+
+ - Usage :
+
+        from Configurables import CaloFutureProcessor
+        from Configurables import CaloFutureMoniDst
+        CaloFutureProcessor(Context = 'Repro' , Sequence = recSeq )
+        CaloFutureMoniDst(Context = 'Repro' , Sequence = moniSeq )
+
+    -> provides consistent CaloFutureReco + Monitoring sequences for 'Repro' context
+
+
+
+!========================== CaloFutureMoniDst v4r4 2010-02-15 =======================
+
+! 2010-02-11 - Marco Cattaneo
+ - Replace dependency on DaVinciMCKernel with MCAssociators, to follow changes
+   in LHCB v29r1
+
+! 2010-01-30 - Dmitry Golubkov
+ - CaloFutureEMuMonitor: add more histograms, crude windows based on rp6 of Dec 2009 data
+ - CaloFutureEMuChecker: move include Kernel/Particle2MCLinker.h from CaloFutureEMuMonitor.h
+
+! 2010-02-04 : Olivier Deschamps
+  - CaloFuturePi0Monitor : fix bad initialization of base class
+  - CaloFutureMoniAlg : init m_detData for non specific calo detector algo (default Ecal is assumed)
+
+! 2010-01-28 : Olivier Deschamps
+ - SpdMonitor    : speed up processing - inherits from CaloFuture2Dview (Albert Puig)
+ - CalOEFlowAlg  : code update from Aurélien.
+  Warning : new CaloFutureEFlow require MCEvent dependency (obtained through DaVinciMCKernel so far)
+            -> to do : split the MC 'checker' part of the code
+
+
+!========================== CaloFutureMoniDst v4r3 2010-01-21 =======================
+! 2010-01-13 - Marco Cattaneo
+ - Follow Gaudi fix #61116: GaudiCommon::Exception now returns void
+
+! 2009-12-11 - Olivier Deschamps
+ - CaloFutureProtoElectronMonitor : make use of proto->info(PrsE) instead of CaloFutureHypo2CaloFuture tool.
+
+! 2009-12-11 - Olivier Deschamps 
+ - CaloFutureMoniAlg : remove verbose line
+ - new algorithm CaloFutureProtoElectronMonitor
+ - CaloFuturePi0Monitor : add pi0 mass peak with Y-selection of clusters.
+
+
+!========================== CaloFutureMoniDst v4r2 2009-12-11 =======================
+! 2009-12-01 - Olivier Deschamps 
+ - CaloFutureMoniAlg : protection against non booked histograms in hfillX methods
+
+! 2009-11-30 - Olivier Deschamps 
+ - CaloFutureMoniAlg : add saturation bin(s) by default for 1D histograms
+
+
+!========================== CaloFutureMoniDst v4r1 2009-10-20 =======================
+! 2009-10-16 - Olivier Deschamps for Aurelien Martens 
+ - Update in CaloFutureEFlowAlg
+
+! 2009-10-06 - Marco Cattaneo
+ - Add link to LHCb-INT-2009-022 note in CaloFutureEMuMonitor.h doxygen header
+
+! 2009-10-01 - Vanya BELYAEV
+ - CaloFutureMoniAlg.h :
+    minor fix for the recent modification in CaloFutureCellCode functions 
+
+! 2009-09-14 - Olivier Deschamps
+ - CaloFuturePi0Monitor : 
+     - selection of non-converted photons
+     - isolation criteria
+     - Add background subtracted histo 
+
+! 2009-09-08 - Olivier Deschamps
+ - Add background histo in resolved pi0 monitor
+ - Fix problem with HashMap<const string, IHistogram*> removing const !
+
+!========================== CaloFutureMoniDst v4r0 2009-09-07 =======================
+! 2009-09-07 - Dmitry GOLUBKOV
+ - CaloFutureEMuMonitor, CaloFutureEMuChecker: add proper calls to the base-class finalize()
+ - CaloFuturePIDsChecker.cpp : fix division by zero in divide()
+
+! 2009-09-01 - Vanya BELYAEV
+ - fix warnings in configurables 
+
+! 2009-08-31 - Olivier Deschamps
+ - fix bug in CaloFutureMoniAlg (SplitAreas/m_split property/member already exists in inherited CaloFuture2DView)
+
+! 2009-08-11 - Vanya BELYAEV
+
+ - futher polishing of configurables 
+
+
+! 2009-08-05 - Vanya BELYAEV
+
+ - add proepr configurable 
+   version incremen to v4r0 
+
+! 2009-07-30 - Dmitry GOLUBKOV
+ - CaloFutureEMuMonitor.cpp add protection when no charged ProtoParticle
+ - cmt/requirements version incremented to v3r10
+
+!========================== CaloFutureMoniDst v3r9 2009-07-28 =======================
+! 2009-07-28 - Marco Cattaneo
+ - Remove obsolete file CaloFutureMoniDst_dll.cpp
+ - Remove not needed includes
+ - Clean up dependencies in requirements
+
+! 2009-07-24 - Chris Jones
+ - change std::map< std::string, XXX * > to 
+   GaudiUtils::HashMap< const std::string, XXX * > for faster lookups.
+
+!========================== CaloFutureMoniDst v3r8 2009-06-17 =======================
+! 2009-06-05 - Olivier Deschamps
+ - change _snprintf() to std::string
+
+!========================== CaloFutureMoniDst v3r7 2009-06-03 =======================
+! 2009-06-03 - Marco Cattaneo
+ - Fix for windows, do not use fabs with int argument, use abs
+ - Use _snprintf, not snprintf on windows
+ 
+! 2009-05-22 - Marco Cattaneo
+ - Fix invalid matrix indices in computation of "shape" in CaloFuturePhotonChecker.cpp
+
+!========================== CaloFutureMoniDst v3r6 2009-05-08 =======================
+! 2009-05-05 - Olivier Deschamps for Aurelien Martens
+  - CaloFutureEFlowAlg.cpp  : add protection 
+  - CaloFutureEFlowAlg.opts : change default setting 
+
+! 2009-04-24 - Marco Cattaneo
+ - Fix compilation warning for gcc43
+ - Replace endreq by endmsg (obsolescent in Gaudi v21)
+
+! 2009-04-21 - Olivier Deschamps for Dmitry Goloubkov
+ - CaloFutureEMuMonitor/Checker.{cpp,h} : produce histogram (+analysis) of CaloFuturePID 
+
+! 2009-04-20 - Olivier Deschamps for Aurelien Martens
+ - CaloFutureEFlowAlg.{cpp,h,opts} : produce histogram for 'Energy-Flow' calibration
+   method (Aurelien Martens)
+
+!========================== CaloFutureMoniDst v3r5 2009-03-10 =======================
+! 2009-03-06 - Olivier Deschamps 
+ - set CaloFutureDQ.opt histo selection as default in CaloFutureMonitor.opts for Brunel
+ - new options : CaloFutureFullMonitoring.opts (to be added to produce the whole histo set)
+
+! 2009-02-20 - Olivier Deschamps 
+ - Clean monitoring algorithms
+ - add protection against missing data inputs here and there
+ - new options : CaloFutureDQ.opts : selection of relevant monitoring histo for Data Quality stuff
+ - CaloFutureMoniAlg : new property 'splitAreas' allow to produce histo per area (all cpp adapted)
+
+!========================== CaloFutureMoniDst v3r4 2009-02-20 =======================
+! 2009-01-20 - Marco Cattaneo
+ - Migrate to LHCb::ParticlePropertySvc
+
+!========================== CaloFutureMoniDst v3r3 2008-11-21 =======================
+! 2008-11-06 - Marco Cattaneo
+ - Fix for gcc 4.3
+
+! 2008-10-17 - Olivier Deschamps
+ - fix memory leak
+
+!========================== CaloFutureMoniDst v3r2 2008-10-02 =======================
+! 2008-09-23 - Marco Cattaneo
+ - Fix compilation warning
+
+! 2008-09-21 - Olivier Deschamps
+ - review histogram production & prepare XXXMonitor for real data.
+ - cleanup algorithm and options
+
+! 2008-09-18 - Marco Cattaneo
+ - Add #units directive to CaloFutureMonitor.opts, needed by Brunel pythonisation
+
+!========================== CaloFutureMoniDst v3r1 2008-07-02 =======================
+! 2008-06-26 - Juan PALACIOS
+ - cmt/requirements
+  . Increase version to v3r1
+ - src/CaloFuturePhotonChecker.cpp
+  . Change all Gaudi::XYZLine and Gaudi::Line for Gaudi::Math::XYZLine and
+    Gaudi::Math::XYZLine respectively (adapting to Kernel/LHCbMath v3)
+
+!========================== CaloFutureMoniDst v3r0p2 2008-04-23 ===================
+! 2008-04-23 - Marco Cattaneo
+ - Remove whitespace in options, needed for Python options parser
+
+!========================== CaloFutureMoniDst v3r0p1 2007-12-03 ===================
+! 2007-12-03 - Marco Cattaneo
+ - Fix a compiler warning
+
+! 2007-11-22 - Olivier Deschamps
+ - fix in CaloFuturePhotonChecker.cpp
+
+!========================== CaloFutureMoniDst v3r0 2007-10-08 ===================
+! 2007-09-24 - Olivier Deschamps
+ - fix against the  PatricleID constructor from int made explicit
+ - fix SpdMonitor.cpp (Albert Puig)
+ - remove dependency on CaloFutureAssociator in requirements
+ - add dependency on DaVinciMCKernel in requirements
+
+! 2007-08-24 - Olivier Deschamps
+ - fix unchecked StatusCodes 
+
+! 2007-08-22 - Albert Puig & Olivier Deschamps
+ - new SpdMonitor algorithm
+
+! 2007-07-25 - Konstantin Beloous & Olivier Deschamps
+ - Major release 
+    -  package updated for DC06
+    -  First step toward an online usage of the Monitoring part 
+    -  histograms production reviewed and improved
+    -  some algorithm names have changed
+    -  2 types of algorithms : Monitor's (relying on data only) and Checker's (relying on MC)
+    - Monitors : CaloFutureDigit, CaloFutureCluster, CaloFutureHypo, ResolvedPi0 & PID's (CaloFutureClusterMatch, CaloFutureHypoMatch)
+          - driven by option/CaloFutureMonitor.opts
+    - Checkers : CaloFutureCluster, Photon, ResolvedPi0, CaloFuturePIDs
+          - driven by option/CaloFutureChecker.opts
+
+!========================== CaloFutureMoniDst v2r1 2005-12-08 ===================
+! 2005-12-08 - Olivier Deschamps
+ - CaloFuturePIDsMonitor.cpp use Track::History == 'Cnv' Tracks only 
+!========================== CaloFutureMoniDst v2r0 2005-11-04 ===================
+! 2005-11-04 - Olivier Deschamps
+ - Adapt to new Track Event Model (TrackEvent v1r4)
+
+  modified file :  
+   src/CaloFuturePIDsMonitor.cpp
+   src/CaloFuturePhotonMonitor.h/cpp
+   src/CaloFutureHypoMatchMonitor.cpp
+   src/CaloFutureClusterMatchMonitor.cpp
+
+ - cmt/requirements 
+   version increment to v2r0
+
+!======================== CaloFutureMoniDst v1r2 2005-06-02 =========================
+! 2005-06-02 - Marco Cattaneo
+ - Adapt job options to change in phase name from BrunelMoni to Moni (for 
+   monitoring without MC truth) and Check (for checking with MC truth)
+
+========================= CaloFutureMoniDst v1r1 2005-05-13 =========================
+! 2005-05-13 - Marco Cattaneo
+ - Fix ambiguous call to overloaded log10 function, for Windows
+
+! 2005-05-08 - Vanya BELYAEV
+   - eliminate all associators 
+   - a lot of minor cosmetic changes 
+   - cmt/requirements 
+    version increment to v1r1 
+
+========================= CaloFutureMoniDst v1r0 2004-10-27 =========================
+! 2004-10-27 - Vanya BELYAEV
+ - tiny improvements in algorithms 
+
+
+! 2004-10-25 - Vanya BELYAEV
+ - the new package: the code is imported from CaloFuture/CaloFutureMonitor package 
+
+! -----------------------------------------------------------------------------
+! The END 
+! -----------------------------------------------------------------------------
diff --git a/CaloFuture/CaloFutureMoniDst/options/Brunel.opts b/CaloFuture/CaloFutureMoniDst/options/Brunel.opts
new file mode 100755
index 0000000000000000000000000000000000000000..1088c1db59b9cfc503da8950f1bc71e32bd02181
--- /dev/null
+++ b/CaloFuture/CaloFutureMoniDst/options/Brunel.opts
@@ -0,0 +1,2 @@
+#include "$CALOFUTUREMONIDSTOPTS/CaloFutureMonitor.opts"
+#include "$CALOFUTUREMONIDSTOPTS/CaloFutureChecker.opts"
diff --git a/CaloFuture/CaloFutureMoniDst/options/CaloFuture2L0Mon.opts b/CaloFuture/CaloFutureMoniDst/options/CaloFuture2L0Mon.opts
new file mode 100644
index 0000000000000000000000000000000000000000..9bb6affe018cbcc411c658ff7ccce5c591c7ef23
--- /dev/null
+++ b/CaloFuture/CaloFutureMoniDst/options/CaloFuture2L0Mon.opts
@@ -0,0 +1,9 @@
+CaloFuture2L0Mon.Members += {
+  "L0CaloFutureScale/Photon2L0CaloFuture"
+    ,"L0CaloFutureScale/Electron2L0CaloFuture"
+    };
+
+Photon2L0CaloFuture.EtFilter=200.*MeV;
+Electron2L0CaloFuture.EtFilter=200.*MeV;
+Photon2L0CaloFuture.SplitAreas=true;
+Electron2L0CaloFuture.SplitAreas=true;
diff --git a/CaloFuture/CaloFutureMoniDst/options/CaloFutureChecker.opts b/CaloFuture/CaloFutureMoniDst/options/CaloFutureChecker.opts
new file mode 100755
index 0000000000000000000000000000000000000000..e64d360412600c87ad0d64d3ece4eb218924539a
--- /dev/null
+++ b/CaloFuture/CaloFutureMoniDst/options/CaloFutureChecker.opts
@@ -0,0 +1,23 @@
+
+
+CheckCALOFUTURESeq.Members +=  {   "GaudiSequencer/CaloFutureRecoChecker"
+                             ,"GaudiSequencer/CaloFuturePIDsChecker"
+};
+
+CaloFutureRecoChecker.Members += { "CaloFutureClusterChecker"
+                             ,"CaloFuturePi0Checker"
+};
+
+
+CaloFuturePIDsChecker.Members += { "CaloFuturePIDsChecker/PIDeEcalChecker",
+                             "CaloFuturePIDsChecker/PIDePrsChecker" ,
+                             "CaloFuturePIDsChecker/PIDeHcalChecker",
+                             "CaloFuturePIDsChecker/PIDeBremChecker", 
+                             "CaloFuturePIDsChecker/PIDmEcalChecker", 
+                             "CaloFuturePIDsChecker/PIDmHcalChecker",
+                             "CaloFuturePhotonChecker"};
+
+
+#include "$CALOFUTUREMONIDSTOPTS/CaloFuturePhotonChecker.opts"
+#include "$CALOFUTUREMONIDSTOPTS/CaloFuturePIDsChecker.opts"
+
diff --git a/CaloFuture/CaloFutureMoniDst/options/CaloFutureClusterMonitor.opts b/CaloFuture/CaloFutureMoniDst/options/CaloFutureClusterMonitor.opts
new file mode 100755
index 0000000000000000000000000000000000000000..19aeace8fc3f656d1439819d83bceccd5915e220
--- /dev/null
+++ b/CaloFuture/CaloFutureMoniDst/options/CaloFutureClusterMonitor.opts
@@ -0,0 +1,2 @@
+CaloFutureClusterMon.Members += { "CaloFutureClusterMonitor/EcalClusterMon"};
+//EcalClusterMon.Input  = "Rec/Calo/EcalClusters";
diff --git a/CaloFuture/CaloFutureMoniDst/options/CaloFutureDQ.opts b/CaloFuture/CaloFutureMoniDst/options/CaloFutureDQ.opts
new file mode 100644
index 0000000000000000000000000000000000000000..2dd49866c4926aa62f42dca4ba3fdf32e40ac0e5
--- /dev/null
+++ b/CaloFuture/CaloFutureMoniDst/options/CaloFutureDQ.opts
@@ -0,0 +1,15 @@
+EcalDigitMon.histoList     = { "1" , "2" , "3" , "6" , "7" };
+HcalDigitMon.histoList     = { "1" , "2" , "3" , "6" , "7" };
+PrsDigitMon.histoList      = { "1" , "2" , "3" , "6" , "7" };
+SpdDigitMon.histoList      = { "1" , "2" , "3" , "6" };
+EcalClusterMon.histoList   = { "1" , "2" , "3" , "4" , "7" , "8" ,  "9" };
+ElectronMon.histoList      = { "1" , "2" , "3" , "7" , "8" , "9" , "10" , "11" ,"14"};
+PhotonMon.histoList        = { "1" , "2" , "3" , "7" , "8" , "9" , "10" , "11" ,"14"};
+SplitPhotonMon.histoList   = { "1" , "2" , "3" , "7" , "8" , "9" , "10" , "11" };
+MergedPi0Mon.histoList     = { "1" , "2" , "3" , "4" , "7" , "8" ,  "9" , "14" };
+ResolvedPi0Mon.histoList   = { "1" , "2" , "3" , "4" , "5" , "6" ,  "7" ,  "8"};
+EtaMon.histoList           = { "1" , "2" , "3" , "4" , "5" , "6" ,  "7" };
+EcalProtoPMon.histoList    = { "All" };
+SpdMon.histoList           = { "All" };
+Photon2L0CaloFuture.histoList    = { "0" , "1" , "2" , "3" };
+Electron2L0CaloFuture.histoList  = { "0" , "1" , "2" , "3" };
diff --git a/CaloFuture/CaloFutureMoniDst/options/CaloFutureDigitMonitor.opts b/CaloFuture/CaloFutureMoniDst/options/CaloFutureDigitMonitor.opts
new file mode 100755
index 0000000000000000000000000000000000000000..8af84ebb5c00537428ec6fcb4dd794eab22d63ab
--- /dev/null
+++ b/CaloFuture/CaloFutureMoniDst/options/CaloFutureDigitMonitor.opts
@@ -0,0 +1,14 @@
+CaloFutureDigitMon.Members   += {   "CaloFutureDigitMonitor/EcalDigitMon",
+                              "CaloFutureDigitMonitor/HcalDigitMon",
+                              "CaloFutureDigitMonitor/PrsDigitMon",
+                              "CaloFutureDigitMonitor/SpdDigitMon"
+};
+
+//EcalDigitMon.EnergyFilter  = 500.*MeV;
+//HcalDigitMon.EnergyFilter  = 500.*MeV;
+//PrsDigitMon.EnergyFilter   = 50.*MeV;
+
+
+//EcalDigitMon.SplitAreas = true;
+//EcalDigitMon.SplitAreas = true;
+//EcalDigitMon.OutputLevel = 2;
diff --git a/CaloFuture/CaloFutureMoniDst/options/CaloFutureFullMonitoring.opts b/CaloFuture/CaloFutureMoniDst/options/CaloFutureFullMonitoring.opts
new file mode 100644
index 0000000000000000000000000000000000000000..d7bb9b62d5622a7ab46c69d5e5ba1577b021c583
--- /dev/null
+++ b/CaloFuture/CaloFutureMoniDst/options/CaloFutureFullMonitoring.opts
@@ -0,0 +1,13 @@
+// Define the monitoring sequence
+#include "$CALOFUTUREMONIDSTOPTS/CaloFutureMonitor.opts"
+// force the complete histo set production 
+EcalDigitMon.histoList   += { "All" };
+HcalDigitMon.histoList   += { "All" };
+PrsDigitMon.histoList    += { "All" };
+SpdDigitMon.histoList    += { "All" }; 
+EcalClusterMon.histoList += { "All" }; 
+ElectronMon.histoList    += { "All" }; 
+PhotonMon.histoList      += { "All" }; 
+SplitPhotonMon.histoList += { "All" };
+MergedPi0Mon.histoList   += { "All" }; 
+ResolvedPi0Mon.histoList += { "All" };
diff --git a/CaloFuture/CaloFutureMoniDst/options/CaloFutureHypoMonitor.opts b/CaloFuture/CaloFutureMoniDst/options/CaloFutureHypoMonitor.opts
new file mode 100755
index 0000000000000000000000000000000000000000..ccc9d81bc807a701e2bbaf5dd305e328cd4ab127
--- /dev/null
+++ b/CaloFuture/CaloFutureMoniDst/options/CaloFutureHypoMonitor.opts
@@ -0,0 +1,23 @@
+CaloFutureHypoMon.Members    += { "CaloFutureHypoMonitor/ElectronMon"               
+                            ,"CaloFutureHypoMonitor/PhotonMon"               
+                            ,"CaloFutureHypoMonitor/SplitPhotonMon" 
+                            ,"CaloFutureHypoMonitor/MergedPi0Mon"
+                            ,"CaloFuturePi0Monitor/ResolvedPi0Mon" 
+                            ,"CaloFuturePi0Monitor/EtaMon" 
+};             
+
+ResolvedPi0Mon.PhotonPtFilter = 200.*MeV;
+ResolvedPi0Mon.IsolationFilter = 3; // temp
+ResolvedPi0Mon.HistoMassMax = 250.; // temp
+
+// Eta->gg
+EtaMon.PhotonMaxPtFilter=1000.*MeV;
+EtaMon.HistoMassMin=400.*MeV;
+EtaMon.HistoMassMax=700.*MeV;
+
+
+// Moning of different Hypotheses
+//ElectronMon.Input    = "Rec/Calo/Electrons";
+//PhotonMon.Input      = "Rec/Calo/Photons";
+//MergedPi0Mon.Input   = "Rec/Calo/MergedPi0s";
+//SplitPhotonMon.Input = "Rec/Calo/SplitPhotons";
diff --git a/CaloFuture/CaloFutureMoniDst/options/CaloFutureMonitor.opts b/CaloFuture/CaloFutureMoniDst/options/CaloFutureMonitor.opts
new file mode 100755
index 0000000000000000000000000000000000000000..1b043606f76c950c4264fd1825efecb9c498d0b4
--- /dev/null
+++ b/CaloFuture/CaloFutureMoniDst/options/CaloFutureMonitor.opts
@@ -0,0 +1,27 @@
+// define the monitoring histo production sequence
+MoniCALOFUTURESeq.Members += { "GaudiSequencer/CaloFutureDigitMon"
+                         ,"GaudiSequencer/CaloFutureEFlowAlg"
+                         ,"GaudiSequencer/CaloFutureClusterMon"
+                         ,"GaudiSequencer/CaloFutureHypoMon"
+                         ,"GaudiSequencer/CaloFutureProtoPMon"
+                         ,"GaudiSequencer/CaloFuturePIDsMon"
+                         ,"GaudiSequencer/CaloFuture2L0Mon" 
+                         ,"SpdMonitor/SpdMon"
+};
+
+#include "$CALOFUTUREMONIDSTOPTS/CaloFutureDigitMonitor.opts" 
+#include "$CALOFUTUREMONIDSTOPTS/CaloFutureClusterMonitor.opts" 
+#include "$CALOFUTUREMONIDSTOPTS/CaloFutureHypoMonitor.opts" 
+#include "$CALOFUTUREMONIDSTOPTS/CaloFutureProtoPMonitor.opts" 
+#include "$CALOFUTUREMONIDSTOPTS/SpdMonitor.opts" 
+#include "$CALOFUTUREMONIDSTOPTS/CaloFuturePIDsMonitor.opts" 
+#include "$CALOFUTUREMONIDSTOPTS/CaloFuture2L0Mon.opts"
+
+#include "$CALOFUTUREMONIDSTOPTS/EcalEFlowAlg.opts"
+#include "$CALOFUTUREMONIDSTOPTS/HcalEFlowAlg.opts"
+#include "$CALOFUTUREMONIDSTOPTS/PrsEFlowAlg.opts" 
+
+
+// define the subset of useful monitoring histos for DQ
+#include "$CALOFUTUREMONIDSTOPTS/CaloFutureDQ.opts"
+
diff --git a/CaloFuture/CaloFutureMoniDst/options/CaloFuturePIDsChecker.opts b/CaloFuture/CaloFutureMoniDst/options/CaloFuturePIDsChecker.opts
new file mode 100755
index 0000000000000000000000000000000000000000..4495723f4b93466d5ce9b3e52db61796e99e4634
--- /dev/null
+++ b/CaloFuture/CaloFutureMoniDst/options/CaloFuturePIDsChecker.opts
@@ -0,0 +1,51 @@
+// Produce plot of efficiency  versus tan(p/Normalisation) plot for track with :
+//   - type = TrackType
+//   - Acceptance == TrackAcceptance
+//   -  DLL<input> > Cut
+//   - Associated MC-type = Particle, 0 (Ghost) and non-Particle 
+
+
+PIDeEcalChecker.Particle      =  11                  ;
+PIDeEcalChecker.Input         = "Rec/Calo/EcalPIDe"  ;
+PIDeEcalChecker.Normalization =  50.0 * GeV          ;
+PIDeEcalChecker.Cut           =  0.0                 ;
+PIDeEcalChecker.TrackType     = "Long"               ;
+PIDeEcalChecker.TrackAcceptance= "Rec/Calo/InAccEcal" ;
+
+
+PIDePrsChecker.Particle      = 11 ;
+PIDePrsChecker.Input         = "Rec/Calo/PrsPIDe"   ;
+PIDePrsChecker.Normalization =  50.0 * GeV ;
+PIDePrsChecker.Cut           =  0.0                 ;
+PIDePrsChecker.TrackType     = "Long" ;
+PIDePrsChecker.TrackAcceptance= "Rec/Calo/InAccPrs" ;
+
+
+PIDeBremChecker.Particle      = 11 ;
+PIDeBremChecker.Input         = "Rec/Calo/BremPIDe"  ;
+PIDeBremChecker.Normalization =  50.0 * GeV ;
+PIDeBremChecker.Cut           =  0.                 ;
+PIDeBremChecker.TrackType     = "Long" ;
+PIDeBremChecker.TrackAcceptance= "Rec/Calo/InAccBrem" ;
+
+PIDeHcalChecker.Particle      = 11 ;
+PIDeHcalChecker.Input         = "Rec/Calo/HcalPIDe"  ;
+PIDeHcalChecker.Normalization =  50.0 * GeV ;
+PIDeHcalChecker.Cut           =  0.                 ;
+PIDeHcalChecker.TrackType     = "Long" ;
+PIDeHcalChecker.TrackAcceptance= "Rec/Calo/InAccHcal" ;
+
+
+PIDmEcalChecker.Particle      = 13 ;
+PIDmEcalChecker.Input         = "Rec/Calo/EcalPIDmu" ;
+PIDmEcalChecker.Normalization =  25.0 * GeV ;
+PIDmEcalChecker.Cut           =  0.                 ;
+PIDmEcalChecker.TrackType     = "Long" ;
+PIDmEcalChecker.TrackAcceptance= "Rec/Calo/InAccEcal" ;
+
+PIDmHcalChecker.Particle      = 13                   ;
+PIDmHcalChecker.Input         = "Rec/Calo/HcalPIDmu" ;
+PIDmHcalChecker.Normalization =  25.0 * GeV          ;
+PIDmHcalChecker.Cut           =  0.                 ;
+PIDmHcalChecker.TrackType     = "Long" ;
+PIDmHcalChecker.TrackAcceptance= "Rec/Calo/InAccHcal" ;
diff --git a/CaloFuture/CaloFutureMoniDst/options/CaloFuturePIDsMonitor.opts b/CaloFuture/CaloFutureMoniDst/options/CaloFuturePIDsMonitor.opts
new file mode 100755
index 0000000000000000000000000000000000000000..9eb592b374d0c9c645ae26b307f174ff43a2f80d
--- /dev/null
+++ b/CaloFuture/CaloFutureMoniDst/options/CaloFuturePIDsMonitor.opts
@@ -0,0 +1,12 @@
+CaloFuturePIDsMon.Members  += { "CaloFutureClusterMatchMonitor/PhotonMatchMon"
+                          ,"CaloFutureHypoMatchMonitor/ElectronMatchMon"     
+                          ,"CaloFutureHypoMatchMonitor/BremMatchMon"
+                          ,"CaloFutureEMuPIDMon/CaloFutureEMuPIDMon"}; 
+// Monitoring of matching relation tables
+//PhotonMatchMon.Input    =   "Rec/Calo/ClusterMatch";
+//PhotonMatchMon.Inputs   = { "Rec/Calo/EcalClusters" };
+//ElectronMatchMon.Input  =   "Rec/Calo/ElectronMatch";
+//ElectronMatchMon.Inputs = { "Rec/Calo/Electrons" };
+//BremMatchMon.Input      = "Rec/Calo/BremMatch"         ;
+//BremMatchMon.Inputs     = { "Rec/Calo/Photons"       } ;
+
diff --git a/CaloFuture/CaloFutureMoniDst/options/CaloFuturePhotonChecker.opts b/CaloFuture/CaloFutureMoniDst/options/CaloFuturePhotonChecker.opts
new file mode 100755
index 0000000000000000000000000000000000000000..18b25408c7ee8fa658e98d249c5395df5d1910da
--- /dev/null
+++ b/CaloFuture/CaloFutureMoniDst/options/CaloFuturePhotonChecker.opts
@@ -0,0 +1,20 @@
+CaloFuturePhotonChecker.Pdf            = true                       ;
+
+
+// Histogram Binning :
+CaloFuturePhotonChecker.EPrsBin=
+  {
+    // Nbin ,   Xmin,   Xmax
+    50,     0.,   200. // EPrs
+  };
+CaloFuturePhotonChecker.Chi2Bin=
+  {
+    // Nbin ,   Xmin,   Xmax
+    26,     0.,   104. // Chi2(Tr)
+  };
+CaloFuturePhotonChecker.SeedBin=
+  {
+    // Nbin ,   Xmin,   Xmax
+    50,     0., 1.  // Shower Shape
+  };
+
diff --git a/CaloFuture/CaloFutureMoniDst/options/CaloFutureProtoPMonitor.opts b/CaloFuture/CaloFutureMoniDst/options/CaloFutureProtoPMonitor.opts
new file mode 100644
index 0000000000000000000000000000000000000000..ded152e95b5e96c14d13ccabd18927d580ac1074
--- /dev/null
+++ b/CaloFuture/CaloFutureMoniDst/options/CaloFutureProtoPMonitor.opts
@@ -0,0 +1,2 @@
+CaloFutureProtoPMon.Members    += { "CaloFutureProtoElectronMonitor/EcalProtoElectronMon"};             
+
diff --git a/CaloFuture/CaloFutureMoniDst/options/EcalEFlowAlg.opts b/CaloFuture/CaloFutureMoniDst/options/EcalEFlowAlg.opts
new file mode 100644
index 0000000000000000000000000000000000000000..0138a4a0e1a5b167bb03459978dc56223ba5f85b
--- /dev/null
+++ b/CaloFuture/CaloFutureMoniDst/options/EcalEFlowAlg.opts
@@ -0,0 +1,20 @@
+CaloFutureEFlowAlg.Members += {   "CaloFutureEFlowAlg/EcalEFlowAlgo"};
+
+// define the subset of useful monitoring histos for EF
+EcalEFlowAlgo.histoList   = { "All" };
+
+//define parameters
+EcalEFlowAlgo.SplitAreas = false;
+EcalEFlowAlgo.EtFilterMax  = -999.;
+EcalEFlowAlgo.EnergyFilterMax = -999;
+EcalEFlowAlgo.ADCFilterMax = -999;
+EcalEFlowAlgo.ADCFilterMin  = -999;
+EcalEFlowAlgo.EtFilterMin  = -999.;
+EcalEFlowAlgo.EnergyFilterMin = -999;
+EcalEFlowAlgo.Simulation = false;
+EcalEFlowAlgo.IgnoreTAE = true;
+EcalEFlowAlgo.IgnoreNonBeamCrossing = true;
+EcalEFlowAlgo.IgnoreNonPhysicsTrigger = false;
+EcalEFlowAlgo.OneDimension = true;
+
+// EcalEFlowAlgo.Profile = true;
diff --git a/CaloFuture/CaloFutureMoniDst/options/HcalEFlowAlg.opts b/CaloFuture/CaloFutureMoniDst/options/HcalEFlowAlg.opts
new file mode 100644
index 0000000000000000000000000000000000000000..77d95f57a76270a2c40087dce29c4a2b146fc7d1
--- /dev/null
+++ b/CaloFuture/CaloFutureMoniDst/options/HcalEFlowAlg.opts
@@ -0,0 +1,20 @@
+CaloFutureEFlowAlg.Members += {   "CaloFutureEFlowAlg/HcalEFlowAlgo"};
+
+// define the subset of useful monitoring histos for EF
+HcalEFlowAlgo.histoList   = { "All" };
+
+//define parameters
+HcalEFlowAlgo.SplitAreas = false;
+HcalEFlowAlgo.EtFilterMax  = -999.;
+HcalEFlowAlgo.EnergyFilterMax = -999;
+HcalEFlowAlgo.ADCFilterMax = -999;
+HcalEFlowAlgo.ADCFilterMin  = -999;
+HcalEFlowAlgo.EtFilterMin  = -999.;
+HcalEFlowAlgo.EnergyFilterMin = -999;
+HcalEFlowAlgo.Simulation = false;
+HcalEFlowAlgo.IgnoreTAE = true;
+HcalEFlowAlgo.IgnoreNonBeamCrossing = true;
+HcalEFlowAlgo.IgnoreNonPhysicsTrigger = false;
+HcalEFlowAlgo.OneDimension = true;
+
+// HcalEFlowAlgo.Profile = true;
diff --git a/CaloFuture/CaloFutureMoniDst/options/PrsEFlowAlg.opts b/CaloFuture/CaloFutureMoniDst/options/PrsEFlowAlg.opts
new file mode 100644
index 0000000000000000000000000000000000000000..47bd723de584e9f0badacaeffd330046ca9ae816
--- /dev/null
+++ b/CaloFuture/CaloFutureMoniDst/options/PrsEFlowAlg.opts
@@ -0,0 +1,20 @@
+CaloFutureEFlowAlg.Members += {   "CaloFutureEFlowAlg/PrsEFlowAlgo"};
+
+// define the subset of useful monitoring histos for EF
+PrsEFlowAlgo.histoList   = { "All" };
+
+//define parameters
+PrsEFlowAlgo.SplitAreas = false;
+PrsEFlowAlgo.EtFilterMax  = -999.;
+PrsEFlowAlgo.EnergyFilterMax = -999;
+PrsEFlowAlgo.ADCFilterMax = -999;
+PrsEFlowAlgo.ADCFilterMin  = -999;
+PrsEFlowAlgo.EtFilterMin  = -999.;
+PrsEFlowAlgo.EnergyFilterMin = -999;
+PrsEFlowAlgo.Simulation = false;
+PrsEFlowAlgo.IgnoreTAE = true;
+PrsEFlowAlgo.IgnoreNonBeamCrossing = true;
+PrsEFlowAlgo.IgnoreNonPhysicsTrigger = false;
+PrsEFlowAlgo.OneDimension = true;
+
+// PrsEFlowAlgo.Profile = true;
diff --git a/CaloFuture/CaloFutureMoniDst/options/SpdMonitor.opts b/CaloFuture/CaloFutureMoniDst/options/SpdMonitor.opts
new file mode 100755
index 0000000000000000000000000000000000000000..6c1fde0a5abd82d8d27411462d362f215bcf919b
--- /dev/null
+++ b/CaloFuture/CaloFutureMoniDst/options/SpdMonitor.opts
@@ -0,0 +1,2 @@
+//SpdMon.HistogramFlag = true; // default
+//SpdMon.EcalThreshold = 700 ; // default
diff --git a/CaloFuture/CaloFutureMoniDst/python/CaloFutureMoniDst/Configuration.py b/CaloFuture/CaloFutureMoniDst/python/CaloFutureMoniDst/Configuration.py
new file mode 100755
index 0000000000000000000000000000000000000000..2849e921afd07d11ad9df21b5cd2ca0f8fe44116
--- /dev/null
+++ b/CaloFuture/CaloFutureMoniDst/python/CaloFutureMoniDst/Configuration.py
@@ -0,0 +1,219 @@
+#!/usr/bin/env gaudirun.py
+# =============================================================================
+## Configurable for CaloFuturerimeter Monitoring
+#  @author Vanya BELYAEV Ivan.Belyaev@nikhe.nl
+#  @date 2008-07-17
+# =============================================================================
+"""
+Configurable for CaloFuturerimeter Monitoring
+"""
+# =============================================================================
+__author__  = "Vanya BELYAEV Ivan.Belyaev@nikhef.nl"
+__version__ = "CVS tag $Name:  $, version $Revision: 1.4 $"
+# =============================================================================
+__all__  = (
+    'CaloFutureMoniDstConf',
+    )
+# =============================================================================
+from Gaudi.Configuration      import *
+
+from LHCbKernel.Configuration import *
+
+from CaloKernel.ConfUtils     import ( addAlgs        ,
+                                       printOnDemand  ,
+                                       prntCmp        ,
+                                       hltContext     , 
+                                       setTheProperty )
+
+from CaloFutureMoniDst.Monitor      import ( digitsMoni     ,
+                                       eflowMoni      , 
+                                       clustersMoni   , 
+                                       hyposMoni      ,
+                                       pi0sMoni       ,
+                                       pidsMoni       ,
+                                       protosMoni     ,
+                                       pidCheck       ,
+                                       recoCheck 
+                                       )
+
+# =============================================================================
+## @class CaloFutureMoniDstConf
+#  Configurable for CaloFuturerimeter Reconstruction
+#  @author Vanya BELYAEV Ivan.Belyaev@nikhef.nl
+#  @date 2008-07-17
+class CaloFutureMoniDstConf(LHCbConfigurableUser):
+    """
+    Class/Configurable to define the calorimeter monitoring
+    
+    """
+   ## define the slots
+    __slots__ = {
+        "Context"              : "Offline"   # The context within which to run
+        , "MeasureTime"        : False       # Measure the time for sequencers
+        , "OutputLevel"        : INFO        # The global output level
+        , 'MonitorSequence'    : None        # The monitor's sequence
+        , 'CheckerSequence'    : None        # The checker's sequence 
+        , 'MoniList'           : [ 'Digits'   ,
+                                   'EFlow'    ,
+                                   'Clusters' ,
+                                   'Hypos'    ,
+                                   'Pi0s'     ,
+                                   'Protos'   ,
+                                   'PIDs'     
+                                   ] 
+        , 'CheckList'          : ['Reco','PIDs']
+        , 'Histograms'         : 'OfflineFull' # Default Histograms level
+        , 'NoSpdPrs'           : False # Upgrade configuration without Prs/Spd
+        , 'Verbose'            : False
+        }
+
+    ## Default Histogram set
+    __known_histograms__ = [ "None", "Online", "OfflineExpress", "OfflineFull", "Expert" ]
+
+ 
+    ## configure monitoring of Digits
+    def digits   ( self ) :
+        """
+        Configure monitoring of Digits
+        
+        """
+        cmp = digitsMoni   ( self.getProp('Context') , self.getProp('NoSpdPrs'))
+        ##
+        return cmp
+
+    
+    ## configure E-Flow monitoring 
+    def eflow ( self ) :
+        """
+        Configure E-Flow monitoring
+        """
+        cmp = eflowMoni ( self.getProp('Context') )
+
+        return cmp
+
+    ## configure Clusters monitoring 
+    def clusters ( self ) :
+        """
+        Configure Clusters monitoring
+        """
+        cmp = clustersMoni ( self.getProp('Context') )
+        
+        return cmp
+
+    ## configure Hypos monitoring 
+    def hypos ( self ) :
+        """
+        Configure Hypos monitoring
+        """
+        cmp = hyposMoni ( self.getProp('Context') )
+        
+        return cmp
+
+    ## configure pi0 monitoring 
+    def pi0s ( self ) :
+        """
+        Configure Pi0s monitoring
+        """
+        cmp = pi0sMoni ( self.getProp('Context') )
+        
+        return cmp
+
+    ## configure pi0 monitoring 
+    def protos ( self ) :
+        """
+        Configure Protos monitoring
+        """
+        cmp = protosMoni ( self.getProp('Context') )
+        
+        return cmp
+
+    
+    ## configure PID monitoring 
+    def pids ( self ) :
+        """
+        Configure PIDs monitoring
+        """
+        cmp = pidsMoni ( self.getProp('Context'), self.getProp("Histograms") )
+      
+        return cmp
+
+
+    #--- configure the checkers
+    def pidChecker ( self ) :
+        cmp = pidCheck( self.getProp('Context'), self.getProp("NoSpdPrs") )      
+        return cmp
+    def recoChecker ( self ) :
+        cmp = recoCheck( self.getProp('Context'))
+        return cmp
+
+    
+    
+    ## Check the configuration
+    def checkConfiguration ( self ) :
+        """
+        Check the configuration
+        """
+
+        if self.getProp( 'Histograms' ) not in self.__known_histograms__:
+            raise RuntimeError("Unknown Histograms option '%s'" % self.getProp( 'Histograms' ))
+
+
+    def printConf(self) :
+        if self.getProp('NoSpdPrs') :
+            log.info("CaloFutureMoniDstConf : upgrade configuration without Spd/Prs")
+        if self.getProp('Verbose') :
+            log.info( self )
+
+ 
+    ## CaloFuturerimeter Monitoring Configuration
+    def applyConf ( self ) :
+        """
+        CaloFuturerimeter Monitor Configuration
+        """
+        log.info ('CaloFutureMoniConf: Apply CaloFuture Monitoring Configuration ')
+
+        self.printConf()
+        
+        self.checkConfiguration()
+        
+
+        #----- MONITORS
+        monList = self.MoniList        
+        seq     = []        
+        if 'Digits'     in monList : addAlgs ( seq , self.digits     () ) 
+        if 'EFlow'      in monList : addAlgs ( seq , self.eflow      () ) 
+        if 'Clusters'   in monList : addAlgs ( seq , self.clusters   () ) 
+        if 'Hypos'      in monList : addAlgs ( seq , self.hypos      () )
+        if 'Pi0s'       in monList : addAlgs ( seq , self.pi0s       () )
+        if 'Protos'     in monList : addAlgs ( seq , self.protos     () )
+        if 'PIDs'       in monList : addAlgs ( seq , self.pids       () )        
+        setTheProperty ( seq , 'Context'     , self.getProp('Context') )        
+        if self.isPropertySet("OutputLevel") :
+            setTheProperty ( seq , 'OutputLevel' , self.getProp('OutputLevel') )
+        setTheProperty ( seq , 'MeasureTime' , self.getProp('MeasureTime') )    
+        if self.isPropertySet('MonitorSequence') :
+            moniSeq=self.getProp('MonitorSequence')
+            addAlgs  ( moniSeq , seq ) 
+            log.info ('Configure main CaloFuture Moni MonitorSequence  : %s '% moniSeq.name() )
+            if self.getProp('Verbose') :
+                log.info ( prntCmp ( moniSeq ) ) 
+
+
+        #----- CHECKERS
+        checkList = self.CheckList        
+        cseq     = []        
+        if 'Reco'     in checkList : addAlgs ( cseq , self.recoChecker     () ) 
+        if 'PIDs'     in checkList : addAlgs ( cseq , self.pidChecker      () ) 
+        setTheProperty ( cseq , 'Context'     , self.getProp('Context') )        
+        if self.isPropertySet("OutputLevel") :
+            setTheProperty ( cseq , 'OutputLevel' , self.getProp('OutputLevel') )
+        setTheProperty ( cseq , 'MeasureTime' , self.getProp('MeasureTime') )    
+
+        if self.isPropertySet('CheckerSequence') :
+            checkSeq= self.getProp('CheckerSequence')
+            addAlgs  ( checkSeq  , cseq ) 
+            log.info ('Configure  CheckerSequence  : %s '% checkSeq.name() )
+            if self.getProp('Verbose') :
+                log.info ( prntCmp ( checkSeq ) ) 
+
+            
diff --git a/CaloFuture/CaloFutureMoniDst/python/CaloFutureMoniDst/Monitor.py b/CaloFuture/CaloFutureMoniDst/python/CaloFutureMoniDst/Monitor.py
new file mode 100755
index 0000000000000000000000000000000000000000..4ebc20ef699539a4b2f5d584aebfdcb0d689e28b
--- /dev/null
+++ b/CaloFuture/CaloFutureMoniDst/python/CaloFutureMoniDst/Monitor.py
@@ -0,0 +1,381 @@
+#!/usr/bin/env python
+# =============================================================================
+# $Id: Monitor.py,v 1.8 2010/05/20 09:55:38 odescham Exp $
+# =============================================================================
+## The major building blocks of CaloFuturerimeter Monitoring
+#  @author Vanya BELYAEV Ivan.Belyaev@nikhe.nl
+#  @date 2008-07-17
+# =============================================================================
+"""
+The major building blocks of CaloFuturerimeter Monitoring
+"""
+# =============================================================================
+__author__  = "Vanya BELYAEV Ivan.Belyaev@nikhef.nl"
+__version__ = "CVS tag $Name:  $, version $Revision: 1.8 $"
+# =============================================================================
+__all__ = (
+    'digitsMoni'     , 
+    'eflowMoni'      , 
+    'clustersMoni'   , 
+    'hyposMoni'      , 
+    'pi0Moni'        , 
+    'pidsMoni'      
+    )
+# =============================================================================
+from Gaudi.Configuration  import *
+
+from Configurables        import   GaudiSequencer
+from CaloKernel.ConfUtils import ( getAlgo        ,
+                                   setTheProperty ) 
+
+from GaudiKernel.SystemOfUnits import  ( MeV , GeV )
+
+
+# =============================================================================
+## prepare digit monitoring
+def digitsMoni ( context ,noSpdPrs=False) :
+    """
+    
+    Prepare digit monitoring
+    
+    """
+    from Configurables import  ( CaloFutureDigitMonitor ,
+                                 SpdMonitor       ) 
+    
+    alg = getAlgo ( GaudiSequencer   , 
+                    "CaloFutureDigitsMoni" ,
+                    context          )
+    
+    alg1 = getAlgo ( CaloFutureDigitMonitor , "EcalDigitMon"  , context ) 
+    alg2 = getAlgo ( CaloFutureDigitMonitor , "HcalDigitMon"  , context ) 
+    if not alg1.isPropertySet('histoList') :
+        alg1.histoList   = [ "1", "2" , "3" , "6" , "7" ]
+    if not alg2.isPropertySet('histoList') :
+        alg2.histoList   = [ "1", "2" , "3" , "6" , "7" ]
+
+    alg.Members = [alg1,alg2]
+
+    if not noSpdPrs :
+        alg3 = getAlgo ( CaloFutureDigitMonitor , "PrsDigitMon"   , context ) 
+        alg4 = getAlgo ( CaloFutureDigitMonitor , "SpdDigitMon"   , context ) 
+        alg5 =  getAlgo ( SpdMonitor , "SpdMon"   , context )
+        if not alg3.isPropertySet('histoList') :
+            alg3.histoList   = [ "1", "2" , "3" , "6" , "7" ]
+        if not alg4.isPropertySet('histoList') :
+            alg4.histoList   = [ "1", "2" , "3" , "6" ]
+        alg.Members += [alg3,alg4,alg5]    
+    setTheProperty ( alg , 'Context' , context )
+    return alg
+
+
+# ============================================================================
+## Define Energy flow monitoring 
+def eflowMoni ( context ) :
+    """
+    Define Energy flow omnitoring 
+    """
+    
+    from Configurables import  CaloFutureEFlowAlg
+    
+    seq = getAlgo ( GaudiSequencer  , 
+                    'CaloFutureEFlowMoni' ,
+                    context         )
+    
+    alg = getAlgo ( CaloFutureEFlowAlg    ,
+                    'EcalEFlowMon'  ,
+                    context         )
+
+    if not alg.isPropertySet('histoList') :
+        alg.histoList       = [ 'all' ]
+    if not alg.isPropertySet('SplitAreas') :
+        alg.SplitAreas      = False
+    if not alg.isPropertySet('OneDimension') :
+        alg.OneDimension    =  True
+    if not alg.isPropertySet('EtFilterMax') :
+        alg.EtFilterMax     =  1 * GeV
+    if not alg.isPropertySet('EnergyFilterMax') :
+        alg.EnergyFilterMax = 10 * GeV
+    
+    seq.Members = [ alg ] 
+
+    setTheProperty ( alg , 'Context' , context )
+    
+    return seq
+
+    
+# =============================================================================
+## prepare cluster monitoring
+def clustersMoni ( context ) :
+    """    
+    Prepare clusters monitoring
+    
+    """
+    
+    from Configurables import  CaloFutureClusterMonitor
+    
+    alg = getAlgo ( GaudiSequencer     , 
+                    "CaloFutureClustersMoni" ,
+                    context            )
+    
+    alg1 = getAlgo ( CaloFutureClusterMonitor ,
+                     'EcalClusterMon'   ,
+                     context            )
+    
+    alg2 = getAlgo ( CaloFutureClusterMonitor      ,
+                     'EcalSplitClusterMon'  ,
+                     context                 )
+ 
+    if not alg1.isPropertySet('histoList') :
+        alg1.histoList = [ "1", "2" , "3" , "4" , "7" , "8" ,  "9" ]
+
+#    delegate to CaloFutureAlgUtils  
+#    alg1.Input = 'Rec/Calo/EcalClusters'
+#    alg2.Input = 'Rec/Calo/EcalSplitClusters'
+
+#    alg.Members = [ alg1 , alg2 ]
+    alg.Members = [ alg1 ] ## do not monitor splitCluster so far
+    
+    setTheProperty ( alg , 'Context' , context )
+    
+    return alg
+
+
+# =============================================================================
+## prepare hypo monitoring
+def hyposMoni ( context ) :
+    """    
+    Prepare hypo monitoring
+    
+    """
+    
+    from Configurables import  CaloFutureHypoMonitor
+
+    alg = getAlgo ( GaudiSequencer    , 
+                    "CaloFutureHyposMoni"   ,
+                    context           )
+    
+    alg1 = getAlgo ( CaloFutureHypoMonitor  ,
+                     'ElectronMon'    ,
+                     context          )
+    alg2 = getAlgo ( CaloFutureHypoMonitor  ,
+                     'PhotonMon'      ,
+                     context          )
+    alg3 = getAlgo ( CaloFutureHypoMonitor  ,
+                     'SplitPhotonMon' ,
+                     context          )
+    alg4 = getAlgo ( CaloFutureHypoMonitor  ,
+                     'MergedPi0Mon'   ,
+                     context          )
+
+    # Delegate I/O to CaloFutureAlgUtils
+#    alg1.Input = 'Rec/Calo/Electrons'
+#    alg2.Input = 'Rec/Calo/Photons'
+#    alg3.Input = 'Rec/Calo/SplitPhotons'
+#    alg4.Input = 'Rec/Calo/MergedPi0s'
+
+
+    if not alg1.isPropertySet('histoList') :
+        alg1 .histoList = [ "1", "2" , "3" , "7" , "8" , "9" , "10" , "11" ,"14"]
+    if not alg2.isPropertySet('histoList') :
+        alg2 .histoList = [ "1", "2" , "3" , "7" , "8" , "9" , "10" , "11" ,"14"]
+    if not alg3.isPropertySet('histoList') :
+        alg3 .histoList = [ "1", "2" , "3" , "7" , "8" , "9" , "10" , "11" ]
+    if not alg4.isPropertySet('histoList') :
+        alg4 .histoList = [ "1", "2" , "3" , "4" , "7", "8" , "9","14"]
+
+ 
+    alg.Members = [ alg1 , alg2 , alg3 , alg4 ]
+
+
+    setTheProperty ( alg , 'Context' , context )
+ 
+    return alg
+
+
+
+
+
+# =============================================================================
+## Define pi0 monitoring
+def pi0sMoni ( context ) :
+    """    
+    Define pi0 monitoring
+    
+    """
+    
+    from Configurables import  CaloFuturePi0Monitor
+
+
+    alg = getAlgo ( GaudiSequencer    , 
+                    "DiPhotonMoni"   ,
+                    context           )
+
+    alg1 = getAlgo  ( CaloFuturePi0Monitor   ,
+                     'ResolvedPi0Mon' ,
+                     context          )
+
+    alg2 = getAlgo  ( CaloFuturePi0Monitor   ,
+                      'EtaMon' ,
+                      context          )
+    
+    if not alg1.isPropertySet('PhotonPtFilter') :
+        alg1.PhotonPtFilter = 500.*MeV;
+
+    if not alg1.isPropertySet('histoList') :
+        alg1.histoList = [ "1", "2" , "3" , "4", "5", "6", "7" ]
+
+
+    if not alg2.isPropertySet('PhotonMaxPtFilter') :
+        alg2.PhotonMaxPtFilter = 1000.*MeV;
+
+    if not alg2.isPropertySet('HistoMassMin') :
+        alg2.HistoMassMin = 400.*MeV;
+
+    if not alg2.isPropertySet('HistoMassMax') :
+        alg2.HistoMassMax = 700.*MeV;
+
+    if not alg2.isPropertySet('histoList') :
+        alg2.histoList = [ "1", "2" , "3" , "4", "5", "6", "7" ]
+
+    alg.Members = [ alg1 , alg2 ]
+    setTheProperty ( alg , 'Context' , context )
+    
+    return alg
+
+# =============================================================================
+## Define pi0 monitoring
+def protosMoni ( context ) :
+    """    
+    Define protoElectron monitoring
+    
+    """
+    
+    from Configurables import  CaloFutureProtoElectronMonitor
+
+    alg = getAlgo  ( CaloFutureProtoElectronMonitor   ,
+                     'ProtoElectronMon' ,
+                     context          )
+
+
+    if not alg.isPropertySet('histoList') :
+        alg.histoList = [ "All" ]
+
+    setTheProperty ( alg , 'Context' , context )
+    
+    return alg
+
+# =============================================================================
+## define CaloFuturePIDs monitoring
+def pidsMoni ( context, Histograms ) :
+    """
+    Define CaloFuturePIDs monitoring
+    """
+    
+    from Configurables import ( CaloFutureClusterMatchMonitor ,
+                                CaloFutureHypoMatchMonitor    ,
+                                CaloFutureEMuPIDMon           ) 
+    
+    alg = getAlgo ( GaudiSequencer ,
+                    'CaloFuturePIDsMoni' ,
+                    context        )
+
+    alg1 = getAlgo ( CaloFutureClusterMatchMonitor  ,
+                     'PhotonMatchMon'         ,
+                     context                  )
+    alg2 = getAlgo ( CaloFutureHypoMatchMonitor     ,
+                     'ElectronMatchMon'       ,
+                     context                  )
+    alg3 = getAlgo ( CaloFutureHypoMatchMonitor     ,
+                     'BremMatchMon'           ,
+                     context                  )
+
+    alg5 = getAlgo ( CaloFutureEMuPIDMon            ,
+                     'CaloFutureEMuPIDMonUncut'     ,
+                     context                  )
+
+    alg6 = getAlgo ( CaloFutureEMuPIDMon            ,
+                     'CaloFutureEMuPIDMonSoft'      ,
+                     context                  )
+
+    alg7 = getAlgo ( CaloFutureEMuPIDMon            ,
+                     'CaloFutureEMuPIDMonHard'      ,
+                     context                  )
+
+    ## Delegate I/O to CaloFutureAlgUtils
+#    alg1.Input  =   'Rec/Calo/ClusterMatch'
+#    alg1.Inputs = [ 'Rec/Calo/EcalClusters' ]    
+#    alg2.Input  =   'Rec/Calo/ElectronMatch'
+#    alg2.Inputs = [ 'Rec/Calo/Electrons'    ]    
+#    alg3.Input  =   'Rec/Calo/BremMatch'
+#    alg3.Inputs = [ 'Rec/Calo/Photons'      ]
+
+    if not alg5.isPropertySet(     'uncut') : alg5.uncut     = True
+    if not alg5.isPropertySet('SplitSides') : alg5.SplitSides= True
+
+    if not alg7.isPropertySet(     'pTmin') : alg7.pTmin     = 500.
+    if not alg7.isPropertySet(  'RichDLLe') : alg7.RichDLLe  = 4.
+    if not alg7.isPropertySet( 'maxEHcalE') : alg7.maxEHcalE = 1000.
+    if not alg7.isPropertySet(   'minPrsE') : alg7.minPrsE   =-1.e10
+
+    alg.Members = [ alg1 , alg2 , alg3 ,        alg5, alg6, alg7 ]
+
+
+    setTheProperty ( alg , 'Context' , context )
+
+    return alg
+
+### ------ CHECKING ----- ###
+def recoCheck( context ) :
+
+    from Configurables import ( CaloFutureClusterChecker,CaloFuturePi0Checker)
+    
+    alg  = getAlgo ( GaudiSequencer    ,'CaloFutureRecoCheck'     , context)
+    alg1 = getAlgo ( CaloFutureClusterChecker,'CaloFutureClusterChecker',context)
+    alg2 = getAlgo ( CaloFuturePi0Checker    ,'CaloFuturePi0Checker'    ,context)
+    alg.Members=[alg1,alg2]
+    setTheProperty(alg,'Context',context)
+    return alg
+
+def pidCheck( context,noSpdPrs=False ) :
+
+    from Configurables import ( CaloFuturePIDsChecker,CaloFuturePhotonChecker)
+    
+    alg  = getAlgo ( GaudiSequencer    ,'CaloFuturePIDsCheck'     , context)
+    alg1 = pidCheckerConf('PIDeEcalChecker',context,11,"Rec/Calo/EcalPIDe",50.0*GeV,0.0,"Long", "Rec/Calo/InAccEcal" )
+    alg2 = pidCheckerConf('PIDeHcalChecker',context,11,"Rec/Calo/HcalPIDe",50.0*GeV,0.0,"Long", "Rec/Calo/InAccHcal" )
+    alg3 = pidCheckerConf('PIDeBremChecker',context,11,"Rec/Calo/BremPIDe",50.0*GeV,0.0,"Long", "Rec/Calo/InAccBrem" )
+    alg4 = pidCheckerConf('PIDmEcalChecker',context,13,"Rec/Calo/EcalPIDmu",25.0*GeV,0.0,"Long", "Rec/Calo/InAccEcal" )
+    alg5 = pidCheckerConf('PIDmHcalChecker',context,13,"Rec/Calo/HcalPIDmu",25.0*GeV,0.0,"Long", "Rec/Calo/InAccHcal" )    
+    alg.Members=[alg1,alg2,alg3,alg4,alg5]
+    if not noSpdPrs :
+        alg6 = pidCheckerConf('PIDePrsChecker',context,11,"Rec/Calo/PrsPIDe",50.0*GeV,0.0,"Long", "Rec/Calo/InAccPrs" )
+        alg.Members += [alg6]
+        # caloPhotonChecker
+        alg7 = getAlgo ( CaloFuturePhotonChecker,'CaloFuturePhotonChecker',context)
+        alg7.Pdf=True
+        alg7.EPrsBin=[50.,0.,200.]
+        alg7.Chi2Bin=[26.,0.,104.]
+        alg7.SeedBin=[50.,0.,1.]
+#        alg.Members += [alg7]
+    setTheProperty(alg,'Context',context)
+    return alg
+
+def pidCheckerConf(name,context,particle,input,norm,cut,type,acc) :
+    from Configurables import ( CaloFuturePIDsChecker )
+    algo = getAlgo ( CaloFuturePIDsChecker,name,context)
+    algo.Particle        = particle
+    algo.Input           = input
+    algo.Normalization   = norm
+    algo.Cut             = cut
+    algo.TrackType       = type
+    algo.TrackAcceptance = acc
+    return algo
+
+    
+# =============================================================================
+if '__main__' == __name__ :
+    print __doc__
+    
+# =============================================================================
+# The END
+# =============================================================================
diff --git a/CaloFuture/CaloFutureMoniDst/python/CaloFutureMoniDst/__init__.py b/CaloFuture/CaloFutureMoniDst/python/CaloFutureMoniDst/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/CaloFuture/CaloFutureMoniDst/src/CaloFutureAlignmentNtp.cpp b/CaloFuture/CaloFutureMoniDst/src/CaloFutureAlignmentNtp.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..38bf6a22ba0fdf9dd7a55bb9f3a1b91aa66ad284
--- /dev/null
+++ b/CaloFuture/CaloFutureMoniDst/src/CaloFutureAlignmentNtp.cpp
@@ -0,0 +1,585 @@
+// Include files
+#include "LHCbMath/LineTypes.h"
+#include "LHCbMath/GeomFun.h"
+//
+#include "CaloFutureAlignmentNtp.h"
+#include "CaloFutureMoniUtils.h"
+
+namespace {
+    // hack to allow for tools with non-const interfaces...
+    template <typename IFace>
+    IFace* fixup(const ToolHandle<IFace>& iface) { return &const_cast<IFace&>(*iface); }
+}
+
+//-----------------------------------------------------------------------------
+// Implementation file for class : CaloFutureAlignmentNtp
+//
+// 2009-12-11 : Olivier Deschamps
+//-----------------------------------------------------------------------------
+
+// Declaration of the Algorithm Factory
+DECLARE_COMPONENT( CaloFutureAlignmentNtp )
+
+namespace {
+  using Line = Gaudi::Math::Line<Gaudi::XYZPoint,Gaudi::XYZVector>;
+
+  // Return distance between two calo cell.
+  double distance( const LHCb::CaloCellID& id1, const LHCb::CaloCellID& id2 ){
+    return sqrt(pow(double(id1.row()-id2.row()), 2)+pow(double(id1.col() - id2.col()),2));
+  }
+}
+
+//==============================================================================
+// Standard constructor, initializes variables
+//==============================================================================
+
+CaloFutureAlignmentNtp::CaloFutureAlignmentNtp( const std::string& name, ISvcLocator* pSvcLocator)
+: Consumer( name, pSvcLocator, {
+    KeyValue{ "VertexLoc"     , ""}, // Lecacy naming
+    KeyValue{ "InputODIN"     , LHCb::ODINLocation::Default                 },
+    KeyValue{ "InputDigits"   , LHCb::CaloFutureAlgUtils::CaloFutureDigitLocation("SPD")},
+    KeyValue{ "InputTracks"   , LHCb::TrackLocation::Default                },
+    KeyValue{ "InputContainer", LHCb::ProtoParticleLocation::Charged },
+})
+{
+  // Tools
+  declareProperty( "ExtrapolatorType" , m_extrapolator );
+}
+
+//==============================================================================
+// Initialization
+//==============================================================================
+
+StatusCode CaloFutureAlignmentNtp::initialize() {
+  StatusCode sc = Consumer::initialize();
+  if( sc.isFailure() ) return sc;
+  if( msgLevel(MSG::DEBUG) ) debug() << "==> Initialize" << endmsg;
+  if( !m_tracks.empty() )info() << "Will only look at track type(s) = " << m_tracks << endmsg;
+  else info() << "Will look at any track type" << endmsg;
+
+  // Get & retrieve & configure tools
+  m_calo = getDet<DeCalorimeter>(DeCalorimeterLocation::Ecal);
+  if(!( m_counterStat.retrieve()
+     && m_caloElectron.retrieve()
+     && m_odin.retrieve()
+     && m_toSpd.retrieve()
+     && m_toPrs.retrieve()
+     && m_extrapolator.retrieve() )){
+    error() << "Unable to retrive one of the ToolHandles" << endmsg;
+    return StatusCode::FAILURE;
+  }
+  m_toSpd->setCalos( "Ecal", "Spd");
+  m_toPrs->setCalos( "Ecal", "Prs");
+
+  // set vertex location
+  if(m_vertLoc == "")
+    m_vertLoc = m_usePV3D ? LHCb::RecVertexLocation::Velo3D : LHCb::RecVertexLocation::Primary;
+
+  //activate pairing when mass filter is on
+  if(m_mas.value().first != -99999 || m_mas.value().second != +99999) m_pairing=true;
+
+  // set vertex location
+  m_vertLoc = inputLocation();  // <-- Careful with the index
+  if(m_vertLoc == "")
+    m_vertLoc = m_usePV3D ? LHCb::RecVertexLocation::Velo3D : LHCb::RecVertexLocation::Primary;
+  updateHandleLocation( *this, "VertexLoc", m_vertLoc );
+
+  return StatusCode::SUCCESS;
+}
+
+//==============================================================================
+
+bool CaloFutureAlignmentNtp::acceptTrack(const LHCb::Track* track) const {
+  if( track == nullptr ) return false;
+  if( m_tracks.empty() ) return true;
+  const int ttype = track->type();
+  return std::any_of(m_tracks.begin(), m_tracks.end(), [ttype](int itype){return itype==ttype;});
+}
+
+//==============================================================================
+
+bool CaloFutureAlignmentNtp::hypoProcessing(const LHCb::CaloHypo* hypo) const {
+  if( hypo == nullptr ) return false;
+  LHCb::CaloMomentum momentum( hypo );
+  const double e  = momentum.e();
+  const double et = momentum.pt();
+  if( !inRange(m_et , et )) return false;
+  if( !inRange(m_e  , e  )) return false;
+  const double ePrs = fixup(m_toPrs)->energy( *hypo , "Prs"  );
+  if( !inRange(m_prs, ePrs)) return false;
+  const double iSpd = fixup(m_toSpd)->multiplicity( *hypo , "Spd");
+  if( !inRange(m_spd, iSpd)) return false;
+  if( m_inArea && !inArea(hypo) ) return false;
+  return true;
+}
+
+//==============================================================================
+
+bool CaloFutureAlignmentNtp::inArea(const LHCb::CaloHypo* hypo) const {
+  const auto hypoR  = position3d(hypo);
+  const auto cell   = m_calo->Cell_( hypoR );
+  if( !cell ){
+    if(m_counterStat->isQuiet()) counter("no cell related to position") += 1;
+    info() << "No valid cell related to position " << hypoR << endmsg;
+    return false;
+  }
+  return cell->neighbors().size() == 8;
+}
+
+
+//==============================================================================
+// Main execution
+//==============================================================================
+
+void CaloFutureAlignmentNtp::operator()(const Vertices& verts, const ODIN& odin,
+      const Digits& digits, const Tracks& tracks, const Protos& protos) const {
+
+  if( msgLevel(MSG::DEBUG) ) debug() << "==> Execute" << endmsg;
+  if( m_counterStat->isQuiet() ) counter("#PV="+ Gaudi::Utils::toString(verts.size()) + " ["+inputLocation()+"]")+=1;
+
+  // 1. Validate event
+  m_odin->getTime();
+  const auto nSpd       = digits.size();
+  const auto nTracks    = tracks.size();
+  const auto nVertices  = verts.size();
+  if( !inRange( m_nSpd, nSpd      )) return;
+  if( !inRange( m_nTrk, nTracks   )) return;
+  if( !inRange( m_nVtx, nVertices )) return;
+  if(m_counterStat->isQuiet()) counter("1-selected events") += 1;
+
+  // Loop over protoparticles
+  for( auto p = protos.begin(); protos.end() != p ; ++p ){
+    const auto proto = *p;
+
+    // 2: Validate proto
+    if( !fixup(m_caloElectron)->set(proto)) continue;
+    if( m_counterStat->isQuiet()) counter("2-selected protos")+=1;
+
+    // 3: Validate track
+    const auto track = proto->track();
+    if( !acceptTrack( track )) continue;
+    if( m_counterStat->isQuiet()) counter("3-selected tracks")+=1;
+
+    // 4: Validate hypo
+    const auto hypo = fixup(m_caloElectron)->electron();
+    if( !hypoProcessing(hypo) ) continue;
+    if( m_counterStat->isQuiet()) counter("4-selected hypos")+=1;
+
+    // 5: Validate electron
+    const auto eOp      = fixup(m_caloElectron)->eOverP();
+    if( !inRange( m_eop   , eOp)) continue;
+    if( !inRange( m_dlle  , proto->info(LHCb::ProtoParticle::additionalInfo::CombDLLe , 9999.))) continue;
+    if( !inRange( m_rdlle , proto->info(LHCb::ProtoParticle::additionalInfo::RichDLLe, 9999.))) continue;
+    if( !inRange( m_bMatch, proto->info(LHCb::ProtoParticle::additionalInfo::CaloBremMatch, 9999.))) continue;
+    if( !inRange( m_eMatch, proto->info(LHCb::ProtoParticle::additionalInfo::CaloElectronMatch, 9999.))) continue;
+    if( !inRange( m_cMatch, proto->info(LHCb::ProtoParticle::additionalInfo::CaloTrMatch, 9999.))) continue;
+    if( m_counterStat->isQuiet()) counter("5-selected electrons")+=1;
+
+    // track extrapolation
+    const auto cluster  = firstCluster(hypo);
+    const auto id       = cluster->seed();
+    const auto hypoR    = position3d(hypo);
+    const auto clusR    = position3d(cluster);
+    const auto statR    = position3d(fixup(m_caloElectron)->caloState());
+    const auto closR    = position3d(fixup(m_caloElectron)->closestState());
+    const auto cs       = momentum(fixup(m_caloElectron)->caloState());
+    const auto theta    = fixup(m_caloElectron)->caloState().momentum().Theta();
+    const auto t        = momentum(track);
+    const auto brem     = fixup(m_caloElectron)->bremstrahlung();
+    const auto hasBrem  = (brem!=nullptr);
+    if( m_brem && !hasBrem ) continue; // is Brem explicitly requested
+
+    const Gaudi::XYZPoint cellR( m_calo->cellX(id) , m_calo->cellY(id), m_calo->cellZ(id) );// seed position
+
+    // Bremstrahllung
+    const auto bP       = momentum(fixup(m_caloElectron)->bremCaloFutureMomentum());
+    const auto bremR    = position3d(brem);
+    const auto bcluster = firstCluster(brem);
+    const auto bid      = bcluster->seed();
+    const auto bclusR   = position3d(bcluster);
+    const auto bcellR   = Gaudi::XYZPoint( m_calo->cellX(bid) , m_calo->cellY(bid), m_calo->cellZ(bid) );// seed
+    const auto dist     = hasBrem ? distance(bid,id) : -1.;
+    if(hasBrem){
+      // brem-electron separation
+      if( bid.area()==id.area() && !inRange( m_dist, dist ) ) continue;
+      if( m_counterStat->isQuiet() ) counter("6-selected electron+Brem")+=1;
+    }
+
+    // perform electron pairing
+    double mas = 9999.;
+    if( m_pairing && m_extrapolator!=0 ){
+      for( auto pp = p+1 ; protos.end() != pp ; ++pp ){
+        const auto proto2 = *pp;
+        if( !fixup(m_caloElectron)->set(proto2) ) continue;;
+        const auto hypo2 = fixup(m_caloElectron)->electron();
+        if( hypo == hypo2 ) continue;
+        if( !hypoProcessing( hypo2 ) ) continue;
+        const auto eOp2 = fixup(m_caloElectron)->eOverP();
+        if( !inRange( m_eop, eOp2 )) continue;
+        if( !inRange( m_dlle , proto2->info(LHCb::ProtoParticle::additionalInfo::CombDLLe, 0.))) continue;
+        if( !inRange( m_rdlle, proto2->info(LHCb::ProtoParticle::additionalInfo::RichDLLe, 0.))) continue;
+        // compute mass
+        const auto t1 = proto->track();
+        const auto t2 = proto2->track();
+        if( !acceptTrack(t2) ) continue;
+        if( t1==nullptr || t2==nullptr ) continue;
+        if( -1 != t1->charge()*t2->charge()) continue;
+        LHCb::State st1 = t1->firstState();
+        LHCb::State st2 = t2->firstState();
+        StatusCode sc = m_extrapolator->propagate(st1, 0.);
+        if(sc.isFailure()) Warning("Propagation 1 failed").ignore();
+        sc = m_extrapolator->propagate(st2, 0.);
+        if(sc.isFailure()) Warning("Propagation 2 failed").ignore();
+        const auto p1 = st1.momentum();
+        const auto p2 = st2.momentum();
+        double m2 = p1.R()*p2.R();
+        m2 -= p1.X()*p2.X();
+        m2 -= p1.Y()*p2.Y();
+        m2 -= p1.Z()*p2.Z();
+        m2 *= 2;
+        if( m2 > 0 ){
+          const double m = sqrt(m2) ;
+          if( m < mas ) mas = m;
+        }
+      }
+      // add mass
+      if( !inRange( m_mas, mas ) ) continue;
+    }
+
+    // Start filling tuple
+    if(m_tuple){
+      auto ntp = nTuple(500, "CaloFutureAlignment", CLID_ColumnWiseTuple);
+      ntp->column( "Spd"        , fixup(m_toSpd)->multiplicity( *hypo, "Spd" ));
+      ntp->column( "Prs"        , fixup(m_toPrs)->energy( *hypo , "Prs" ));
+      ntp->column( "BremEleDist", dist );
+      ntp->column( "TrackMatch" , proto->info(LHCb::ProtoParticle::additionalInfo::CaloTrMatch, 9999.));
+      ntp->column( "ElecMatch"  , proto->info(LHCb::ProtoParticle::additionalInfo::CaloElectronMatch, 9999.));
+      ntp->column( "BremMatch"  , proto->info(LHCb::ProtoParticle::additionalInfo::CaloBremMatch, 9999.));
+      ntp->column( "TrajectoryL", proto->info(LHCb::ProtoParticle::additionalInfo::CaloTrajectoryL, 9999.));
+      ntp->column( "VeloCharge" , proto->info(LHCb::ProtoParticle::additionalInfo::VeloCharge, -1.));
+      ntp->column( "DLLe"       , proto->info(LHCb::ProtoParticle::additionalInfo::CombDLLe, 0.));
+      ntp->column( "RichDLLe"   , proto->info(LHCb::ProtoParticle::additionalInfo::RichDLLe, 0.));
+      // hypo info
+      ntp->column("EoP"   , eOp );
+      ntp->column("hypoE" , LHCb::CaloMomentum(hypo).e());
+      ntp->column("hypoR" , hypoR );
+      // track info
+      ntp->column("Charge"        , track->charge());
+      ntp->column("TrackP"        , t);
+      ntp->column("TrackR"        , statR);
+      ntp->column("ClosestR"      , closR);
+      ntp->column("caloState"     , cs );
+      ntp->column("caloStateErrX" , sqrt( fixup(m_caloElectron)->caloState().covariance()(0,0)));
+      ntp->column("caloStateErrY" , sqrt( fixup(m_caloElectron)->caloState().covariance()(1,1)));
+      ntp->column("caloStateErrTX", sqrt( fixup(m_caloElectron)->caloState().covariance()(2,2)));
+      ntp->column("caloStateErrTY", sqrt( fixup(m_caloElectron)->caloState().covariance()(3,3)));
+      ntp->column("incidence",theta);
+      // cluster info
+      ntp->column("id"      , id.index());
+      ntp->column("ClusterE", cluster->e());
+      ntp->column("ClusterR", clusR);
+      ntp->column("SeedR"   , cellR);
+      // brem info
+      ntp->column("BremId"      , bid.index());
+      ntp->column("BremP"       , bP);
+      ntp->column("BremR"       , bremR);
+      ntp->column("BremClusterR", bclusR);
+      ntp->column("BremSeedR"   , bcellR);
+
+      double bStX=0;
+      double bStY=0;
+      double bStTX=0;
+      double bStTY=0;
+      double bStCX=0;
+      double bStCY=0;
+
+      if( hasBrem ){
+        auto bState = (LHCb::State*) track->stateAt(LHCb::State::Location::BegRich1);
+        if( bState == nullptr ){
+          bState = track->states()[0];
+          debug() << track->states();
+          Warning("BegRich1 state does not exists - used first state", StatusCode::SUCCESS).ignore();
+        }
+        bStX  = sqrt( bState->covariance()(0,0) );
+        bStY  = sqrt( bState->covariance()(1,1) );
+        bStTX = sqrt( bState->covariance()(2,2) );
+        bStTY = sqrt( bState->covariance()(3,3) ) ;
+        const auto dz = bremR.Z()-bState->z();
+        bStCX = bState->covariance()(0,0) +  bState->covariance()(2,2) * dz * dz +  bState->covariance()(0,2) * 2.*dz;
+        bStCY = bState->covariance()(1,1) +  bState->covariance()(3,3) * dz * dz +  bState->covariance()(1,3) * 2.*dz;
+        bStCX = (bStCX > 0) ? sqrt( bStCX) : 0;
+        bStCY = (bStCY > 0) ? sqrt( bStCY) : 0;
+      }
+      ntp->column( "bStateErrX" , bStX);
+      ntp->column( "bStateErrY" , bStY);
+      ntp->column( "bStateErrTX", bStTX);
+      ntp->column( "bStateErrTY", bStTY);
+      ntp->column( "bCaloStateX", bStCX);
+      ntp->column( "bCaloStateY", bStCY);
+
+      // odin info
+      ntp->column("run"        , odin.runNumber());
+      ntp->column("event"      , (double) odin.eventNumber() );
+      ntp->column("triggertype", odin.triggerType());
+      ntp->column("nSpd"       , nSpd      );
+      ntp->column("nTracks"    , nTracks   );
+      ntp->column("nVertices"  , nVertices );
+      if(m_pairing) ntp->column("MinMee",mas);
+      ntp->write();
+      if(m_counterStat->isQuiet()) counter("7-Events in ntuple")+=1;
+    }
+
+    // Histogramming
+    if( !m_histo && !m_profil ) return;
+
+    std::string prof ="";
+
+    if(m_counterStat->isQuiet()) counter("8-Events in histos")+=1;
+
+    const std::string area   = id.areaName() ;
+    const std::string side   = (id.col() < 32) ? "C" : "A";
+    const std::string level  = (id.row() < 32) ? "Bottom" : "Top";
+    const std::string barea  = bid.areaName() ;
+    const std::string bside  = (bid.col() < 32) ? "C" : "A";
+    const std::string blevel = (bid.row() < 32) ? "Bottom" : "Top";
+
+    const std::string charge = (track->charge() > 0 ) ? "electron" : "positron";
+    std::vector<std::string> q{ "all", charge };
+
+    std::vector<std::string> bsplit{
+      "all/",
+      barea+"/all/",
+      barea+"/"+charge+"/all/",
+      barea+"/"+bside+"/all/",
+      barea+"/"+bside+"/"+charge+"/all/",
+      barea+"/"+bside+"/"+ blevel +"/all/",
+      barea+"/"+bside+"/"+ blevel +"/"+charge+"/all/",
+      barea+"/"+blevel+"/all/",
+      barea+"/"+blevel+"/"+charge+"/all/",
+      barea+"/"+blevel+"/"+ bside +"/all/",
+      barea+"/"+blevel+"/"+ bside +"/"+charge+"/all/",
+    };
+
+    std::vector<std::string> split{
+      "all/",
+      area+"/all/",
+      area+"/"+charge+"/all/",
+      area+"/"+side+"/all/",
+      area+"/"+side+"/"+charge+"/all/",
+      area+"/"+side+"/"+ level +"/all/",
+      area+"/"+side+"/"+ level +"/"+charge+"/all/",
+      area+"/"+level+"/all/",
+      area+"/"+level+"/"+charge+"/all/",
+      area+"/"+level+"/"+ side +"/all/",
+      area+"/"+level+"/"+ side +"/"+charge+"/all/",
+    };
+
+    // ------ brem aligment (DeltaXX versus ThetaYY)
+    const double thMin  = -0.30;
+    const double thMax  = +0.30;
+    const double bthX   = t.X()/t.Z();
+    const double bthY   = t.Y()/t.Z();
+    const double step   = (thMax-thMin)/m_thBin;
+    if( hasBrem ){
+      const double bdceX  = (bcellR.X() - bthX*bcellR.Z()); // relative to cell
+      const double bdceY  = (bcellR.Y() - bthY*bcellR.Z());
+      const double bdbX   = (bremR.X()  - bthX*bremR.Z());  // relative to hypo
+      const double bdbY   = (bremR.Y()  - bthY*bremR.Z());
+      const double bdclX  = (bclusR.X() - bthX*bclusR.Z()); // relative to cluster
+      const double bdclY  = (bclusR.Y() - bthY*bclusR.Z());
+
+      // extrapolate at Z = ShowerMax plane !!
+      Gaudi::XYZPoint origin(0,0,0);
+      Gaudi::XYZVector vector(bthX,bthY,1.);
+      const Line line( origin ,vector );
+      const auto plane  = m_calo->plane(CaloPlane::ShowerMax);
+      const auto point  = intersection(line,plane);
+      const double bdpX = (bremR.X() - bthX*point.Z());
+      const double bdpY = (bremR.Y() - bthY*point.Z());
+
+      const std::string bbinX = "bin"+Gaudi::Utils::toString( int((bthX-thMin)/step) );
+      const std::string bbinY = "bin"+Gaudi::Utils::toString( int((bthY-thMin)/step) );
+      std::vector<std::string> bhat{ "", bbinX, bbinY };
+
+      plot1D(eOp,"eOp control (all)", 0.5, 2.,100);
+      for( const auto label1: q ){
+        const std::string base = "BremAlign/Delta/" + label1 + "/";
+        if(m_histo){
+          for( const auto label2: bhat ){
+            plot1D( bdceX, label1+"Cell/"+label2+"/dX"   , "dX  : Cell-Brem(CellZ)"      , m_min, m_max, m_bin );
+            plot1D( bdceY, label1+"Cell/"+label2+"/dY"   , "dY  : Cell-Brem(CellZ)"      , m_min, m_max, m_bin );
+            plot1D( bdclX, label1+"Cluster/"+label2+"/dX", "dX  : Cluster-Brem(ClusterZ)", m_min, m_max, m_bin );
+            plot1D( bdclY, label1+"Cluster/"+label2+"/dY", "dY  : Cluster-Brem(ClusterZ)", m_min, m_max, m_bin );
+            plot1D( bdbX , label1+"Hypo/"+label2+"/dX"   , "dX  : Hypo-Brem(HypoZ)"      , m_min, m_max, m_bin );
+            plot1D( bdbY , label1+"Hypo/"+label2+"/dY"   , "dY  : Hypo-Brem(HypoZ)"      , m_min, m_max, m_bin );
+            plot1D( bdpX , label1+"HypoSM/"+label2+"/dX" , "dX  : Hypo-Brem(ShowerMax)"  , m_min, m_max, m_bin );
+            plot1D( bdpY , label1+"HypoSM//"+label2+"/dY", "dY  : Hypo-Brem(ShowerMax)"  , m_min, m_max, m_bin );
+          }
+        }
+        if(m_profil){
+          profile1D( bthX, bdceX , label1+"Cell/dX.thX"   , "dX.vs.thX: Cell-Brem(CellZ)"      , thMin, thMax, m_thBin, prof, m_min, m_max );
+          profile1D( bthY, bdceX , label1+"Cell/dX.thY"   , "dX.vs.thY: Cell-Brem(CellZ)"      , thMin, thMax, m_thBin, prof, m_min, m_max );
+          profile1D( bthX, bdclX , label1+"Cluster/dX.thX", "dX.vs.thX: Cluster-Brem(ClusterZ)", thMin, thMax, m_thBin, prof, m_min, m_max );
+          profile1D( bthY, bdclX , label1+"Cluster/dX.thY", "dX.vs.thY: Cluster-Brem(ClusterZ)", thMin, thMax, m_thBin, prof, m_min, m_max );
+          profile1D( bthX, bdbX  , label1+"Hypo/dX.thX"   , "dX.vs.thX: Hypo-Brem(HypoZ)"      , thMin, thMax, m_thBin, prof, m_min, m_max );
+          profile1D( bthY, bdbX  , label1+"Hypo/dX.thY"   , "dX.vs.thY: Hypo-Brem(HypoZ)"      , thMin, thMax, m_thBin, prof, m_min, m_max );
+          profile1D( bthX, bdpX  , label1+"HypoSM/dX.thX" , "dX.vs.thX: Hypo-Brem(ShoweMax)"   , thMin, thMax, m_thBin, prof, m_min, m_max );
+          profile1D( bthY, bdpX  , label1+"HypoSM/dX.thY" , "dX.vs.thY: Hypo-Brem(ShowerMax)"  , thMin, thMax, m_thBin, prof, m_min, m_max );
+          profile1D( bthX, bdceY , label1+"Cell/dY.thX"   , "dY.vs.thX: Hypo-Brem(CellZ)"      , thMin, thMax, m_thBin, prof, m_min, m_max );
+          profile1D( bthY, bdceY , label1+"Cell/dY.thY"   , "dY.vs.thY: Hypo-Brem(CellZ)"      , thMin, thMax, m_thBin, prof, m_min, m_max );
+          profile1D( bthX, bdclY , label1+"Cluster/dY.thX", "dY.vs.thX: Cluster-Brem(ClusterZ)", thMin, thMax, m_thBin, prof, m_min, m_max );
+          profile1D( bthY, bdclY , label1+"Cluster/dY.thY", "dY.vs.thY: Cluster-Brem(ClusterZ)", thMin, thMax, m_thBin, prof, m_min, m_max );
+          profile1D( bthX, bdbY  , label1+"Hypo/dY.thX"   , "dY.vs.thX: Hypo-Brem(HypoZ)"      , thMin, thMax, m_thBin, prof, m_min, m_max );
+          profile1D( bthY, bdbY  , label1+"Hypo/dY.thY"   , "dY.vs.thY: Hypo-Brem(HypoZ)"      , thMin, thMax, m_thBin, prof, m_min, m_max );
+          profile1D( bthX, bdpY  , label1+"HypoSM/dY.thX" , "dY.vs.thX: Hypo-Brem(ShowerMax)"  , thMin, thMax, m_thBin, prof, m_min, m_max );
+          profile1D( bthY, bdpY  , label1+"HypoSM/dY.thY" , "dY.vs.thY: Hypo-Brem(ShowerMax)"  , thMin, thMax, m_thBin, prof, m_min, m_max );
+        }
+      }
+
+      // S-shape
+      const auto bsize  = m_calo->cellSize(bid);
+      const auto batx   = (bthX*bremR.Z()  - bcellR.X())/bsize; // brem provides the 'true' position @ HypoZ
+      const auto baty   = (bthY*bremR.Z()  - bcellR.Y())/bsize;
+      const auto batxSM = (bthX*point.Z()  - bcellR.X())/bsize; // brem provides the 'true' position @ ShowerMax
+      const auto batySM = (bthY*point.Z()  - bcellR.Y())/bsize;
+      const auto babx   = (bclusR.X()      - bcellR.X())/bsize; // e-weighted barycenter (cluster)
+      const auto baby   = (bclusR.Y()      - bcellR.Y())/bsize;
+      const auto bacx   = (bremR.X()       - bcellR.X())/bsize; // S-shape corrected barycenter (hypo)
+      const auto bacy   = (bremR.Y()       - bcellR.Y())/bsize;
+
+      for( const auto label: bsplit ){
+        std::string base = "BremAlign/Sshape/" + label;
+        if(m_histo){
+          plot2D( batx  , babx, base + "Cluster/X"  , "bremX(HypoZ) / clusterX "   , -1*m_r, +1*m_r, -1*m_r, +1*m_r, m_b, m_b );
+          plot2D( baty  , baby, base + "Cluster/Y"  , "bremY(HypoZ) / clusterY"    , -1*m_r, +1*m_r, -1*m_r, +1*m_r, m_b, m_b );
+          plot2D( batx  , bacx, base + "Hypo/X"     , "bremX(HypoZ) / hypoX"       , -1*m_r, +1*m_r, -1*m_r, +1*m_r, m_b, m_b );
+          plot2D( baty  , bacy, base + "Hypo/Y"     , "bremY(HypoZ) / hypoY"       , -1*m_r, +1*m_r, -1*m_r, +1*m_r, m_b, m_b );
+          plot2D( batxSM, babx, base + "ClusterSM/X", "bremX(ShowerMax) / clusterX", -1*m_r, +1*m_r, -1*m_r, +1*m_r, m_b, m_b );
+          plot2D( batySM, baby, base + "ClusterSM/Y", "bremY(ShowerMax) / clusterY", -1*m_r, +1*m_r, -1*m_r, +1*m_r, m_b, m_b );
+          plot2D( batxSM, bacx, base + "HypoSM/X"   , "bremX(ShowerMax) / hypoX"   , -1*m_r, +1*m_r, -1*m_r, +1*m_r, m_b, m_b );
+          plot2D( batySM, bacy, base + "HypoSM/Y"   , "bremY(ShowerMax) / hypoY"   , -1*m_r, +1*m_r, -1*m_r, +1*m_r, m_b, m_b );
+        }
+        if(m_profil){
+          base = "BremAlign/Sshape/" + label;
+          profile1D( batx  , babx, base + "Cluster/profX"  , "bremX(HypoZ) / clusterX "   , -1*m_r, +1*m_r, m_b , prof, -1*m_r, 1*m_r );
+          profile1D( baty  , baby, base + "Cluster/profY"  , "bremY(HypoZ) / clusterY"    , -1*m_r, +1*m_r, m_b , prof, -1*m_r, 1*m_r );
+          profile1D( batx  , bacx, base + "Hypo/profX"     , "bremX(HypoZ) / hypoX"       , -1*m_r, +1*m_r, m_b , prof, -1*m_r, 1*m_r );
+          profile1D( baty  , bacy, base + "Hypo/profY"     , "bremY(HypoZ) / hypoY"       , -1*m_r, +1*m_r, m_b , prof, -1*m_r, 1*m_r );
+          profile1D( batxSM, babx, base + "ClusterSM/profX", "bremX(ShowerMax) / clusterX", -1*m_r, +1*m_r, m_b , prof, -1*m_r, 1*m_r );
+          profile1D( batySM, baby, base + "ClusterSM/profY", "bremY(ShowerMax) / clusterY", -1*m_r, +1*m_r, m_b , prof, -1*m_r, 1*m_r );
+          profile1D( batxSM, bacx, base + "HypoSM/profX"   , "bremX(ShowerMax) / hypoX"   , -1*m_r, +1*m_r, m_b , prof, -1*m_r, 1*m_r );
+          profile1D( batySM, bacy, base + "HypoSM/profY"   , "bremY(ShowerMax) / hypoY"   , -1*m_r, +1*m_r, m_b , prof, -1*m_r, 1*m_r );
+
+          base = "BremAlign/iSshape/" + label;
+          profile1D( babx, batx  , base + "Cluster/profX"  , "bremX(HypoZ) .vs. clusterX "    , -1*m_r, +1*m_r, m_b , prof, -1*m_r, 1*m_r);
+          profile1D( baby, baty  , base + "Cluster/profY"  , "bremY(HypoZ) .vs. clusterY"     , -1*m_r, +1*m_r, m_b , prof, -1*m_r, 1*m_r);
+          profile1D( bacx, batx  , base + "Hypo/profX"     , "bremX(HypoZ) .vs. hypoX"        , -1*m_r, +1*m_r, m_b , prof, -1*m_r, 1*m_r);
+          profile1D( bacy, baty  , base + "Hypo/profY"     , "bremY(HypoZ) .vs. hypoY"        , -1*m_r, +1*m_r, m_b , prof, -1*m_r, 1*m_r);
+          profile1D( babx, batxSM, base + "ClusterSM/profX", "bremX(ShowerMax) .vs. clusterX" , -1*m_r, +1*m_r, m_b , prof, -1*m_r, 1*m_r);
+          profile1D( baby, batySM, base + "ClusterSM/profY", "bremY(ShowerMax) .vs. clusterY" , -1*m_r, +1*m_r, m_b , prof, -1*m_r, 1*m_r);
+          profile1D( bacx, batxSM, base + "HypoSM/profX"   , "bremX(ShowerMax) .vs. hypoX"    , -1*m_r, +1*m_r, m_b , prof, -1*m_r, 1*m_r);
+          profile1D( bacy, batySM, base + "HypoSM/profY"   , "bremY(ShowerMax) .vs. hypoY"    , -1*m_r, +1*m_r, m_b , prof, -1*m_r, 1*m_r);
+        }
+      }
+    }
+
+
+    // ----- track extrapolator alignment
+    const double thX  = hypoR.X()/hypoR.Z();
+    const double thY  = hypoR.Y()/hypoR.Z();
+    const double dsX  = (hypoR.X() - statR.X()); // extrapolate @ ShowerMax plane
+    const double dsY  = (hypoR.Y() - statR.Y());
+    const double dcX  = (hypoR.X() - closR.X()); // extrapolate @ closest state
+    const double dcY  = (hypoR.Y() - closR.Y());
+    const double dceX = (cellR.X() - statR.X()); // relative to cell
+    const double dceY = (cellR.Y() - statR.Y());
+    const double dclX = (clusR.X() - statR.X()); // relative to cluster
+    const double dclY = (clusR.Y() - statR.Y());
+
+    // plot delta's
+    const std::string binX = "bin"+Gaudi::Utils::toString( int((thX-thMin)/step) );
+    const std::string binY = "bin"+Gaudi::Utils::toString( int((thY-thMin)/step) );
+    const std::vector<std::string> hat{ "all", binX, binY };
+
+    for( const auto label1: q ){
+      std::string base = "ElectronAlign/Delta/" + label1 + "/";
+      if(m_histo){
+        for( const auto label2: hat ){
+          plot1D( dceX, base+"Cell/"+label2+"/dX"   , "dX  : Cell-Track(CellZ)"       , m_min, m_max, m_bin );
+          plot1D( dceY, base+"Cell/"+label2+"/dY"   , "dY  : Cell-Track(CellZ)"       , m_min, m_max, m_bin );
+          plot1D( dclX, base+"Cluster/"+label2+"/dX", "dX  : Cluster-Track(ClusterZ)" , m_min, m_max, m_bin );
+          plot1D( dclY, base+"Cluster/"+label2+"/dY", "dY  : Cluster-Track(ClusterZ)" , m_min, m_max, m_bin );
+          plot1D( dsX , base+"HypoSM/"+label2+"/dX" , "dX  : Hypo-Track(ShowerMax)"   , m_min, m_max, m_bin );
+          plot1D( dsY , base+"HypoSM/"+label2+"/dY" , "dY  : Hypo-Track(ShowerMax)"   , m_min, m_max, m_bin );
+          plot1D( dcX , base+"Hypo/"+label2+"/dX"   , "dX  : Hypo-Track(HypoZ)"       , m_min, m_max, m_bin );
+          plot1D( dcY , base+"Hypo/"+label2+"/dY"   , "dY  : Hypo-Track(HypoZ)"       , m_min, m_max, m_bin );
+        }
+      }
+      if(m_profil){
+        profile1D( bthX, dceX, base+"Cell/dX.thX"   , "dX.vs.thX: Cell-Track(CellZ)"      , thMin, thMax, m_thBin, prof, m_min, m_max );
+        profile1D( bthY, dceX, base+"Cell/dX.thY"   , "dX.vs.thY: Cell-Track(CellZ)"      , thMin, thMax, m_thBin, prof, m_min, m_max );
+        profile1D( bthX, dclX, base+"Cluster/dX.thX", "dX.vs.thX: Cluster-Track(ClusterZ)", thMin, thMax, m_thBin, prof, m_min, m_max );
+        profile1D( bthY, dclX, base+"Cluster/dX.thY", "dX.vs.thY: Cluster-Track(ClusterZ)", thMin, thMax, m_thBin, prof, m_min, m_max );
+        profile1D( bthX, dcX , base+"Hypo/dX.thX"   , "dX.vs.thX: Hypo-Track(HypoZ)"      , thMin, thMax, m_thBin, prof, m_min, m_max );
+        profile1D( bthY, dcX , base+"Hypo/dX.thY"   , "dX.vs.thY: Hypo-Track(HypoZ)"      , thMin, thMax, m_thBin, prof, m_min, m_max );
+        profile1D( bthX, dsX , base+"HypoSM/dX.thX" , "dX.vs.thX: Hypo-Track(ShowerMax)"  , thMin, thMax, m_thBin, prof, m_min, m_max );
+        profile1D( bthY, dsX , base+"HypoSM/dX.thY" , "dX.vs.thY: Hypo-Track(ShowerMax)"  , thMin, thMax, m_thBin, prof, m_min, m_max );
+        profile1D( bthX, dceY, base+"Cell/dY.thX"   , "dY.vs.thX: Hypo-Track(CellZ)"      , thMin, thMax, m_thBin, prof, m_min, m_max );
+        profile1D( bthY, dceY, base+"Cell/dY.thY"   , "dY.vs.thY: Hypo-Track(CellZ)"      , thMin, thMax, m_thBin, prof, m_min, m_max );
+        profile1D( bthX, dclY, base+"Cluster/dY.thX", "dY.vs.thX: Hypo-Track(ClusterZ)"   , thMin, thMax, m_thBin, prof, m_min, m_max );
+        profile1D( bthY, dclY, base+"Cluster/dY.thY", "dY.vs.thY: Hypo-Track(ClusterZ)"   , thMin, thMax, m_thBin, prof, m_min, m_max );
+        profile1D( bthX, dcY , base+"Hypo/dY.thX"   , "dY.vs.thX: Hypo-Track(HypoZ)"      , thMin, thMax, m_thBin, prof, m_min, m_max );
+        profile1D( bthY, dcY , base+"Hypo/dY.thY"   , "dY.vs.thY: Hypo-Track(HypoZ)"      , thMin, thMax, m_thBin, prof, m_min, m_max );
+        profile1D( bthX, dsY , base+"HypoSM/dY.thX" , "dY.vs.thX: Hypo-Track(ShowerMax)"  , thMin, thMax, m_thBin, prof, m_min, m_max );
+        profile1D( bthY, dsY , base+"HypoSM/dY.thY" , "dY.vs.thY: Hypo-Track(ShowerMax)"  , thMin, thMax, m_thBin, prof, m_min, m_max );
+      }
+    }
+
+    // S-shape
+    const double size   = m_calo->cellSize(id);
+    const double atx    = ( closR.X() - cellR.X())/size; // track propagation provides the 'true' position @ HypoZ
+    const double aty    = ( closR.Y() - cellR.Y())/size;
+    const double atxSM  = ( statR.X() - cellR.X())/size; // track propagation provides the 'true' position @ ShowerMax
+    const double atySM  = ( statR.Y() - cellR.Y())/size;
+    const double abx    = ( clusR.X() - cellR.X())/size; // e-weighted barycenter (cluster)
+    const double aby    = ( clusR.Y() - cellR.Y())/size;
+    const double acx    = ( hypoR.X() - cellR.X())/size; // S-shape corrected barycenter (hypo)
+    const double acy    = ( hypoR.Y() - cellR.Y())/size;
+
+    for( const auto label: split ){
+      std::string base = "ElectronAlign/Sshape/" + label;
+      if(m_histo){
+        plot2D( atx  , abx, base + "Cluster/X"  , "trackX(bestZ) .vs. clusterX "    , -1*m_r, +1*m_r, -1*m_r, +1*m_r, m_b, m_b );
+        plot2D( aty  , aby, base + "Cluster/Y"  , "trackY(bestZ) .vs. clusterY"     , -1*m_r, +1*m_r, -1*m_r, +1*m_r, m_b, m_b );
+        plot2D( atx  , acx, base + "Hypo/X"     , "trackX(bestZ) .vs. hypoX"        , -1*m_r, +1*m_r, -1*m_r, +1*m_r, m_b, m_b );
+        plot2D( aty  , acy, base + "Hypo/Y"     , "trackY(bestZ) .vs. hypoY"        , -1*m_r, +1*m_r, -1*m_r, +1*m_r, m_b, m_b );
+        plot2D( atxSM, abx, base + "ClusterSM/X", "trackX(ShowerMax) .vs. clusterX" , -1*m_r, +1*m_r, -1*m_r, +1*m_r, m_b, m_b );
+        plot2D( atySM, aby, base + "ClusterSM/Y", "trackY(ShowerMax) .vs. clusterY" , -1*m_r, +1*m_r, -1*m_r, +1*m_r, m_b, m_b );
+        plot2D( atxSM, acx, base + "HypoSM/X"   , "trackX(ShowerMax) .vs. hypoX"    , -1*m_r, +1*m_r, -1*m_r, +1*m_r, m_b, m_b );
+        plot2D( atySM, acy, base + "HypoSM/Y"   , "trackY(ShowerMax) .vs. hypoY"    , -1*m_r, +1*m_r, -1*m_r, +1*m_r, m_b, m_b );
+      }
+      if(m_profil){
+        profile1D( atx  , abx, base + "Cluster/profX"   , "trackX(bestZ) .vs. clusterX "    , -1*m_r, +1*m_r, m_b, prof, -1*m_r, 1*m_r );
+        profile1D( aty  , aby, base + "Cluster/profY"   , "trackY(bestZ) .vs. clusterY"     , -1*m_r, +1*m_r, m_b, prof, -1*m_r, 1*m_r );
+        profile1D( atx  , acx, base + "Hypo/profX"      , "trackX(bestZ) .vs. hypoX"        , -1*m_r, +1*m_r, m_b, prof, -1*m_r, 1*m_r );
+        profile1D( aty  , acy, base + "Hypo/profY"      , "trackY(bestZ) .vs. hypoY"        , -1*m_r, +1*m_r, m_b, prof, -1*m_r, 1*m_r );
+        profile1D( atxSM, abx, base + "ClusterSM/profX" , "trackX(ShowerMax) .vs. clusterX" , -1*m_r, +1*m_r, m_b, prof, -1*m_r, 1*m_r );
+        profile1D( atySM, aby, base + "ClusterSM/profY" , "trackY(ShowerMax) .vs. clusterY" , -1*m_r, +1*m_r, m_b, prof, -1*m_r, 1*m_r );
+        profile1D( atxSM, acx, base + "HypoSM/profX"    , "trackX(ShowerMax) .vs. hypoX"    , -1*m_r, +1*m_r, m_b, prof, -1*m_r, 1*m_r );
+        profile1D( atySM, acy, base + "HypoSM/profY"    , "trackY(ShowerMax) .vs. hypoY"    , -1*m_r, +1*m_r, m_b, prof, -1*m_r, 1*m_r );
+        base = "ElectronAlign/iSshape/" + label;
+        profile1D( abx, atx  , base + "Cluster/profX"   , "trackX(bestZ) .vs. clusterX "    , -1*m_r, +1*m_r, m_b, prof, -1*m_r, 1*m_r );
+        profile1D( aby, aty  , base + "Cluster/profY"   , "trackY(bestZ) .vs. clusterY"     , -1*m_r, +1*m_r, m_b, prof, -1*m_r, 1*m_r );
+        profile1D( acx, atx  , base + "Hypo/profX"      , "trackX(bestZ) .vs. hypoX"        , -1*m_r, +1*m_r, m_b, prof, -1*m_r, 1*m_r );
+        profile1D( acy, aty  , base + "Hypo/profY"      , "trackY(bestZ) .vs. hypoY"        , -1*m_r, +1*m_r, m_b, prof, -1*m_r, 1*m_r );
+        profile1D( abx, atxSM, base + "ClusterSM/profX" , "trackX(ShowerMax) .vs. clusterX" , -1*m_r, +1*m_r, m_b, prof, -1*m_r, 1*m_r );
+        profile1D( aby, atySM, base + "ClusterSM/profY" , "trackY(ShowerMax) .vs. clusterY" , -1*m_r, +1*m_r, m_b, prof, -1*m_r, 1*m_r );
+        profile1D( acx, atxSM, base + "HypoSM/profX"    , "trackX(ShowerMax) .vs. hypoX"    , -1*m_r, +1*m_r, m_b, prof, -1*m_r, 1*m_r );
+        profile1D( acy, atySM, base + "HypoSM/profY"    , "trackY(ShowerMax) .vs. hypoY"    , -1*m_r, +1*m_r, m_b, prof, -1*m_r, 1*m_r );
+      }
+    }
+  }
+  return;
+}
+
+//==============================================================================
diff --git a/CaloFuture/CaloFutureMoniDst/src/CaloFutureAlignmentNtp.h b/CaloFuture/CaloFutureMoniDst/src/CaloFutureAlignmentNtp.h
new file mode 100644
index 0000000000000000000000000000000000000000..86e9487ba901b55f4f34620ce691262ae96a90c4
--- /dev/null
+++ b/CaloFuture/CaloFutureMoniDst/src/CaloFutureAlignmentNtp.h
@@ -0,0 +1,114 @@
+#ifndef CALOFUTUREALIGNEMENTNTP_H 
+#define CALOFUTUREALIGNEMENTNTP_H 1
+
+// Include files
+// from Gaudi
+#include "GaudiAlg/Consumer.h"
+#include "GaudiAlg/GaudiTupleAlg.h"
+#include "GaudiKernel/IEventTimeDecoder.h"
+#include "Event/ODIN.h" 
+#include "Event/ProtoParticle.h"
+#include "Event/RecVertex.h"
+#include "Event/Track.h"
+#include "CaloDet/DeCalorimeter.h"
+#include "CaloFutureInterfaces/ICaloFutureHypo2CaloFuture.h"
+#include "CaloFutureInterfaces/IFutureCounterLevel.h"
+// #include "CaloFutureInterfaces/ICaloFutureHypoEstimator.h"
+#include "CaloFutureUtils/CaloFutureAlgUtils.h"
+#include "CaloFutureUtils/CaloMomentum.h"
+#include "CaloFutureUtils/ICaloFutureElectron.h"
+#include "TrackInterfaces/ITrackExtrapolator.h"
+
+
+// List of Consumers dependencies
+namespace {
+  using Vertices = LHCb::RecVertices;
+  using ODIN = LHCb::ODIN;
+  using Digits = LHCb::CaloDigits;
+  using Tracks = LHCb::Tracks;
+  using Protos = LHCb::ProtoParticles;
+}
+
+//==============================================================================
+
+/** @class CaloFutureAlignmentNtp CaloFutureAlignmentNtp.h
+ *  
+ *
+ *  @author Olivier Deschamps
+ *  @date   2009-12-11
+ */
+
+class CaloFutureAlignmentNtp final
+: public Gaudi::Functional::Consumer<void(const Vertices&, const ODIN&, const Digits&, const Tracks&, const Protos&),
+    Gaudi::Functional::Traits::BaseClass_t<GaudiTupleAlg>>
+{
+public: 
+  /// Standard constructor
+  CaloFutureAlignmentNtp( const std::string& name, ISvcLocator* pSvcLocator );
+
+  StatusCode initialize() override;    ///< Algorithm initialization
+  void operator()(const Vertices&, const ODIN&, const Digits&, const Tracks&, const Protos&) const override;
+
+  /// C++11 non-copyable idiom
+  CaloFutureAlignmentNtp() = delete;
+  CaloFutureAlignmentNtp( const CaloFutureAlignmentNtp& ) = delete;
+  CaloFutureAlignmentNtp &operator=( const CaloFutureAlignmentNtp& ) = delete;
+
+private:
+  bool acceptTrack(const LHCb::Track*) const;
+  bool hypoProcessing(const LHCb::CaloHypo* hypo) const;
+  bool inArea(const LHCb::CaloHypo* hypo) const;
+
+  // Tools
+  DeCalorimeter* m_calo = nullptr;
+  std::string m_vertLoc;
+
+  ToolHandle<IFutureCounterLevel>      m_counterStat  { "FutureCounterLevel"};
+  ToolHandle<ICaloFutureElectron>      m_caloElectron { "CaloFutureElectron"                            , this };
+  ToolHandle<IEventTimeDecoder>  m_odin         { "OdinTimeDecoder/OdinDecoder"             , this };
+  ToolHandle<ICaloFutureHypo2CaloFuture>     m_toSpd        { "CaloFutureHypo2CaloFuture/CaloFutureHypo2Spd"              , this };
+  ToolHandle<ICaloFutureHypo2CaloFuture>     m_toPrs        { "CaloFutureHypo2CaloFuture/CaloFutureHypo2Prs"              , this };
+  ToolHandle<ITrackExtrapolator> m_extrapolator { "TrackRungeKuttaExtrapolator/Extrapolator", this };
+
+  // Flags -- init
+  Gaudi::Property<bool> m_usePV3D { this, "UsePV3D", false};
+  Gaudi::Property<std::vector<int>> m_tracks { this, "TrackTypes", { LHCb::Track::Types::Long }};
+
+  // Flags -- global cuts
+  Gaudi::Property<std::pair<double, double>> m_nSpd { this, "SpdMult"  , { 0. , 250.    }};
+  Gaudi::Property<std::pair<double, double>> m_nTrk { this, "nTracks"  , { 0. , 350.    }};
+  Gaudi::Property<std::pair<double, double>> m_nVtx { this, "nVertices", { -1., 999999. }};
+  Gaudi::Property<bool> m_inArea {this, "inAreaAcc", true};
+
+  // Flags -- hypo cuts
+  Gaudi::Property<std::pair<double, double>> m_e   { this, "EFilter"  , { 0.  , 99999999. }};
+  Gaudi::Property<std::pair<double, double>> m_et  { this, "EtFilter" , { 150., 999999.   }};
+  Gaudi::Property<std::pair<double, double>> m_prs { this, "PrsFilter", { 10. , 1024     }};
+  Gaudi::Property<std::pair<double, double>> m_spd { this, "SpdFilter", { .5  , 9999.    }};
+
+  // Flags
+  Gaudi::Property<std::pair<double, double>> m_eop    { this, "EoPFilter"          , { 0.7       , 1.3}};
+  Gaudi::Property<std::pair<double, double>> m_dlle   { this, "DLLeFilter"         , { -9999999. , 9999999.}};
+  Gaudi::Property<std::pair<double, double>> m_rdlle  { this, "RichDLLeFilter"     , { 0.        , 99999.}};
+  Gaudi::Property<std::pair<double, double>> m_bMatch { this, "BremMatchFilter"    , { -99999999., 99999999.}};
+  Gaudi::Property<std::pair<double, double>> m_eMatch { this, "ElectronMatchFilter", { -999999.  , 999999.}};
+  Gaudi::Property<std::pair<double, double>> m_cMatch { this, "ClusterMatchFilter" , { -999999.  , 999999.}};
+  Gaudi::Property<std::pair<double, double>> m_mas    { this, "MassFilter"         , { -99999.   , 99999.}};
+  Gaudi::Property<std::pair<double, double>> m_dist   { this, "BremEleDistFilter"  , { 4.        , 99999.}};
+
+  Gaudi::Property<bool>  m_pairing { this, "EmlectronPairing"    , true};
+  Gaudi::Property<float> m_min     { this, "DeltaMin"            , -150.};
+  Gaudi::Property<float> m_max     { this, "DeltaMax"            , +150.};
+  Gaudi::Property<int>   m_thBin   { this, "ThetaBin"            , 14};
+  Gaudi::Property<int>   m_bin     { this, "DeltaBin"            , 150};
+  Gaudi::Property<bool>  m_brem    { this, "ElectronWithBremOnly", false};
+  Gaudi::Property<float> m_r       { this, "SshapeRange"         , 0.7};
+  Gaudi::Property<int>   m_b       { this, "SshapeBin"           , 50};
+  
+  // Flags -- outputs
+  Gaudi::Property<bool> m_histo  { this, "Histo"  , true};
+  Gaudi::Property<bool> m_tuple  { this, "Tuple"  , true};
+  Gaudi::Property<bool> m_profil { this, "Profile", true};
+  
+};
+#endif // CALOFUTUREALIGNEMENTNTP_H
diff --git a/CaloFuture/CaloFutureMoniDst/src/CaloFutureClusterChecker.cpp b/CaloFuture/CaloFutureMoniDst/src/CaloFutureClusterChecker.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f037ad823aedf1214e22562ab4393edb7198557e
--- /dev/null
+++ b/CaloFuture/CaloFutureMoniDst/src/CaloFutureClusterChecker.cpp
@@ -0,0 +1,115 @@
+// Includes
+#include "GaudiAlg/Consumer.h"
+#include "Relations/RelationWeighted1D.h"
+#include "Event/CaloCluster.h"
+#include "Event/MCParticle.h"
+#include "CaloFutureMoniAlg.h"
+
+// =============================================================================
+
+/** @class CaloFutureClusterChecker CaloFutureClusterChecker.cpp
+ *
+ *  The algorithm for trivial monitoring of MCTruthing of
+ *  "CaloClusters" with Tracks.
+ *  It produces 5 histograms:
+ *
+ *  <ol>
+ *  <li> Total Link              distribution               </li>
+ *  <li> Link multiplicity       distribution               </li>
+ *  <li> Minimal Weight          distribution               </li>
+ *  <li> Maximal Weight          distribution               </li>
+ *  <li>         Weight          distribution               </li>
+ *  </ol>
+ *
+ *  Histograms reside in the directory @p /stat/"Name" , where
+ *  @ "Name" is the name of the algorithm
+ *
+ *  @see   CaloFutureMoniAlg
+ *  @see GaudiHistoAlg
+ *  @see GaudiAlgorithm
+ *  @see      Algorithm
+ *  @see     IAlgorithm
+ *
+ *  @author Vanya Belyaev Ivan.Belyaev@itep.ru
+ *  @date   02/11/2001
+ */
+
+using Input = LHCb::RelationWeighted1D<LHCb::CaloCluster,LHCb::MCParticle,float>;
+using Clusters = LHCb::CaloCluster::Container;
+
+
+class CaloFutureClusterChecker final
+: public Gaudi::Functional::Consumer<void(const Input&, const Clusters&, const Clusters&),
+    Gaudi::Functional::Traits::BaseClass_t<CaloFutureMoniAlg>>
+{
+public:
+  StatusCode initialize() override;
+  void operator()(const Input&, const Clusters&, const Clusters&) const override;
+
+  CaloFutureClusterChecker( const std::string &name, ISvcLocator *pSvcLocator );
+};
+
+// =============================================================================
+
+DECLARE_COMPONENT( CaloFutureClusterChecker )
+
+// =============================================================================
+
+CaloFutureClusterChecker::CaloFutureClusterChecker( const std::string &name, ISvcLocator *pSvcLocator )
+: Consumer( name, pSvcLocator, {
+    KeyValue{ "Input" , "Relations/"+LHCb::CaloClusterLocation::Default },
+    KeyValue{ "InputClusters"     , LHCb::CaloClusterLocation::Ecal },
+    KeyValue{ "InputSplitClusters", LHCb::CaloClusterLocation::EcalSplit }
+}){}
+
+// =============================================================================
+
+StatusCode CaloFutureClusterChecker::initialize(){
+  StatusCode sc = Consumer::initialize();
+  if ( sc.isFailure() ) return sc;
+  hBook1( "1", "log10(#Links+1)  '" + inputLocation() + "'", 0,  5 );
+  hBook1( "2", "Rels/Cluster     '" + inputLocation() + "'", 0, 50 );
+  hBook1( "3", "Minimal weight/e '" + inputLocation() + "'", 0,  2.0 );
+  hBook1( "4", "Maximal weight/e '" + inputLocation() + "'", 0,  2.0 );
+  hBook1( "5", "        Weight/e '" + inputLocation() + "'", 0,  2.0 );
+  if( m_split ){
+    Warning( "No area spliting allowed for CaloFutureClusterChecker").ignore();
+    m_split = false;
+  }
+  return StatusCode::SUCCESS;
+}
+
+// =============================================================================
+
+void CaloFutureClusterChecker::operator()(const Input& table, const Clusters& clusters1, const Clusters& clusters2) const {
+  // produce histos ?
+  if ( !produceHistos() ) return;
+
+  // total number of links
+  hFill1( "1", log10( table.relations().size() + 1. ) );
+
+  // loop over clusters
+  auto filler = [&table, this](auto& clusters){
+    for( const auto& cluster: clusters ){
+      const auto& range = table.relations( cluster );
+      // number of relations per cluster
+      hFill1( "2", range.size() );
+      if ( range.empty() ) continue;
+      // cluster energy
+      const double e = cluster->e();
+      // minimal weight
+      hFill1( "3", range.front().weight() / e );
+      // maximal weight
+      hFill1( "4", range.back().weight() / e );
+      // all weights
+      for( const auto& relation: range ){
+        hFill1( "5", relation.weight() / e );
+      }
+    } // end of loop over clusters
+  };
+
+  filler(clusters1);
+  filler(clusters2);
+
+  return;
+}
diff --git a/CaloFuture/CaloFutureMoniDst/src/CaloFutureClusterMatchMonitor.cpp b/CaloFuture/CaloFutureMoniDst/src/CaloFutureClusterMatchMonitor.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7503372ccd6e04298c25b335479e4d9a5f63c757
--- /dev/null
+++ b/CaloFuture/CaloFutureMoniDst/src/CaloFutureClusterMatchMonitor.cpp
@@ -0,0 +1,127 @@
+// Includes
+#include "GaudiAlg/Consumer.h"
+#include "Relations/RelationWeighted2D.h"
+#include "Event/CaloCluster.h"
+#include "Event/Track.h"
+#include "CaloFutureUtils/CaloFuture2Track.h"
+#include "CaloFutureMoniAlg.h"
+
+#include "CaloFutureMoniUtils.h" // Local
+
+// =============================================================================
+
+/** @class CaloFutureClusterMatchMonitor CaloFutureClusterMatchMonitor.cpp
+ *
+ *  The algorithm for trivial monitoring of matching of
+ *  "CaloFutureClusters" with Tracks.
+ *  It produces 5 histograms:
+ *
+ *  <ol>
+ *  <li> Total Link              distribution               </li>
+ *  <li> Link multiplicity       distribution               </li>
+ *  <li> Minimal Weight          distribution               </li>
+ *  <li> Maximal Weight          distribution               </li>
+ *  <li>         Weight          distribution               </li>
+ *  </ol>
+ *
+ *  Histograms reside in the directory @p /stat/"Name" , where
+ *  @ "Name" is the name of the algorithm
+ *
+ *  @see   CaloFutureMoniAlg
+ *  @see GaudiHistoAlg
+ *  @see GaudiAlgorithm
+ *  @see     Algorithm
+ *  @see    IAlgorithm
+ *
+ *  @author Vanya Belyaev Ivan.Belyaev@itep.ru
+ *  @date   02/11/2001
+ */
+
+using Input = LHCb::RelationWeighted2D< LHCb::CaloCluster, LHCb::Track, float >;
+using Clusters = LHCb::CaloCluster::Container;
+
+class CaloFutureClusterMatchMonitor final
+: public Gaudi::Functional::Consumer<void(const Input&, const Clusters&, const Clusters&),
+    Gaudi::Functional::Traits::BaseClass_t<CaloFutureMoniAlg>>
+{
+public:
+  /// standard algorithm initialization
+  StatusCode initialize() override;
+  void operator()(const Input&, const Clusters&, const Clusters&) const override;
+
+  CaloFutureClusterMatchMonitor( const std::string &name, ISvcLocator *pSvcLocator );
+};
+
+// =============================================================================
+
+DECLARE_COMPONENT( CaloFutureClusterMatchMonitor )
+
+// =============================================================================
+
+CaloFutureClusterMatchMonitor::CaloFutureClusterMatchMonitor( const std::string &name, ISvcLocator *pSvcLocator )
+: Consumer( name, pSvcLocator, {
+    KeyValue{ "Input"             , "" },
+    KeyValue{ "InputClusters"     , "" },
+    KeyValue{ "InputSplitClusters", "" }
+}){
+  updateHandleLocation( *this, "Input" , LHCb::CaloFutureAlgUtils::CaloFutureIdLocation("ClusterMatch", context() ));
+  updateHandleLocation( *this, "InputClusters", LHCb::CaloFutureAlgUtils::CaloFutureClusterLocation(name,context() ));
+  updateHandleLocation( *this, "InputSplitClusters", LHCb::CaloFutureAlgUtils::CaloFutureSplitClusterLocation( context() ));
+}
+
+// =============================================================================
+
+StatusCode CaloFutureClusterMatchMonitor::initialize(){
+  StatusCode sc = Consumer::initialize();
+  if ( sc.isFailure() ) return sc;
+
+  hBook1( "1", "log10(#Links+1) '"+inputLocation()+"'", 0,    4, 100 );
+  hBook1( "2", "Tracks per cluster",                    0,   25,  25 );
+  hBook1( "3", "Minimal weight",                        0,  100, 200 );
+  hBook1( "4", "Maximal weight",                        0, 1000, 200 );
+  hBook1( "5", "Weights",                               0, 1000, 500 );
+  if( m_split ){
+    Warning( "No area spliting allowed for CaloFutureClusterMatchMonitor").ignore();
+    m_split = false;
+  }
+  return StatusCode::SUCCESS;
+}
+
+// =============================================================================
+
+void CaloFutureClusterMatchMonitor::operator()(const Input& table, const Clusters& clusters1, const Clusters& clusters2 ) const {
+
+  // produce histos ?
+  if ( !produceHistos() ) return;
+
+  // total number of links
+  hFill1( "1", log10( table.relations().size() + 1. ) );
+
+  // loop over all clusters
+  auto filler = [&table, this](auto& clusters){
+    for( const auto& cluster: clusters ){
+      const auto& range = table.relations( cluster );
+      // number of related tracks
+      hFill1( "2", range.size() );
+      if ( range.empty() ) continue;
+      // minimal weight
+      hFill1( "3", range.front().weight() );
+      // maximal weight
+      hFill1( "4", range.back().weight() );
+      // all weights
+      for( const auto& relation: range ){
+        hFill1( "5", relation.weight() );
+      }
+    } // end of loop over clusters
+  };
+
+  filler(clusters1);
+  filler(clusters2);
+
+  if(m_counterStat->isQuiet()){
+    counter("Monitor " + inputLocation<0>()) += table.relations().size();
+    counter("Monitor " + inputLocation<1>()) += clusters1.size();
+    counter("Monitor " + inputLocation<2>()) += clusters2.size();
+  }
+  return;
+}
diff --git a/CaloFuture/CaloFutureMoniDst/src/CaloFutureClusterMonitor.cpp b/CaloFuture/CaloFutureMoniDst/src/CaloFutureClusterMonitor.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ca02636c7e252bb624fe84344ba7d48e4eac90f0
--- /dev/null
+++ b/CaloFuture/CaloFutureMoniDst/src/CaloFutureClusterMonitor.cpp
@@ -0,0 +1,136 @@
+// Includes
+#include "GaudiAlg/Consumer.h"
+#include "Event/CaloCluster.h"
+#include "CaloFutureMoniAlg.h"
+
+// =============================================================================
+
+/** @class CaloFutureClusterMonitor CaloFutureClusterMonitor.cpp
+ *
+ *  The algorithm for trivial monitoring of "CaloFutureCluster" containers.
+ *  The algorithm produces 8 histograms:
+ *
+ *  <ol>
+ *  <li> @p CaloCluster multiplicity                    </li>
+ *  <li> @p CaloCluster size (number of cells)          </li>
+ *  <li> @p CaloCluster energy distribution             </li>
+ *  <li> @p CaloCluster transverse energy distribution  </li>
+ *  <li> @p CaloCluster x-distribution                  </li>
+ *  <li> @p CaloCluster y-distribution                  </li>
+ *  <li> @p CaloCluster x vs y-distribution             </li>
+ *  </ol>
+ *
+ *  Histograms reside in the directory @p /stat/"Name" , where
+ *  @ "Name" is the name of the algorithm
+ *
+ *  @see   CaloFutureMoniAlg
+ *  @see GaudiHistoAlg
+ *  @see GaudiAlgorithm
+ *  @see      Algorithm
+ *  @see     IAlgorithm
+ *
+ *  @author Vanya Belyaev Ivan.Belyaev@itep.ru
+ *  @date   02/11/2001
+ */
+
+using Input = LHCb::CaloCluster::Container;
+
+class CaloFutureClusterMonitor final
+: public Gaudi::Functional::Consumer<void(const Input&),
+    Gaudi::Functional::Traits::BaseClass_t<CaloFutureMoniAlg>>
+{
+public:
+  /// standard algorithm initialization
+  StatusCode initialize() override;
+  void operator()(const Input&) const override;
+
+  CaloFutureClusterMonitor( const std::string &name, ISvcLocator *pSvcLocator );
+};
+
+// =============================================================================
+
+DECLARE_COMPONENT( CaloFutureClusterMonitor )
+
+// =============================================================================
+
+CaloFutureClusterMonitor::CaloFutureClusterMonitor( const std::string &name, ISvcLocator *pSvcLocator )
+: Consumer( name, pSvcLocator, KeyValue{ "Input", {}}
+){
+  m_multMax = 200;
+  m_multBin = 100;
+  auto Input = LHCb::CaloFutureAlgUtils::CaloFutureClusterLocation( name, context() );
+  updateHandleLocation( *this, "Input", Input );
+}
+
+// =============================================================================
+
+/// standard algorithm initialization
+StatusCode CaloFutureClusterMonitor::initialize(){
+  StatusCode sc = Consumer::initialize();
+  if ( sc.isFailure() ) return sc;
+  hBook1( "1", "# of Clusters " + inputLocation()               , m_multMin   , m_multMax   , m_multBin );
+  hBook1( "2", "Cluster digit multiplicity " + inputLocation()  , m_sizeMin   , m_sizeMax   , m_sizeBin );
+  hBook1( "3", "Cluster Energy " + inputLocation()              , m_energyMin , m_energyMax , m_energyBin );
+  hBook1( "4", "Cluster Et " + inputLocation()                  , m_etMin     , m_etMax     , m_etBin );
+  hBook1( "5", "Cluster x " + inputLocation()                   , m_xMin      , m_xMax      , m_xBin );
+  hBook1( "6", "Cluster y " + inputLocation()                   , m_yMin      , m_yMax      , m_yBin );
+  hBook2( "7", "Cluster barycenter position x vs y " + inputLocation()                , m_xMin    , m_xMax    , m_xBin, m_yMin, m_yMax, m_yBin );
+  hBook2( "8", "Energy-weighted cluster barycenter position x vs y " + inputLocation(), m_xMin    , m_xMax    , m_xBin, m_yMin, m_yMax, m_yBin );
+  hBook1( "9", "Cluster digit used for Energy multiplicity " + inputLocation()        , m_sizeMin , m_sizeMax , m_sizeBin );
+  return StatusCode::SUCCESS;
+}
+
+// =============================================================================
+// standard execution method
+// =============================================================================
+
+// StatusCode CaloFutureClusterMonitor::execute(){
+void CaloFutureClusterMonitor::operator()(const Input& clusters) const {
+
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+    debug() << " Producing histo " << produceHistos() << endmsg;
+  // produce histos ?
+  if ( !produceHistos() ) return;
+
+  if ( clusters.empty() ){
+    if( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+      debug() << "Found empty cluster in " << inputLocation() << endmsg;
+    return;
+  }
+
+  // fill multiplicity histogram
+  initFutureCounters();
+
+  for( const auto& cluster: clusters ){
+    if ( 0 == cluster ) continue;
+    const double e = cluster->position().e();
+    const double x = cluster->position().x();
+    const double y = cluster->position().y();
+    const double z = cluster->position().z();
+    const double et = e * sqrt( x*x + y*y ) / sqrt( x*x+y*y+z*z );
+    if( e  < m_eFilter) continue;
+    if( et < m_etFilter) continue;
+    const auto id = cluster->seed();
+    count( id );
+    hFill1(id, "2", cluster->entries().size() );
+    hFill1(id, "3", e  );
+    hFill1(id, "4", et );
+    hFill1(id, "5", x  );
+    hFill1(id, "6", y  );
+    hFill2(id, "7", x,y );
+    hFill2(id, "8", x,y,e);
+
+    int iuse = 0;
+    for( const auto& entry: cluster->entries() ){
+      if( 0 != (LHCb::CaloDigitStatus::UseForEnergy & entry.status()) ) iuse++;
+    }
+    hFill1(id,"9", iuse );
+    if(doHisto("10"))fillCaloFuture2D("10", id, 1., "Cluster position 2Dview " + inputLocation() );
+    if(doHisto("11"))fillCaloFuture2D("11", id, e , "Cluster Energy 2Dview " + inputLocation() );
+
+  }
+  // fill counter
+  fillFutureCounters("1");
+
+  return;
+}
diff --git a/CaloFuture/CaloFutureMoniDst/src/CaloFutureDigitMonitor.cpp b/CaloFuture/CaloFutureMoniDst/src/CaloFutureDigitMonitor.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..254718916ee0591aeec4a25a222fe6216ef157f1
--- /dev/null
+++ b/CaloFuture/CaloFutureMoniDst/src/CaloFutureDigitMonitor.cpp
@@ -0,0 +1,154 @@
+// Includes
+#include "GaudiAlg/Consumer.h"
+#include "Event/CaloDigit.h"
+#include "CaloDet/DeCalorimeter.h"
+#include "CaloFutureMoniAlg.h"
+
+// =============================================================================
+
+/** @class CaloFutureDigitMonitor CaloFutureDigitMonitor.cpp
+ *
+ *  The algorithm for trivial monitoring of "CaloDigit" containers.
+ *  The algorithm produces the following histograms:
+ *   1. CaloDigit multiplicity
+ *   2. CaloDigit ocupancy 2D plot per area
+ *   3. CaloDigit energy 2D plot per area
+ *  The same set of histograms, but with cut on Et (or E), is produced if specified
+ *
+ *  Histograms reside in the directory @p /stat/"Name" , where
+ *  @p "Name" is the name of the algorithm
+ *
+ *  @see   CaloFutureMoniAlg
+ *  @see GaudiHistoAlg
+ *  @see GaudiAlgorithm
+ *  @see      Algorithm
+ *  @see     IAlgorithm
+ *
+ *  @author Konstantin Belous Konstantin.Beloous@itep.ru
+ *  @date   21/06/2007
+ */
+
+using Input = LHCb::CaloDigit::Container;
+
+class CaloFutureDigitMonitor final
+: public Gaudi::Functional::Consumer<void(const Input&),
+    Gaudi::Functional::Traits::BaseClass_t<CaloFutureMoniAlg>>
+{
+public:
+  StatusCode initialize() override;
+  void operator()(const Input&) const override;
+
+  CaloFutureDigitMonitor( const std::string &name, ISvcLocator *pSvcLocator );
+
+private:
+  DeCalorimeter *m_calo = nullptr;
+  Gaudi::Property<bool> m_spectrum {this, "Spectrum", false, "activate spectrum per channel histogramming"};
+};
+
+// =============================================================================
+
+DECLARE_COMPONENT( CaloFutureDigitMonitor )
+
+// =============================================================================
+
+CaloFutureDigitMonitor::CaloFutureDigitMonitor( const std::string &name, ISvcLocator *pSvcLocator )
+: Consumer( name, pSvcLocator,
+  KeyValue{ "Input", LHCb::CaloFutureAlgUtils::CaloFutureDigitLocation("") }
+){
+  updateHandleLocation( *this, "Input", LHCb::CaloFutureAlgUtils::CaloFutureDigitLocation(name));
+}
+
+// =============================================================================
+// standard initialize method
+// =============================================================================
+
+StatusCode CaloFutureDigitMonitor::initialize(){
+  StatusCode sc = Consumer::initialize();
+  if ( sc.isFailure() ) return sc;
+
+  if      ( "Ecal" == detData() ) {
+    m_calo = getDet<DeCalorimeter>( DeCalorimeterLocation::Ecal );  }
+  else if ( "Hcal" == detData() ) {
+    m_calo = getDet<DeCalorimeter>( DeCalorimeterLocation::Hcal );  }
+  else if ( "Prs"  == detData() ){
+    m_calo = getDet<DeCalorimeter>( DeCalorimeterLocation::Prs  );  }
+  else if ( "Spd"  == detData() ) {
+    m_calo = getDet<DeCalorimeter>( DeCalorimeterLocation::Spd  );  }
+  else {
+    return Error( "Unknown detector name "+detData() );
+  }
+
+  hBook1( "1", detData() + " : # of Digits"   , m_multMin   ,   m_multMax,  m_multBin   );
+  if( detData() != "Spd" ) hBook1( "2", detData() + "  digits energy" , m_energyMin ,   m_energyMax,  m_energyBin );
+  if( detData() != "Spd" && detData() != "Prs")hBook1( "3", detData() + "  digits Et"     , m_etMin ,   m_etMax  , m_etBin);
+  hBook1(  "4", "Hypo X        " + inputLocation(),  m_xMin      ,    m_xMax      , m_xBin    );
+  hBook1(  "5", "Hypo Y        " + inputLocation(),  m_yMin      ,    m_yMax      , m_yBin );
+  hBook2(  "6", "Digit position x vs y   " + inputLocation(),  m_xMin, m_xMax, m_xBin, m_yMin, m_yMax, m_yBin);
+  hBook2(  "7", "Energy-weighted digit position x vs y " + inputLocation(),m_xMin, m_xMax, m_xBin, m_yMin, m_yMax, m_yBin);
+
+  info() << detData() << " digits from " << inputLocation() << endmsg;
+
+  return StatusCode::SUCCESS;
+}
+
+// ============================================================================
+// standard execution method
+// ============================================================================
+
+void CaloFutureDigitMonitor::operator()(const Input& digits) const {
+
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+    debug() << name() << " execute " << endmsg;
+
+  // produce histos ?
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+    debug() << " Producing histo " << produceHistos() << endmsg;
+  if ( !produceHistos() ) return; // StatusCode::SUCCESS;
+
+  if ( digits.empty() ){
+    if( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+      debug() << "Found empty container in " << inputLocation() << endmsg;
+    return;
+  }
+
+  initFutureCounters();
+
+  for( const auto& digit: digits ){
+    if ( digit == nullptr ) continue;
+    const auto id = digit->cellID();
+    const auto e  = digit->e();
+    const auto et = e * m_calo->cellSine( id );
+    if( e  < m_eFilter) continue;
+    if( et < m_etFilter) continue;
+    count( id );
+    hFill1(id , "2", e  );
+    if( detData() != "Spd" && detData() != "Prs")hFill1(id, "3", et );
+    const double x = m_calo->cellCenter(id).X();
+    const double y = m_calo->cellCenter(id).Y();
+    hFill1(id, "4", x  );
+    hFill1(id, "5", y  );
+    hFill2(id, "6", x, y );
+    hFill2(id, "7", x, y, e );
+    if(doHisto("8")) fillCaloFuture2D("8", id , 1. , detData() + " digits position 2D view");
+    if( detData() != "Spd" && doHisto("9") ) fillCaloFuture2D("9", id , e  , detData() + " digits energy 2D view");
+
+    if (m_spectrum) {
+      if( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+        debug() << "Filling cell by cell histograms" << endmsg;
+      const int col = id.col();
+      const int row = id.row();
+      std::ostringstream tit;
+      tit << detData() << " channel : " << id;
+      const auto unit = detData() + "Cells/" + id.areaName() + "/"
+        + Gaudi::Utils::toString(row) + ";" + Gaudi::Utils::toString(col);
+      if( UNLIKELY( msgLevel(MSG::VERBOSE) ) )
+        verbose() << " et  " << et << " cell " << unit << endmsg;
+      if( detData() == "Prs")
+        plot1D(e , unit, tit.str(), m_energyMin, m_energyMax, m_energyBin);
+      else
+        plot1D(et, unit, tit.str(), m_etMin, m_etMax, m_etBin);
+    }
+  }
+  fillFutureCounters("1");
+  return; // StatusCode::SUCCESS;
+}
diff --git a/CaloFuture/CaloFutureMoniDst/src/CaloFutureEFlowAlg.cpp b/CaloFuture/CaloFutureMoniDst/src/CaloFutureEFlowAlg.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ac29a2eb840523bc8e788cadf59d5cb12a1ad513
--- /dev/null
+++ b/CaloFuture/CaloFutureMoniDst/src/CaloFutureEFlowAlg.cpp
@@ -0,0 +1,108 @@
+#include "CaloFutureEFlowBase.h"
+#include "GaudiAlg/Consumer.h"
+#include "Event/ODIN.h"
+
+/*
+  Class CaloFutureEFlowAlg
+
+  Refactored from the original implementation to allow migration to Gaudi::Functional,
+  such that this class's computation doesn't rely on MC objects.
+
+  Author: Chitsanu Khurewathanakul
+  Data  : 2016-10-29
+ */
+
+class CaloFutureEFlowAlg final
+: public Gaudi::Functional::Consumer<void(const Input&, const LHCb::ODIN&),
+    Gaudi::Functional::Traits::BaseClass_t<CaloFutureEFlowBase>>
+{
+public:
+  void operator()(const Input&, const LHCb::ODIN&) const override;
+
+  CaloFutureEFlowAlg(const std::string &name, ISvcLocator *pSvcLocator);
+
+private:
+  Gaudi::Property<bool> m_simulation              { this, "Simulation"             , true};
+  Gaudi::Property<bool> m_ignoreTAE               { this, "IgnoreTAE"              , true};
+  Gaudi::Property<bool> m_ignoreNonBeamCrossing   { this, "IgnoreNonBeamCrossing"  , true};
+  Gaudi::Property<bool> m_ignoreNonPhysicsTrigger { this, "IgnoreNonPhysicsTrigger", true};
+};
+
+//==============================================================================
+
+DECLARE_COMPONENT( CaloFutureEFlowAlg )
+
+//==============================================================================
+
+CaloFutureEFlowAlg::CaloFutureEFlowAlg( const std::string &name, ISvcLocator *pSvcLocator )
+  : Consumer( name, pSvcLocator, {
+      KeyValue{ "Input"      , "" },
+      KeyValue{ "InputODIN"  , LHCb::ODINLocation::Default },
+  })
+{
+  // Configure Input, based on detData()
+  updateHandleLocation( *this, "Input", digitLocation());
+}
+
+//==============================================================================
+// Main execution
+//==============================================================================
+
+void CaloFutureEFlowAlg::operator()(const Input& digits, const LHCb::ODIN& evt) const {
+
+  // In simulated sample, it bypasses this check
+  if(!m_simulation) {
+    if( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+      debug() << "Event: " << evt.eventNumber() << " Run: " << evt.runNumber() << endmsg;
+
+    const LHCb::ODIN::BXTypes bxtype = evt.bunchCrossingType();
+    const unsigned int tae           = evt.timeAlignmentEventWindow();
+    const unsigned int trigger       = evt.triggerType();
+
+    if( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+      debug() << " TAE " << tae
+              << " BXType " << bxtype
+              << " trigger type " << trigger
+              << endmsg;
+
+    if (tae!=0 && m_ignoreTAE) {
+      if( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+        debug() << " TAE WINDOW SET TO " << tae << " WILL SKIP THE EVENT " << endmsg;
+      return;
+    }
+    if (bxtype!=3 && m_ignoreNonBeamCrossing) {
+      //3 =  BeamCrossing
+      if( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+        debug() << " BEAM CROSSING TYPE IS " << bxtype << " WILL SKIP THE EVENT " << endmsg;
+      return;
+    }
+    if (trigger!=1 && m_ignoreNonPhysicsTrigger){
+      //1 = PhysicsTrigger
+      if( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+        debug() << " TRIGGER TYPE IS " << trigger << " WILL SKIP THE EVENT " << endmsg;
+      return;
+    }
+    if( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+      debug() << " TAE " << tae
+              << " BXType " << bxtype
+              << " trigger type " << trigger
+              << endmsg;
+  }
+
+  // produce histos ?
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+    debug() << " Producing histo " << produceHistos() << endmsg;
+  if ( !produceHistos() ) return;
+
+  // get input data
+  if ( digits.empty() ){
+    if( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+      debug() << "Empty digit found at " << inputLocation() << endmsg;
+    return;
+  }
+
+  // Main execution in the CaloFutureEFlowBase
+  process_digits(digits);
+}
+
+//==============================================================================
diff --git a/CaloFuture/CaloFutureMoniDst/src/CaloFutureEFlowBase.cpp b/CaloFuture/CaloFutureMoniDst/src/CaloFutureEFlowBase.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d58ac9316919a5f86b5e21f7647620704c232610
--- /dev/null
+++ b/CaloFuture/CaloFutureMoniDst/src/CaloFutureEFlowBase.cpp
@@ -0,0 +1,84 @@
+// Includes
+#include "CaloFutureEFlowBase.h"
+
+//-----------------------------------------------------------------------------
+// Implementation file for class : CaloFutureEFlowAlg
+//
+// 2009-04-08 : Aurelien Martens
+//-----------------------------------------------------------------------------
+
+//==============================================================================
+// Initialization
+//==============================================================================
+
+StatusCode CaloFutureEFlowBase::initialize() {
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) debug() << "==> Initialize" << endmsg;
+  StatusCode sc = CaloFutureMoniAlg::initialize();
+  if ( sc.isFailure() ) return sc;
+
+  // Configure pointer to detector
+  const auto loc = deCaloFutureLocation();
+  if(loc == ""){
+    return Error( "Unknown detector name "+detData() );
+  }
+  m_calo = getDetIfExists<DeCalorimeter>(loc);
+  if (!m_calo) return Error("No DeCalorimeter for "+detData());
+
+  hBook1( "4", detData() + " : # of Digits",  m_calo->numberOfCells(), 0, m_calo->numberOfCells());
+  
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) debug()  << " initialized" << endmsg;
+  return  StatusCode::SUCCESS;
+}
+
+//==============================================================================
+// Main execution
+//==============================================================================
+
+void CaloFutureEFlowBase::process_digits(const Input& digits) const {
+  // Reset the counter
+  initFutureCounters();
+  
+  // Loop over digits
+  for( const auto& digit: digits ){
+    if( 0 == digit ) continue;
+    
+    const auto id = digit->cellID();
+    if(!(m_calo->valid(id) && !m_calo->isPinId(id))) continue;
+    
+    const double e  = digit->e();
+    const double et = e * m_calo->cellSine(id);
+
+    if( UNLIKELY( msgLevel(MSG::VERBOSE) ) ) 
+      verbose() << " before thresholds :  cellID " << id.index() << " e " << e << " et " << et << endmsg;
+
+    if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+      debug() << "thresholds are EMin " << m_eFilterMin << " EMax " << m_eFilterMax
+              << " EtMin " << m_etFilterMin << " EtMax " << m_etFilterMax << endmsg;
+    
+    const double pedShift = m_calo->pedestalShift();
+    const double gain     = m_calo->cellGain(id);
+    const int adc = (gain !=0.) ? (int) floor((e + pedShift) / gain) : (int) 0;
+ 
+    // Skip poor input
+    if( adc < m_ADCFilterMin  && m_ADCFilterMin !=-999) continue;
+    if( adc > m_ADCFilterMax  && m_ADCFilterMax !=-999) continue;
+    if( e   < m_eFilterMin    && m_eFilterMin   !=-999) continue;
+    if( e   > m_eFilterMax    && m_eFilterMax   !=-999) continue;
+    if( et  < m_etFilterMin   && m_etFilterMin  !=-999) continue;
+    if( et  > m_etFilterMax   && m_etFilterMax  !=-999) continue;
+
+    if( UNLIKELY( msgLevel(MSG::VERBOSE) ) ) 
+      verbose() << " cellID " << id.index() << " e " << e << " et " << et << endmsg;
+    
+    count( id );    
+    if(doHisto("1")) fillCaloFuture2D("1", id , 1. , detData() + " digits position 2D view");
+    if(doHisto("2")) fillCaloFuture2D("2", id , e  , detData() + " energy weighted - digits position 2D view");
+    if(doHisto("3")) fillCaloFuture2D("3", id , et , detData() + " Et weighted - digits position 2D view");
+  
+  } // end loop over digits
+
+  // Finally
+  fillFutureCounters("4");  
+}
+
+//==============================================================================
diff --git a/CaloFuture/CaloFutureMoniDst/src/CaloFutureEFlowBase.h b/CaloFuture/CaloFutureMoniDst/src/CaloFutureEFlowBase.h
new file mode 100644
index 0000000000000000000000000000000000000000..3f7b601b43f96b3874a819ed05b11831325ead71
--- /dev/null
+++ b/CaloFuture/CaloFutureMoniDst/src/CaloFutureEFlowBase.h
@@ -0,0 +1,77 @@
+#ifndef CALOFUTUREENERGYFLOWMONITOR_H 
+#define CALOFUTUREENERGYFLOWMONITOR_H 1
+
+// Includes
+#include "Event/CaloDigit.h"
+#include "CaloDet/DeCalorimeter.h"
+#include "CaloFutureMoniAlg.h"
+
+// =============================================================================
+
+/** @class CaloFutureEFlowAlg CaloFutureEFlowAlg.h
+ *  
+ *
+ *  The algorithm for dedicated "EnergyFlow" monitoring of "CaloDigits" containers.
+ *  The algorithm produces the following histograms:
+ *   1. CaloDigit multiplicity
+ *   2. CaloDigit ocupancy 2D plot per area
+ *   3. CaloDigit energy and transverse energy 2D plot per area
+ *  The same set of histograms, but with cut on Et (or E), is produced if specified
+ *
+ *  Histograms reside in the directory @p /stat/"Name" , where
+ *  @p "Name" is the name of the algorithm
+ *
+ *  @see   CaloFutureMoniAlg
+ *  @see GaudiHistoAlg
+ *  @see GaudiAlgorithm
+ *  @see      Algorithm
+ *  @see     IAlgorithm
+ *
+ *  @author Aurelien Martens
+ *  @date   2009-04-08
+ */
+
+namespace {
+  using Input = LHCb::CaloDigit::Container;
+}
+
+class CaloFutureEFlowBase: public CaloFutureMoniAlg {
+
+public:
+  using CaloFutureMoniAlg::CaloFutureMoniAlg;
+  StatusCode initialize() override;
+
+protected:
+  DeCalorimeter *m_calo = nullptr;
+
+  // Helper method to determine input location from detector name
+  std::string digitLocation() const {
+    if(detData()     == "Ecal" ){ return LHCb::CaloDigitLocation::Ecal; }
+    else if(detData()== "Hcal" ){ return LHCb::CaloDigitLocation::Hcal; }
+    else if(detData()== "Prs"  ){ return LHCb::CaloDigitLocation::Prs; }
+    else if(detData()== "Spd"  ){ return LHCb::CaloDigitLocation::Spd; }    
+    return "";
+  }
+
+  std::string deCaloFutureLocation() const {
+    if      ( "Ecal" == detData() ) { return DeCalorimeterLocation::Ecal; }  
+    else if ( "Hcal" == detData() ) { return DeCalorimeterLocation::Hcal; }
+    else if ( "Prs"  == detData() ) { return DeCalorimeterLocation::Prs; }  
+    else if ( "Spd"  == detData() ) { return DeCalorimeterLocation::Spd; }  
+    return "";
+  }
+
+  // Main computation to be shared by subclass
+  void process_digits(const Input&) const;
+
+private:
+  Gaudi::Property<float> m_eFilterMin   { this, "EnergyFilterMin", -999};
+  Gaudi::Property<float> m_etFilterMin  { this, "EtFilterMin"    , -999};
+  Gaudi::Property<float> m_eFilterMax   { this, "EnergyFilterMax", -999};
+  Gaudi::Property<float> m_etFilterMax  { this, "EtFilterMax"    , -999};
+  Gaudi::Property<int>   m_ADCFilterMin { this, "ADCFilterMin"   , -999};
+  Gaudi::Property<int>   m_ADCFilterMax { this, "ADCFilterMax"   , -999};
+
+};
+#endif // CALOFUTUREENERGYFLOWMONITOR_H
+
diff --git a/CaloFuture/CaloFutureMoniDst/src/CaloFutureEFlowMC.cpp b/CaloFuture/CaloFutureMoniDst/src/CaloFutureEFlowMC.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..46d1047f1c08dad0b6bec7dbfd20a262d16f9b26
--- /dev/null
+++ b/CaloFuture/CaloFutureMoniDst/src/CaloFutureEFlowMC.cpp
@@ -0,0 +1,137 @@
+#include "CaloFutureEFlowBase.h"
+#include "GaudiAlg/Consumer.h"
+
+/*
+  Class CaloFutureEFlowMC
+
+  Refactored from the original implementation to allow migration to Gaudi::Functional,
+  such that this class's computation specialized in MC objects.
+
+  Author: Chitsanu Khurewathanakul
+  Data  : 2016-10-29
+ */
+
+namespace {
+  using MCHits = LHCb::MCCaloHit::Container;
+}
+
+class CaloFutureEFlowMC final
+: public Gaudi::Functional::Consumer<void(const Input&, const MCHits&),
+    Gaudi::Functional::Traits::BaseClass_t<CaloFutureEFlowBase>>
+{
+public:
+  StatusCode initialize() override;
+  void operator()(const Input&, const MCHits&) const override;
+
+  CaloFutureEFlowMC(const std::string &name, ISvcLocator *pSvcLocator);
+
+private:
+  Gaudi::Property<std::string> m_slot {this, "Slot", "", "pile up evetn '' or Prev/ or Next/  "};
+  Gaudi::Property<bool> m_mctruth {this, "MCTruth", false};
+
+  const short int m_pidKplus = 321;
+  const short int m_pidKminus = -321;
+  const short int m_pidPiplus = 211;
+  const short int m_pidPiminus = -211;
+};
+
+//==============================================================================
+
+DECLARE_COMPONENT( CaloFutureEFlowMC )
+
+//==============================================================================
+
+CaloFutureEFlowMC::CaloFutureEFlowMC( const std::string &name, ISvcLocator *pSvcLocator )
+  : Consumer( name, pSvcLocator, {
+      KeyValue{ "Input"      , "" },
+      KeyValue{ "InputMCHits", "" },
+  })
+{}
+
+//==============================================================================
+// Initialization
+//==============================================================================
+
+StatusCode CaloFutureEFlowMC::initialize() {
+  StatusCode sc = Consumer::initialize();
+  if ( sc.isFailure() ) return sc;
+
+  // Configure InputMCHits, after m_slot is frozen
+  // getting detector name from instance's name (so it requires the algo's name
+  // to start with the detector name, e.g., EcalEFlowMon
+  int index = name().find_last_of(".") +1 ; // return 0 if '.' not found --> OK !!
+  auto detectorName = name().substr( index, 4 );
+  if ( name().substr(index,3) == "Prs" ) detectorName = "Prs";
+  if ( name().substr(index,3) == "Spd" ) detectorName = "Spd";
+  auto InputMCHits = m_slot + "MC/" + detectorName + "/Hits";
+  updateHandleLocation( *this, "InputMCHits", InputMCHits );
+
+  return StatusCode::SUCCESS;
+}
+
+//==============================================================================
+// Main execution
+//==============================================================================
+
+void CaloFutureEFlowMC::operator()(const Input& digits, const MCHits& hits) const {
+
+  // produce histos ?
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+    debug() << " Producing histo " << produceHistos() << endmsg;
+  if ( !produceHistos() ) return;
+
+  // get input data
+  if ( digits.empty() ){
+    if( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+      debug() << "Empty digit found at " << inputLocation() << endmsg;
+    return;
+  }
+
+  // Main execution in the CaloFutureEFlowBase
+  process_digits(digits);
+
+  // Extra work for on MCTruth if requested
+  if (!m_mctruth) return;
+
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+    debug() << "LOOKING FOR MCTRUTH" << endmsg;
+
+  // Loop over MC hits
+  for( const auto& hit: hits ){
+    if ( hit == nullptr ) continue;
+    const auto id = hit->cellID();
+    if( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+      debug() << "hit " << hit << " id " << id << endmsg;
+    if(!(m_calo->valid(id) && !m_calo->isPinId( id ))) continue ;
+
+    const double e = hit->activeE();
+    const int pid = hit->particle()->particleID().pid();
+
+    if( UNLIKELY( msgLevel(MSG::VERBOSE) ) )
+      verbose() << " cellID " << id.index() << " e " << e  << endmsg;
+
+    if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) {
+      debug() << " part " << hit->particle() << endmsg;
+      debug() << " partID " << pid
+              << " origin vtx " << hit->particle()->originVertex()->position() << endmsg;
+    }
+
+    // Fill the histos
+    if(pid==m_pidKplus) {
+      if(doHisto("5")) fillCaloFuture2D("5", id, 1., detData() + " K+ digits position 2D view");
+      if(doHisto("6")) fillCaloFuture2D("6", id, e , detData() + " K+ energy weighted - digits position 2D view");
+    }
+    else if(pid==m_pidKminus) {
+      if(doHisto("7")) fillCaloFuture2D("7", id, 1., detData() + " K- digits position 2D view");
+      if(doHisto("8")) fillCaloFuture2D("8", id, e , detData() + " K- energy weighted - digits position 2D view");
+    }
+    else if(pid==m_pidPiplus) {
+      if(doHisto("9"))  fillCaloFuture2D("9" , id, 1., detData() + " Pi+ digits position 2D view");
+      if(doHisto("10")) fillCaloFuture2D("10", id, e , detData() + " Pi+ energy weighted - digits position 2D view");
+    }
+    else if(pid==m_pidPiminus) {
+      if(doHisto("11")) fillCaloFuture2D("11", id, 1., detData() + " Pi- digits position 2D view");
+      if(doHisto("12")) fillCaloFuture2D("12", id, e , detData() + " Pi- energy weighted - digits position 2D view");
+    }
+  }
+}
diff --git a/CaloFuture/CaloFutureMoniDst/src/CaloFutureEMuPIDMon.cpp b/CaloFuture/CaloFutureMoniDst/src/CaloFutureEMuPIDMon.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a48da0d4039cd64ef208aef5c61a68d72e4fad57
--- /dev/null
+++ b/CaloFuture/CaloFutureMoniDst/src/CaloFutureEMuPIDMon.cpp
@@ -0,0 +1,183 @@
+// Includes
+#include "GaudiAlg/Consumer.h"
+#include "AIDA/IAxis.h"
+#include "Event/Track.h"
+#include "Event/ProtoParticle.h"
+#include "Relations/IRelation.h"
+#include "Relations/IRelationWeighted.h"
+#include "CaloFutureUtils/CaloFuture2Track.h"
+#include "CaloFutureMoniAlg.h"
+
+// =============================================================================
+
+/** @class CaloFutureEMuPIDMon CaloFutureEMuPIDMon.cpp
+ *
+ *  Class for monitoring some CaloFuturePID quantities
+ *
+ *  @author Dmitry Golubkov
+ *  @date   2010-03-25
+ */
+
+using Input = LHCb::ProtoParticle::Container;
+
+class CaloFutureEMuPIDMon final
+: public Gaudi::Functional::Consumer<void(const Input&),
+    Gaudi::Functional::Traits::BaseClass_t<CaloFutureMoniAlg>>
+{
+public:
+  StatusCode initialize() override;
+  void operator()(const Input&) const override;
+
+  /// Standard constructor
+  CaloFutureEMuPIDMon( const std::string &name, ISvcLocator *isvc );
+
+private:
+  Gaudi::Property<bool> m_uncut
+    {this, "uncut", false, "true = do not apply the cuts"};
+
+  Gaudi::Property<float> m_minPt
+    {this, "pTmin", 250., "minimal pT of the track [MeV/c]"};
+
+  Gaudi::Property<float> m_maxPt
+    {this, "pTmax", 1.e10, "maximal pT of the track [MeV/c]"};
+
+  Gaudi::Property<float> m_RichDLLe
+    {this, "RichDLLe", -1.e10, "minimal ProtoParticle::additionalInfo::RichDLLe for electron id"};
+
+  Gaudi::Property<float> m_maxEHcalE
+    {this, "maxEHcalE", 1.e10, "maximal ProtoParticle::additionalInfo::CaloHcalE for electron id [MeV/c]"};
+
+  Gaudi::Property<float> m_minPrsE
+    {this, "minPrsE", 15., "minimal ProtoParticle::additionalInfo::CaloPrsE for electron id [MeV/c]"};
+
+  Gaudi::Property<unsigned long int> m_nEventMin
+    {this, "nEventMin", 200, "minimal number of events to check"};
+
+  Gaudi::Property<bool> m_muonLoose
+    {this, "useIsMuonLoose", true, "use IsMuonLoose instead of IsMuon for muon selection"};
+};
+
+DECLARE_COMPONENT( CaloFutureEMuPIDMon )
+
+// =============================================================================
+
+/** Standard constructor
+ *  @param name name of the algorithm instance
+ *  @param isvc pointer to the Service Locator
+ */
+CaloFutureEMuPIDMon::CaloFutureEMuPIDMon( const std::string &name, ISvcLocator *pSvcLocator )
+: Consumer( name, pSvcLocator,
+    KeyValue{ "Input", LHCb::ProtoParticleLocation::Charged }
+){
+  setProperty( "histoList",           std::vector<std::string>{ { "All" } } ).ignore();
+  setProperty( "removeFromHistoList", std::vector<std::string>() ).ignore();
+  setProperty( "SaturationBin1D",     false).ignore();
+  setProperty( "SaturationBin2D",     false).ignore();
+}
+
+// =============================================================================
+
+/**
+ * initialize the algorithm, define the histograms
+ */
+StatusCode CaloFutureEMuPIDMon::initialize(){
+  StatusCode sc = Consumer::initialize();
+  if ( sc.isFailure() ) return sc;
+
+  hBook1(    "eop",    "E/p", 0.05,  2.55, 50);
+
+  // for the time being let's not split MIP plots into A and C sides
+  bool old_m_splitSides = m_splitSides;
+  m_splitSides = false;
+
+  hBook1(  "prsem",  "E Prs",  0.5,  25.5, 25);
+  hBook1( "ecalem", "E Ecal",  40., 2040., 50);
+  hBook1( "hcalem", "E Hcal", 100., 5100., 50);
+
+  m_splitSides = old_m_splitSides;
+
+  return StatusCode::SUCCESS;
+}
+
+
+// =============================================================================
+// standard execution method
+// =============================================================================
+
+void CaloFutureEMuPIDMon::operator()(const Input& particles) const {
+
+  if( !produceHistos() ) return; // StatusCode::SUCCESS;
+  if( m_counterStat->isQuiet()) ++counter("nEvents");
+
+  // -------------------------------------------------------------------
+  // Track loop
+  // -------------------------------------------------------------------
+
+  for( const auto& proto: particles ){
+    if ( 0 == proto ) continue ;
+    const auto track = proto->track() ;
+    if ( 0 == track ) continue ;
+    if ( track->type() < LHCb::Track::Types::Long ) continue;
+    if ( ( track->pt() < m_minPt || track->pt() > m_maxPt ) && !m_uncut ) continue;
+
+    const bool  inprs = (proto->info( LHCb::ProtoParticle::additionalInfo::InAccPrs,  double(false) )!=0);
+    const bool inecal = (proto->info( LHCb::ProtoParticle::additionalInfo::InAccEcal, double(false) )!=0);
+    const bool inhcal = (proto->info( LHCb::ProtoParticle::additionalInfo::InAccHcal, double(false) )!=0);
+
+    const float prse  = (float) proto->info(LHCb::ProtoParticle::additionalInfo::CaloPrsE,  -1 * Gaudi::Units::GeV);
+    const float ecale = (float) proto->info(LHCb::ProtoParticle::additionalInfo::CaloEcalE, -1 * Gaudi::Units::GeV);
+    const float hcale = (float) proto->info(LHCb::ProtoParticle::additionalInfo::CaloHcalE, -1 * Gaudi::Units::GeV);
+
+
+    // -----------------------------------------------------------------
+    // electron histograms
+    // e.g.:  "pt>0.5&&inecal==1&&(hcale<=0||hcale>0&&inhcal==1&&hcale<1000.)&&rdlle>4"
+    //   or:  "pt>250&&inecal==1&&prse>15"
+    // -----------------------------------------------------------------
+
+    do {
+      if ( !inecal )                                                   break; // ----
+      float rdlle = (float) proto->info( LHCb::ProtoParticle::additionalInfo::RichDLLe, -9999.);
+      if ( rdlle < m_RichDLLe && !m_uncut )                            break; // ----
+      if ( inhcal && hcale > m_maxEHcalE && !m_uncut)                  break; // ----
+      if ( prse < m_minPrsE && !m_uncut )                              break; // ----
+
+      const auto hypos = proto->calo();
+      const LHCb::CaloHypo* m_electron = NULL;
+
+      for( const auto& hypo: hypos ){
+        if ( LHCb::CaloHypo::Hypothesis::EmCharged == hypo->hypothesis() ) m_electron = hypo;
+      }
+
+      // E/p histogram
+      if ( m_electron ){
+        double eoverp = m_electron->position()->e() / track->p() ;
+        if (eoverp > 0.){
+          const auto clust = *(m_electron->clusters().begin());
+          if( clust ){
+            const auto cell = clust->seed();
+            hFill1( cell, "eop",  eoverp );
+          }
+        }
+      }
+    } while( false );
+
+
+    // -----------------------------------------------------------------
+    // muon histograms
+    // -----------------------------------------------------------------
+
+    bool ismuon = (0!=
+                   ( proto->muonPID()
+                     ? ( m_muonLoose ? proto->muonPID()->IsMuonLoose() : proto->muonPID()->IsMuon() )
+                     : false)
+                   );
+
+    if ( ismuon || m_uncut ){
+      if ( inprs) hFill1( "prsem",  prse);
+      if (inecal) hFill1("ecalem", ecale);
+      if (inhcal) hFill1("hcalem", hcale);
+    }
+  }
+  return; // StatusCode::SUCCESS;
+}
diff --git a/CaloFuture/CaloFutureMoniDst/src/CaloFutureElectronNtp.cpp b/CaloFuture/CaloFutureMoniDst/src/CaloFutureElectronNtp.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..bfb0cfb189603c43203c31fcc3d8c4e26697ff46
--- /dev/null
+++ b/CaloFuture/CaloFutureMoniDst/src/CaloFutureElectronNtp.cpp
@@ -0,0 +1,272 @@
+// Include files
+#include "CaloFutureElectronNtp.h"
+#include "CaloFutureMoniUtils.h"
+
+
+namespace {
+  /// hack to allow for tools with non-const interfaces...
+  template <typename IFace>
+  IFace* fixup(const ToolHandle<IFace>& iface) { return &const_cast<IFace&>(*iface); }
+}
+//------------------------------------------------------------------------------
+// Implementation file for class : CaloFutureElectronNtp
+//
+// 2009-12-11 : Olivier Deschamps
+//------------------------------------------------------------------------------
+
+// Declaration of the Algorithm Factory
+DECLARE_COMPONENT( CaloFutureElectronNtp )
+
+//==============================================================================
+// Standard constructor, initializes variables
+//==============================================================================
+
+CaloFutureElectronNtp::CaloFutureElectronNtp( const std::string& name, ISvcLocator* pSvcLocator)
+: Consumer( name, pSvcLocator, {
+    KeyValue{ "InputODIN"     , LHCb::ODINLocation::Default          },
+    KeyValue{ "InputContainer", LHCb::ProtoParticleLocation::Charged },
+    KeyValue{ "VertexLoc"     , LHCb::RecVertexLocation::Primary     }
+}) {}
+
+//==============================================================================
+// Initialization
+//==============================================================================
+
+StatusCode CaloFutureElectronNtp::initialize(){
+  StatusCode sc = Consumer::initialize();
+  if ( sc.isFailure() ) return sc;
+  if ( msgLevel(MSG::DEBUG) ) debug() << "==> Initialize" << endmsg;
+  if( !m_tracks.empty() )info() << "Will only look at track type(s) = " << m_tracks.value() << endmsg;
+  else info() << "Will look at any track type" << endmsg;
+
+  // Get, retrieve, configure tools
+  m_calo = getDet<DeCalorimeter>(DeCalorimeterLocation::Ecal);
+  if(!( m_counterStat.retrieve()
+     && m_caloElectron.retrieve()
+     && m_odin.retrieve()
+     && m_toSpd.retrieve()
+     && m_toPrs.retrieve()
+     && m_extrapolator.retrieve() )){
+    error() << "Unable to retrive one of the ToolHandles" << endmsg;
+    return StatusCode::FAILURE;
+  }
+  m_toSpd->setCalos( "Ecal" ,"Spd");
+  m_toPrs->setCalos( "Ecal" ,"Prs");
+
+  // set vertex location
+  m_vertLoc = inputLocation<2>();  // <-- Careful with the index, 'VertexLoc' is 3rd.
+  // use fallback if null (forced by user)
+  if(m_vertLoc == "")
+    m_vertLoc = m_usePV3D ? LHCb::RecVertexLocation::Velo3D : LHCb::RecVertexLocation::Primary;
+  updateHandleLocation( *this, "VertexLoc", m_vertLoc );
+
+  return StatusCode::SUCCESS;
+}
+
+//==============================================================================
+
+// Warning, not actually a const member function, as it modifies the internal
+// state of m_caloElectron. Use with care.
+// Note, extra flag count to count at the specific place. Because this method
+// is used on both first-electron, and second-electron, the counting should only
+// be enabled in the first one only.
+bool CaloFutureElectronNtp::set_and_validate( const LHCb::ProtoParticle* proto, bool count ) const {
+  // abort if fail to set
+  if( !fixup(m_caloElectron)->set(proto) ) return false;
+  // counting
+  if( count && m_counterStat->isQuiet() ) counter("proto electron")+=1;
+  // abort if no hypo obtained
+  const auto hypo = fixup(m_caloElectron)->electron();
+  if ( hypo == nullptr ) return false;
+  // abort if null track
+  const auto track = proto->track();
+  if ( track == nullptr ) return false;
+  // abort if not matching track whitelist
+  if(!m_tracks.empty()){
+    const auto ttype = proto->track()->type();
+    if(!std::any_of(m_tracks.begin(), m_tracks.end(),
+        [ttype](int itype){return itype==ttype;})){
+      return false;
+    }
+  }
+  // Abort if poor energy
+  LHCb::CaloMomentum mmt( hypo );
+  const double e = mmt.e();
+  const double et= mmt.pt();
+  if( !inRange(m_et , et )) return false;
+  if( !inRange(m_e  , e  )) return false;
+  const double ePrs = proto->info(LHCb::ProtoParticle::additionalInfo::CaloPrsE, 0.);
+  if( !inRange(m_prs, ePrs)) return false;
+  const double eOp = fixup(m_caloElectron)->eOverP();
+  if( !inRange( m_eop, eOp)) return false;
+  // finally
+  if( count && m_counterStat->isQuiet() ) counter("Selected electron")+=1;
+  return true;
+}
+
+// Calculated the squared of the invar mass of two tracks
+// The result can be negative.
+double CaloFutureElectronNtp::invar_mass_squared( const LHCb::Track* t1, const LHCb::Track* t2 ) const {
+  auto st1  = t1->firstState();
+  auto st2  = t2->firstState();
+  auto sc   = m_extrapolator->propagate(st1, 0.);
+  if(sc.isFailure()) Warning("Propagation 1 failed").ignore();
+  sc = m_extrapolator->propagate(st2, 0.);
+  if(sc.isFailure()) Warning("Propagation 2 failed").ignore();
+  const auto p1 = st1.momentum();
+  const auto p2 = st2.momentum();
+  double m2 = p1.R()*p2.R();
+  m2 -= p1.X()*p2.X();
+  m2 -= p1.Y()*p2.Y();
+  m2 -= p1.Z()*p2.Z();
+  m2 *= 2;
+  return m2;
+}
+
+//==============================================================================
+// Main execution
+//==============================================================================
+
+void CaloFutureElectronNtp::operator()(const ODIN& odin, const Protos& protos,
+                                 const Vertices& verts) const {
+
+  if ( msgLevel(MSG::DEBUG) ) debug() << "==> Execute" << endmsg;
+
+  // GET ODIN INFO
+  m_odin->getTime();
+  ulonglong evt = odin.eventNumber();
+  int run       = odin.runNumber();
+  int tty       = odin.triggerType();
+
+  // Loop over each protoparticle
+  for( auto p = protos.begin(); protos.end() != p ; ++p ){
+    const auto proto = *p;
+    if(!set_and_validate(proto, true)) continue;
+
+    // Retrieve info for tuple
+    const auto ePrs         = proto->info(LHCb::ProtoParticle::additionalInfo::CaloPrsE, 0.);
+    const auto track1       = proto->track();
+    const auto hypo         = fixup(m_caloElectron)->electron();
+    const auto iSpd         = (int) fixup(m_toSpd)->multiplicity( *hypo , "Spd" );
+    const auto track1mmt    = momentum(track1);
+    const auto caloCluster  = firstCluster(hypo);
+    const auto caloCellId   = caloCluster->seed();
+    const auto caloState    = fixup(m_caloElectron)->caloState();
+    const auto caloStateMmt = momentum(caloState);
+    const auto brem         = fixup(m_caloElectron)->bremstrahlung();
+    const auto bremCellId   = firstCluster(brem)->seed();
+    const auto bremMmt      = momentum(fixup(m_caloElectron)->bremCaloFutureMomentum());
+    const auto eOp          = fixup(m_caloElectron)->eOverP();
+    const auto e            = LHCb::CaloMomentum(hypo).e();
+
+    // dielectron filter
+    double mas = 999999.;
+    if( m_pairing ){
+      for( auto pp = p+1 ; protos.end () != pp ; ++pp ){
+        const auto proto2 = *pp;
+        if(!set_and_validate(proto2)) continue;
+        // abort if same pair (shouldn't happen)
+        const auto hypo2 = fixup(m_caloElectron)->electron();
+        if( hypo == hypo2 ) continue;
+        // Need opposite charge
+        const auto t1 = proto->track();
+        const auto t2 = proto2->track();
+        if( -1 != t1->charge()*t2->charge()) continue;
+        // compute mass
+        const auto m2 = invar_mass_squared( t1, t2 );
+        if(m2 > 0){
+          const auto m = sqrt(m2) ;
+          if(m < mas) mas = m;
+        }
+      }
+    }
+    if( mas > 0 && mas < 100 && m_counterStat->isQuiet()) counter("Selected (di)electron")+=1;
+
+    // proto info
+    if(m_tuple){
+      auto ntp = nTuple(500, "e_tupling" ,CLID_ColumnWiseTuple);
+      ntp->column("Spd"        , iSpd );
+      ntp->column("Prs"        , ePrs );
+      ntp->column("TrackMatch" , proto->info(LHCb::ProtoParticle::additionalInfo::CaloTrMatch, 9999.));
+      ntp->column("ElecMatch"  , proto->info(LHCb::ProtoParticle::additionalInfo::CaloElectronMatch, 9999.));
+      ntp->column("BremMatch"  , proto->info(LHCb::ProtoParticle::additionalInfo::CaloBremMatch, 9999.));
+      ntp->column("TrajectoryL", proto->info(LHCb::ProtoParticle::additionalInfo::CaloTrajectoryL, 9999.));
+      ntp->column("VeloCharge" , proto->info(LHCb::ProtoParticle::additionalInfo::VeloCharge, -1.));
+      ntp->column("DLLe"       , proto->info(LHCb::ProtoParticle::additionalInfo::CombDLLe, 0.));
+      ntp->column("RichDLLe"   , proto->info(LHCb::ProtoParticle::additionalInfo::RichDLLe, 0.));
+      // hypo info
+      ntp->column("EoP"        , eOp );
+      ntp->column("HypoE"      , e );
+      ntp->column("HypoR"      , position3d(hypo)         );
+      ntp->column("HypoTheta"  , position3d(hypo).theta() );
+     // track info
+      ntp->column("TrackP"     , track1mmt);
+      ntp->column("TrackR"     , position3d(caloState));
+      ntp->column("caloState"  , caloStateMmt);
+      ntp->column("incidence"  , caloStateMmt.theta());
+      ntp->column("incidenceX" , atan2(caloStateMmt.X(),caloStateMmt.Z()));
+      ntp->column("incidenceY" , atan2(caloStateMmt.Y(),caloStateMmt.Z()));
+      ntp->column("trackType"  , track1->type());
+      ntp->column("trackProb"  , track1->probChi2());
+      // cluster info
+      ntp->column("id"         , caloCellId.index());
+      ntp->column("ClusterE"   , caloCluster->e());
+      ntp->column("ClusterR"   , position3d(caloCluster) );
+      // brem info
+      ntp->column("BremId"     , bremCellId.index());
+      ntp->column("BremP"      , bremMmt );
+      // odin info
+      ntp->column("run"        , run );
+      ntp->column("event"      , (double) evt );
+      ntp->column("triggertype", tty );
+      if(m_pairing) ntp->column("MinMee" , mas);
+      ntp->write();
+    }
+
+    // histogramming / channel
+    const auto trmatch = proto->info(LHCb::ProtoParticle::additionalInfo::CaloTrMatch, 9999.);
+    if(m_histo && iSpd != 0 && trmatch < 25){
+      fillH( eOp, track1mmt, caloCellId );
+      if( m_pairing && mas >0. && mas < 100. ) fillH( eOp, track1mmt, caloCellId, "conversion/" );
+    }
+
+    // vertices
+    const auto nVert = verts.size();
+    if(m_counterStat->isQuiet()) counter("#PV="+ Gaudi::Utils::toString(nVert) + " ["+ m_vertLoc+"]")+=1;
+
+    if( m_trend ){
+      std::string sNpv = "PV" + Gaudi::Utils::toString( nVert ) +"/";
+      std::string sRun =  "r" + Gaudi::Utils::toString( run   ) +"/";
+      std::string base = "Trend/";
+      plot1D(eOp, base+"allPV/allRun/eOp","e/p spectrum for all run & allPV"          , 0. , 2.5, 250);
+      plot1D(eOp, base+"allPV/"+sRun+"eOp","e/p spectrum for run = "+sRun             , 0. , 2.5, 250);
+      plot1D(eOp, base+sNpv+sRun+"eOp","e/p spectrum for PV="+sNpv+" (run = "+sRun+")", 0. , 2.5, 250);
+      plot1D(eOp, base+sNpv+"allRun/eOp","e/p spectrum for PV="+sNpv+" (all run)"     , 0. , 2.5, 250);
+    }
+  }
+  return;
+}
+//=============================================================================
+
+void CaloFutureElectronNtp::fillH(double eOp, Gaudi::LorentzVector t, LHCb::CaloCellID id,std::string hat) const {
+  if(!m_histo) return;
+  std::string zone=id.areaName();
+  plot1D(eOp, hat+"all/eOp"  , "all/eOp"  , 0., 3., 300);
+  plot1D(eOp, hat+zone+"/eOp", zone+"/eOp", 0., 3., 300);
+  if( m_splitFEBs ){
+    std::ostringstream sid;
+    int feb = m_calo->cardNumber( id );
+    sid << hat << "crate" << format("%02i", m_calo->cardCrate( feb ) ) <<  "/"
+        << "feb"   << format( "%02i" , m_calo->cardSlot( feb  ) )<< "/"
+        <<Gaudi::Utils::toString( m_calo->cardColumn( id ) + nColCaloCard * m_calo->cardRow( id ) );
+    plot1D(eOp, sid.str() , sid.str() , 0., 3., 300);
+  }
+  if( m_splitE && t.P() < 200. * Gaudi::Units::GeV ){  // put a limit at 200 GeV
+    int ebin=( t.P() / 5000.)*5; // 1 GeV binning
+    std::ostringstream sid ;
+    sid << "/E_"<< ebin<<"/eOp";
+    if(m_counterStat->isQuiet()) counter(sid.str()+"[<p>]") += t.P();
+    plot1D(eOp, hat+zone+sid.str() , zone+sid.str() , 0., 3., 300);
+    plot1D(eOp, hat+"all"+sid.str(), "all"+sid.str(), 0., 3., 300);
+  }
+}
diff --git a/CaloFuture/CaloFutureMoniDst/src/CaloFutureElectronNtp.h b/CaloFuture/CaloFutureMoniDst/src/CaloFutureElectronNtp.h
new file mode 100644
index 0000000000000000000000000000000000000000..27d9b4831363765a2e4b06a7c488cf1d7f28ec25
--- /dev/null
+++ b/CaloFuture/CaloFutureMoniDst/src/CaloFutureElectronNtp.h
@@ -0,0 +1,79 @@
+#ifndef CALOFUTUREELECTRONNTP_H 
+#define CALOFUTUREELECTRONNTP_H 1
+
+// Include files
+#include "GaudiAlg/Consumer.h"
+#include "GaudiAlg/GaudiTupleAlg.h"
+#include "GaudiKernel/IEventTimeDecoder.h"
+#include "Event/ODIN.h" 
+#include "Event/ProtoParticle.h"
+#include "Event/RecVertex.h"
+#include "CaloDet/DeCalorimeter.h"
+#include "CaloFutureInterfaces/ICaloFutureHypo2CaloFuture.h"
+#include "CaloFutureInterfaces/IFutureCounterLevel.h"
+#include "CaloFutureUtils/ICaloFutureElectron.h"
+#include "TrackInterfaces/ITrackExtrapolator.h"
+
+// List of Consumers dependencies
+namespace {
+  using ODIN = LHCb::ODIN;
+  using Protos = LHCb::ProtoParticles;
+  using Vertices = LHCb::RecVertices;
+}
+
+//==============================================================================
+
+/** @class CaloFutureElectronNtp CaloFutureElectronNtp.h
+ *  
+ *
+ *  @author Olivier Deschamps
+ *  @date   2009-12-11
+ */
+class CaloFutureElectronNtp final
+: public Gaudi::Functional::Consumer<void(const ODIN&, const Protos&, const Vertices&),
+    Gaudi::Functional::Traits::BaseClass_t<GaudiTupleAlg>>
+{
+public: 
+  CaloFutureElectronNtp( const std::string& name, ISvcLocator* pSvcLocator );
+  StatusCode initialize() override;
+  void operator()(const ODIN&, const Protos&, const Vertices&) const override;
+
+  /// C++11 non-copyable idiom
+  CaloFutureElectronNtp() = delete;
+  CaloFutureElectronNtp( const CaloFutureElectronNtp& ) = delete;
+  CaloFutureElectronNtp &operator=( const CaloFutureElectronNtp& ) = delete;
+
+private:
+  DeCalorimeter* m_calo = nullptr;
+  std::string m_vertLoc;
+
+  ToolHandle<IFutureCounterLevel>      m_counterStat  { "FutureCounterLevel" };
+  ToolHandle<ICaloFutureElectron>      m_caloElectron { "CaloFutureElectron"                            , this };
+  ToolHandle<IEventTimeDecoder>  m_odin         { "OdinTimeDecoder/OdinDecoder"             , this };
+  ToolHandle<ICaloFutureHypo2CaloFuture>     m_toSpd        { "CaloFutureHypo2CaloFuture/CaloFutureHypo2Spd"              , this };
+  ToolHandle<ICaloFutureHypo2CaloFuture>     m_toPrs        { "CaloFutureHypo2CaloFuture/CaloFutureHypo2Prs"              , this };
+  ToolHandle<ITrackExtrapolator> m_extrapolator { "TrackRungeKuttaExtrapolator/Extrapolator", this };
+
+  Gaudi::Property<std::pair<double, double>> m_e   { this, "EFilter"  , { 0.  , 99999999}};
+  Gaudi::Property<std::pair<double, double>> m_et  { this, "EtFilter" , { 200., 999999.}};
+  Gaudi::Property<std::pair<double, double>> m_prs { this, "PrsFilter", { 50. , 9999999.}};
+  Gaudi::Property<std::pair<double, double>> m_eop { this, "EoPFilter", { 0.  , 2.5}};
+  
+  Gaudi::Property<bool> m_pairing {this, "ElectronPairing", true};
+  Gaudi::Property<bool> m_histo   {this, "Histo", true};
+  Gaudi::Property<bool> m_tuple   {this, "Tuple", true};
+  Gaudi::Property<bool> m_trend   {this, "Trend", false};
+  Gaudi::Property<bool> m_usePV3D {this, "UsePV3D", false};
+  Gaudi::Property<bool> m_splitFEBs{this, "splitFEBs", false};
+  Gaudi::Property<bool> m_splitE  {this, "splitE", false};
+
+  Gaudi::Property<std::vector<int>> m_tracks 
+    {this, "TrackTypes", {LHCb::Track::Types::Long, LHCb::Track::Types::Downstream}};
+
+  bool set_and_validate( const LHCb::ProtoParticle* proto, bool count=false ) const;
+  double invar_mass_squared( const LHCb::Track* t1, const LHCb::Track* t2 ) const;
+  void fillH(double eOp,Gaudi::LorentzVector t, LHCb::CaloCellID id,std::string hat="") const;
+
+};
+
+#endif // CALOFUTUREELECTRONNTP_H
diff --git a/CaloFuture/CaloFutureMoniDst/src/CaloFutureHypoMatchMonitor.cpp b/CaloFuture/CaloFutureMoniDst/src/CaloFutureHypoMatchMonitor.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f0645fff126c94c731823ab12ce553da064e4d7e
--- /dev/null
+++ b/CaloFuture/CaloFutureMoniDst/src/CaloFutureHypoMatchMonitor.cpp
@@ -0,0 +1,126 @@
+// Includes
+#include "GaudiAlg/Consumer.h"
+#include "Relations/RelationWeighted2D.h"
+#include "Event/CaloHypo.h"
+#include "Event/Track.h"
+#include "CaloFutureMoniAlg.h"
+
+// =============================================================================
+
+/** @class CaloFutureHypoMatchMonitor CaloFutureHypoMatchMonitor.cpp
+ *
+ *  The algorithm for trivial monitoring of matching of
+ *  "CaloFutureClusters" with Tracks.
+ *  It produces 5 histograms:
+ *
+ *  <ol>
+ *  <li> @p log10(#Relations+1)  distribution               </li>
+ *  <li> Link multiplicity       distribution               </li>
+ *  <li> Minimal Weight          distribution               </li>
+ *  <li> Maximal Weight          distribution               </li>
+ *  <li>         Weight          distribution               </li>
+ *  </ol>
+ *
+ *  Histograms reside in the directory @p /stat/"Name" , where
+ *  @ "Name" is the name of the algorithm
+ *
+ *  @see   CaloFutureMoniAlg
+ *  @see GaudiHistoAlg
+ *  @see GaudiAlgorithm
+ *  @see      Algorithm
+ *  @see     IAlgorithm
+ *
+ *  @author Vanya Belyaev Ivan.Belyaev@itep.ru
+ *  @date   02/11/2001
+ */
+
+using Input   = LHCb::RelationWeighted2D< LHCb::CaloHypo, LHCb::Track, float >;
+using Inputs  = LHCb::CaloHypo::Container;
+
+class CaloFutureHypoMatchMonitor final
+: public Gaudi::Functional::Consumer<void(const Input&, const Inputs&),
+    Gaudi::Functional::Traits::BaseClass_t<CaloFutureMoniAlg>>
+{
+public:
+  StatusCode initialize() override;
+  void operator()(const Input&, const Inputs&) const override;
+
+  CaloFutureHypoMatchMonitor( const std::string &name, ISvcLocator *pSvcLocator );
+};
+
+// =============================================================================
+
+DECLARE_COMPONENT( CaloFutureHypoMatchMonitor )
+
+// =============================================================================
+
+CaloFutureHypoMatchMonitor::CaloFutureHypoMatchMonitor( const std::string &name, ISvcLocator *pSvcLocator )
+: Consumer( name, pSvcLocator, {
+    KeyValue{ "Input" , "" },
+    KeyValue{ "Inputs", "" }
+}){
+  /*
+  * During genconf.exe, the default name "DefaultName" is not well-supported
+  * by the CaloFutureAlgUtils, returning the null string "" as a location path,
+  * which will raise exception in `updateHandleLocation` --> `setProperty`.
+  * To get around this, the location will only be updated outside the genconf.
+  */
+  if( name != "DefaultName" ){
+    const auto Input  = LHCb::CaloFutureAlgUtils::CaloFutureIdLocation(name, context());
+    const auto Inputs = LHCb::CaloFutureAlgUtils::CaloFutureHypoLocation(name, context());
+    updateHandleLocation( *this, "Input" , Input  );
+    updateHandleLocation( *this, "Inputs", Inputs );
+  }
+}
+
+// =============================================================================
+
+/// standard algorithm initialization
+StatusCode CaloFutureHypoMatchMonitor::initialize(){
+  StatusCode sc = Consumer::initialize(); // must be executed first
+  if ( sc.isFailure() ) return sc; // error already printedby GaudiAlgorithm
+  std::string common = "'" + inputLocation() + "' " + name();
+  hBook1( "1", "log10(#Links+1) " + common, 0,    4, 100 );
+  hBook1( "2", "Rels per Hypo   " + common, 0,   25,  50 );
+  hBook1( "3", "Min weight      " + common, 0,  100, 200 );
+  hBook1( "4", "Max weight      " + common, 0, 1000, 200 );
+  hBook1( "5", "Weights         " + common, 0, 1000, 500 );
+  if( m_split ){
+    Warning( "No area spliting allowed for CaloFutureHypoMatchMonitor").ignore();
+    m_split = false;
+  }
+  return StatusCode::SUCCESS;
+}
+
+// =============================================================================
+// standard execution method
+// =============================================================================
+
+void CaloFutureHypoMatchMonitor::operator()(const Input& table, const Inputs& hypos) const {
+
+  if ( !produceHistos() ) return;
+
+  // logarithm of ( total number of links + 1 )
+  hFill1( "1", log10( table.relations().size() + 1. ) );
+
+  // loop over all hypos
+  for( const auto& hypo: hypos ){
+    const auto range = table.relations( hypo );
+    // number of related tracks
+    hFill1( "2", range.size() );
+    if ( range.empty() ) continue;
+    // minimal weight
+    hFill1( "3", range.front().weight() );
+    // maximal weight
+    hFill1( "4", range.back().weight() );
+    // all weights
+    for( const auto& relation: range ){
+      hFill1( "5", relation.weight() );
+    }
+  } // end of loop over hypos
+
+  if( m_counterStat->isQuiet()) counter("Monitor " + inputLocation<1>()) += hypos.size();
+  if( m_counterStat->isQuiet()) counter("Monitor " + inputLocation() ) += table.relations().size();
+
+  return;
+}
diff --git a/CaloFuture/CaloFutureMoniDst/src/CaloFutureHypoMonitor.cpp b/CaloFuture/CaloFutureMoniDst/src/CaloFutureHypoMonitor.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6ae6e2e9bc9009a59ccf0b37b8e46740415285ea
--- /dev/null
+++ b/CaloFuture/CaloFutureMoniDst/src/CaloFutureHypoMonitor.cpp
@@ -0,0 +1,183 @@
+// Includes
+#include "GaudiAlg/Consumer.h"
+#include "Event/CaloHypo.h"
+#include "Event/CaloDataFunctor.h"
+#include "CaloDet/DeCalorimeter.h"
+#include "CaloFutureUtils/CaloMomentum.h"
+#include "CaloFutureUtils/CaloFutureAlgUtils.h"
+#include "CaloFutureMoniAlg.h"
+
+// =============================================================================
+
+/** @class CaloFutureHypoMonitor CaloFutureHypoMonitor.cpp
+ *
+ *  The algorithm for trivial monitoring of "CaloHypo" container
+ *  The algorithm produces 10 histograms:
+ *  <ol>
+ *  <li> @p CaloHypo multiplicity                           </li>
+ *  <li> @p CaloHypo energy distribution                    </li>
+ *  <li> @p CaloHypo transverse momentum distribution       </li>
+ *  <li> @p CaloHypo mass distribution                      </li>
+ *  <li> @p CaloHypo x distribution                         </li>
+ *  <li> @p CaloHypo y distribution                         </li>
+ *  <li> multiplicity of     @p CaloCluster per @p CaloHypo </li>
+ *  <li> multiplicity of Spd @p CaloDigit   per @p CaloHypo </li>
+ *  <li> multiplicity of Prs @p CaloDigit   per @p CaloHypo </li>
+ *  <li> CaloHypo x vs y distribution                       </li>
+ *  </ol>
+ *  Histograms reside in the directory @p /stat/"Name" , where
+ *  @ "Name" is the name of the algorithm
+ *
+ *  @see CaloFutureAlgorithm
+ *  @see     Algorithm
+ *  @see    IAlgorithm
+ *
+ *  @author Vanya Belyaev Ivan.Belyaev@itep.ru
+ *  @date   02/11/2001
+ */
+
+using Input = LHCb::CaloHypo::Container;
+
+class CaloFutureHypoMonitor final
+: public Gaudi::Functional::Consumer<void(const Input&, const LHCb::CaloClusters&),
+    Gaudi::Functional::Traits::BaseClass_t<CaloFutureMoniAlg>>
+{
+public:
+  /// standard algorithm initialization
+  StatusCode initialize() override;
+  void operator()(const Input&, const LHCb::CaloClusters&) const override;
+
+  CaloFutureHypoMonitor( const std::string &name, ISvcLocator *pSvcLocator );
+
+private:
+  Gaudi::Property<int>   m_clusBin { this, "NClusterBin", 5 };
+  Gaudi::Property<float> m_clusMax { this, "NClusterMax", 5.};
+  Gaudi::Property<float> m_clusMin { this, "NClusterMin", 0.};
+  Gaudi::Property<int>   m_spdBin  { this, "NSpdBin"    , 10 };
+  Gaudi::Property<float> m_spdMax  { this, "NSpdMax"    , 10.};
+  Gaudi::Property<float> m_spdMin  { this, "NSpdMin"    , 0. };
+  Gaudi::Property<int>   m_prsBin  { this, "NPrsBin"    , 10 };
+  Gaudi::Property<float> m_prsMax  { this, "NPrsMax"    , 10.};
+  Gaudi::Property<float> m_prsMin  { this, "NPrsMin"    , 0. };
+};
+
+DECLARE_COMPONENT( CaloFutureHypoMonitor )
+
+// =============================================================================
+
+CaloFutureHypoMonitor::CaloFutureHypoMonitor( const std::string &name, ISvcLocator *pSvcLocator )
+: Consumer( name, pSvcLocator, {
+    KeyValue{ "Input"        , "" },
+    KeyValue{ "InputClusters", "" },
+  }
+){
+  m_multMax = 250;
+  m_multBin =  50;
+
+  /*
+  * During genconf.exe, the default name "DefaultName" is not well-supported
+  * by the CaloFutureAlgUtils, returning the null string "" as a location path,
+  * which will raise exception in `updateHandleLocation` --> `setProperty`.
+  * To get around this, the location will only be updated outside the genconf.
+  */
+  if( name != "DefaultName" ){
+    const auto InputData = LHCb::CaloFutureAlgUtils::CaloFutureHypoLocation(name,context());
+    const auto InputClusters = LHCb::CaloFutureAlgUtils::CaloFutureClusterLocation(name,context());
+    updateHandleLocation( *this, "Input", InputData );
+    updateHandleLocation( *this, "InputClusters", InputClusters );
+  }
+}
+
+// =============================================================================
+
+/// standard algorithm initialization
+StatusCode CaloFutureHypoMonitor::initialize(){
+  StatusCode sc = Consumer::initialize(); // must be executed first
+  if ( sc.isFailure() ) return sc; // error already printedby GaudiAlgorithm
+  hBook1(  "1", "# of Hypos    " + inputLocation(),  m_multMin   , m_multMax  , m_multBin   );
+  hBook1(  "2", "Hypo Energy   " + inputLocation(),  m_energyMin , m_energyMax, m_energyBin );
+  hBook1(  "3", "Hypo Pt       " + inputLocation(),  m_etMin     , m_etMax    , m_etBin     );
+  if( inputLocation() == "Rec/Calo/MergedPi0s" || inputLocation() == "Hlt/Calo/MergedPi0s"  )
+    hBook1("4", "Hypo Mass     " + inputLocation(),  m_massMin   , m_massMax  , m_massBin   );
+  hBook1(  "5", "Hypo X        " + inputLocation(),  m_xMin      , m_xMax     , m_xBin      );
+  hBook1(  "6", "Hypo Y        " + inputLocation(),  m_yMin      , m_yMax     , m_yBin      );
+  hBook1(  "7", "Clusters/Hypo " + inputLocation(),  m_clusMin   , m_clusMax  , m_clusBin   );
+  hBook1(  "8", "Spd/Hypo      " + inputLocation(),  m_spdMin    , m_spdMax   , m_spdBin    );
+  hBook1(  "9", "Prs/Hypo      " + inputLocation(),  m_prsMin    , m_prsMax   , m_prsBin    );
+  hBook2( "10", "Hypo barycenter position x vs y   " + inputLocation(),  m_xMin, m_xMax, m_xBin, m_yMin, m_yMax, m_yBin);
+  hBook2( "11", "Energy-weighted hypo barycenter position x vs y " + inputLocation(), m_xMin,m_xMax, m_xBin, m_yMin, m_yMax, m_yBin);
+  hBook1( "14", "#Hypo/#Cluster" + inputLocation(), 0., 1.,100);
+  return StatusCode::SUCCESS;
+}
+
+// =============================================================================
+// standard execution method
+// =============================================================================
+
+void CaloFutureHypoMonitor::operator()(const Input& hypos, const LHCb::CaloClusters& clusters) const {
+  // produce histos ?
+  if ( !produceHistos() ) return;
+
+  // check data
+  if( hypos.empty() ){
+    if( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+      debug() << "Empty hypos found in" << inputLocation() << endmsg;
+    return;
+  }
+
+  // get functor
+  LHCb::CaloDataFunctor::DigitFromCalo spd( DeCalorimeterLocation::Spd );
+  LHCb::CaloDataFunctor::DigitFromCalo prs( DeCalorimeterLocation::Prs );
+
+  initFutureCounters();
+
+  // Start looping over hypo
+  for( const auto& hypo: hypos ){
+    LHCb::CaloMomentum momentum( hypo );
+    const double e = momentum.e();
+    const double et= momentum.pt();
+    const double mass=momentum.momentum().mass();
+    if(e    < m_eFilter) continue;
+    if(et   < m_etFilter) continue;
+    if(mass < m_massFilterMin || mass > m_massFilterMax) continue;
+    auto id = LHCb::CaloCellID();
+    if( hypo->clusters().size() > 0 ){
+      const auto cluster = *(hypo->clusters().begin());
+      if( 0 != cluster) id = cluster->seed();
+    }
+
+    // Start filling histo
+    count(id);
+    hFill1(id, "2", e  );
+    hFill1(id, "3", et );
+    if( inputLocation() == "Rec/Calo/MergedPi0s" || inputLocation() == "Hlt/Calo/MergedPi0s" )hFill1(id, "4", mass );
+
+    const auto position = hypo->position();
+    if( position != nullptr ){
+      hFill1(id, "5", position->x() );
+      hFill1(id, "6", position->y() );
+      hFill2(id, "10", position->x(),position->y() );
+      hFill2(id, "11", position->x(),position->y() , e);
+    }
+
+    const auto digits = hypo->digits();
+    hFill1(id, "7", hypo->clusters().size() );
+    hFill1(id, "8", std::count_if( digits.begin(), digits.end(), spd ) );
+    hFill1(id, "9", std::count_if( digits.begin(), digits.end(), prs ) );
+
+    if( !(id == LHCb::CaloCellID()) ){
+      if(doHisto("12"))fillCaloFuture2D("12", id , 1. ,  "Hypo position 2Dview " + inputLocation() );
+      if(doHisto("13"))fillCaloFuture2D("13", id , e  ,  "Hypo Energy 2Dview " + inputLocation() );
+    }
+
+  }
+  // fill multiplicity histogram
+  fillFutureCounters("1");
+
+  //cluster fraction (no area-splittable so far)
+  const int nClus = clusters.size();
+  const double frac = nClus>0 ? (double) m_count / (double) nClus : 0.;
+  hFill1("14",frac);
+
+  return;
+}
diff --git a/CaloFuture/CaloFutureMoniDst/src/CaloFutureHypoNtp.cpp b/CaloFuture/CaloFutureMoniDst/src/CaloFutureHypoNtp.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ccc04f844a4194b9f961ff5b669481898cdd4a27
--- /dev/null
+++ b/CaloFuture/CaloFutureMoniDst/src/CaloFutureHypoNtp.cpp
@@ -0,0 +1,180 @@
+// Include files
+// from Gaudi
+#include "Event/MCParticle.h"
+#include "CaloFutureUtils/CaloFutureAlgUtils.h"
+#include "CaloFutureUtils/CaloMomentum.h"
+// locals
+#include "CaloFutureHypoNtp.h"
+#include "CaloFutureMoniUtils.h"
+
+namespace {
+  /// hack to allow for tools with non-const interfaces...
+  template <typename IFace>
+  IFace* fixup(const ToolHandle<IFace>& iface) { return &const_cast<IFace&>(*iface); }
+}
+// =============================================================================
+
+DECLARE_COMPONENT( CaloFutureHypoNtp )
+
+// =============================================================================
+
+CaloFutureHypoNtp::CaloFutureHypoNtp( const std::string &name, ISvcLocator *pSvcLocator )
+: Consumer( name, pSvcLocator, {
+    KeyValue{ "InputODIN", LHCb::ODINLocation::Default       },
+    KeyValue{ "InputL0"  , LHCb::L0DUReportLocation::Default },
+    KeyValue{ "Locations", "" },
+    KeyValue{ "TrackLoc" , LHCb::TrackLocation::Default      },
+    KeyValue{ "VertexLoc", LHCb::RecVertexLocation::Primary  }
+})
+{}
+
+// =============================================================================
+
+StatusCode CaloFutureHypoNtp::initialize(){
+  StatusCode sc = Consumer::initialize();
+  if ( sc.isFailure() ) return sc;
+  // retrieve tools
+  if(!( m_2MC.retrieve()
+        && m_counterStat.retrieve()
+        && m_estimator.retrieve() )){
+    error() << "Unable to retrive one of the ToolHandles" << endmsg;
+    return StatusCode::FAILURE;
+  }
+
+  // Configure tool
+  std::string seed = m_seed     ? "true" : "false";
+  std::string line = m_extrapol ? "true" : "false";
+  std::string neig = m_neig     ? "true" : "false";
+  m_estimator->hypo2CaloFuture()->_setProperty("Seed", seed).ignore();
+  m_estimator->hypo2CaloFuture()->_setProperty("PhotonLine", line).ignore();
+  m_estimator->hypo2CaloFuture()->_setProperty("AddNeighbors", neig).ignore();
+
+  // Configure input locations
+  using namespace LHCb::CaloHypoLocation;
+  // get the user-override input
+  auto loc = inputLocation<2>();  // <-- Careful with the index, 'Location' is 3rd.
+  std::vector<std::string> m_locs{};
+  if( loc != "" ) m_locs.push_back(loc);
+  // get the respective input from Hypos
+  for( const auto h: m_hypos ){
+    if(h == "Photons")          m_locs.push_back( LHCb::CaloFutureAlgUtils::PathFromContext( context() , Photons      ));
+    else if(h == "Electrons")   m_locs.push_back( LHCb::CaloFutureAlgUtils::PathFromContext( context() , Electrons    ));
+    else if(h == "MergedPi0s")  m_locs.push_back( LHCb::CaloFutureAlgUtils::PathFromContext( context() , MergedPi0s   ));
+    else if(h == "SplitPhotons")m_locs.push_back( LHCb::CaloFutureAlgUtils::PathFromContext( context() , SplitPhotons ));
+  }
+  // Finally, update handle
+  updateHandleLocation( *this, "Locations", boost::algorithm::join(m_locs,"&"));
+
+  return StatusCode::SUCCESS;
+}
+
+
+// =============================================================================
+// standard execution method
+// =============================================================================
+
+void CaloFutureHypoNtp::operator()(const ODIN& odin, const L0& l0, const Hypos& hypos,
+    const Tracks& tracks, const Vertices& verts) const {
+
+  using namespace CaloFutureDataType;
+
+  // declare tuple
+  Tuple ntp = (!m_tupling) ? Tuple{nullptr} : nTuple(500, "HypoNtp", CLID_ColumnWiseTuple);
+
+  // Collect global info (in pre-Functional implementation, some are optionals)
+  const auto run    = odin.runNumber();
+  const auto evt    = (double) odin.eventNumber();
+  const auto tty    = odin.triggerType();
+  const auto nSpd   = (int) l0.dataValue("Spd(Mult)");
+  const auto nTrack = tracks.size();
+  const auto nVert  = verts.size();
+
+  // loop over hypo containers
+  bool ok = true;
+  for( const auto& hypo: hypos ){
+    // hypo string
+    std::ostringstream type("");
+    type << hypo->hypothesis();
+    std::string hypothesis = type.str();
+
+    // filtering hypo
+    if( !inRange( m_et   , fixup(m_estimator)->data( hypo, HypoEt  , 0. ))) continue;
+    if( !inRange( m_e    , fixup(m_estimator)->data( hypo, HypoE   , 0. ))) continue;
+    if( !inRange( m_spdM , fixup(m_estimator)->data( hypo, HypoSpdM, 0. ))) continue;
+    if( !inRange( m_prsE , fixup(m_estimator)->data( hypo, HypoPrsE, 0. ))) continue;
+
+    // MC-associated filtering
+    if( m_checker ){
+      const auto mcp = fixup(m_2MC)->from(hypo)->bestMC();
+      if( mcp == nullptr ) continue;
+      if( m_mcID >= 0 && (int) mcp->particleID().abspid() != m_mcID) continue;
+    }
+
+    // PrintOut
+    if ( m_print ){
+      info() << "+++ Run/Evt " << run << "/" << evt << endmsg;
+      info() << " === hypothesis " << hypo->hypothesis() << "(" << tesLocation(hypo) << ")" << endmsg;
+      if( m_checker ) fixup(m_2MC)->from(hypo)->descriptor();
+    }
+
+    // DataTypes statistics
+    for( int i = 0 ; i < CaloFutureDataType::Last ; ++i){
+      const auto val = fixup(m_estimator)->data( hypo, (DataType) i, 0. );
+      if(m_stat && m_counterStat->isQuiet()) counter( Name[i] + " for " + hypothesis ) += val;
+      if(m_tupling) ok &= ntp->column( Name[i], val );
+      if(m_print) info() << "   --> " << Name[i] << " : " << val << endmsg;
+    }
+
+    // Tupling
+    if( m_tupling){
+
+      // hypothesis
+      ok &= ntp->column( "hypothesis", hypo->hypothesis() );
+
+      // kinematics
+      const auto cluster = fixup(m_estimator)->toCluster(CaloFutureClusterType::SplitOrMain);
+      ok &= ntp->column( "ClusterR" , position3d(cluster) );
+      ok &= ntp->column( "HypoR"    , position3d(hypo)    );
+      ok &= ntp->column( "HypoP"    , momentum(hypo)      );
+
+      // matched tracks
+      for( int match = 0 ; match < CaloFutureMatchType::Last ; ++match){
+        const auto track = fixup(m_estimator)->toTrack( (CaloFutureMatchType::MatchType) match );
+        ok &= ntp->column( CaloFutureMatchType::Name[match] + "TrackP" , momentum(track) );
+      }
+
+      // odin info
+      ok &= ntp->column("Run"        , run   );
+      ok &= ntp->column("Event"      , evt   );
+      ok &= ntp->column("Triggertype", tty   );
+      ok &= ntp->column("Nvertices"  , nVert );
+      ok &= ntp->column("NTracks"    , nTrack);
+      ok &= ntp->column("spdMult"    , nSpd  );
+
+      // Checker Mode (MC info)
+      if( m_checker ){
+        int id = -999;
+        double weight = -999;
+        double quality = -999;
+        const auto mcp = fixup(m_2MC)->from(hypo)->bestMC();
+        if( mcp != nullptr ){
+          id     = mcp->particleID().pid();
+          weight = fixup(m_2MC)->from(hypo)->weight( mcp );
+          quality= fixup(m_2MC)->from(hypo)->quality( mcp );
+        }
+        ok &= ntp->column( "MCid", id      );
+        ok &= ntp->column( "MCw" , weight  );
+        ok &= ntp->column( "MCq" , quality );
+      }
+      ok &= ntp->write();
+    }
+  }
+
+  // Finally, report
+  if(ok){
+    if(m_counterStat->isQuiet()) counter("Events in tuple") += 1;
+  } else {
+    Warning("Error with ntupling", StatusCode::SUCCESS).ignore();
+  }
+  return;
+}
diff --git a/CaloFuture/CaloFutureMoniDst/src/CaloFutureHypoNtp.h b/CaloFuture/CaloFutureMoniDst/src/CaloFutureHypoNtp.h
new file mode 100644
index 0000000000000000000000000000000000000000..c05309e974c4de57fa783855d40ee44635d36f8d
--- /dev/null
+++ b/CaloFuture/CaloFutureMoniDst/src/CaloFutureHypoNtp.h
@@ -0,0 +1,59 @@
+#ifndef CALOFUTUREHYPONTP_H
+#define CALOFUTUREHYPONTP_H 1
+
+#include "GaudiAlg/Consumer.h"
+#include "GaudiAlg/GaudiTupleAlg.h"
+#include "GaudiKernel/IEventTimeDecoder.h"
+#include "Event/CaloHypo.h"
+#include "Event/L0DUReport.h"
+#include "Event/ODIN.h"
+#include "Event/RecVertex.h"
+#include "CaloFutureInterfaces/ICaloFutureHypoEstimator.h"
+#include "CaloFutureInterfaces/IFutureCounterLevel.h"
+#include "CaloFutureInterfaces/ICaloFuture2MCTool.h"
+
+// List of Consumers dependencies
+namespace {
+  using ODIN = LHCb::ODIN;
+  using L0 = LHCb::L0DUReport;
+  using Hypos = LHCb::CaloHypo::Container;
+  using Tracks = LHCb::Tracks;
+  using Vertices = LHCb::RecVertices;
+}
+
+// ============================================================================
+
+class CaloFutureHypoNtp final
+: public Gaudi::Functional::Consumer<void(const ODIN&, const L0&, const Hypos&, const Tracks&, const Vertices&),
+    Gaudi::Functional::Traits::BaseClass_t<GaudiTupleAlg>>
+{
+public:
+  CaloFutureHypoNtp( const std::string& name, ISvcLocator* pSvcLocator );
+  StatusCode initialize() override;
+  void operator()(const ODIN&, const L0&, const Hypos&, const Tracks&, const Vertices&) const override;
+
+private:
+  ToolHandle<ICaloFuture2MCTool> m_2MC              = {"CaloFuture2MCTool", this};
+  ToolHandle<IFutureCounterLevel> m_counterStat     = {"FutureCounterLevel"};
+  ToolHandle<ICaloFutureHypoEstimator> m_estimator  = {"CaloFutureHypoEstimator", this};
+
+  Gaudi::Property<bool> m_extrapol { this, "Extrapolation", true};
+  Gaudi::Property<bool> m_seed     { this, "AddSeed"      , false};
+  Gaudi::Property<bool> m_neig     { this, "AddNeighbors" , false};
+
+  Gaudi::Property<std::pair<double,double>> m_et   {this, "RangePt"  , {100., 15000.  }};
+  Gaudi::Property<std::pair<double,double>> m_e    {this, "RangeE"   , {0.  , 5000000 }};
+  Gaudi::Property<std::pair<double,double>> m_spdM {this, "RangeSpdM", {0.  , 5000000.}};
+  Gaudi::Property<std::pair<double,double>> m_prsE {this, "RangePrsE", {0.  , 9999.   }};
+
+  Gaudi::Property<std::vector<std::string>> m_hypos
+    {this, "Hypos", {"Electrons", "Photons", "MergedPi0s"}};
+
+  Gaudi::Property<bool> m_tupling { this, "Tupling"    , true};
+  Gaudi::Property<bool> m_checker { this, "CheckerMode", false};
+  Gaudi::Property<bool> m_print   { this, "Printout"   , false};
+  Gaudi::Property<bool> m_stat    { this, "Statistics" , true};
+  Gaudi::Property<int>  m_mcID    { this, "MCID"       , -99999999};
+
+};
+#endif // CALOFUTUREHYPONTP_H
diff --git a/CaloFuture/CaloFutureMoniDst/src/CaloFutureMoniAlg.cpp b/CaloFuture/CaloFutureMoniDst/src/CaloFutureMoniAlg.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..fbd9b0928d7c17fc85cf601876614bf8f001e7d1
--- /dev/null
+++ b/CaloFuture/CaloFutureMoniDst/src/CaloFutureMoniAlg.cpp
@@ -0,0 +1,354 @@
+// Includes 
+#include "CaloFutureMoniAlg.h"
+
+//------------------------------------------------------------------------------
+// Implementation file for class : CaloFutureMoniAlg
+//
+// 2008-09-03 : Olivier Deschamps
+//------------------------------------------------------------------------------
+
+//==============================================================================
+// Standard constructor, initializes variables
+//==============================================================================
+
+CaloFutureMoniAlg::CaloFutureMoniAlg( const std::string& name, ISvcLocator* pSvcLocator )
+: CaloFuture2Dview( name, pSvcLocator )
+{
+  // Areas
+  m_mcount.reserve(m_nAreas);
+  m_scount.reserve(2);
+
+  //set default detectorName
+  m_detData = LHCb::CaloFutureAlgUtils::CaloFutureNameFromAlg( name );
+  if ( m_detData == "Prs" ) 
+    m_energyMax = 300.* Gaudi::Units::MeV;
+  if ( m_detData == "Spd" ) 
+    m_energyMax = 10.* Gaudi::Units::MeV;    
+}
+
+//==============================================================================
+// Initialization
+//==============================================================================
+
+StatusCode CaloFutureMoniAlg::initialize() {
+  StatusCode sc = CaloFuture2Dview::initialize();
+  if ( sc.isFailure() ) return sc;
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) debug() << "==> Initialize" << endmsg;
+
+  m_counterStat.retrieve().ignore();
+  if("" == histoTopDir()) setHistoTopDir("CaloFutureMoniDst/");
+
+  if( m_split && m_splitSides ){
+    warning() << "Cannot split simultaneously the calo sides and areas, so far - Area splitting wins" << endmsg;
+    m_splitSides=false;
+  }  
+  return StatusCode::SUCCESS;
+}
+
+//==============================================================================
+
+void CaloFutureMoniAlg::initFutureCounters() const {
+  m_count = 0;
+  for(unsigned int i = 0; i != m_nAreas ; ++i){
+    m_mcount[i]=0;
+  }
+  for(unsigned int i = 0; i <2 ; ++i){
+    m_scount[i]=0;
+  }
+}
+
+//==============================================================================
+
+void CaloFutureMoniAlg::count(LHCb::CaloCellID id) const {
+  m_count++;
+  if( !(id == LHCb::CaloCellID()) ){
+    int area = id.area();
+    m_mcount[area]++;
+    int col = id.col();
+    int side = 1;
+    if( CaloCellCode::CaloNameFromNum(id.calo()) == "Hcal"){
+      if(col<16)side = 0;
+    }
+    else if(col<32){
+      side = 0;
+    }
+    m_scount[side]++;
+  }
+}
+
+//==============================================================================
+
+void CaloFutureMoniAlg::fillFutureCounters(std::string unit) const {
+  fill(m_h1[unit], m_count , 1);
+
+  // Source monitor. Fetch from "Input" field if existed.
+  // This required consistent naming across its functional children.
+  std::string cname{"Monitor"};
+  if(hasProperty("Input"))
+    cname += " "+getProperty("Input").toString();
+  if( m_counterStat->isQuiet()) counter(cname) += m_count;
+  
+  // Split monitor
+  if( m_splitSides ){
+    for(unsigned int i = 0;i < 2 ;++i){
+      std::string side = (i==0) ? "C-side" : "A-side";
+      if( m_scount[i] == 0 ) continue;
+      GaudiAlg::HistoID id(side + "/"+unit);
+      fill(m_h1[id], m_scount[i] , 1);
+      if( m_counterStat->isQuiet()) counter("Monitor (" + side +")"  ) += m_scount[i];
+    }    
+  } else if( m_split ){
+    for(unsigned int i = 0;i != m_nAreas;++i){
+      //std::string area = CaloFutureCellCode::CaloFutureAreaFromNum( CaloFutureCellCode::CaloFutureNumFromName( m_detData ), i );
+      std::string area = CaloCellCode::caloArea ( CaloCellCode::caloNum ( m_detData ), i );
+      if( !validArea( area )||  m_mcount[i] == 0) continue;
+      GaudiAlg::HistoID id(area + "/"+unit);
+      fill(m_h1[id], m_mcount[i] , 1);
+      if( m_counterStat->isQuiet()) counter("Monitored (" + area +")"  ) += m_mcount[i];
+    }    
+  }
+}
+
+//==============================================================================
+// BOOKINGS
+//==============================================================================
+
+void CaloFutureMoniAlg::hBook1( const std::string hid,
+                          const std::string titl,
+                          const double low,
+                          const double high,
+                          const unsigned long bins ){ 
+  if(!doHisto(hid)) return;
+
+  if( m_splitSides ){
+    if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+      debug() << "Booking histogram1D per calo side" << endmsg;
+    for(unsigned int i = 0;i <2 ;++i){
+      std::string side = (i==0) ? "C-side" : "A-side";
+      GaudiAlg::HistoID id(side + "/" + hid);
+      std::string tit = titl + " (" + side + ")";
+      m_h1[id] = book1D( id, tit, low, high, bins );
+    }      
+  }
+  else if(m_split){
+    if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+      debug() << "Booking histogram1D per calo area" << endmsg;
+    for(unsigned int i = 0;i != m_nAreas;++i){
+      // std::string area = CaloFutureCellCode::CaloFutureAreaFromNum( CaloFutureCellCode::CaloFutureNumFromName( m_detData ), i );
+      std::string area = CaloCellCode::caloArea ( CaloCellCode::caloNum( m_detData ), i );
+      if( !validArea( area )) continue;
+      GaudiAlg::HistoID id(area + "/" + hid);
+      std::string tit = titl + " (" + area + ")";
+      m_h1[id] = book1D( id, tit, low, high, bins );
+    }
+  }
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+    debug() << "Booking histogram1D for whole calo" << endmsg;
+  m_h1[hid] = book1D( hid, titl, low, high, bins );
+}
+
+//==============================================================================
+
+void CaloFutureMoniAlg::h1binLabel( const std::string hid, int bin, std::string label ) const {
+  if(!doHisto(hid)) return;
+
+  if( m_splitSides ){
+    for(unsigned int i = 0;i <2 ;++i){
+      std::string side = (i==0) ? "C-side" : "A-side";
+      GaudiAlg::HistoID id(side + "/" + hid);
+      const auto th = Gaudi::Utils::Aida2ROOT::aida2root( m_h1[id] );
+      th->GetXaxis()->SetBinLabel( bin  , label.c_str() );
+    }      
+  }
+  else if(m_split){
+    for(unsigned int i = 0;i != m_nAreas;++i){
+      // std::string area = CaloFutureCellCode::CaloFutureAreaFromNum( CaloFutureCellCode::CaloFutureNumFromName( m_detData ), i );
+      std::string area = CaloCellCode::caloArea ( CaloCellCode::caloNum( m_detData ), i );
+      if( !validArea( area )) continue;
+      GaudiAlg::HistoID id(area + "/" + hid);
+      const auto th = Gaudi::Utils::Aida2ROOT::aida2root( m_h1[id] );
+      th->GetXaxis()->SetBinLabel( bin  , label.c_str() );
+    }
+  }
+  const auto th = Gaudi::Utils::Aida2ROOT::aida2root( m_h1[hid] );
+  th->GetXaxis()->SetBinLabel( bin, label.c_str() );
+}
+
+//==============================================================================
+
+void CaloFutureMoniAlg::hBook2( const std::string hid, const std::string titl,
+                          const double lowx, const double highx, const unsigned long binsx,
+                          const double lowy, const double highy, const unsigned long binsy ){ 
+  if(!doHisto(hid)) return;
+  if( m_splitSides ){
+    if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+      debug() << "Booking histogram2D per calo side" << endmsg;
+    for(unsigned int i = 0;i <2 ;++i){
+      std::string side = (i==0) ? "C-side" : "A-side";
+      GaudiAlg::HistoID id(side + "/" + hid);
+      std::string tit = titl + " (" + side + ")";
+      m_h2[id] = book2D( id, tit, lowx, highx, binsx, lowy, highy, binsy );
+    }
+  }
+  else if( m_split ){
+    if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+      debug() << "Booking histogram2D per calo region" << endmsg;
+    for(unsigned int i = 0;i != m_nAreas;++i){
+      std::string area = CaloCellCode::caloArea ( CaloCellCode::caloNum( m_detData ), i );
+      if( !validArea( area )) continue;
+      GaudiAlg::HistoID id(area + "/" + hid);
+      std::string tit = titl + " (" + area + ")";
+      m_h2[id] = book2D( id, tit, lowx, highx, binsx, lowy, highy, binsy );
+    }
+  }
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+    debug() << "Booking histogram2D for whole calo" << endmsg;
+  m_h2[hid] = book2D( hid, titl, lowx, highx, binsx, lowy, highy, binsy );
+}
+
+//==============================================================================
+// FILLING
+//==============================================================================
+
+void CaloFutureMoniAlg::hFill1(std::string hid, double value, double w ) const { 
+  if(!doHisto(hid)) return;
+  const auto h  = m_h1[hid];
+  if( h == nullptr ) return;
+  double bins = (double) h->axis().bins();
+  double step = h->axis().upperEdge() - h->axis().lowerEdge();
+  step = ( bins == 0) ? 0 : step/bins/2.;
+  if(m_sat){
+    if( value < h->axis().lowerEdge() )value = h->axis().lowerEdge()+step;
+    if( value > h->axis().upperEdge() )value = h->axis().upperEdge()-step;
+  }
+  fill(h,value,w);
+}
+
+void CaloFutureMoniAlg::hFill2(std::string hid, double x, double y, double w ) const { 
+  if(!doHisto(hid)) return;
+  const auto h = m_h2[hid];
+  if( h == nullptr ) return;
+  double xbins = (double) h->xAxis().bins();
+  double xstep = h->xAxis().upperEdge() - h->xAxis().lowerEdge();
+  xstep = ( xbins == 0) ? 0 : xstep/xbins/2.;
+  double ybins = (double) h->yAxis().bins();
+  double ystep = h->yAxis().upperEdge() - h->yAxis().lowerEdge();
+  ystep = ( ybins == 0) ? 0 : ystep/ybins/2.;
+
+  if(m_sat2D){
+    if( x < h->xAxis().lowerEdge() )x = h->xAxis().lowerEdge()+xstep;
+    if( x > h->xAxis().upperEdge() )x = h->xAxis().upperEdge()-xstep;
+    if( y < h->yAxis().lowerEdge() )y = h->yAxis().lowerEdge()+ystep;
+    if( y > h->yAxis().upperEdge() )y = h->yAxis().upperEdge()-ystep;
+  }
+  fill(h,x,y,w); 
+}
+
+void CaloFutureMoniAlg::hFill1(LHCb::CaloCellID cellID , std::string hid, double value, double w ) const{ 
+  if(!doHisto(hid)) return;
+  const auto h = m_h1[hid];
+  if( h == nullptr ) return;
+  double bins = (double) h->axis().bins();
+  double step = h->axis().upperEdge() - h->axis().lowerEdge();
+  step = ( bins == 0) ? 0 : step/bins/2.;
+  if(m_sat){
+    if( value < h->axis().lowerEdge() )value = h->axis().lowerEdge()+step;
+    if( value > h->axis().upperEdge() )value = h->axis().upperEdge()-step;
+  }
+
+  if( m_splitSides && !(cellID == LHCb::CaloCellID()) ) {
+    int col = cellID.col();
+    int cal = cellID.calo();
+    std::string side = "A-side";      
+    if( CaloCellCode::CaloNameFromNum(cal)  == "Hcal"){
+      if(col<16)side = "C-side";
+    }
+    else if(col<32){
+      side = "C-side";
+    }
+    GaudiAlg::HistoID id(side + "/" + hid);
+    const auto hh = m_h1[id];
+    if( hh == nullptr ) return;
+    fill(hh,value,w);
+  }
+  else if( m_split && !(cellID == LHCb::CaloCellID()) ) {
+    std::string area = CaloCellCode::caloArea ( CaloCellCode::caloNum( m_detData ), cellID.area() );
+    if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+      debug() << "Filling histogram2D per calo region " << cellID << endmsg;
+    if( validArea( area ) ){
+      if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+        debug() << "valid area " << area << endmsg;
+      GaudiAlg::HistoID id(area + "/" + hid);
+      const auto hh = m_h1[id];
+      if( hh == nullptr ) return;
+      fill(hh,value,w);
+    }
+  }
+  fill(h,value,w);
+}
+
+void CaloFutureMoniAlg::hFill2( LHCb::CaloCellID cellID , std::string hid, double x, double y, double w ) const { 
+  if(!doHisto(hid)) return;
+  const auto h = m_h2[hid];
+  if( h == nullptr ) return;
+  double xbins = (double) h->xAxis().bins();
+  double xstep = h->xAxis().upperEdge() - h->xAxis().lowerEdge();
+  xstep = ( xbins == 0) ? 0 : xstep/xbins/2.;
+  double ybins = (double) h->yAxis().bins();
+  double ystep = h->yAxis().upperEdge() - h->yAxis().lowerEdge();
+  ystep = ( ybins == 0) ? 0 : ystep/ybins/2.;
+  if(m_sat2D){
+    if( x < h->xAxis().lowerEdge() )x = h->xAxis().lowerEdge()+xstep;
+    if( x > h->xAxis().upperEdge() )x = h->xAxis().upperEdge()-xstep;
+    if( y < h->yAxis().lowerEdge() )y = h->yAxis().lowerEdge()+ystep;
+    if( y > h->yAxis().upperEdge() )y = h->yAxis().upperEdge()-ystep;
+  }
+
+  if( m_splitSides && !(cellID == LHCb::CaloCellID()) ) {
+    int col = cellID.col();
+    int cal = cellID.calo();
+    std::string side = "A-side";      
+    if( CaloCellCode::CaloNameFromNum(cal)  == "Hcal"){
+      if(col<16)side = "C-side";
+    }
+    else if(col<32){
+      side = "C-side";
+    }
+    GaudiAlg::HistoID id(side + "/" + hid);
+    const auto hh = m_h2[id];
+    fill(hh,x,y,w);
+  }
+  else if( m_split && !(cellID == LHCb::CaloCellID()) ){
+    // std::string area = CaloFutureCellCode::CaloFutureAreaFromNum( CaloFutureCellCode::CaloFutureNumFromName( m_detData ), cellID.area() );
+    std::string area = CaloCellCode::caloArea ( CaloCellCode::caloNum ( m_detData ), cellID.area() );
+    if( validArea( area )  ){
+      GaudiAlg::HistoID id(area + "/" + hid);
+      const auto hh = m_h2[id];
+      fill(hh,x,y,w); 
+    }      
+    fill(h,x,y,w); 
+  }else{
+    fill(h,x,y,w); 
+  } 
+}
+
+//==============================================================================
+// MISC
+//==============================================================================
+
+bool CaloFutureMoniAlg::doHisto( const std::string histo ) const {
+  // blacklist has highest priority
+  if(std::any_of( m_removeHisto.begin(), m_removeHisto.end(), 
+      [histo](std::string h){return histo == h;})) return false;
+  // Followup by whitelist, "ALL"
+  return std::any_of( m_histoList.begin(), m_histoList.end(),
+      [histo](std::string h){return histo==h || "All"==h;});
+}
+
+//==============================================================================
+
+bool CaloFutureMoniAlg::validArea( const std::string area ) const {
+  return std::any_of( m_areas.begin(), m_areas.end(), [area](auto s){return s==area;} );
+}
+
+//==============================================================================
diff --git a/CaloFuture/CaloFutureMoniDst/src/CaloFutureMoniAlg.h b/CaloFuture/CaloFutureMoniDst/src/CaloFutureMoniAlg.h
new file mode 100644
index 0000000000000000000000000000000000000000..1d1000f50672fb419457f10df820304eee9f26bf
--- /dev/null
+++ b/CaloFuture/CaloFutureMoniDst/src/CaloFutureMoniAlg.h
@@ -0,0 +1,128 @@
+#ifndef CALOFUTUREMONIDST_CALOFUTUREMONIALG_H 
+#define CALOFUTUREMONIDST_CALOFUTUREMONIALG_H 1
+// ============================================================================
+// Include files
+// ============================================================================
+// from Gaudi
+// ============================================================================
+
+#include "GaudiAlg/GaudiHistoAlg.h"
+#include "GaudiKernel/HashMap.h"
+#include "GaudiUtils/Aida2ROOT.h"
+#include "CaloFutureUtils/CaloFuture2Dview.h"
+#include "CaloFutureUtils/CaloFutureAlgUtils.h"
+#include "CaloFutureInterfaces/IFutureCounterLevel.h"
+#include "Kernel/CaloCellID.h"
+#include "AIDA/IAxis.h"
+#include "AIDA/IHistogram1D.h"
+#include "AIDA/IHistogram2D.h"
+#include "TROOT.h"
+
+// ============================================================================
+// AIDA 
+// ============================================================================
+#include "AIDA/IHistogram1D.h"
+
+// @class CaloFutureMoniAlg CaloFutureMoniAlg.h
+//
+//   @see GaudiHistoAlg
+//   @see GaudiAlgorithm
+//   @see      Algorithm
+//   @see     IAlgorithm
+
+class CaloFutureMoniAlg : public CaloFuture2Dview{
+
+public:
+  // Standard constructor
+  //   @param   name        algorithm name
+  //   @param   pSvcLocator pointer to service locator
+  CaloFutureMoniAlg( const std::string &name, ISvcLocator *pSvcLocator );  
+  StatusCode initialize() override;
+  
+  // address/location/name in Transient Store of detector data
+  const std::string &detData() const { return m_detData; }
+  // set address/location/name in Transient Store of detector data
+  void setDetData( const std::string &addr ) { m_detData = addr; }
+  
+  // booking histogram
+  void initFutureCounters() const;
+  void count(LHCb::CaloCellID id = LHCb::CaloCellID() ) const;
+  void fillFutureCounters(std::string) const;
+  void hBook1( const std::string, const std::string, const double low=0,
+               const double high=100, const unsigned long bins=100 );
+  void h1binLabel( const std::string hid,int bin, std::string label ) const;
+  void hBook2( const std::string hid,
+               const std::string titl,
+               const double lowx=0,
+               const double highx=100,
+               const unsigned long binsx=100,
+               const double lowy=0,
+               const double highy=100,
+               const unsigned long binsy=100 );
+  
+  // fill histogram
+  void hFill1(std::string hid, double value, double w=1. ) const;
+  void hFill2(std::string hid, double x, double y, double w=1. ) const;
+  void hFill1(LHCb::CaloCellID cellID, std::string hid, double value, double w=1. ) const;
+  void hFill2(LHCb::CaloCellID cellID, std::string hid, double x, double y, double w=1. ) const;
+
+private:
+  Gaudi::Property<std::string> m_detData {this, "Detector", "Ecal", "address/location/name in Transient Store of detector data"};
+  
+protected:
+  ToolHandle<IFutureCounterLevel> m_counterStat { "FutureCounterLevel" };
+
+  // Histogram Map
+  GaudiUtils::HashMap< std::string, AIDA::IHistogram1D * > m_h1;
+  GaudiUtils::HashMap< std::string, AIDA::IHistogram2D * > m_h2;
+
+  // Properties
+  Gaudi::Property<float> m_energyMin { this, "HistoEnergyMin"      , 0.};
+  Gaudi::Property<float> m_etMin     { this, "HistoEtMin"          , 0.};
+  Gaudi::Property<float> m_massMin   { this, "HistoMassMin"        , 0.};
+  Gaudi::Property<float> m_xMin      { this, "HistoXMin"           , -4 * Gaudi::Units::meter};
+  Gaudi::Property<float> m_yMin      { this, "HistoYMin"           , -4 * Gaudi::Units::meter};
+  Gaudi::Property<float> m_multMin   { this, "HistoMultiplicityMin", 0.};
+  Gaudi::Property<float> m_sizeMin   { this, "HistoSizeMin"        , 0.};
+
+  Gaudi::Property<float> m_energyMax { this, "HistoEnergyMax"      , 250. * Gaudi::Units::GeV};
+  Gaudi::Property<float> m_etMax     { this, "HistoEtMax"          , 15. * Gaudi::Units::GeV};
+  Gaudi::Property<float> m_massMax   { this, "HistoMassMax"        , 250.*Gaudi::Units::MeV};
+  Gaudi::Property<float> m_xMax      { this, "HistoXMax"           , +4 * Gaudi::Units::meter};
+  Gaudi::Property<float> m_yMax      { this, "HistoYMax"           , +4 * Gaudi::Units::meter};
+  Gaudi::Property<float> m_multMax   { this, "HistoMultiplicityMax", 2000.};
+  Gaudi::Property<float> m_sizeMax   { this, "HistoSizeMax"        , 25.};
+
+  Gaudi::Property<int> m_energyBin { this, "HistoEnergyBin"      , 100};
+  Gaudi::Property<int> m_etBin     { this, "HistoEtBin"          , 100};
+  Gaudi::Property<int> m_massBin   { this, "HistoMassBin"        , 100};
+  Gaudi::Property<int> m_xBin      { this, "HistoXBin"           , 50};
+  Gaudi::Property<int> m_yBin      { this, "HistoYBin"           , 50};
+  Gaudi::Property<int> m_multBin   { this, "HistoMultiplicityBin", 100};
+  Gaudi::Property<int> m_sizeBin   { this, "HistoSizeBin"        , 25};
+
+  Gaudi::Property<float> m_eFilter       { this, "EnergyFilter" , -100.};
+  Gaudi::Property<float> m_etFilter      { this, "EtFilter"     , -100.};
+  Gaudi::Property<float> m_massFilterMin { this, "MassWindowMin", -9999999.};
+  Gaudi::Property<float> m_massFilterMax { this, "MassWindowMax", +9999999.};
+  
+  Gaudi::Property<bool> m_sat        { this, "SaturationBin1D", true};
+  Gaudi::Property<bool> m_sat2D      { this, "SaturationBin2D", false};
+  Gaudi::Property<bool> m_print      { this, "PrintOut"       , false};
+  Gaudi::Property<bool> m_splitSides { this, "SplitSides"     , false};
+
+  Gaudi::Property<std::vector<std::string>> m_histoList   { this, "histoList"          , { "All"}};
+  Gaudi::Property<std::vector<std::string>> m_removeHisto { this, "removeFromHistoList", { }};
+  Gaudi::Property<std::vector<std::string>> m_areas       { this, "listOfAreas"        , { "Outer" , "Middle", "Inner"}, "list of areas to be split"};
+  
+  const unsigned int m_nAreas = 1 << (CaloCellCode::BitsArea +1);
+  
+  // For const operator()
+  mutable unsigned int m_count = 0;
+  mutable std::vector<unsigned int> m_mcount;
+  mutable std::vector<unsigned int> m_scount;
+  
+  bool doHisto( const std::string histo ) const;
+  bool validArea( const std::string area ) const;
+};
+#endif // CALOFUTUREMONIDST_CALOFUTUREMONIALG_H
diff --git a/CaloFuture/CaloFutureMoniDst/src/CaloFutureMoniUtils.h b/CaloFuture/CaloFutureMoniDst/src/CaloFutureMoniUtils.h
new file mode 100644
index 0000000000000000000000000000000000000000..b7413e0d46421913a05a3f76cda566df5e64a835
--- /dev/null
+++ b/CaloFuture/CaloFutureMoniDst/src/CaloFutureMoniUtils.h
@@ -0,0 +1,96 @@
+#include "GaudiKernel/Plane3DTypes.h"
+#include "GaudiKernel/Vector3DTypes.h"
+#include "LHCbMath/Line.h"
+#include "LHCbMath/GeomFun.h"
+#include "CaloFutureUtils/CaloMomentum.h"
+
+inline bool inRange(const std::pair<double,double> range, double value){
+  return (value>=range.first) && (value<=range.second);
+}  
+
+inline bool inRange(const std::pair<int,int> range, int value){
+  return (value==0 && range.first==1 ) || (value>0 &&range.second==1);
+}
+
+//==============================================================================
+
+// Helper method to calculate intersection, when only interested in a point,
+// assuming that the intersection exists.
+// Usage:
+//    const auto cross = intersection(line, plane);
+inline Gaudi::XYZPoint intersection(const Gaudi::Math::Line<Gaudi::XYZPoint,Gaudi::XYZVector>& line, const Gaudi::Plane3D& plane){
+  Gaudi::XYZPoint cross;
+  double mu;
+  Gaudi::Math::intersection<Gaudi::Math::Line<Gaudi::XYZPoint,Gaudi::XYZVector>,Gaudi::Plane3D,Gaudi::XYZPoint>(line, plane, cross, mu);
+  return cross;
+}
+
+//==============================================================================
+
+// shamelessly stolen from Vanya's LHCb/Phys/LoKiCore/src/Print.cpp
+inline std::string tesLocation( const ContainedObject* obj ){
+  if ( obj == nullptr ) { return "" ; }
+  const auto parent = obj->parent();
+  if ( parent == nullptr ) { return "" ; }
+  const auto reg = parent->registry();
+ if ( reg == nullptr ) { return "" ; }
+  return reg->identifier();
+}
+
+//==============================================================================
+
+// Idiom I often encountered
+// inline LHCb::CaloCellID firstClusterSeed( const LHCb::CaloHypo* hypo ){
+inline SmartRef<LHCb::CaloCluster> firstCluster( const LHCb::CaloHypo* hypo ){
+  SmartRef<LHCb::CaloCluster> cluster;
+  if( hypo != nullptr ){
+    const auto clusters = hypo->clusters();
+    if( !clusters.empty() ){
+      cluster = *clusters.begin();
+    }
+  }
+  return cluster;
+}
+
+//==============================================================================
+
+// Adapters for ntuple, guard against nullptr too
+inline Gaudi::XYZPoint position3d( const LHCb::CaloHypo* obj ){
+  if( obj == nullptr ) return Gaudi::XYZPoint();
+  return Gaudi::XYZPoint( obj->position()->x(), obj->position()->y(), obj->position()->z() );
+}
+// e.g. from firstCluster(hypo)
+inline Gaudi::XYZPoint position3d( const LHCb::CaloCluster* obj ){
+  if( obj == nullptr ) return Gaudi::XYZPoint();
+  return Gaudi::XYZPoint( obj->position().x(), obj->position().y(), obj->position().z() );
+}
+inline Gaudi::XYZPoint position3d( const LHCb::State& obj ){
+  return obj.position();
+}
+inline Gaudi::LorentzVector position4d( const LHCb::CaloCluster* obj ){
+  if( obj == nullptr ) return Gaudi::LorentzVector();  
+  return Gaudi::LorentzVector( obj->position().x(), obj->position().y(), obj->position().z(), obj->e() );
+}
+
+// e.g., from 
+inline Gaudi::LorentzVector momentum( const LHCb::CaloHypo* obj ){
+  if( obj == nullptr ) return Gaudi::LorentzVector();
+  return Gaudi::LorentzVector(LHCb::CaloMomentum(obj).momentum());
+}
+// e.g., from proto->track()
+inline Gaudi::LorentzVector momentum( const LHCb::Track* obj ){
+  if( obj == nullptr ) return Gaudi::LorentzVector();
+  return Gaudi::LorentzVector(obj->momentum().x(), obj->momentum().y(), obj->momentum().z(), obj->p());
+}
+// e.g., from m_caloElectron->caloState()
+inline Gaudi::LorentzVector momentum( const LHCb::State& obj ){
+  return Gaudi::LorentzVector(obj.momentum().x(), obj.momentum().y(), obj.momentum().z(), obj.p());
+}
+// e.g., from m_caloElectron->bremCaloMomentum()
+inline Gaudi::LorentzVector momentum( LHCb::CaloMomentum obj ){
+  return Gaudi::LorentzVector( obj.momentum().x(), obj.momentum().y(),
+                               obj.momentum().z(), obj.momentum().e());  
+}
+
+
+//==============================================================================
diff --git a/CaloFuture/CaloFutureMoniDst/src/CaloFuturePIDsChecker.cpp b/CaloFuture/CaloFutureMoniDst/src/CaloFuturePIDsChecker.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7607ef8aff7037469733d1592ca5217fecee32dd
--- /dev/null
+++ b/CaloFuture/CaloFutureMoniDst/src/CaloFuturePIDsChecker.cpp
@@ -0,0 +1,277 @@
+// Includes
+#include "GaudiAlg/Consumer.h"
+#include "AIDA/IAxis.h"
+#include "Event/Track.h"
+#include "Event/MCParticle.h"
+// #include "Relations/IRelation.h"
+#include "Relations/Relation1D.h"
+// #include "Relations/IRelationWeighted.h"
+#include "Kernel/Particle2MCLinker.h"
+#include "CaloFutureUtils/CaloFuture2Track.h"
+#include "boost/lexical_cast.hpp"
+#include "CaloFutureMoniAlg.h"
+
+// =============================================================================
+
+namespace {
+  /** extract the momentum from Track
+   *  @param  track pointer to the track
+   *  @return the momentum of the track
+   */
+  constexpr double momentum( const LHCb::Track *track ){
+    return track != nullptr ? track->closestState( 0.0 ).p() : -100*Gaudi::Units::GeV;
+  }
+
+}
+
+using Input = LHCb::Relation1D<LHCb::Track,float>;
+using Inputs = LHCb::Track::Container;
+using AccTable = LHCb::Relation1D<LHCb::Track,bool>;
+
+// =============================================================================
+
+/** @class CaloFuturePIDsChecker CaloFuturePIDsChecker.cpp
+ *
+ *  Class for monitoring the CaloFuturePIDs quantities
+ *
+ *  The major properties
+ *
+ *  - "Input"
+ *   The default value is                      ""
+ *   The PID-quantity to be monitored, relation table of
+ *   type IRelation<Track,float>
+ *
+ *  - "Inputs"
+ *   The default value is :         TrackLocation::Default
+ *   The list of Track containers to be monitored
+ *
+ *   - "Tr2MCP"
+ *   The default value is :          "Rec/Relations/Tr2MCP"
+ *   The location in TES the relation table of type
+ *   IRelationWeighted<Track,MCParticle,double>
+ *
+ *    - "Particle"
+ *    The default value is :         11
+ *    Particle ID for "signal" hypothesis
+ *
+ *    - "Cut"
+ *    The default value is :          0
+ *    The cut on PID to be used for monitoring
+ *
+ *    - "Normialization"
+ *    The default value is :          50 GeV
+ *    The normalization factor used for histogramming
+ *
+ *  @author Vanya BELYAEV Ivan.Belyaev@itep.ru
+ *  @date   2004-02-15
+ */
+
+class CaloFuturePIDsChecker final
+: public Gaudi::Functional::Consumer<void(const Input&, const Inputs&, const AccTable&),
+    Gaudi::Functional::Traits::BaseClass_t<CaloFutureMoniAlg>>
+{
+public:
+  StatusCode initialize() override;
+  StatusCode finalize() override;
+  void operator()(const Input&, const Inputs&, const AccTable&) const override;
+
+  CaloFuturePIDsChecker( const std::string &name, ISvcLocator *isvc );
+
+protected:
+  /// transformation function for momentum
+  inline double pFunc( const double value ) const
+  { return tanh( value / m_pNorm );}
+
+  /// h3=h1/h2
+  StatusCode divide( AIDA::IHistogram1D *hh1, AIDA::IHistogram1D *hh2,
+                     AIDA::IHistogram1D *hh3 ) const;
+
+private:
+  // Track -> MC associator
+  Object2MCLinker<LHCb::Track>* m_track2MCLink = nullptr;
+
+  Gaudi::Property<unsigned int> m_pid
+    {this, "Particle", 11, "particle to be identified"};
+
+  Gaudi::Property<float> m_cut
+    {this, "Cut", 0., "cut value"};
+
+  Gaudi::Property<float> m_pNorm
+    {this, "Normalization", 50 * Gaudi::Units::GeV, "momentum normalization"};
+
+  Gaudi::Property<std::string> m_typName
+    {this, "TrackType", "ALL"};
+
+  LHCb::Track::Types m_typ = LHCb::Track::Types::TypeUnknown;
+  bool m_checkType = true;
+};
+
+// =============================================================================
+
+DECLARE_COMPONENT( CaloFuturePIDsChecker )
+
+// =============================================================================
+
+CaloFuturePIDsChecker::CaloFuturePIDsChecker( const std::string &name, ISvcLocator *isvc )
+: Consumer( name, isvc, {
+    KeyValue{ "Input"          , "" },
+    KeyValue{ "Inputs"         , LHCb::TrackLocation::Default },
+    KeyValue{ "TrackAcceptance", "Rec/Calo/InAccEcal" }
+})
+{}
+
+// =============================================================================
+
+StatusCode CaloFuturePIDsChecker::initialize(){
+  StatusCode sc = Consumer::initialize(); // must be executed first
+  if ( sc.isFailure() ) return sc; // error already printedby GaudiAlgorithm
+
+  const std::string mom = "tanh(P/"
+    + boost::lexical_cast<std::string>( m_pNorm / Gaudi::Units::GeV )
+    + " GeV/c) ";
+  const std::string cut  = "with cut 'DLL>"
+    + boost::lexical_cast<std::string>( m_cut.value() ) + "' ";
+
+  hBook1(  "1", "DLL for 'Signal'",     -5, 5 );
+  hBook1(  "2", "DLL for 'Ghosts'",     -5, 5 );
+  hBook1(  "3", "DLL for 'Background'", -5, 5 );
+
+  hBook1( "11", mom +                "for 'Signal'",     0, 1.02, 51 );
+  hBook1( "12", mom +                "for 'Ghosts'",     0, 1.02, 51 );
+  hBook1( "13", mom +                "for 'Background'", 0, 1.02, 51 );
+
+  hBook1( "21", mom + cut +          "for 'Signal'",     0, 1.02, 51 );
+  hBook1( "22", mom + cut +          "for 'Ghosts'",     0, 1.02, 51 );
+  hBook1( "23", mom + cut +          "for 'Background'", 0, 1.02, 51 );
+
+  hBook1( "31", "Eff " + mom + cut + "for 'Signal'",     0, 1.02, 51 );
+  hBook1( "32", "Eff " + mom + cut + "for 'Ghosts'",     0, 1.02, 51 );
+  hBook1( "33", "Eff " + mom + cut + "for 'Background'", 0, 1.02, 51 );
+
+  m_track2MCLink = new Object2MCLinker<LHCb::Track>( this, "", "", inputLocation<1>() );
+  if( m_split ){
+    Warning( "No area spliting allowed for CaloFuturePIDsChecker").ignore();
+    m_split = false;
+  }
+
+  if ( LHCb::CaloFutureAlgUtils::toUpper(m_typName.value()) == "ALL" )
+    m_checkType = false;
+  else
+    m_typ = LHCb::Track::TypesToType(m_typName.value());
+
+  return StatusCode::SUCCESS;
+}
+
+// =============================================================================
+
+StatusCode CaloFuturePIDsChecker::finalize(){
+  StatusCode sc = divide( m_h1["21"], m_h1["11"], m_h1["31"] );
+  if(sc.isSuccess())sc=divide( m_h1["22"], m_h1["12"], m_h1["32"] );
+  if(sc.isSuccess())sc= divide( m_h1["23"], m_h1["13"], m_h1["33"] );
+  if(!sc.isSuccess())error()<<"Failed dividing histograms " << endmsg;
+
+  if( nullptr != m_track2MCLink ) delete m_track2MCLink;
+  m_track2MCLink = nullptr;
+
+  return Consumer::finalize();
+}
+
+
+// =============================================================================
+
+void CaloFuturePIDsChecker::operator()(const Input& pidTable, const Inputs& tracks, const AccTable& accTable) const {
+
+  // produce histos ?
+  if ( !produceHistos() ) return;
+
+  // Loop over tracks
+  for( const auto& track: tracks ){
+
+    // Abort if track type mismatched
+    if( m_checkType && track->type() != m_typ ) continue;
+
+    // Abort if track is outside acceptance
+    if(accTable.relations(track).front().to() == false) continue;
+
+    // get MC truth
+    double maxWeight = 0;
+    const LHCb::MCParticle* mc = m_track2MCLink->first(track, maxWeight);
+    auto mcp = (LHCb::MCParticle*) mc;
+    if( mc != nullptr ){
+      do{
+        double weight = 0;
+        mc = m_track2MCLink->next(weight);
+        if(weight > maxWeight){
+          maxWeight = weight;
+          mcp = (LHCb::MCParticle*) mc;
+        }
+      }while( mc != nullptr );
+    }
+
+    // retrieve calo pid information
+    const auto calo = pidTable.relations( track );
+
+    // get THE LAST pid
+    const double DLL = calo.empty() ? -1000.0 : calo.back().to();
+    if ( 0 == mcp )                                 hFill1("2",  DLL); //ghosts
+    else if ( mcp->particleID().abspid() == m_pid ) hFill1("1",  DLL); //signal
+    else                                            hFill1("3",  DLL); //background
+
+    // evaluate the function of momentum
+    const double pMom = pFunc( momentum( track ) );
+    if ( 0 == mcp )                       hFill1("12", pMom); //ghosts
+    else if ( mcp->particleID().abspid() == m_pid ) hFill1("11", pMom); //signal
+    else                                       hFill1("13", pMom); //background
+
+    // apply DLL cut
+    if ( DLL < m_cut ) continue;
+    if ( 0 == mcp )                       hFill1("22", pMom); //ghosts
+    else if ( mcp->particleID().abspid() == m_pid ) hFill1("21", pMom); //signal
+    else                                       hFill1("23", pMom); //background
+  }
+  return;
+}
+
+// =============================================================================
+// Divide the histograms
+// =============================================================================
+
+StatusCode CaloFuturePIDsChecker::divide( AIDA::IHistogram1D *hh1
+                                  , AIDA::IHistogram1D *hh2
+                                  , AIDA::IHistogram1D *hh3 ) const
+{ if (( 0 == hh1 ) || ( 0 == hh2 ) || ( 0 == hh3 )){
+    return Error( "AIDA::IHistogram1D* points to NULL" );
+  }
+  const IAxis &axis1 = hh1->axis();
+  const IAxis &axis2 = hh2->axis();
+  const IAxis &axis3 = hh3->axis();
+  const int nBins = axis3.bins();
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+    debug() << "DIVIDE nbins " << nBins << endmsg;
+
+  if (( axis1.bins() != nBins ) || ( axis2.bins() != nBins ))
+  { return Error( "Different histogram specifications" );
+  }
+  double count = 0;
+  for( int nBin = 0; nBin < nBins; ++nBin )
+  { const double v1 = hh1->binHeight( nBin );
+    const double v2 = hh2->binHeight( nBin );
+    const double x  = 0.5 * ( axis3.binLowerEdge ( nBin ) +
+                              axis3.binUpperEdge ( nBin ) );
+
+// fill the histogram
+    if ( 0 != v2 ) hh3->fill( x, v1/v2 );
+    if ( 0 != v1) count += 1.;
+  }
+
+  const double content = hh3->sumBinHeights();
+  if ( 0 != count ){
+    info() << "'" << hh3->title()   << "' = "
+           << (content/count)*100 << "[%]" << endmsg;
+  }else{
+    info() << "'" << hh1->title()
+           << "' contains no filled bins - histogram ratio undefined" << endmsg;
+  }
+
+  return StatusCode::SUCCESS;
+}
diff --git a/CaloFuture/CaloFutureMoniDst/src/CaloFuturePhotonChecker.cpp b/CaloFuture/CaloFutureMoniDst/src/CaloFuturePhotonChecker.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..794ce5726e363c268b548f4621006205b81d8587
--- /dev/null
+++ b/CaloFuture/CaloFutureMoniDst/src/CaloFuturePhotonChecker.cpp
@@ -0,0 +1,612 @@
+// Include files
+// STD & STL
+#include <algorithm>
+// from Gaudi
+#include "GaudiKernel/Plane3DTypes.h"
+#include "GaudiKernel/Point3DTypes.h"
+#include "GaudiKernel/Vector3DTypes.h"
+// From PartProp
+#include "Kernel/IParticlePropertySvc.h"
+#include "Kernel/ParticleProperty.h"
+#include "Event/MCParticle.h"
+#include "Event/MCVertex.h"
+#include "Event/CaloHypo.h"
+#include "CaloFutureUtils/CaloFuture2Track.h"
+#include "CaloFutureUtils/CaloMomentum.h"
+#include "CaloFutureUtils/ClusterFunctors.h"
+#include "CaloFutureInterfaces/ICaloFutureHypoLikelihood.h"
+#include "CaloDet/DeCalorimeter.h"
+// local
+#include "CaloFuturePhotonChecker.h"
+#include "CaloFutureMoniUtils.h"
+
+DECLARE_COMPONENT( CaloFuturePhotonChecker )
+
+// =============================================================================
+
+namespace {
+  // math transform
+  constexpr double transform(double e){
+    return (e<1.e-10) ? 0. : std::max({ log(1.35914*e)-6.21461, 5.5 });
+  }
+}
+
+// =============================================================================
+/** @file
+ *
+ *  Implementation file for class CaloFuturePhotonChecker
+ *  Photon Selection Monitoring
+ *  (LHCb 2004-03)
+ *
+ *  @author Frederic Machefert frederic.machefert@in2p3.fr
+ *  @date   2004-15-04
+ */
+// =============================================================================
+
+CaloFuturePhotonChecker::CaloFuturePhotonChecker( const std::string &name, ISvcLocator *pSvcLocator )
+: Consumer( name, pSvcLocator, {
+    KeyValue{ "Input"           , LHCb::CaloHypoLocation::Photons    },  // Legacy naming
+    KeyValue{ "InputMCPs"       , LHCb::MCParticleLocation::Default  },
+    KeyValue{ "CC2TrTableName"  , LHCb::CaloFutureIdLocation::ClusterMatch },  // Legacy naming
+    KeyValue{ "CC2MCPTableName" , "Relations/"+LHCb::CaloClusterLocation::Default },// Legacy naming
+    KeyValue{ "InputIDTable"    , LHCb::CaloFutureIdLocation::PhotonID     }
+}) {}
+
+// =============================================================================
+
+StatusCode CaloFuturePhotonChecker::initialize(){ 
+  StatusCode sc = Consumer::initialize();
+  if ( sc.isFailure() ) return sc;
+
+  //----- locate particle property service
+  LHCb::IParticlePropertySvc* ppSvc = svc<LHCb::IParticlePropertySvc>( "LHCb::ParticlePropertySvc", true );
+  if( 0 == ppSvc ) return Error("Could not locate LHCb::ParticlePropertySvc!");
+
+  const auto ppg = ppSvc->find( m_gammaName );
+  if( 0 == ppg ) {
+    error() << "Could not locate particle ' " <<m_gammaName << " '" << endmsg;
+    return StatusCode::FAILURE;
+  }
+  m_gammaID = ppg->pid() ;
+  
+  const auto ppp = ppSvc->find( m_pi0Name );
+  if( 0 == ppp ) {
+    error() << "Could not locate particle ' " << m_pi0Name << " '" << endmsg;
+    return StatusCode::FAILURE;
+  }
+  m_pi0ID = ppp->pid() ;
+  
+  info() << "Photon/Pi0 particle properties locatlized." << endmsg;
+
+  //----- Detector recovery
+
+  m_ecal = getDet<DeCalorimeter>( DeCalorimeterLocation::Ecal );
+  m_spd  = getDetIfExists<DeCalorimeter>( DeCalorimeterLocation::Spd );
+  m_prs  = getDetIfExists<DeCalorimeter>( DeCalorimeterLocation::Prs );
+  if( !m_spd || !m_prs) return Error("DeCalorimeter does not exist for Prs/Spd");
+  
+  m_ecalPlane = m_ecal->plane( CaloPlane::ShowerMax );
+  m_spdPlane  = m_spd->plane ( CaloPlane::Middle    );
+  m_prsPlane  = m_prs->plane ( CaloPlane::Middle    );
+  
+  const auto spdFront = m_spd->plane( CaloPlane::Front );
+  const auto normal   = spdFront.Normal();
+  m_zConv  = -spdFront.HesseDistance() / normal.Z(); 
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+    debug() <<  "z conversion definition is set to SPD front : " << m_zConv << endmsg;
+  
+  //----- Tool recovery
+
+
+  //----- Check data consistency
+  if (m_prsbin.size()!=3)  { return Error("Wrong Binning Parameter (EPrs)"); }
+  if (m_chi2bin.size()!=3) { return Error("Wrong Binning Parameter (Chi2Tk)"); }
+  if (m_seedbin.size()!=3) { return Error("Wrong Binning Parameter (ESeed)"); }
+
+  // Reset Monitoring parameter
+  for (int i=0 ; i<m_nbinpt ; ++i){
+    m_mc_g.push_back(0);
+    m_rec_bkg.push_back(0);
+    m_rec_sig.push_back(0);
+  }
+
+  m_lh_mcg=0;
+  m_lh_mcg_conv=0;
+  m_lh_mcg_noconv=0;
+  for (int i=0 ; i<m_nbinlh ; ++i){
+    m_lh_recsig.push_back(0);
+    m_lh_recbkg.push_back(0);
+    m_lh_recsig_conv.push_back(0);
+    m_lh_recsig_spd.push_back(0);
+    m_lh_recbkg_spd.push_back(0);
+    m_lh_recsig_noconv.push_back(0);
+    m_lh_recsig_nospd.push_back(0);
+    m_lh_recbkg_nospd.push_back(0);
+  }
+
+  // Likelihood Output for Signal / Background
+  m_lhSig    = book1D( "Lh_Sig_noSpd","likelihood Signal - no SPD"     ,0.,1.,50);
+  m_lhSigSpd = book1D( "Lh_Sig_Spd"  ,"likelihood Signal - SPD hit"    ,0.,1.,50);
+  m_lhBkg    = book1D( "Lh_Bkg_noSpd","likelihood Background - no SPD" ,0.,1.,50);
+  m_lhBkgSpd = book1D( "Lh_Bkg_Spd"  ,"likelihood Background - SPD hit",0.,1.,50);
+
+  // Efficiency / Purity versus Pt
+  m_efficiency = book1D( "Efficiency" ,"Photon Selection Efficiency vs Pt",m_ptmin,m_ptmax,m_nbinpt);
+  m_purity     = book1D( "Purity" ,"Photon Selection Purity vs Pt",m_ptmin,m_ptmax,m_nbinpt);
+  
+  m_effpur       = book2D( "Eff_Pur", "Efficiency vs Purity - Lh cut",0.,1.,100,0.,1.,100);
+  m_effpur_spd   = book2D( "Eff_Pur_Spd", "Efficiency vs Purity - Lh cut - no Conv. sample",0.,1.,100,0.,1.,100);
+  m_effpur_nospd = book2D( "Eff_Pur_noSpd", "Efficiency vs Purity - Lh cut - Conv. sample",0.,1.,100,0.,1.,100);
+
+
+  // Probability Density Functions Definitions
+  if (m_pdf){
+    m_signalEPrs2D=defHisto(int(m_prsbin[ 0 ]),m_prsbin[ 1 ],m_prsbin[ 2 ],
+                           10, std::string("Signal_Prs_noSpdHit"));
+    m_signalChi22D=defHisto(int(m_chi2bin[ 0 ]),m_chi2bin[ 1 ],m_chi2bin[ 2 ],
+                           20, std::string("Signal_Chi2Tk_noSpdHit"));
+    m_signalSeed2D=defHisto(int(m_seedbin[ 0 ]),m_seedbin[ 1 ],m_seedbin[ 2 ],
+                            30, std::string("Signal_ESeed_noSpdHit"));
+
+    m_signalEPrsSpd2D=defHisto(int(m_prsbin[ 0 ]),m_prsbin[ 1 ],m_prsbin[ 2 ],
+                              15, std::string("Signal_Prs_SpdHit"));
+    m_signalChi2Spd2D=defHisto(int(m_chi2bin[ 0 ]),m_chi2bin[ 1 ],m_chi2bin[ 2 ],
+                              25, std::string("Signal_Chi2Tk_SpdHit"));
+    m_signalSeedSpd2D=defHisto(int(m_seedbin[ 0 ]),m_seedbin[ 1 ],m_seedbin[ 2 ],
+                              35, std::string("Signal_ESeed_SpdHit"));
+
+    m_backgrEPrs2D=defHisto(int(m_prsbin[ 0 ]),m_prsbin[ 1 ],m_prsbin[ 2 ],
+                           110, std::string("Background_Prs_noSpdHit"));
+    m_backgrChi22D=defHisto(int(m_chi2bin[ 0 ]),m_chi2bin[ 1 ],m_chi2bin[ 2 ],
+                           120, std::string("Background_Chi2Tk_noSpdHit"));
+    m_backgrSeed2D=defHisto(int(m_seedbin[ 0 ]),m_seedbin[ 1 ],m_seedbin[ 2 ],
+                            130, std::string("Background ESeed_noSpdHit"));
+
+    m_backgrEPrsSpd2D=defHisto(int(m_prsbin[ 0 ]),m_prsbin[ 1 ],m_prsbin[ 2 ],
+                              115, std::string("Background_Prs_SpdHit"));
+    m_backgrChi2Spd2D=defHisto(int(m_chi2bin[ 0 ]),m_chi2bin[ 1 ],m_chi2bin[ 2 ],
+                              125, std::string("Background_Chi2Tk_SpdHit"));
+    m_backgrSeedSpd2D=defHisto(int(m_seedbin[ 0 ]),m_seedbin[ 1 ],m_seedbin[ 2 ],
+                              135, std::string("Background_ESeed_SpdHit"));
+   }   
+   
+  if( m_split ){
+    Warning( "No area spliting allowed for CaloFuturePhotonChecker").ignore();
+    m_split = false;
+  }    
+  return StatusCode::SUCCESS;
+}
+// ============================================================================
+
+// ============================================================================
+/** standard algorithm finalization
+ *  @see CaloFutureAlgorithm
+ *  @see     Algorithm
+ *  @see    IAlgorithm
+ *  @return status code
+ */
+// ============================================================================
+
+StatusCode CaloFuturePhotonChecker::finalize(){
+
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) debug() << "==> Finalize" << endmsg;
+
+  info() << "************* Photon Monitoring *****************"<<endmsg;
+  info() << "Number of Events Analyzed : " << m_nEvents << endmsg;
+  info()
+    //<< "MCPhotons (Signal def.) in sample: "<<m_nMCPhotons<<" - "
+    <<m_nPhotons<<" Photons (Signal def.) out of "<<m_nCandidates<<" hypos processed."
+    <<" - "<<m_nWrongs<<" hypos rejected."<<endmsg;
+  char line[70];
+  info() << endmsg;
+  info() << "     Et(GeV)        | Efficiency |   Purity   "<<endmsg;
+  info() << "----------------------------------------------"<<endmsg;
+  for (int i=0; i<m_nbinpt ; ++i){
+    double pt= m_ptmin+double(i)*(m_ptmax-m_ptmin)/double(m_nbinpt);
+    double eff=(m_mc_g[i]>0) ? double(m_rec_sig[i])/double(m_mc_g[i]) : 0.;
+    double pur=(m_rec_sig[i]+m_rec_bkg[i]>0) ? m_rec_sig[i]/(m_rec_sig[i]+m_rec_bkg[i]) : 0. ;
+    sprintf(line," [ %5.2f - %5.2f ]  |    %4.2f    |    %4.2f    ",
+      pt/1000.,(pt+(m_ptmax-m_ptmin)/double(m_nbinpt))/1000.,eff,pur);
+
+    info() << line <<endmsg;
+
+    fill(m_efficiency,pt,eff);
+    fill(m_purity,pt,pur);
+  }
+  info() << endmsg;
+  info() << "  L>= |   Total   |   No Conv |    Conv   "<<endmsg;
+  info() << "      | Eff   Pur | Eff   Pur | Eff   Pur "<<endmsg;
+  info() << " -----------------------------------------"<<endmsg;
+  for (int i=0; i<m_nbinlh ; ++i){
+    double eff=(m_lh_mcg>0) ? m_lh_recsig[i]/m_lh_mcg : 0.;
+    double effnoconv=(m_lh_mcg_noconv>0) ? m_lh_recsig_noconv[i]/m_lh_mcg_noconv : 0.;
+    double effconv=(m_lh_mcg_conv>0) ? m_lh_recsig_conv[i]/m_lh_mcg_conv : 0.;
+    double pur=(m_lh_recsig[i]+m_lh_recbkg[i]>0) ? m_lh_recsig[i]/(m_lh_recsig[i]+m_lh_recbkg[i]) : 0. ;
+    double purnoconv = 
+      (m_lh_recsig_nospd[i]+m_lh_recbkg_nospd[i]>0) ? m_lh_recsig_nospd[i]/(m_lh_recsig_nospd[i]+m_lh_recbkg_nospd[i]) : 0. ;
+    double purconv=(m_lh_recsig_spd[i]+m_lh_recbkg_spd[i]>0) ?m_lh_recsig_spd[i]/(m_lh_recsig_spd[i]+m_lh_recbkg_spd[i]) : 0. ;
+
+    fill(m_effpur,pur,eff,1.);
+    fill(m_effpur_nospd,purnoconv,effnoconv,1.);
+    fill(m_effpur_spd,purconv,effconv,1.);
+
+    sprintf(line," %3.2f | %3.2f %3.2f | %3.2f %3.2f | %3.2f %3.2f", 
+            double(i)/double(m_nbinlh),eff,pur,effnoconv,purnoconv,effconv,purconv);
+
+    info() << line <<endmsg;
+
+  }
+  info() << "*************************************************"<<endmsg;
+
+  return Consumer::finalize() ;
+}
+// ============================================================================
+
+// ============================================================================
+/** standard algorithm execution
+ *  @see CaloFutureAlgorithm
+ *  @see     Algorithm
+ *  @see    IAlgorithm
+ *  @return status code
+ */
+// ============================================================================
+
+void CaloFuturePhotonChecker::operator()(const Input& hypos, const MCPs& mcParts, 
+                                   const Table& table, const MCTable& gtable, 
+                                   const IDTable& idTable) const {
+  
+  // increment number of events
+  m_nEvents++;
+
+  // // get MC photons
+  // if( !exist<MCPs>(LHCb::MCParticleLocation::Default))
+  //   return Warning("NO MC information",StatusCode::SUCCESS);  
+  // MCPs* mcParts = get<MCPs>(LHCb::MCParticleLocation::Default);
+  
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+    debug() << "MC Particles extracted from event : " << mcParts.size() << endmsg;
+
+  // Loop over each mc particle  
+  for( const auto& part: mcParts ){
+
+    if ( !(m_gammaID == part->particleID()) ) continue; // select MC-gamma
+    if ( part->momentum().pz() < 0.)          continue; // Pz Acceptance 
+    if ( part->momentum().pt() < m_etmin )    continue; // Et acceptance
+
+    // Origin vertex
+    const auto vertex = part->originVertex();
+    if ( vertex == nullptr )                             continue; // ask for a vertex
+    if ((m_dz>0) && (fabs(vertex->position().Z())>m_dz)) continue; // origin vertex acceptance ... in z
+    if ((m_dr>0) && (vertex->position().Rho()>m_dr) )    continue; // ... and in (x,y)
+    
+    // Ecal acceptance
+    Line line( vertex->position(), part->momentum().Vect() );
+    const auto cross = intersection(line, m_ecalPlane);
+    const Gaudi::XYZPoint hit(cross);
+    if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+      debug() << "MC part momentum " << part->momentum() 
+              << " crosses Ecal Plane at point "<< cross << " -> cellID : " << m_ecal->Cell( hit ) << endmsg;
+    if( !m_ecal->valid( m_ecal->Cell( hit ) ) ) continue; // Ecal acceptance.
+
+    // Conversion 
+    Gaudi::XYZPoint decay(0., 0., 1.*Gaudi::Units::km);
+    const auto decays = part->endVertices();
+    for( const auto& vertex: decays ){
+      if( vertex->position().z() < decay.Z() ) decay = vertex->position();
+    }
+
+    if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+      debug() << "MC gamma endVertex.z() " << decay.Z() << endmsg;
+
+    // belong to a merged pi0 ?
+    if (isMergedPi0(part)) {
+      if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+        debug() <<"Merged Pi0 photons removed from Signal sample"<<endmsg;
+      continue;
+    }
+    m_nMCPhotons++;
+
+    int ibin = int(m_nbinpt*( part->momentum().pt() - m_ptmin)/(m_ptmax-m_ptmin));
+    if( ibin>=0 && ibin<m_nbinpt ){
+      // efficiency / purity versus pt
+      m_mc_g[ibin]++;
+      // efficiency / purity versus likelihood
+      m_lh_mcg++;
+      if( decay.Z() > m_zConv ){
+        m_lh_mcg_noconv++;
+        if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+          debug() << " Not converted " << m_zConv << endmsg;
+      }
+      else {
+        m_lh_mcg_conv++;
+        if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+          debug() << " converted " << m_zConv << endmsg;
+      }
+    }
+  } // end loop over mcp
+  
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+    debug() << " MC part all/no-conv/conv" << m_lh_mcg << "/"<<m_lh_mcg_noconv<<"/"<<m_lh_mcg_conv<< endmsg;
+  
+
+  // loop over hypos
+  for( const auto& hypo: hypos ){
+
+    // skip nulls
+    if( hypo == nullptr ){
+      if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+        debug() <<"empty CaloHypo : skipping"<<endmsg;
+      continue ;
+    }
+     
+    LHCb::CaloMomentum momentum( hypo );
+    m_nCandidates++;
+
+    // Transverse Momentum
+    if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+      debug() << "==> Processing new CaloHypo : Et=" << momentum.momentum().pt() << endmsg;
+    if( momentum.momentum().pt() < m_etmin ) continue;
+    if (hypo->clusters().size()!=1){
+      warning() <<"Photon Hypothesis : number of clusters!=1 ..."<<endmsg;
+      continue;
+    }
+     
+    const auto cluster = hypo->clusters().front();
+    if( cluster == 0 )
+      { Warning( " *CaloCluster* points to NULL ").ignore();continue; }
+
+    const auto entries = cluster->entries();
+    if( entries.empty() ){Warning( " *CaloCluster* empty ").ignore();continue;}
+     
+    const auto iseed = LHCb::ClusterFunctors::locateDigit( entries.begin(), entries.end(), LHCb::CaloDigitStatus::SeedCell);
+    if( iseed == entries.end() ){Warning(" *SeedCell* not found ").ignore();continue;}
+     
+    const auto seed = iseed->digit();
+    if( 0 == seed ){Warning( " SeedCell *Digit* points to NULL! ").ignore();continue;}
+
+    // seed cell area
+    const auto m_area = seed->cellID().area() ;
+     
+    // Energy
+    const double energy = momentum.momentum().e();
+    if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+      debug() << "- Energy [MeV]=" << energy << endmsg;
+
+    // Chi2
+    const auto range = table.relations( cluster );
+    const double chi2 = range.empty() ? 1.e+6 : range.front().weight();
+    if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+      debug() << " - Chi2        ="<<chi2<<endmsg;
+     
+    // Cell seed
+    const double eSeed = energy>0. ? (seed->e())/energy : -1.;
+    if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+      debug()<<" - Seed Energy ="<<eSeed<<endmsg;
+     
+    //Spd hit and Prs deposit
+    Line line( Gaudi::XYZPoint(0.,0.,0.) , momentum.momentum().Vect() );
+    const auto spdPoint = intersection(line, m_spdPlane);
+    const auto prsPoint = intersection(line, m_prsPlane);
+    const auto cellSpd  = m_spd->Cell( spdPoint );
+    const auto cellPrs  = m_prs->Cell( prsPoint );
+     
+    double eSpd=0.;
+    double ePrs=0.;
+
+    // Get CaloFutureCell Deposits in the SPD and PRS
+    if( !(LHCb::CaloCellID() == cellSpd) ){
+      for( const auto& digit: hypo->digits() ){
+        if( digit->cellID() == cellSpd ){
+	   			eSpd = digit->e();
+        }
+      }
+      if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+        debug() << " - SPD " << cellSpd << " Energy  =" << eSpd << endmsg;
+    }
+
+    if( !(LHCb::CaloCellID() == cellPrs) ){
+      for( const auto& digit: hypo->digits() ){
+        if( digit->cellID() == cellPrs ){
+          ePrs = digit->e();
+        }
+      }
+      if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+        debug() << " - PRS " << cellPrs << " Energy  =" << ePrs << endmsg;
+    }
+
+    // // ***
+    // double likelihood = -1.;
+    // if( NULL != idTable ){
+    //   const auto idRange = idTable->relations( hypo ) ;
+    //   if( !idRange.empty() ) likelihood = idRange.front().to();
+    // }
+    const auto idRange = idTable.relations( hypo ) ;
+    const double likelihood = idRange.empty() ? -1. : idRange.front().to();
+    if(likelihood<0.){m_nWrongs++;}
+
+
+    // MCTruth Information
+    Gaudi::XYZPoint decay( 0., 0., 1.*Gaudi::Units::km );
+    double wmax=-1.e6;
+    double dr=1.e+6;
+    double dz=1.e+6;
+    double de=1.e+6;
+    bool isSignal=false;
+    bool isPhoton=false;
+    bool isMerged=false;
+
+    for( const auto& mc: gtable.relations(cluster) ){
+      const auto mcpart = mc.to();
+     	if( mcpart == 0 ) continue; 
+      if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+        debug() << "mctruth : --> pid=" << mcpart->particleID().pid() << " weight=" << mc.weight() << endmsg;
+      if( !(m_gammaID == mcpart->particleID()) ) continue;
+	    if( mc.weight() < wmax ) continue;
+      wmax = mc.weight();
+       
+      if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) {
+       debug() << "A MC-gamma matches the hypo "  << endmsg;       
+       debug() << " Energy :  " << mcpart->momentum().e() << endmsg;       
+      }
+       
+      isPhoton = true;
+      const auto vertex = mcpart->originVertex();
+      if( vertex == 0 ){
+        warning() << "MC-gamma has no origin vertex !" << endmsg;
+        continue;
+      }
+           
+      // selection
+      dr = vertex->position().Rho();
+      dz = vertex->position().z();
+      de = fabs(energy - mcpart->momentum().e())/energy;
+      if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+        debug() << "Gamma parameters : dr=" << dr << " - dz=" << dz << " - de=" << de << endmsg;
+
+      for( const auto& v: mcpart->endVertices() ){
+        if(v->position().z() < decay.Z()){
+          decay = v->position();
+        }
+      }
+
+      // Check against truth, register if it's indeed from Pi0
+      if( isMergedPi0(mcpart) ) isMerged=true;
+    }
+     
+    // Collect good signal
+    if ( de < m_de && ((m_dr<0)||(dr<m_dr)) && ((m_dz<0)||(dz<m_dz)) && isPhoton && !isMerged){
+      m_nPhotons++;
+      isSignal = true;
+      if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+        debug() << "Candidate is Signal according to MC" << endmsg;
+    } else {
+      if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+        debug() <<"Candidate is Background according to MC (photon, merged)" << isPhoton << " " << isMerged << endmsg;
+    }
+    
+    // Efficiency and purity versus pt
+    if( likelihood > m_lhcut ){
+      int ibin = int(m_nbinpt*(momentum.momentum().pt()-m_ptmin)/(m_ptmax-m_ptmin));
+      if( ibin>=0 && ibin<m_nbinpt ){
+        if (isSignal) {m_rec_sig[ibin]++;}
+        else {m_rec_bkg[ibin]++;}
+      }
+    }
+
+    // Efficiency and purity versus likelihood
+    int lhbin = int(likelihood*double(m_nbinlh));
+    for( int l=0; l<lhbin; l++ ){
+      if (isSignal) {
+        m_lh_recsig[l]++;
+        if (eSpd>1.){m_lh_recsig_spd[l]++;}
+        else {m_lh_recsig_nospd[l]++;}
+        if (decay.Z()>m_zConv) {m_lh_recsig_noconv[l]++;}
+        else {m_lh_recsig_conv[l]++;}
+      } else {
+        m_lh_recbkg[l]++;
+        if (eSpd>1.){m_lh_recbkg_spd[l]++;}
+        else {m_lh_recbkg_nospd[l]++;}
+      }
+    }
+
+    // Fill General Monitoring histograms
+    if (isSignal){
+      if (eSpd>1.){
+        fill(m_lhSigSpd,likelihood,1.);
+      } else{
+        fill(m_lhSig,likelihood,1.);
+      }
+    }
+    else{
+      if (eSpd>1.){
+        fill(m_lhBkgSpd,likelihood,1.);
+      } else{
+        fill(m_lhBkg,likelihood,1.);
+      }
+    }
+
+    if (m_pdf) {
+      double eTransf = transform ( energy );
+      if (isSignal){
+      	if (eSpd>1.){
+      	  fill(m_signalEPrsSpd2D [ m_area ], ePrs , eTransf,1.);
+      	  fill(m_signalChi2Spd2D [ m_area ], chi2 , eTransf,1.);
+      	  fill(m_signalSeedSpd2D [ m_area ], eSeed, eTransf,1.);
+      	} else {
+      	  fill(m_signalEPrs2D [ m_area ], ePrs , eTransf,1.);
+      	  fill(m_signalChi22D [ m_area ], chi2 , eTransf,1.);
+      	  fill(m_signalSeed2D [ m_area ], eSeed, eTransf,1.);
+      	}
+      } else {
+      	if (eSpd>1.){
+      	  fill(m_backgrEPrsSpd2D [ m_area ], ePrs , eTransf,1.);
+      	  fill(m_backgrChi2Spd2D [ m_area ], chi2 , eTransf,1.);
+      	  fill(m_backgrSeedSpd2D [ m_area ], eSeed, eTransf,1.);
+      	}
+      	else {
+      	  fill(m_backgrEPrs2D [ m_area ], ePrs , eTransf,1.);
+      	  fill(m_backgrChi22D [ m_area ], chi2 , eTransf,1.);
+      	  fill(m_backgrSeed2D [ m_area ], eSeed, eTransf,1.);
+      	}
+      }
+    }
+  } // End loop over hypo
+  
+  return; // StatusCode::SUCCESS;
+}
+
+// =============================================================================
+
+std::vector<AIDA::IHistogram2D*> CaloFuturePhotonChecker::defHisto(
+	const unsigned int bin, const double xmin, const double xmax,
+	const unsigned int nhisto, std::string hname){
+
+  std::vector<AIDA::IHistogram2D*> histoList;
+  char histoname[60];
+
+  for (unsigned int area=0; area<3; ++area){
+    AIDA::IHistogram2D* histo;
+    sprintf(histoname,"%s_%i",hname.c_str(),nhisto+area);
+    histo = book2D(histoname,histoname,
+		   (int)(xmin),(int)(xmax),bin,
+		   0., 6.,6);
+    if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+      debug() <<"booking Histo ..."<<histoname<<endmsg; 
+    histoList.push_back(histo);
+  }
+  return histoList;
+}
+
+
+// =============================================================================
+
+// Return True if the given mcparticle 
+bool CaloFuturePhotonChecker::isMergedPi0( const LHCb::MCParticle* mcpart ) const {
+  bool isMerged = false;
+  const auto mother = mcpart->mother();
+  if( mother != nullptr ){
+    if( m_pi0ID == mother->particleID() ){
+      const auto decayPi0 = mcpart->originVertex();
+      const auto products = decayPi0->products();
+      if( products.size() == 2 ){
+        for( const auto& pi0daughter: products ){
+          if( mcpart == pi0daughter ) {continue;}
+          const Line line1( decayPi0->position(), mcpart->momentum().Vect() );
+          const Line line2( decayPi0->position(), pi0daughter->momentum().Vect() );
+          const auto hit1 = intersection(line1, m_ecalPlane);
+          const auto hit2 = intersection(line2, m_ecalPlane);
+          const auto distance = (hit1 - hit2).R();
+          const double param = m_mergedDist*(m_ecal->cellSize(m_ecal->Cell( hit1 ))+
+                                      m_ecal->cellSize(m_ecal->Cell( hit2 )))/2.;
+          if( distance<param ){
+            isMerged = true;
+            if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+              debug() << "Pi0->Merged Photon :  distance=" << distance
+                      << "  < Criteria=" << param << " mm" << endmsg;
+          }
+        }
+      }
+    }
+  }
+  return isMerged;
+}
diff --git a/CaloFuture/CaloFutureMoniDst/src/CaloFuturePhotonChecker.h b/CaloFuture/CaloFutureMoniDst/src/CaloFuturePhotonChecker.h
new file mode 100644
index 0000000000000000000000000000000000000000..289fd8f8784491a3780118ed0fbd0728dd2fc72b
--- /dev/null
+++ b/CaloFuture/CaloFutureMoniDst/src/CaloFuturePhotonChecker.h
@@ -0,0 +1,146 @@
+#ifndef CALOFUTUREPHOTONCHECKER_H
+#define CALOFUTUREPHOTONCHECKER_H 1
+
+// Includes
+#include "GaudiAlg/Consumer.h"
+#include "LHCbMath/Line.h"
+#include "Event/Track.h"
+#include "Event/MCParticle.h"
+#include "Relations/RelationWeighted.h"
+#include "Relations/Relation.h"
+#include "CaloFutureMoniAlg.h"
+
+// Aliases
+using Input   = LHCb::CaloHypo::Container;
+using MCPs    = LHCb::MCParticles;
+using Table   = Relations::RelationWeighted<LHCb::CaloCluster,LHCb::Track,float>;
+using MCTable = Relations::RelationWeighted<LHCb::CaloCluster,LHCb::MCParticle,float>;
+using IDTable = Relations::Relation<LHCb::CaloHypo,float>;
+using Line    = Gaudi::Math::Line<Gaudi::XYZPoint,Gaudi::XYZVector>;
+
+
+// =============================================================================
+
+/** @class CaloFuturePhotonChecker CaloFuturePhotonChecker.h
+ *
+ *  Photon Selection Monitoring
+ *  (LHCb 2004-03)
+ *
+ *  @author Frederic Machefert frederic.machefert@in2p3.fr
+ *  @date   2004-15-04
+ */
+
+class CaloFuturePhotonChecker final
+: public Gaudi::Functional::Consumer<void(const Input&, const MCPs&, const Table&, const MCTable&, const IDTable&),
+    Gaudi::Functional::Traits::BaseClass_t<CaloFutureMoniAlg>>
+{
+public:
+  // GaudiAlgorithm
+  StatusCode initialize() override;
+  StatusCode finalize  () override;
+
+  // Gaudi::Functional
+  void operator()(const Input&, const MCPs&, const Table&, const MCTable&, const IDTable&) const override;
+
+  CaloFuturePhotonChecker( const std::string& name, ISvcLocator* pSvc );
+
+protected:
+  std::vector<AIDA::IHistogram2D*> defHisto(const unsigned int,
+                                      const double, const double,
+                                      const unsigned int,
+                                      const std::string);
+
+  bool isMergedPi0( const LHCb::MCParticle* ) const;
+
+private:
+  // FutureCounters
+  mutable unsigned int m_nEvents     = 0;
+  mutable unsigned int m_nCandidates = 0;
+  mutable unsigned int m_nPhotons    = 0;
+  mutable unsigned int m_nMCPhotons  = 0;
+  mutable unsigned int m_nWrongs     = 0;
+
+  // more counters
+  mutable std::vector<double> m_mc_g;
+  mutable std::vector<double> m_rec_bkg;
+  mutable std::vector<double> m_rec_sig;
+  mutable double              m_lh_mcg;
+  mutable std::vector<double> m_lh_recsig;
+  mutable std::vector<double> m_lh_recbkg;
+  mutable double              m_lh_mcg_conv;
+  mutable std::vector<double> m_lh_recsig_conv;
+  mutable std::vector<double> m_lh_recsig_spd;
+  mutable std::vector<double> m_lh_recbkg_spd;
+  mutable double              m_lh_mcg_noconv;
+  mutable std::vector<double> m_lh_recsig_noconv;
+  mutable std::vector<double> m_lh_recsig_nospd;
+  mutable std::vector<double> m_lh_recbkg_nospd;
+
+  // Detector Information
+  DeCalorimeter* m_ecal = nullptr;
+  DeCalorimeter* m_spd  = nullptr;
+  DeCalorimeter* m_prs  = nullptr;
+
+  Gaudi::Plane3D m_ecalPlane;
+  Gaudi::Plane3D m_prsPlane;
+  Gaudi::Plane3D m_spdPlane;
+
+  double         m_zConv = 0.;
+
+  // Tools
+  std::string m_IDTableName = LHCb::CaloFutureIdLocation::PhotonID;
+
+  // Particle Properties
+  std::string      m_gammaName {"gamma"};
+  LHCb::ParticleID m_gammaID {0};
+  std::string      m_pi0Name {"pi0"};
+  LHCb::ParticleID m_pi0ID {0};
+
+  // histogramming related variables
+  Gaudi::Property<bool>                m_pdf     {this, "Pdf", false};
+  Gaudi::Property<std::vector<double>> m_prsbin  {this, "EPrsBin", {50,0.,200.}};
+  Gaudi::Property<std::vector<double>> m_chi2bin {this, "Chi2Bin", {26,0.,104.}};
+  Gaudi::Property<std::vector<double>> m_seedbin {this, "SeedBin", {50,0.,1.  }};
+
+  // Signal/background definitions
+  Gaudi::Property<float> m_etmin      { this, "Etmin"     , 200.*Gaudi::Units::MeV};
+  Gaudi::Property<float> m_dr         { this, "Dr"        , -1.};
+  Gaudi::Property<float> m_dz         { this, "Dz"        , -1.};
+  Gaudi::Property<float> m_de         { this, "DE"        , 0.25};
+  Gaudi::Property<float> m_mergedDist { this, "MergedDist", 1.5};
+
+  // histograms
+
+  AIDA::IHistogram1D*   m_lhSig    = nullptr;
+  AIDA::IHistogram1D*   m_lhSigSpd = nullptr;
+  AIDA::IHistogram1D*   m_lhBkg    = nullptr;
+  AIDA::IHistogram1D*   m_lhBkgSpd = nullptr;
+
+  Gaudi::Property<int> m_nbinlh {this, "LhNBin", 20};
+  AIDA::IHistogram2D*   m_effpur       = nullptr;
+  AIDA::IHistogram2D*   m_effpur_spd   = nullptr;
+  AIDA::IHistogram2D*   m_effpur_nospd = nullptr;
+
+  Gaudi::Property<int>   m_nbinpt { this, "PtNBin"    , 20};
+  Gaudi::Property<float> m_lhcut  { this, "LhCut"     , 0.3};
+  Gaudi::Property<float> m_ptmin  { this, "PtMinHisto", 0. *Gaudi::Units::MeV};
+  Gaudi::Property<float> m_ptmax  { this, "PtMaxHisto", 10.*Gaudi::Units::GeV};
+  AIDA::IHistogram1D*   m_efficiency = nullptr;
+  AIDA::IHistogram1D*   m_purity     = nullptr;
+
+  std::vector<AIDA::IHistogram2D*> m_signalEPrs2D;
+  std::vector<AIDA::IHistogram2D*> m_backgrEPrs2D;
+  std::vector<AIDA::IHistogram2D*> m_signalChi22D;
+  std::vector<AIDA::IHistogram2D*> m_backgrChi22D;
+  std::vector<AIDA::IHistogram2D*> m_signalSeed2D;
+  std::vector<AIDA::IHistogram2D*> m_backgrSeed2D;
+
+  std::vector<AIDA::IHistogram2D*> m_signalEPrsSpd2D;
+  std::vector<AIDA::IHistogram2D*> m_backgrEPrsSpd2D;
+  std::vector<AIDA::IHistogram2D*> m_signalChi2Spd2D;
+  std::vector<AIDA::IHistogram2D*> m_backgrChi2Spd2D;
+  std::vector<AIDA::IHistogram2D*> m_signalSeedSpd2D;
+  std::vector<AIDA::IHistogram2D*> m_backgrSeedSpd2D;
+};
+
+#endif // CALOFUTUREPHOTONCHECKER_H
diff --git a/CaloFuture/CaloFutureMoniDst/src/CaloFuturePi0Checker.cpp b/CaloFuture/CaloFutureMoniDst/src/CaloFuturePi0Checker.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8f96f27ab33458efe390e663b6c7ff7e48cd981a
--- /dev/null
+++ b/CaloFuture/CaloFutureMoniDst/src/CaloFuturePi0Checker.cpp
@@ -0,0 +1,157 @@
+// Includes
+#include "GaudiAlg/Consumer.h"
+// #include "Relations/IRelationWeighted.h"
+#include "Relations/RelationWeighted.h"
+#include "Kernel/IParticlePropertySvc.h"
+#include "Kernel/ParticleProperty.h"
+#include "Event/CaloHypo.h"
+#include "Event/MCParticle.h"
+#include "CaloDet/DeCalorimeter.h"
+#include "CaloFutureUtils/CaloMomentum.h"
+#include "CaloFutureUtils/ClusterFunctors.h"
+#include "CaloFutureMoniAlg.h"
+#include "Relations/RelationWeighted1D.h"
+
+// ============================================================================
+
+/** @class CaloFuturePi0Checker CaloFuturePi0Checker.cpp
+ *
+ *  Simple MC pi0 monitoring algorithm
+ *  It produces 2 histograms
+ *  <ol>
+ *  <li> "Raw" mass distribution of 2 photons </li>
+ *  <li> Mass distribution of 2 photons after Pt cut for each photon </li>
+ *  <li> Mass distribution of 2 photons after Pt cut for combination </li>
+ *  </ol>
+ *
+ *  @see CaloFutureAlgorithm
+ *  @see     Algorithm
+ *  @see    IAlgorithm
+ *
+ *  @author Vanya BELYAEV Ivan.Belyaev@itep.ru
+ *  @date   02/11/2001
+ */
+
+using Input   = LHCb::RelationWeighted1D<LHCb::CaloCluster,LHCb::MCParticle,float>;
+using Inputs  = LHCb::CaloHypo::Container;
+using Photon  = const LHCb::CaloHypo;
+
+class CaloFuturePi0Checker final
+: public Gaudi::Functional::Consumer<void(const Input&, const Inputs&),
+    Gaudi::Functional::Traits::BaseClass_t<CaloFutureMoniAlg>>
+{
+public:
+  StatusCode initialize() override;
+  void operator()(const Input&, const Inputs&) const override;
+
+  CaloFuturePi0Checker( const std::string &name, ISvcLocator *pSvcLocator );
+
+private:
+  LHCb::ClusterFunctors::ClusterFromCaloFuture m_calo = DeCalorimeterLocation::Ecal;
+
+  LHCb::ParticleID m_pi0ID{0};
+
+  Gaudi::Property<float> m_cut { this, "Cut", float(50 * Gaudi::Units::perCent), "photon purity cut"};
+
+  Gaudi::Property<std::string> m_pi0Name {this, "Ancestor", "pi0"};
+};
+
+// =============================================================================
+
+DECLARE_COMPONENT( CaloFuturePi0Checker )
+
+// =============================================================================
+
+CaloFuturePi0Checker::CaloFuturePi0Checker( const std::string &name, ISvcLocator *pSvcLocator )
+: Consumer( name, pSvcLocator, {
+    KeyValue{ "Input" , "Relations/"+LHCb::CaloClusterLocation::Default },
+    KeyValue{ "Inputs", LHCb::CaloHypoLocation::Photons }
+}){
+  // set the appropriate defualt value for detector data
+  setDetData( DeCalorimeterLocation::Ecal );
+}
+
+// =============================================================================
+
+StatusCode CaloFuturePi0Checker::initialize(){
+  StatusCode sc = Consumer::initialize(); // must be executed first
+  if ( sc.isFailure() ) return sc; // error already printedby GaudiAlgorithm
+
+  // re-initialize the Ecal cluster selector
+  m_calo.setCaloFuture( detData() );
+
+  // locate particle eproperty service
+  auto ppS = svc<LHCb::IParticlePropertySvc>( "LHCb::ParticlePropertySvc", true );
+  if ( 0 == ppS ) return StatusCode::FAILURE;
+
+  const auto pp = ppS->find( m_pi0Name );
+  if ( pp == nullptr ) return Error( "Could not locate particle '"+m_pi0Name+"'" );
+  m_pi0ID = pp->pid();
+
+  hBook1( "1", "Gamma-Gamma mass       " , 0, 1, 500 );
+  hBook1( "2", "Gamma-Gamma mass (MCpi0 match)" , 0, 1, 500 );
+  if( m_split ){
+    Warning( "No area spliting allowed for CaloFuturePi0Checker").ignore();
+    m_split = false;
+  }
+  return StatusCode::SUCCESS;
+}
+
+// =============================================================================
+
+void CaloFuturePi0Checker::operator()(const Input& table, const Inputs& photons ) const {
+
+  using namespace LHCb::ClusterFunctors;
+
+  // loop over the first photon
+  for( auto g1 = photons.begin(); photons.end() != g1; ++g1 ){
+    Photon *photon1 = *g1;
+    if ( photon1 == nullptr ) continue;
+    LHCb::CaloMomentum momentum1( photon1 );
+
+    // get Ecal cluster
+    const auto clusters1 = photon1->clusters();
+    if ( clusters1.empty() ) continue;
+    const auto cluster1 = ( 1 == clusters1.size() ) ? clusters1.begin() :
+      std::find_if( clusters1.begin(), clusters1.end(), m_calo );
+    if ( clusters1.end() == cluster1 ) continue;
+
+    // get all MCtruth information for this cluster
+    const float cut1 = (float) ((*cluster1)->e() * m_cut);
+    const auto range1 = table.relations( *cluster1, cut1, true );
+
+    // loop over the second photon
+    for( auto g2 = g1 + 1; photons.end() != g2; ++g2 ){
+      Photon *photon2 = *g2;
+      if ( photon2 == nullptr ) continue;
+      LHCb::CaloMomentum momentum2( photon2 );
+
+      // get Ecal cluster
+      const auto clusters2 = photon2->clusters();
+      if ( clusters2.empty() ) continue;
+      auto cluster2 = ( 1 == clusters2.size() ) ? clusters2.begin() :
+        std::find_if( clusters2.begin(), clusters2.end(), m_calo );
+      if ( clusters2.end() == cluster2 ) continue;
+
+      // get all MCtruth information for this cluster
+      const float cut2 = (float)((*cluster2)->e() * m_cut);
+      const auto range2 = table.relations( *cluster2, cut2, true );
+
+      // double loop for search the common ancestor
+      LHCb::MCParticle *pi0 = nullptr;
+      for( auto mc1 = range1.begin();( pi0 == nullptr ) && ( range1.end() != mc1 ); ++mc1 ){
+        if ( mc1->to() == nullptr ) continue;
+        for ( auto mc2 = range2.begin(); ( pi0 == nullptr ) && ( range2.end() != mc2 ); ++mc2 ){
+          if ( mc1->to() != mc2->to() ) continue; // common ancestor?
+          if ( m_pi0ID == mc1->to()->particleID() ) pi0 = mc1->to();
+        } // end of second MC loop
+      } // end of first MC loop
+
+      const double mass = (momentum1.momentum()+momentum2.momentum()).mass();
+      hFill1( "1", mass/Gaudi::Units::GeV );
+      if ( pi0 == nullptr ) continue;
+      hFill1( "2", mass/Gaudi::Units::GeV );
+    } // end of loop over second photon
+  } // end of loop over first photon
+  return; // StatusCode::SUCCESS;
+}
diff --git a/CaloFuture/CaloFutureMoniDst/src/CaloFuturePi0Monitor.cpp b/CaloFuture/CaloFutureMoniDst/src/CaloFuturePi0Monitor.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..037c5b97b88a98441753b7e963e2686cea976557
--- /dev/null
+++ b/CaloFuture/CaloFutureMoniDst/src/CaloFuturePi0Monitor.cpp
@@ -0,0 +1,206 @@
+// Includes
+#include "GaudiAlg/Consumer.h"
+#include <vector>
+#include "Event/Particle.h"
+#include "Event/CaloHypo.h"
+#include "CaloDet/DeCalorimeter.h"
+#include "CaloFutureUtils/CaloMomentum.h"
+#include "CaloFutureUtils/CaloFutureParticle.h"
+#include "CaloFutureInterfaces/ICaloFutureHypo2CaloFuture.h"
+#include "CaloFutureMoniAlg.h"
+
+namespace {
+    // hack to allow for tools with non-const interfaces...
+    template <typename IFace>
+    IFace* fixup(const ToolHandle<IFace>& iface) { return &const_cast<IFace&>(*iface); }
+}
+
+// =============================================================================
+
+/** @class CaloFuturePi0Monitor CaloFuturePi0Monitor.cpp
+ *
+ *  Simple pi0 monitoring algorithm
+ *
+ *  @see   CaloFutureMoniAlg
+ *  @see GaudiHistoAlg
+ *  @see GaudiAlgorithm
+ *  @see      Algorithm
+ *  @see     IAlgorithm
+ *
+ *  @author Vanya Belyaev Ivan.Belyaev@itep.ru
+ *  @date   02/11/2001
+ */
+
+using Input = LHCb::CaloHypo::Container;
+
+class CaloFuturePi0Monitor final
+: public Gaudi::Functional::Consumer<void(const Input&),
+    Gaudi::Functional::Traits::BaseClass_t<CaloFutureMoniAlg>>
+{
+public:
+  StatusCode initialize() override;
+  void operator()(const Input&) const override;
+
+  CaloFuturePi0Monitor( const std::string &name, ISvcLocator *pSvcLocator );
+
+private:
+  DeCalorimeter* m_calo = nullptr;
+  ToolHandle<ICaloFutureHypo2CaloFuture> m_toSpd{"CaloFutureHypo2CaloFuture/CaloFutureHypo2Spd", this};
+  ToolHandle<ICaloFutureHypo2CaloFuture> m_toPrs{"CaloFutureHypo2CaloFuture/CaloFutureHypo2Prs", this};
+
+  bool valid_photon(const LHCb::CaloHypo* g) const;
+
+  Gaudi::Property<float> m_ptPhoton    { this, "PhotonPtFilter"    , 250 * Gaudi::Units::MeV};
+  Gaudi::Property<float> m_ptMaxPhoton { this, "PhotonMaxPtFilter" , 0};
+  Gaudi::Property<float> m_isol        { this, "IsolationFilter"   , 4};
+  Gaudi::Property<float> m_prsPhoton   { this, "PhotonPrsFilterMin", 10*Gaudi::Units::MeV};
+  Gaudi::Property<float> m_yCut        { this, "RejectedYBand"     , 300};
+  Gaudi::Property<bool>  m_conv        { this, "AllowConverted"    , false};
+};
+
+// =============================================================================
+
+DECLARE_COMPONENT( CaloFuturePi0Monitor )
+
+// =============================================================================
+
+CaloFuturePi0Monitor::CaloFuturePi0Monitor( const std::string &name, ISvcLocator *pSvcLocator )
+: Consumer( name, pSvcLocator, KeyValue{ "Input", "" } )
+{
+  m_multMax = 150;
+  const auto Input = LHCb::CaloFutureAlgUtils::CaloFutureHypoLocation("Photons",context());
+  updateHandleLocation( *this, "Input", Input );
+}
+
+// =============================================================================
+
+StatusCode CaloFuturePi0Monitor::initialize(){
+  StatusCode sc = Consumer::initialize(); // must be executed first
+  if ( sc.isFailure() ) return sc; // error already printedby GaudiAlgorithm
+  hBook1( "1", "(gg) multiplicity " + inputLocation() , m_multMin  , m_multMax  , m_multBin   );
+  hBook1( "2", "(gg) energy " + inputLocation()       , m_energyMin, m_energyMax, m_energyBin );
+  hBook1( "3", "(gg) et     " + inputLocation()       , m_etMin    , m_etMax    , m_etBin     );
+  hBook1( "4", "(gg) mass   " + inputLocation()       , m_massMin  , m_massMax  , m_massBin   );
+  hBook1( "5", "(gg) combinatorial background" + inputLocation()   , m_massMin  , m_massMax , m_massBin );
+  hBook1( "6", "bkg-substracted (gg) mass   " + inputLocation()    , m_massMin  , m_massMax , m_massBin );
+  hBook1( "7", "(gg) mass  for |y|-gamma > " + Gaudi::Utils::toString(m_yCut) + " "
+          + inputLocation()  , m_massMin  , m_massMax , m_massBin );
+  hBook2( "8", "(gg) mass per cell  " + inputLocation(), 0, 6016, 6016,  m_massMin  , m_massMax , m_massBin );
+
+  // Get, retrieve, configure tools
+  m_calo = getDet<DeCalorimeter>(DeCalorimeterLocation::Ecal);
+  if(!( m_toSpd.retrieve() && m_toPrs.retrieve() )){
+    error() << "Unable to retrive one of the ToolHandles" << endmsg;
+    return StatusCode::FAILURE;
+  }
+  m_toSpd->setCalos( "Ecal" ,"Spd");
+  m_toPrs->setCalos( "Ecal" ,"Prs");
+
+  // set mass window to histo range
+  m_massFilterMin = m_massMin;
+  m_massFilterMax = m_massMax;
+
+  return StatusCode::SUCCESS;
+}
+
+// =============================================================================
+
+void CaloFuturePi0Monitor::operator()(const Input& photons) const {
+
+  if ( !produceHistos() ) return;
+  if ( photons.empty() ) return;
+
+  // Params for lookup later down the loop
+  const auto& cells = m_calo->cellParams();
+
+  // loop over the first photon
+  initFutureCounters();
+  for( auto g1 = photons.begin(); photons.end() != g1; ++g1 ){
+    if( !valid_photon(*g1) ) continue;
+    LHCb::CaloMomentum momentum1( *g1 );
+    Gaudi::LorentzVector v1( momentum1.momentum() );
+
+    // loop over the second photon
+    for( auto g2 = std::next(g1); photons.end() != g2; ++g2 ){
+      if( !valid_photon(*g2) ) continue;
+      LHCb::CaloMomentum momentum2( *g2 );
+      if( std::max(momentum1.pt(),momentum2.pt()) < m_ptMaxPhoton) continue;
+      Gaudi::LorentzVector v2( momentum2.momentum() );
+
+      // background shape from (x,y)->(-x,-y) symmetrized g2
+      Gaudi::LorentzVector v2Sym( v2 );
+      v2Sym.SetPx( -v2.Px() );
+      v2Sym.SetPy( -v2.Py() );
+      Gaudi::LorentzVector bkg( v1 + v2Sym );
+      Gaudi::XYZPoint p2Sym( -(*g2)->position()->x() , -(*g2)->position()->y() , (*g2)->position()->z() );
+      bool isBkg = ( bkg.e() > m_eFilter &&
+                     bkg.pt() > m_etFilter &&
+                     bkg.mass() > m_massFilterMin &&
+                     bkg.mass() < m_massFilterMax );
+
+      // check pi0
+      Gaudi::LorentzVector pi0( v1 + v2 );
+      bool isPi0 = ( pi0.e() > m_eFilter &&
+                     pi0.pt() > m_etFilter &&
+                     pi0.mass() > m_massFilterMin &&
+                     pi0.mass() < m_massFilterMax );
+
+      if( !isPi0 && !isBkg) continue;
+
+      // Get cellIDs
+      auto id1 = LHCb::CaloCellID();
+      auto id2 = LHCb::CaloCellID();
+      if ( (*g1)->clusters().size() > 0 ){
+        const auto cluster = *((*g1)->clusters().begin());
+        if( cluster != 0 ) id1 = cluster->seed();
+      }
+      if ( (*g2)->clusters().size() > 0 ){
+        const auto cluster = *((*g2)->clusters().begin());
+        if( cluster != 0 ) id2 = cluster->seed();
+      }
+
+      // define pi0 area
+      const auto id = (id1.area() == id2.area() ) ? id1 : LHCb::CaloCellID();
+
+      // isolation criteria
+      Gaudi::XYZPoint p1( (*g1)->position()->x() , (*g1)->position()->y() , (*g1)->position()->z() );
+      Gaudi::XYZPoint p2( (*g2)->position()->x() , (*g2)->position()->y() , (*g2)->position()->z() );
+      const auto vec      = p2 - p1;
+      const auto vecSym   = p2Sym - p1;
+      const auto cSize    = std::max( m_calo->cellSize(id1), m_calo->cellSize(id2) );
+      const auto isol     = (cSize > 0) ? vec.Rho() / cSize : 0;
+      const auto isolSym  = (cSize > 0) ? vecSym.Rho() / cSize : 0;
+      const auto y1       = m_calo->cellCenter(id1).Y();
+      const auto y2       = m_calo->cellCenter(id2).Y();
+
+      if( isPi0 && isol > m_isol){
+        count(id);
+        hFill1(id, "2", pi0.e()   );
+        hFill1(id, "3", pi0.pt()  );
+        hFill1(id, "4", pi0.mass());
+        hFill1(id, "6", pi0.mass(), 1.);
+        if( fabs(y1) > m_yCut && fabs(y2) > m_yCut )hFill1("7",pi0.mass(), 1.);
+        int index = cells.index( id );
+        hFill2("8", index, pi0.mass() );
+      }
+      if( isBkg && isolSym > m_isol){
+        hFill1(id, "5", bkg.mass());
+        hFill1(id, "6", bkg.mass(), -1.);
+      }
+    }
+  }
+  fillFutureCounters("1");
+  return; // StatusCode::SUCCESS;
+}
+
+// =============================================================================
+
+bool CaloFuturePi0Monitor::valid_photon(const LHCb::CaloHypo* g) const {
+  // Return True if this photon is valid to continue the computation
+  if( g == nullptr ) return false;
+  if( !m_conv && fixup(m_toSpd)->multiplicity( *g , "Spd" ) > 0 ) return false;
+  if( fixup(m_toPrs)->energy ( *g, "Prs"  ) < m_prsPhoton ) return false;
+  LHCb::CaloMomentum momentum( g );
+  if(momentum.pt() < m_ptPhoton) return false;
+  return true;
+}
diff --git a/CaloFuture/CaloFutureMoniDst/src/CaloFuturePi0Ntp.cpp b/CaloFuture/CaloFutureMoniDst/src/CaloFuturePi0Ntp.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c48e61e94876d923add9c0e5e510b8a946e6004f
--- /dev/null
+++ b/CaloFuture/CaloFutureMoniDst/src/CaloFuturePi0Ntp.cpp
@@ -0,0 +1,349 @@
+// Includes
+// #include "Event/CaloFutureHypo.h"
+#include "CaloFutureUtils/CaloMomentum.h"
+#include "CaloFuturePi0Ntp.h"
+#include "CaloFutureMoniUtils.h"
+
+namespace {
+  /// hack to allow for tools with non-const interfaces...
+  template <typename IFace>
+  IFace* fixup(const ToolHandle<IFace>& iface) { return &const_cast<IFace&>(*iface); }
+}
+// =============================================================================
+
+DECLARE_COMPONENT( CaloFuturePi0Ntp )
+
+namespace {
+  // Return new 4D LorentzVector with first-3 spatial components normalized to 1
+  // and the last component equal to 1. The space norm ==1, the 4dnorm==0.
+  Gaudi::LorentzVector normalize( Gaudi::XYZPoint v3 ){
+    return Gaudi::LorentzVector{ v3.X()/v3.R(), v3.Y()/v3.R(), v3.Z()/v3.R(), 1. };
+  }
+}
+
+// =============================================================================
+
+CaloFuturePi0Ntp::CaloFuturePi0Ntp( const std::string &name, ISvcLocator *pSvcLocator )
+: Consumer( name, pSvcLocator, { KeyValue{ "InputODIN", LHCb::ODINLocation::Default       },
+                                 KeyValue{ "InputL0"  , LHCb::L0DUReportLocation::Default },
+                                 KeyValue{ "Locations", LHCb::CaloHypoLocation::Photons   },
+                                 KeyValue{ "VertexLoc", "" } } )
+{}
+
+// =============================================================================
+
+StatusCode CaloFuturePi0Ntp::initialize(){
+  StatusCode sc = GaudiTupleAlg::initialize();
+  if ( sc.isFailure() ) return sc;
+
+  // retrieve & configure tools
+  m_calo = getDet<DeCalorimeter>(DeCalorimeterLocation::Ecal);
+  if(!( m_counterStat.retrieve()
+     && m_odin.retrieve()
+     && m_toSpd.retrieve()
+     && m_toPrs.retrieve() )){
+    error() << "Unable to retrive one of the ToolHandles" << endmsg;
+    return StatusCode::FAILURE;
+  }
+  m_toSpd->setCalos( "Ecal" ,"Spd");
+  m_toPrs->setCalos( "Ecal" ,"Prs");
+
+  // set vertex location
+  auto vertLoc = inputLocation<3>();  // <-- Careful with the index, 'VertexLoc' is 4th.
+  if(vertLoc.empty()) {
+    vertLoc = ( m_usePV3D ? LHCb::RecVertexLocation::Velo3D
+                          : LHCb::RecVertexLocation::Primary );
+    updateHandleLocation( *this, "VertexLoc", vertLoc );
+  }
+
+  return StatusCode::SUCCESS;
+}
+
+
+// =============================================================================
+// standard execution method
+// =============================================================================
+
+void CaloFuturePi0Ntp::operator()(const ODIN& odin, const L0& l0, const Hypos& hypos,
+                             const Vertices& verts) const {
+
+  // Collect global info (in pre-Functional implementation, some are optionals)
+  m_odin->getTime();
+  const auto run    = odin.runNumber();
+  const auto evt    = (double) odin.eventNumber();
+  const auto tty    = odin.triggerType();
+  const auto nSpd   = (int) l0.dataValue("Spd(Mult)");
+  const auto nVert  = verts.size();
+  if(m_counterStat->isQuiet()) counter("#PV="+ Gaudi::Utils::toString(nVert) + " ["+ inputLocation<3>()+"]")+=1;
+
+  // Start looping over hypos
+  bool ok = false;
+  for( auto g1 = hypos.begin(); hypos.end() != g1; ++g1 ){
+    const auto p1 = *g1;
+    if ( p1 == nullptr ) continue;
+
+    LHCb::CaloMomentum mt1( p1 );
+    if( !inRange( m_ppt ,  mt1.pt() ) )continue;
+    if( !inRange( m_conv , fixup(m_toSpd)->multiplicity ( *p1 , "Spd") ) )continue;
+    if( !inRange( m_prsE , fixup(m_toPrs)->energy ( *p1 , "Prs"  ) ) )continue;
+
+    const auto v1     = momentum(p1);
+    const auto point1 = position3d(p1);
+    const auto prs1   = fixup(m_toPrs)->energy( *p1 , "Prs"  );
+    const auto spd1   = fixup(m_toSpd)->multiplicity( *p1 , "Spd");
+    const auto cl1    = firstCluster(p1);
+    if( cl1 == 0 ) continue; // SmartRef not overload with nullptr yet
+
+    const auto id1  = cl1->seed();
+    const auto pos1 = position3d(cl1);
+    const auto c1   = position4d(cl1);
+    const auto cc1  = normalize(pos1)   * cl1->e();
+    const auto ccc1 = normalize(point1) * cl1->e();
+
+    // loop over the second photon
+    for( auto g2 = g1 + 1; hypos.end() != g2; ++g2 ){
+      const auto p2 = *g2;
+      if ( p2 == nullptr ) continue;
+
+      LHCb::CaloMomentum mt2( p2 );
+      if( !inRange( m_ppt ,  mt2.pt() ) )continue;
+      if( !inRange( m_conv , fixup(m_toSpd)->multiplicity ( *p2 , "Spd") ) )continue;
+      if( !inRange( m_prsE , fixup(m_toPrs)->energy ( *p2 , "Prs"  ) ) )continue;
+
+      const auto v2     = momentum(p2);
+      const auto point2 = position3d(p2);
+      const auto pi0    = v1 + v2;
+
+      // background shape from (x,y)->(-x,-y) symmetrized g2
+      Gaudi::LorentzVector v2Sym( v2 );
+      v2Sym.SetPx( -v2.Px() );
+      v2Sym.SetPy( -v2.Py() );
+      const auto bkg = v1 + v2Sym;
+      Gaudi::XYZPoint p2Sym( -p2->position()->x() , -p2->position()->y() , p2->position()->z() );
+
+      bool isBkg = inRange(m_e, bkg.e())
+                && inRange(m_pt, bkg.pt())
+                && inRange(m_mass, bkg.mass());
+      bool isPi0 = inRange(m_e, pi0.e())
+                && inRange(m_pt, pi0.pt())
+                && inRange(m_mass, pi0.mass());
+
+      if( !isPi0 && !isBkg ) continue;
+
+      // Get cellIDs
+      const auto cl2 = firstCluster(p2);
+      const auto id2 = cl2->seed();
+      if( cl2 == 0 ) continue; // SmartRef not overload with nullptr yet
+
+      // isolation criteria
+      const auto vec      = point2 - point1;
+      const auto vecSym   = p2Sym - point1;
+      const auto cSize    = std::max(m_calo->cellSize(id1), m_calo->cellSize(id2));
+      const auto isol     = (cSize > 0) ? vec.Rho() / cSize : 0;
+      const auto isolSym  = (cSize > 0) ? vecSym.Rho() / cSize : 0;
+
+      isPi0 = isPi0 && inRange( m_isol, isol );
+      isBkg = isBkg && inRange( m_isol, isolSym );
+
+      if( (isPi0 ) || (m_bkg && isBkg ) ){
+
+        const auto prs2 = fixup(m_toPrs)->energy ( *p2 , "Prs"  );
+        const auto spd2 = fixup(m_toSpd)->multiplicity ( *p2 , "Spd");
+        const auto spd  = (spd1>0)*2 + (spd2>0)*1;
+        const auto pi0m = isPi0 ? pi0.mass() : 0.;
+        const auto bkgm = isBkg ? bkg.mass() : 0.;
+        const auto  typ = (isPi0)*1 + (isBkg)*2;
+        const auto c2   = position4d(cl2);
+        const auto pos2 = position3d(cl2);
+        const auto cc2  = normalize(pos2)   * cl2->e();
+        const auto ccc2 = normalize(point2) * cl2->e();
+
+        // cluster mass
+        const auto cc     = cc1 + cc2;
+        const auto ccc    = ccc1 + ccc2;
+        const auto ccmas  = (isPi0) ? cc.mass()  : 0;
+        const auto cccmas = (isPi0) ? ccc.mass() : 0;
+
+        if(m_counterStat->isQuiet()) counter("candidates for #PV="+ Gaudi::Utils::toString(nVert) + " ["+ inputLocation<3>()+"]")+=1;
+
+        // Write tuple on-demand
+        if( m_tuple ){
+          auto ntp = nTuple(500, "pi0_tupling", CLID_ColumnWiseTuple);
+          ntp->column( "p1"     , v1      );
+          ntp->column( "p2"     , v2      );
+          ntp->column( "r1"     , point1  );
+          ntp->column( "r2"     , point2  );
+          ntp->column( "prs1"   , prs1    );
+          ntp->column( "prs2"   , prs2    );
+          ntp->column( "spd"    , spd     );
+          ntp->column( "id1"    , id1.index() );
+          ntp->column( "id2"    , id2.index() );
+          ntp->column( "cl1"    , c1      );
+          ntp->column( "cl2"    , c2      );
+          ntp->column( "mass"   , pi0m    );
+          ntp->column( "type"   , typ     );
+          ntp->column( "p"      , pi0     );
+          ntp->column( "clmass" , ccmas   );
+          ntp->column( "clEmass", cccmas  );
+          if(m_bkg)ntp->column("bkg",bkgm );
+          // odin info
+          ntp->column("run"   , run         );
+          ntp->column("event" , (double) evt );
+          ntp->column("triggertype", tty );
+          // #vertices
+          ntp->column("Nvertices", nVert);
+          // #SpdMult
+          ntp->column("spdMult", nSpd);
+          ok = ntp->write().isSuccess();
+        }
+        if( !isPi0 ) continue;
+        // histograms for tuning
+        if( m_histo ){
+          hTuning("Cluster"  , nSpd, spd, prs1, prs2, ccc1, id1, ccc2, id2, nVert );
+          hTuning("Corrected", nSpd, spd, prs1, prs2, v1  , id1, v2  , id2, nVert );
+        }
+        if( m_trend && spd == 0){
+          std::string sNpv = "PV" + Gaudi::Utils::toString( nVert ) +"/";
+          std::string sRun =  "r" + Gaudi::Utils::toString( run   ) +"/";
+          std::string base = "Trend/";
+          plot1D(pi0m, base+"allPV/allRun/mass" ,"di-photon mass spectrum for all run & allPV"     , m_hMin, m_hMax, m_hBin);
+          plot1D(pi0m, base+"allPV/"+sRun+"mass","di-photon mass spectrum for all PV & run = "+sRun, m_hMin, m_hMax, m_hBin);
+          if(id1.area() == id2.area()){
+            const auto sarea = id1.areaName() ;
+            plot1D(pi0m, base+"allPV/"+sRun+sarea,"di-photon mass spectrum for all PV & run = "+sRun, m_hMin, m_hMax, m_hBin);
+          }
+          plot1D(pi0m, base+sNpv+sRun+"mass","di-photon mass spectrum for PV="+sNpv+" (run = "+sRun+")", m_hMin, m_hMax, m_hBin);
+          plot1D(pi0m, base+sNpv+"allRun/mass","di-photon mass spectrum for PV="+sNpv+" (all run)"     , m_hMin, m_hMax, m_hBin);
+        }
+      }
+    }
+  }
+  if(ok && m_counterStat->isQuiet()) counter("Events in tuple") += 1;
+  else Warning("Error with ntupling", StatusCode::SUCCESS).ignore();
+  return;
+}
+
+//==============================================================================
+
+void CaloFuturePi0Ntp::hTuning(std::string base, int event_nSpd, int spd, double prs1, double prs2,
+                         const Gaudi::LorentzVector c1, const LHCb::CaloCellID id1,
+                         const Gaudi::LorentzVector c2, const LHCb::CaloCellID id2,int nVert) const {
+
+
+  std::string s1 = id1.areaName() ;
+  std::string s2 = id2.areaName() ;
+  std::string sarea = ( id1.area() > id2.area() )? s1+s2 : s2+s1;
+  // log(E) bins
+  int ble1 = int( (log( c1.e() )/m_leBin) );
+  int ble2 = int( (log( c2.e() )/m_leBin) );
+  // Et bins
+  int bet1 = int( c1.Pt() / m_etBin );
+  int bet2 = int( c2.Pt() / m_etBin );
+  // theta bins
+  int bth1 = int( c1.Theta() / m_thBin/pow(2.,(double)2-id1.area() ));
+  int bth2 = int( c2.Theta() / m_thBin/pow(2.,(double)2-id2.area() ));
+
+  // spd bins
+  int spdslot = int( event_nSpd / m_spdBin );
+
+  std::string sspd;
+  if ( spd==0 ) sspd = "gg";
+  else if (spd==1 || spd == 2) sspd = "gee";
+  else if( spd==3) sspd = "eeee";
+
+  int prs = 0;
+  if( prs1 > 5)prs += 1;
+  if( prs2 > 5)prs += 1;
+
+  const std::string sprs = "prs" + Gaudi::Utils::toString( prs );
+
+  const auto di = c1+c2;
+
+  // pi0->gg versus nPV
+  std::string sVert = "PV" + Gaudi::Utils::toString( nVert );
+  plot1D(di.mass(), base+"/"+sVert+"/all" , base+"/all  #PV="+Gaudi::Utils::toString( nVert ) , m_hMin, m_hMax, m_hBin);
+  plot1D(di.mass(), base+"/"+sVert+"/"+sspd+"/all" ,
+         base+"/"+sspd+"/all  #PV="+Gaudi::Utils::toString( nVert ) , m_hMin, m_hMax, m_hBin);
+  const double Y1 = m_calo->cellCenter( id1 ).Y();
+  const double Y2 = m_calo->cellCenter( id2 ).Y();
+  if( fabs(Y1)<300 && fabs(Y2)<300){
+    plot1D(di.mass(), base+"/"+sVert+"/band" , base+"/band  #PV="+Gaudi::Utils::toString( nVert ) , m_hMin, m_hMax, m_hBin);
+    plot1D(di.mass(), base+"/"+sVert+"/"+sspd+"/band" ,
+           base+"/"+sspd+"/band  #PV="+Gaudi::Utils::toString( nVert ) , m_hMin, m_hMax, m_hBin);
+  }
+
+  // pi0->gg versus spdMult
+  std::string nSpd = "Spd" + Gaudi::Utils::toString( spdslot*m_spdBin );
+  plot1D(di.mass(), base+"/"+nSpd+"/all" , base+"/all  #Spd="+Gaudi::Utils::toString( spdslot*m_spdBin ),m_hMin,m_hMax,m_hBin);
+  plot1D(di.mass(), base+"/"+nSpd+"/"+sspd+"/all" ,
+         base+"/"+sspd+"/all  #Spd="+Gaudi::Utils::toString( spdslot*m_spdBin ),m_hMin,m_hMax,m_hBin);
+
+  if( fabs(Y1)<300 && fabs(Y2)<300){
+    plot1D(di.mass(),base+"/"+nSpd+"/band",base+"/band  #Spd="+Gaudi::Utils::toString( spdslot*m_spdBin ),m_hMin,m_hMax,m_hBin);
+    plot1D(di.mass(),base+"/"+nSpd+"/"+sspd+"/band",
+           base+"/"+sspd+"/band  #Spd="+Gaudi::Utils::toString( spdslot*m_spdBin ),m_hMin,m_hMax,m_hBin);
+  }
+
+  // highPt selection
+  if( spd == 0 && di.Pt() > 2000 && c1.Pt()>800 && c2.Pt() >800)
+    plot1D(di.mass(), base+"/all_highPt_sel1" , base+"/all highPt  sel1 spd == 0" , m_hMin, m_hMax, m_hBin);
+  if( spd == 0 &&  ((c1.Pt()>1050 && c2.Pt() >250) || (c2.Pt()>1050 && c1.Pt() >250)) )
+    plot1D(di.mass(), base+"/all_highPt_sel2" , base+"/all highPt sel2 spd == 0" , m_hMin, m_hMax, m_hBin);
+
+
+  plot1D(di.mass(), base+"/all" , base+"/all" , m_hMin, m_hMax, m_hBin);
+  plot1D(di.mass(), base+"/"+sarea+"/all" , base+"/"+sarea+"/all" , m_hMin, m_hMax, m_hBin);
+  plot1D(di.mass(), base+"/"+sarea+"/"+sspd+"/all" , base+"/"+sarea+"/"+sspd+"/all" , m_hMin, m_hMax, m_hBin);
+  plot1D(di.mass(), base+"/"+sarea+"/"+sspd+"/"+sprs+"/all" , base+"/"+sarea+"/"+sspd+"/"+sprs+"/all" , m_hMin, m_hMax, m_hBin);
+
+
+  std::string u  = base +"/" + sarea +"/"+ sspd +"/" + sprs +"/Energy/all";
+  std::string u1 = base +"/" + sarea +"/"+ sspd +"/" + sprs +"/Energy/b"+Gaudi::Utils::toString( (double) ble1 * m_leBin );
+  std::string u2 = base +"/" + sarea +"/"+ sspd +"/" + sprs +"/Energy/b"+Gaudi::Utils::toString( (double) ble2 * m_leBin );
+  plot1D( di.mass(), u1 , u1 , m_hMin, m_hMax, m_hBin);
+  if( u2 != u1 ) plot1D( di.mass(), u2,u2,m_hMin, m_hMax, m_hBin );
+  plot1D( di.mass(), u , u , m_hMin, m_hMax, m_hBin);
+
+  if( (prs1 < 5 && spd == 0 ) || (prs2<5 && spd == 0 ) ){
+    std::string tu = base +"/" + sarea +"/EcalTuning/Energy/";
+    std::string bin;
+    if( prs1 < 5 )bin = Gaudi::Utils::toString( (double) ble1*m_leBin );
+    else if( prs2<5 )bin = Gaudi::Utils::toString( (double) ble2*m_leBin );
+    plot1D( di.mass(), tu+bin  , tu+bin  , m_hMin, m_hMax, m_hBin );
+    plot1D( di.mass(), tu+"all", tu+"all", m_hMin, m_hMax, m_hBin );
+  }
+
+
+  std::string uu  = base +"/" + sarea +"/"+ sspd +"/" + sprs +"/Pt/all";
+  std::string uu1 = base +"/" + sarea +"/"+ sspd +"/" + sprs +"/Pt/b"+Gaudi::Utils::toString( (double) bet1 * m_etBin );
+  std::string uu2 = base +"/" + sarea +"/"+ sspd +"/" + sprs +"/Pt/b"+Gaudi::Utils::toString( (double) bet2 * m_etBin );
+  plot1D( di.mass(), uu1 , uu1 , m_hMin, m_hMax, m_hBin);
+  if( uu2 != uu1) plot1D( di.mass(), uu2,uu2,m_hMin, m_hMax, m_hBin);
+  plot1D( di.mass(), uu , uu , m_hMin, m_hMax, m_hBin);
+  if( (prs1 < 5 && spd == 0) || (prs2<5 && spd == 0) ){
+    std::string tu = base +"/" + sarea +"/EcalTuning/Pt/";
+    std::string bin;
+    if( prs1 < 5 ) bin = Gaudi::Utils::toString( (double) bet1*m_etBin );
+    else if( prs2<5 ) bin = Gaudi::Utils::toString( (double) bet2*m_etBin );
+    plot1D( di.mass(), tu+bin  , tu+bin  , m_hMin, m_hMax, m_hBin );
+    plot1D( di.mass(), tu+"all", tu+"all", m_hMin, m_hMax, m_hBin );
+  }
+
+
+  std::string uuu  = base +"/" + sarea +"/"+ sspd +"/" + sprs + "/Theta/all";
+  std::string uuu1 = base +"/" + sarea +"/"+ sspd +"/" + sprs +
+    "/Theta/b"+Gaudi::Utils::toString( (double) bth1 * m_thBin*pow(2.,(double)2-id1.area()));
+  std::string uuu2 = base +"/" + sarea +"/"+ sspd +"/" + sprs +
+    "/Theta/b"+Gaudi::Utils::toString( (double) bth2 * m_thBin*pow(2.,(double)2-id2.area()));
+  plot1D( di.mass(), uuu1 , uuu1 , m_hMin, m_hMax, m_hBin);
+  if( uu2 != uu1) plot1D( di.mass(), uuu2,uuu2,m_hMin, m_hMax, m_hBin);
+  plot1D( di.mass(), uuu , uuu , m_hMin, m_hMax, m_hBin);
+  if( (prs1 < 5 && spd == 0) || (prs2<5 && spd == 0  ) ){
+    std::string tu = base +"/" + sarea +"/EcalTuning/Theta/";
+    std::string bin;
+    if( prs1 < 5  )bin = Gaudi::Utils::toString( (double)  bth1 * m_thBin*pow(2.,(double) 2-id1.area()) );
+    else if( prs2<5 )bin = Gaudi::Utils::toString( (double) bth2 * m_thBin*pow(2.,(double) 2-id2.area()) );
+    plot1D( di.mass(), tu+bin  , tu+bin  , m_hMin, m_hMax, m_hBin );
+    plot1D( di.mass(), tu+"all", tu+"all", m_hMin, m_hMax, m_hBin );
+  }
+}
diff --git a/CaloFuture/CaloFutureMoniDst/src/CaloFuturePi0Ntp.h b/CaloFuture/CaloFutureMoniDst/src/CaloFuturePi0Ntp.h
new file mode 100644
index 0000000000000000000000000000000000000000..023bab7fcef4fc52b6c505f36761331b82086b0b
--- /dev/null
+++ b/CaloFuture/CaloFutureMoniDst/src/CaloFuturePi0Ntp.h
@@ -0,0 +1,70 @@
+// Includes
+#include "GaudiAlg/Consumer.h"
+#include "GaudiAlg/GaudiTupleAlg.h"
+#include "GaudiKernel/IEventTimeDecoder.h"
+#include "Event/L0DUReport.h"
+#include "Event/ODIN.h"
+#include "Event/RecVertex.h"
+#include "CaloDet/DeCalorimeter.h"
+#include "CaloFutureInterfaces/ICaloFutureHypo2CaloFuture.h"
+#include "CaloFutureInterfaces/IFutureCounterLevel.h"
+
+// List of Consumers dependencies
+namespace {
+  using ODIN = LHCb::ODIN;
+  using L0 = LHCb::L0DUReport;
+  using Hypos = LHCb::CaloHypo::Container;
+  using Vertices = LHCb::RecVertices;
+}
+
+// =============================================================================
+
+class CaloFuturePi0Ntp final
+: public Gaudi::Functional::Consumer<void(const ODIN&, const L0&, const Hypos&, const Vertices&),
+    Gaudi::Functional::Traits::BaseClass_t<GaudiTupleAlg>>
+{
+public:
+  /// standard algorithm initialization
+  CaloFuturePi0Ntp( const std::string& name, ISvcLocator* pSvcLocator );
+  StatusCode initialize() override;
+  void operator()(const ODIN&, const L0&, const Hypos&, const Vertices&) const override;
+
+private:
+  void hTuning(std::string, int, int, double, double,
+               const Gaudi::LorentzVector, const LHCb::CaloCellID ,
+               const Gaudi::LorentzVector, const LHCb::CaloCellID , int nVert) const;
+
+  // Tools
+  DeCalorimeter* m_calo = nullptr;
+  ToolHandle<IFutureCounterLevel> m_counterStat { "FutureCounterLevel" };
+  ToolHandle<IEventTimeDecoder> m_odin    { "OdinTimeDecoder/OdinDecoder", this };
+  ToolHandle<ICaloFutureHypo2CaloFuture> m_toSpd      { "CaloFutureHypo2CaloFuture/CaloFutureHypo2Spd" , this };
+  ToolHandle<ICaloFutureHypo2CaloFuture> m_toPrs      { "CaloFutureHypo2CaloFuture/CaloFutureHypo2Prs" , this };
+
+  Gaudi::Property<std::pair<double,double>> m_ppt
+    {this, "PhotonPt", {250., 15000.}};
+
+  Gaudi::Property<std::pair<double,double>> m_isol
+    {this, "Isolation", {0., 9999.}, "Warning: a cut biases the pi0 mass"};
+
+  Gaudi::Property<std::pair<int   , int>>    m_conv { this, "Conversion", { 1   , 1}};
+  Gaudi::Property<std::pair<double, double>> m_prsE { this, "PrsE"      , { 0.  , 9999.}};
+  Gaudi::Property<std::pair<double, double>> m_pt   { this, "Pt"        , { 200., 15000}};
+  Gaudi::Property<std::pair<double, double>> m_e    { this, "E"         , { 0.  , 500000}};
+  Gaudi::Property<std::pair<double, double>> m_mass { this, "Mass"      , { 50. , 900.}};
+
+  Gaudi::Property<float>  m_leBin {this, "leBin", 0.25};
+  Gaudi::Property<float>  m_etBin {this, "etBin", 150.};
+  Gaudi::Property<float>  m_thBin {this, "thBin", 0.005};
+
+  Gaudi::Property<float> m_hMin    { this, "hMin"      , 0.};
+  Gaudi::Property<float> m_hMax    { this, "hMax"      , 900.};
+  Gaudi::Property<int>   m_hBin    { this, "hBin"      , 450};
+  Gaudi::Property<int>   m_spdBin  { this, "spdBin"    , 50};
+  Gaudi::Property<bool>  m_tuple   { this, "Tuple"     , true};
+  Gaudi::Property<bool>  m_histo   { this, "Histo"     , true};
+  Gaudi::Property<bool>  m_trend   { this, "Trend"     , false};
+  Gaudi::Property<bool>  m_usePV3D { this, "UsePV3D"   , false};
+  Gaudi::Property<bool>  m_bkg     { this, "Background", false};
+
+};
diff --git a/CaloFuture/CaloFutureMoniDst/src/CaloFutureProtoElectronMonitor.cpp b/CaloFuture/CaloFutureMoniDst/src/CaloFutureProtoElectronMonitor.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7eef17de49bbeea6356826b236ae96c92a6ab659
--- /dev/null
+++ b/CaloFuture/CaloFutureMoniDst/src/CaloFutureProtoElectronMonitor.cpp
@@ -0,0 +1,219 @@
+// Includes
+#include "CaloFutureUtils/CaloMomentum.h"
+#include "CaloFutureProtoElectronMonitor.h"
+
+namespace {
+  /// hack to allow for tools with non-const interfaces...
+  template <typename IFace>
+  IFace* fixup(const ToolHandle<IFace>& iface) { return &const_cast<IFace&>(*iface); }
+}
+//-----------------------------------------------------------------------------
+// Implementation file for class : CaloFutureProtoElectronMonitor
+//
+// 2009-12-11 : Olivier Deschamps
+//-----------------------------------------------------------------------------
+
+// Declaration of the Algorithm Factory
+DECLARE_COMPONENT( CaloFutureProtoElectronMonitor )
+
+
+//==============================================================================
+// Standard constructor, initializes variables
+//==============================================================================
+
+CaloFutureProtoElectronMonitor::CaloFutureProtoElectronMonitor( const std::string& name,
+                                                    ISvcLocator* pSvcLocator)
+: Consumer( name , pSvcLocator,
+    KeyValue{ "Input", LHCb::ProtoParticleLocation::Charged }
+)
+{
+  declareProperty("ExtrapolatorType"  , m_extrapolator ) ;
+
+  // Protected vars in parent
+  m_massFilterMax = 100;
+  m_multMax = 100;
+  m_massMin = 0;
+  m_massMax = 5000;
+  m_massBin = 500;
+}
+
+//==============================================================================
+// Initialization
+//==============================================================================
+
+StatusCode CaloFutureProtoElectronMonitor::initialize() {
+  StatusCode sc = Consumer::initialize(); // must be executed first
+  if ( sc.isFailure() ) return sc;  // error printed already by GaudiAlgorithm
+
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) debug() << "==> Initialize" << endmsg;
+
+  if( !m_tracks.empty() )info() << "Will only look at track type(s) = " << m_tracks.value() << endmsg;
+  else
+    info() << "Will look at any track type" << endmsg;
+
+  // Get, retrieve, configure tools
+  if(!( m_caloElectron.retrieve() && m_extrapolator.retrieve() )){
+    error() << "Unable to retrive one of the ToolHandles" << endmsg;
+    return StatusCode::FAILURE;
+  }
+
+  // histograms
+  hBook1(  "1", "# of CaloElectron protoP   " + inputLocation(),  m_multMin   ,    m_multMax   , m_multBin  );
+  hBook1(  "2", "CaloElectron protoP Energy   " + inputLocation(),  m_energyMin ,    m_energyMax , m_energyBin );
+  hBook1(  "3", "CaloElectron protoP Pt       " + inputLocation(),  m_etMin     ,    m_etMax     , m_etBin);
+  hBook2(  "4", "CaloElectron protoP barycenter position x vs y   "
+           + inputLocation(),  m_xMin, m_xMax, m_xBin, m_yMin, m_yMax, m_yBin);
+  hBook2(  "5", "Energy-weighted CaloElectron protoP  barycenter position x vs y "
+           + inputLocation(),m_xMin,m_xMax, m_xBin, m_yMin, m_yMax, m_yBin);
+  hBook1(  "6", "e/p  " + inputLocation(),  m_eOpMin ,    m_eOpMax , m_eOpBin );
+  hBook1(  "7", "Eprs  " + inputLocation(),  0. , 300. , m_energyBin );
+  if( m_pairing ){
+    hBook1(  "8", "m(track pair)  " + inputLocation()  ,  m_massMin   , m_massMax  ,  m_massBin );
+    hBook1(  "9", "m(clust pair)  " + inputLocation()  ,  m_massMin   , m_massMax  ,  m_massBin );
+    hBook1(  "10", "e/p for M(ee) < " + Gaudi::Utils::toString(m_massFilterMax)
+             + inputLocation(),  m_eOpMin ,    m_eOpMax , m_eOpBin );
+  }
+  return StatusCode::SUCCESS;
+}
+
+//==============================================================================
+// Main execution
+//==============================================================================
+
+bool CaloFutureProtoElectronMonitor::valid_track(const LHCb::ProtoParticle* proto) const {
+  // Return false if the proto's track fails to meet requested track type
+  if(m_tracks.empty()) return true;
+  const auto ptype = (int) proto->track()->type();
+  auto valid = [ptype](const auto trtype){return ptype==trtype;};
+  return std::any_of( std::begin(m_tracks), std::end(m_tracks), valid );
+}
+
+void CaloFutureProtoElectronMonitor::operator()(const Input& protos) const {
+
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) debug() << "==> Execute" << endmsg;
+  if ( !produceHistos() ) return;
+
+  initFutureCounters();
+
+  // Loop over protoparticles
+  for( auto p = protos.begin(); protos.end() != p ; ++p ){
+    const auto proto = *p;
+
+    // Abort if track type mismatched
+    if( !valid_track(proto) ) continue;
+
+    // Abort if electron casting fail
+    if( !fixup(m_caloElectron)->set(proto)) continue;
+
+    // Abort if null hypo
+    const auto hypo = fixup(m_caloElectron)->electron();
+    if ( hypo == nullptr ) continue;
+
+    // Abort if energy too low
+    LHCb::CaloMomentum momentum( hypo );
+    const double e    = momentum.e();
+    const double et   = momentum.pt();
+    if( e < m_eFilter ) continue;
+    if( et < m_etFilter ) continue;
+    const double ePrs = proto->info(LHCb::ProtoParticle::additionalInfo::CaloPrsE, 0.);
+    if( m_prsCut > 0 && ePrs < m_prsCut ) continue;
+
+    // Retrieve the seed id
+    auto id = LHCb::CaloCellID();
+    if ( hypo->clusters().size() > 0 ){
+      SmartRef<LHCb::CaloCluster> cluster = *(hypo->clusters().begin());
+      id = cluster->seed();
+    }
+    double eOp = fixup(m_caloElectron)->eOverP();
+
+    // Fill histograms
+    count(id);
+    hFill1(id, "2", e  );
+    hFill1(id, "3", et );
+    const auto position = hypo->position();
+    if( position != nullptr ){
+      hFill2(id, "4", position->x(),position->y() );
+      hFill2(id, "5", position->x(),position->y() , e);
+    }
+    hFill1(id, "6", eOp );
+    hFill1(id, "7", ePrs );
+
+    // perform electron pairing
+    if( !m_pairing ) continue;
+
+    // For electron paring, need an extrapolator tool before continuing
+    if( m_extrapolator == 0 ){
+      Warning("No extrapolator defined").ignore();
+      continue;
+    }
+
+    // Loop over second electron
+    for( auto pp = p+1 ; protos.end() != pp ; ++pp ){
+      const auto proto2 = *pp;
+
+      // Abort if track type mismatched
+      if( !valid_track(proto2) ) continue;
+
+      // Abort if fail hypo, or duplicate
+      if( !fixup(m_caloElectron)->set(proto2) ) continue;;
+      const auto hypo2 = fixup(m_caloElectron)->electron();
+      if ( hypo2 == nullptr ) continue;
+      if( hypo == hypo2 ) continue;
+
+      // filtering proto2
+      LHCb::CaloMomentum momentum2( hypo2 );
+      const double e2 = momentum2.e();
+      const double et2 = momentum2.pt();
+      if(e2 < m_eFilter) continue;
+      if(et2 < m_etFilter) continue;
+      const double ePrs2 = proto2->info(LHCb::ProtoParticle::additionalInfo::CaloPrsE, 0.);
+      if( m_prsCut > 0 &&  ePrs2 < m_prsCut )continue;
+
+      // Combine hypo
+      LHCb::CaloMomentum momentumSum( hypo );
+      momentumSum.addCaloPosition( hypo2 );
+      const double caloM = momentumSum.mass();
+
+      // Validate tracks
+      const auto t1 = proto->track();
+      const auto t2 = proto2->track();
+      if( t1 == nullptr || t2 == nullptr ) continue;
+      if( t1->charge()*t2->charge() != -1 ) continue;
+      auto st1 = t1->firstState();
+      auto st2 = t2->firstState();
+
+
+      // bool accept2 = m_tracks.empty() ? true : false;
+      // for(std::vector<int>::iterator itr = m_tracks.begin();m_tracks.end() != itr;++itr){
+      //   if( (int)t2->type() == *itr)accept2=true;
+      // }
+      // if( !accept2 )continue;
+
+      // Propagation
+      StatusCode sc = m_extrapolator->propagate(st1, 0.);
+      if(sc.isFailure()) Warning("Propagation 1 failed").ignore();
+      sc = m_extrapolator->propagate(st2, 0.);
+      if(sc.isFailure()) Warning("Propagation 2 failed").ignore();
+
+      // Finally, fill the histos
+      const auto p1 = st1.momentum();
+      const auto p2 = st2.momentum();
+      double m2 = p1.R()*p2.R();
+      m2 -= p1.X()*p2.X();
+      m2 -= p1.Y()*p2.Y();
+      m2 -= p1.Z()*p2.Z();
+      m2 *= 2;
+      const double m = (m2>0) ? sqrt(m2) : 0;
+      hFill1(id, "8", m );
+      hFill1(id, "9", caloM );
+      if( m2 < m_massFilterMax ){
+        hFill1(id, "10", eOp );
+        const double eOp2 = fixup(m_caloElectron)->eOverP();
+        hFill1(id, "10", eOp2 );
+      }
+    }
+  }
+  fillFutureCounters("1");
+  return;
+}
+//=============================================================================
diff --git a/CaloFuture/CaloFutureMoniDst/src/CaloFutureProtoElectronMonitor.h b/CaloFuture/CaloFutureMoniDst/src/CaloFutureProtoElectronMonitor.h
new file mode 100644
index 0000000000000000000000000000000000000000..968fde0fe9354a0ce61d010f57ecfe1ab9cd9067
--- /dev/null
+++ b/CaloFuture/CaloFutureMoniDst/src/CaloFutureProtoElectronMonitor.h
@@ -0,0 +1,61 @@
+#ifndef CALOFUTUREPROTOELECTRONMONITOR_H
+#define CALOFUTUREPROTOELECTRONMONITOR_H 1
+
+// Includes
+#include "GaudiAlg/Consumer.h"
+#include "Event/ProtoParticle.h"
+#include "CaloFutureUtils/ICaloFutureElectron.h"
+#include "TrackInterfaces/ITrackExtrapolator.h"
+#include "CaloFutureMoniAlg.h"
+
+namespace {
+  using Input = LHCb::ProtoParticles;
+}
+
+/** @class CaloFutureProtoElectronMonitor CaloFutureProtoElectronMonitor.h
+ *
+ *
+ *  @author Olivier Deschamps
+ *  @date   2009-12-11
+ */
+class CaloFutureProtoElectronMonitor final
+: public Gaudi::Functional::Consumer<void(const Input&),
+    Gaudi::Functional::Traits::BaseClass_t<CaloFutureMoniAlg>>
+{
+public:
+  /// Standard constructor
+  CaloFutureProtoElectronMonitor( const std::string& name, ISvcLocator* pSvcLocator );
+  StatusCode initialize() override;
+  void operator()(const Input&) const override;
+
+  /// C++11 non-copyable idiom
+  CaloFutureProtoElectronMonitor( const CaloFutureProtoElectronMonitor& ) = delete;
+  CaloFutureProtoElectronMonitor &operator=( const CaloFutureProtoElectronMonitor& ) = delete;
+
+private:
+  ToolHandle<ICaloFutureElectron>      m_caloElectron { "CaloFutureElectron", this };
+  ToolHandle<ITrackExtrapolator> m_extrapolator { "TrackRungeKuttaExtrapolator/Extrapolator", this };
+
+  bool valid_track(const LHCb::ProtoParticle* proto) const;
+
+  Gaudi::Property<float> m_eOpMin
+    {this, "HistoEoPMin", 0.};
+
+  Gaudi::Property<float> m_eOpMax
+    {this, "HistoEoPMax", 3.};
+
+  Gaudi::Property<int> m_eOpBin
+    {this, "HistoEoPBin", 100};
+
+  Gaudi::Property<float> m_prsCut
+    {this, "PrsCut", 50.* Gaudi::Units::MeV};
+
+  Gaudi::Property<bool> m_pairing
+    {this, "ElectronPairing", false};
+
+  Gaudi::Property<std::vector<int>> m_tracks
+    {this, "TrackTypes", 
+    {LHCb::Track::Types::Long, LHCb::Track::Types::Downstream}};
+
+};
+#endif // CALOFUTUREPROTOELECTRONMONITOR_H
diff --git a/CaloFuture/CaloFutureMoniDst/src/L0CaloFutureScale.cpp b/CaloFuture/CaloFutureMoniDst/src/L0CaloFutureScale.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ae2d861155cd52da75273f63b141ca99992487a6
--- /dev/null
+++ b/CaloFuture/CaloFutureMoniDst/src/L0CaloFutureScale.cpp
@@ -0,0 +1,163 @@
+// Includes
+#include "GaudiAlg/Consumer.h"
+#include "CaloDet/DeCalorimeter.h"
+#include "Event/CaloHypo.h"
+#include "Event/CaloDataFunctor.h"
+#include "Event/L0CaloCandidate.h"
+#include "Event/L0DUBase.h"
+#include "CaloFutureUtils/CaloMomentum.h"
+#include "CaloFutureUtils/CaloFutureAlgUtils.h"
+#include "CaloFutureMoniAlg.h"
+
+// ============================================================================
+
+namespace {
+  using Input = LHCb::CaloHypo::Container;
+  using Inputs = LHCb::L0CaloCandidates;
+
+  // Return True if this candidate match with the reference cellID
+  bool l0calo_match( const LHCb::CaloCellID& id, const LHCb::L0CaloCandidate* cand ){
+    const auto l0id = cand->id();
+    // abort if area mismatched
+    if( l0id.area() != id.area() || abs((int)l0id.row()-(int)id.row())>1 || abs((int)l0id.col()-(int)id.col())>1)
+      return false;
+    // abort if type mismatched
+    const auto type = cand->type();
+    if( type != L0DUBase::CaloType::Electron && type != L0DUBase::CaloType::Photon)
+      return false;
+    // This is the one, stop search
+    return true;
+  }
+}
+
+//------------------------------------------------------------------------------
+
+class L0CaloFutureScale final
+: public Gaudi::Functional::Consumer<void(const Input&, const Inputs&),
+    Gaudi::Functional::Traits::BaseClass_t<CaloFutureMoniAlg>>
+{
+public:
+  /// standard algorithm initialization
+  StatusCode initialize() override;
+  void operator()(const Input&, const Inputs&) const override;
+
+  L0CaloFutureScale( const std::string &name, ISvcLocator *pSvcLocator );
+
+private:
+  Gaudi::Property<int>   m_ratBin { this, "RatioMin", 0.2};
+  Gaudi::Property<float> m_ratMax { this, "RatioMax", 1.7};
+  Gaudi::Property<float> m_ratMin { this, "RatioBin", 150};
+
+  DeCalorimeter* m_ecal = nullptr;
+};
+
+// =============================================================================
+
+DECLARE_COMPONENT( L0CaloFutureScale )
+
+// =============================================================================
+
+L0CaloFutureScale::L0CaloFutureScale( const std::string &name, ISvcLocator *pSvcLocator )
+: Consumer( name, pSvcLocator, {
+    KeyValue{ "Input" , "" },
+    KeyValue{ "Inputs", LHCb::L0CaloCandidateLocation::Full },
+})
+{
+  /*
+  * During genconf.exe, the default name "DefaultName" is not well-supported
+  * by the CaloFutureAlgUtils, returning the null string "" as a location path,
+  * which will raise exception in `updateHandleLocation` --> `setProperty`.
+  * To get around this, the location will only be updated outside the genconf.
+  */
+  if( name != "DefaultName" ){
+    const auto Input = LHCb::CaloFutureAlgUtils::CaloFutureHypoLocation( name , context() );
+    updateHandleLocation( *this, "Input", Input );
+  }
+}
+
+// =============================================================================
+
+StatusCode L0CaloFutureScale::initialize(){
+  StatusCode sc = Consumer::initialize(); // must be executed first
+  if ( sc.isFailure() ) return sc; // error already printedby GaudiAlgorithm
+  hBook1(  "0", "matched L0Calo type " + inputLocation(),  0   ,    2   , 2  );
+  h1binLabel("0",1,"L0Electron");
+  h1binLabel("0",2,"L0Photon");
+
+  hBook1(  "1", "L0Calo(Et)/CaloHypo(Et) " + inputLocation(),  m_ratMin   ,    m_ratMax   , m_ratBin  );
+  hBook1(  "2", "L0Calo(Et)/CaloCluster(Et) " + inputLocation(),  m_ratMin   ,    m_ratMax   , m_ratBin  );
+  hBook1(  "3", "CaloCluster/CaloHypo(Et) " + inputLocation(),  m_ratMin   ,    m_ratMax   , m_ratBin  );
+  m_ecal = getDet<DeCalorimeter>( DeCalorimeterLocation::Ecal );
+  return StatusCode::SUCCESS;
+}
+
+
+// =============================================================================
+
+void L0CaloFutureScale::operator()(const Input& hypos, const Inputs& candidates) const {
+
+  // produce histos ?
+  if ( !produceHistos() ) return;
+
+  // check data
+  if ( hypos.empty() ){
+    if( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+      debug() << "Found empty hypos at " << inputLocation() << endmsg;
+    return; // StatusCode::SUCCESS;
+  }
+
+  // Begin loop
+  initFutureCounters();
+  for( const auto& hypo: hypos ){
+
+    // Abort if ET too low
+    LHCb::CaloMomentum momentum( hypo );
+    const double et = momentum.pt();
+    if(et < m_etFilter) continue;
+
+    // Abort if no clusters found
+    if( hypo->clusters().size() == 0 ) continue;
+
+    // Retrieve the first cluster ID
+    // SmartRef<LHCb::CaloCluster> cluster;
+    const auto cluster = *(hypo->clusters().begin());
+    const auto id = cluster->seed();
+
+    // L0Calo matching
+    LHCb::L0CaloCandidate* cand = nullptr;
+    for( auto* cand0: candidates ){
+      // This is the one, stop search
+      if( l0calo_match( id, cand )){
+        cand = cand0;
+        break;
+      }
+    }
+
+    // Abort if not found
+    if( cand == nullptr ){
+      if( m_counterStat->isQuiet()) counter("Matching L0cluster not found")+=1;
+      continue;
+    }
+
+    const auto l0et = cand->etCode();
+    const auto type = cand->type();
+
+    // Calculate & fill histogram
+    if( m_counterStat->isQuiet()) counter("Matching L0type") += type;
+    double hratio = 20.*double(l0et) / et;
+    double cratio = 20.*double(l0et) / (cluster->e() * m_ecal->cellSine( id )) ;
+    double ratio  = (cluster->e() * m_ecal->cellSine( id )) / et;
+
+    count(id);
+    hFill1(id, "0", type    );
+    hFill1(id, "1", hratio  );
+    hFill1(id, "2", cratio  );
+    hFill1(id, "3", ratio   );
+
+    if(doHisto("4"))fillCaloFuture2D("4", id, hratio,  "L0Cluster(Et)/CaloHypo(Et) 2Dview"   );
+    if(doHisto("5"))fillCaloFuture2D("5", id, cratio,  "L0Cluster(Et)/CaloCuster(Et) 2Dview" );
+    if(doHisto("6"))fillCaloFuture2D("6", id, cratio,  "CaloCluster(Et)/CaloHypo(Et) 2Dview" );
+  }
+
+  return;
+}
diff --git a/CaloFuture/CaloFutureMoniDst/src/SpdMonitorFuture.cpp b/CaloFuture/CaloFutureMoniDst/src/SpdMonitorFuture.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9c220b59e0f48d6433a57a4b6381e9c9352c6d23
--- /dev/null
+++ b/CaloFuture/CaloFutureMoniDst/src/SpdMonitorFuture.cpp
@@ -0,0 +1,105 @@
+// Includes
+#include "GaudiAlg/Consumer.h"
+#include "Event/CaloDigit.h"
+#include "CaloDet/DeCalorimeter.h"
+#include "CaloFutureMoniAlg.h"
+
+// using namespace LHCb;
+// using namespace Gaudi::Units;
+
+//==============================================================================
+/** @file
+ *
+ *  Implementation file for class SpdMonitorFuture
+ *
+ *  SPD Monitoring
+ *
+ *  @author Albert Puig apuignav@cern.ch
+ *  @date   2007-15-07
+ */
+//==============================================================================
+
+using Input = LHCb::CaloDigits;
+
+class SpdMonitorFuture final
+: public Gaudi::Functional::Consumer<void(const Input&),
+    Gaudi::Functional::Traits::BaseClass_t<CaloFutureMoniAlg>>
+{
+public:
+  StatusCode initialize() override;
+  StatusCode finalize() override;
+  void operator()(const Input&) const override;
+
+  SpdMonitorFuture( const std::string& name, ISvcLocator* pSvc );
+
+private:
+  DeCalorimeter *m_detSpd = nullptr;
+  CaloVector<int> m_neighN;
+  mutable unsigned int m_nEvents = 0;
+};
+
+//==============================================================================
+
+DECLARE_COMPONENT( SpdMonitorFuture )
+
+//==============================================================================
+
+SpdMonitorFuture::SpdMonitorFuture( const std::string &name, ISvcLocator *pSvcLocator )
+: Consumer( name, pSvcLocator, {
+    KeyValue{ "Input", LHCb::CaloDigitLocation::Spd },
+}){
+  m_split=true;  // Area splitting is the default !
+}
+
+//==============================================================================
+
+StatusCode SpdMonitorFuture::initialize() {
+  StatusCode sc = Consumer::initialize();
+  if (sc.isFailure()) return sc;
+  // Loads the detectors
+  m_detSpd = getDet<DeCalorimeter>( DeCalorimeterLocation::Spd );
+  // Histograms
+  bookCaloFuture2D( "1", "Spd occupancy", "Spd" );
+  bookCaloFuture2D( "2", "Spd neighbor occupancy", "Spd" );
+
+  // Initialize neighbor matrix
+  for(unsigned int cellIt = 0; cellIt != m_detSpd->numberOfCells(); cellIt++){
+    const auto& cell  = m_detSpd->cellIdByIndex(cellIt);
+    const auto& neigh = m_detSpd->zsupNeighborCells(cell);
+    m_neighN.addEntry(neigh.size(), cell);
+  }
+  return StatusCode::SUCCESS;
+}
+
+//==============================================================================
+
+StatusCode SpdMonitorFuture::finalize() {
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) debug() << "==> Finalize" << endmsg;
+  info() << "Number of Events Analyzed : " << m_nEvents << endmsg;
+  return Consumer::finalize() ;
+}
+
+//==============================================================================
+
+void SpdMonitorFuture::operator()(const Input& digitsSpd) const {
+
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) debug() << "==> Execute " << endmsg;
+
+  // Fill histos
+  for(const auto& digit: digitsSpd){
+    if (digit==nullptr) continue;
+    const auto cell = digit->cellID();
+    // histo1
+    if(doHisto("1")) fillCaloFuture2D( "1", cell, 1.0 );
+    // histo2
+    if( doHisto("2") ){
+      const auto neighs = m_detSpd->zsupNeighborCells(cell);
+      for(const auto neighCell: neighs){
+        const auto value = (float) 1./float(m_neighN[cell]);
+        fillCaloFuture2D( "2", neighCell , value );
+      }
+    }
+  }
+  m_nEvents++;
+  return;
+}
diff --git a/CaloFuture/CaloFuturePIDs/CMakeLists.txt b/CaloFuture/CaloFuturePIDs/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..d54a71d36a284aef23ba0130b1f5fdbdfcfbe943
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/CMakeLists.txt
@@ -0,0 +1,29 @@
+################################################################################
+# Package: CaloFuturePIDs
+################################################################################
+gaudi_subdir(CaloFuturePIDs v5r22)
+
+gaudi_depends_on_subdirs(CaloFuture/CaloFutureInterfaces
+                         CaloFuture/CaloFutureUtils
+                         GaudiAlg
+                         Kernel/LHCbKernel
+                         Kernel/LHCbMath
+                         Kernel/Relations
+                         Tr/TrackInterfaces)
+
+find_package(AIDA)
+find_package(Boost)
+
+find_package(Boost)
+find_package(ROOT)
+include_directories(SYSTEM ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS})
+
+gaudi_add_module(CaloFuturePIDs
+                 src/*.cpp
+                 INCLUDE_DIRS AIDA Tr/TrackInterfaces
+                 LINK_LIBRARIES CaloFutureUtils GaudiAlgLib LHCbKernel LHCbMathLib RelationsLib)
+
+gaudi_install_python_modules()
+
+gaudi_env(SET CALOFUTUREPIDSOPTS \${CALOFUTUREPIDSROOT}/options)
+
diff --git a/CaloFuture/CaloFuturePIDs/doc/release.notes b/CaloFuture/CaloFuturePIDs/doc/release.notes
new file mode 100755
index 0000000000000000000000000000000000000000..aadb9f7bedda1ce329627c9cbe89bc38fb25bab3
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/doc/release.notes
@@ -0,0 +1,532 @@
+!------------------------------------------------------------------------------
+! Package     : CaloFuture/CaloFuturePIDs
+! Responsible : Olivier Deschamps odescham@in2p3.fr
+! Purpose     : CaloFuturerimeter PIDs 
+!------------------------------------------------------------------------------
+
+! 2016-08-16 - Olivier Deschamps
+  - implement counter() switch based on FutureCounterLevel tool
+
+!========================= CaloFuturePIDs v5r22 2016-03-17 =========================
+! 2016-03-05 - Olivier Deschamps
+  - CaloFuturePIDs configurable :  add slots to configure the Accepted Track::Types 
+  - src : add counter per track type in match algs
+
+! 2016-02-24 - Olivier Deschamps
+  - fix clang warning in friend declarations of ToolFactory (class->struct)
+
+!========================= CaloFuturePIDs v5r21 2016-01-28 =========================
+! 2016-25-01 - Olivier Deschamps
+ - CaloFuturePhotonMatch,CaloFutureElectronMatch, CaloFutureBremMatch tools : 
+        - move m_position and m_plane data members to the base tool (CaloFutureTrackMatch) and invoke a BeginEvent reset 
+        - this fixes the (rare) initialization issues producing difference in the offline versus online reconstruction
+
+!========================= CaloFuturePIDs v5r20p1 2015-10-13 =========================
+! 2015-08-12 - Gerhard Raven
+ - remove #include of obsolete Gaudi headers
+
+!========================= CaloFuturePIDs v5r20 2014-11-05 =========================
+! 2014-11-04 - Dima Golubkov
+  - CaloFutureElectronMatch : change back to extrapolation to the ZShowerMax plane
+
+!========================= CaloFuturePIDs v5r19 2014-09-08 =========================
+! 2014-07-25 - Dima Golubkov
+  - CaloFutureElectronMatch, CaloFutureBremMatch.cpp, CaloFuturePhotonMatch.cpp : decrease verbosity of tolerable errors to WARNING
+
+! 2014-07-23 - Olivier Deschamps for Dima
+  - CaloFutureElectronMatch : extrapolate the track to the CaloFutureHypo Z position instead of ZShowerMax plane
+
+!========================= CaloFuturePIDs v5r18p1 2014-07-14 ========================
+! 2014-06-27 - Olivier Deschamps
+ - Fix minor typo in a printout
+
+!========================= CaloFuturePIDs v5r18 2014-06-10 =========================
+! 2014-05-28 - Dmitry Golubkov
+ - CaloFutureTrackMatch.h : remove unused i_updateField() declaration
+
+! 2014-05-28 - Marco Cattaneo
+ - Fix some unprotected StatusCodes in CaloFutureTrackMatch.h
+
+!========================= CaloFuturePIDs v5r17 2014-05-13 =========================
+! 2014-05-06 - Marco Cattaneo
+ - Remove debug() from CaloFutureTrackAlg::_setProperty and CaloFutureTrackTool::_setProperty
+   This function is called in the constructor, when the OutputLevel is not initialised
+
+! 2014-04-15 - Oleg Stenyakin
+ - CaloFutureTrackMatch : fix warnings
+
+! 2014-04-14 - Oleg Stenyakin
+ - CaloFutureTrackMatch.{h,cpp} : the X-correction for the e+, e- track-cluster  matching
+   for each zone of the ECAL is added. Parameters of the correction are loaded
+   from the CondDB by default, added protection if the Conditions are missing.
+
+!========================= CaloFuturePIDs v5r16 2014-03-18 =========================
+! 2014-03-06 - Olivier Deschamps
+ -  python/Configuration.py : propagate OutputLevel value to calo sequences only when the property is explicity set
+
+!========================= CaloFuturePIDs v5r15 2013-10-24 =========================
+! 2013-10-09 - Olivier Deschamps
+ -  python/CaloFuturePIDs/*.py : 
+        - possibility to set-up a configuration without active Spd/Prs  (NoSpdPrs = <False> flag)
+        - see CaloFutureReco releases.notes for detail
+
+!========================= CaloFuturePIDs v5r14 2013-06-03 =========================
+! 2013-05-13 - Marco Cattaneo
+ - Fix include paths following previous change
+ - Remove 'do nothing' finalize methods
+
+! 2013-05-10 - Olivier Deschamps
+  - move CaloFutureTrackAlg/Match/Tool.{cpp,h} from CaloFutureUtils
+
+!========================= CaloFuturePIDs v5r13 2012-11-28 =========================
+! 2012-11-22 - Marco Clemencic
+ - Added CMake configuration file.
+
+! 2012-10-17 - Marco Cattaneo
+ - In CaloFutureTrack2IDAlg, return Error from initialize if undefined Input, removes
+   need for Assert in execute
+ - Fix trivial icc remarks
+
+! 2012-10-08 - Marco Cattaneo
+ - In Configuration.py, remove setting of MeasureTime=true in sequencers,
+   should not be the default, and should in any case use TimingAuditor.
+
+!========================= CaloFuturePIDs v5r12 2012-03-27 =========================
+! 2012-03-15 - Marco Cattaneo
+ - Fix unprotected debug() MsgStreams
+ - Fix trivial icc remarks
+ - Fix UNINIT_CTOR defects
+
+!========================= CaloFuturePIDs v5r11 2011-12-15 =========================
+! 2011-12-09 - Olivier Deschamps 
+  - CaloFuturePIDs/PIDs.py : fix external cluster setup
+
+!========================= CaloFuturePIDs v5r10 2011-11-08 =========================
+! 2011-09-30 - Olivier Deschamps for Victor Coco
+  - CaloFuturePhotonMatch : fix Hcal matching setup
+
+!========================= CaloFuturePIDs v5r9 2011-04-27 =========================
+! 2011-04-24 - Olivier Deschamps
+  - update CaloFutureProcessor configurable with 'ExternalClusters' slot
+
+!========================== CaloFuturePIDs v5r8 2010-09-24 ========================
+! 2010-09-20 - Olivier Deschamps
+  - CaloFuturePhotonIdALg :  fix unchecked StatusCode
+
+! 2010-09-01 - Olivier Deschamps
+  - fix compilation warning on windows
+
+! 2010-08-27 - Olivier Deschamps
+  - python/PID.py : new class referencePDF() to feed HistogramDataSvc with default THS PDFs
+  - CaloFuturePhotonIDAlg : simplify using the new CaloFutureHypoEstimator tool
+
+!========================== CaloFuturePIDs v5r7 2010-08-25 ========================
+! 2010-08-17 - Olivier Deschamps
+ - new version of CaloFuturePhotonIDAlg (get data from condDB or THS) from F. Machefert 
+ - python/PIDs.py : remove default hardcoded neutralID PDF
+ - python/Configuration.py : add PIDList to select the PID component(s) to be added to the caloPIDs sequence
+
+
+!========================== CaloFuturePIDs v5r6p1 2010-06-21 ========================
+! 2010-06-04 - Rob Lambert
+ - Fixes for some windows warnings savannah 15808
+
+!========================== CaloFuturePIDs v5r6 2010-05-21 =========================
+! 2010-05-20 - Olivier Deschamps
+ - python/Configuration.py : reduce verbosity
+
+
+! 2010-05-19 - Gerhard Raven
+ - only summarize 'match' errors, do not print (see https://savannah.cern.ch/bugs/?67077) 
+
+!========================== CaloFuturePIDs v5r5 2010-03-19 =========================
+! 2010-03-12 - Dmitry Golubkov
+ - CaloFutureID2DLL - enable CondDB by default, add protection if the Condition is missing
+ - BremPIDeAlg, FutureEcalPIDeAlg, FutureEcalPIDmuAlg, FutureHcalPIDeAlg, FutureHcalPIDmuAlg, FuturePrsPIDeAlg - set default Condition and histogram names
+
+
+! 2010-03-08 - Olivier Deschamps
+ - Configurables : 
+   - adapt to changes in CaloKernel/ConfUtils
+   - make all component context-dependent
+   - add few slots (SkipNeutral, SkipCharged )
+   - add new components for neutral PIDs
+
+
+ - options :
+   - clean options (remove obsolete) -> options directory is now empty
+
+ - src :
+   - new algorithm CaloFuturePhotonIdALg : produce <Hypo,Likelihood> relation table -> NeutralProtoPALg
+      -> remove obsolete CaloFuturePhotonEstimatorTool and CaloFutureSingleGammaTool
+   - use TrackRungeKuttaExtrapolator by default everywhere
+   - add counters to monitor algorithms I/O 
+
+ - TODO : 
+   - CaloFuturePIDsConf : split the sequence by CaloFuturePIDs technique and add PIDsList configuration (to be synchronized with CaloFutureReclo/Processor)
+
+
+! 2010-02-28 - Olivier Deschamps
+  - PhotonMatchAlg : remove forgotten lines overwritting the context dependent TES I/O
+
+!========================== CaloFuturePIDs v5r4 2010-02-15 =========================
+! 2009-11-17 - Olivier Deschamps
+ - PIDs.py : use RungeKutta extrapolator instead of HeraB for HLT processing
+
+! 2010-02-08 - Dmitry Golubkov
+ - CaloFutureID2DLL - optionally read the DLLs from CondDB
+ - cmt/requirements - version incremented to v5r4
+
+!========================== CaloFuturePIDs v5r3 2010-01-21 =========================
+! 2010-01-13 - Marco Cattaneo
+ - Follow Gaudi fix #61116: GaudiCommon::Exception now returns void
+
+!========================== CaloFuturePIDs v5r2 2009-11-13 =========================
+! 2009-11-13 - Rob Lambert
+ - Tagged the package
+
+! 2009-10-30 - Olivier Deschamps
+ 
+ -  fix unchecked StatusCode
+
+
+! 2009-10-30 - Vanya Belyaev
+
+ -  suppress few warnigs 
+
+! 2009-10-25 - Vanya Belyaev
+
+ - add ICaloFutureDigit4Track interface for all <CALOFUTURE>EnergyForTrack tools 
+
+ - CaloFutureEnergyForTrack.cpp
+
+    fix the typo in  property name 
+
+ - cmt/requirements
+   
+     version increment to v5r2 
+
+!========================== CaloFuturePIDs v5r1p1 2009-09-30 =========================
+! 2009-09-30 - Olivier Deschamps
+ - reduce CaloFutureTrackMatchAlg verbosity 
+
+! 2009-09-03 - Olivier Deschamps 
+ - reduce InCaloFutureAcceptance/CaloFutureTrackMatchAlg verbosity when no good tracks found (warning->debug)
+ - add protection against missing inputs
+
+!========================== CaloFuturePIDs v5r1 2009-09-03 =========================
+! 2009-09-03 - Marco Cattaneo
+ - Remove obsolete file src/CaloFuturePIDs_dll.cpp
+
+! 2009-09-01 - Vanya BELYAEV
+ - suppress warnings for consigurables 
+ - cmt/requirements 
+      version increment to v5r1 
+
+!========================== CaloFuturePIDs v5r0 2009-08-31 =========================
+! 2009-08-21 - Olivier Deschamps
+  - implement generic context-dependent TES I/O
+
+! 2009-08-10 - Vanya BELYAEV
+
+ - polish the configurables 
+
+! 2009-08-05 - Vanya BELYAEV
+
+ - add the configurables 
+ - version increment to v5r0 
+
+!========================== CaloFuturePIDs v4r17 2009-05-25 =========================
+! 2009-05-15 - Marco Cattaneo
+ - Fix untested StatusCode on Warning() and Error() calls
+ - Replace endreq with endmsg
+
+!========================== CaloFuturePIDs v4r16 2009-05-08 =========================
+! 2009-04-16 - Olivier Deschamps
+ - fix unchecked StatusCode
+
+!========================== CaloFuturePIDs v4r15 2009-03-11 =========================
+! 2009-03-11 - Victor Egorychev
+ - AddNeigbours in FutureEcalEnergyForTrack and HcalEnrgyForTrack changed to FALSE
+
+!========================== CaloFuturePIDs v4r14p1 2008-01-12 =======================
+! 2008-12-10 - Marco Cattaneo
+ - Fix gcc 4.3 compilation warnings
+
+!========================== CaloFuturePIDs v4r14 2008-11-21 =========================
+! 2008-10-10 - Olivier Deschamps
+ - fix unitialized variable in CaloFutureID2DLL.cpp
+
+!========================== CaloFuturePIDs v4r13 2008-07-18 =========================
+! 2008-07-17 - Olivier Deschamps
+ - duplicate PhotonPDF.opts for Hlt usage (HltPhotonPDF.opts)
+
+!========================== CaloFuturePIDs v4r12 2008-07-02 =========================
+! 2008-06-27 - Olivier Deschamps
+ - CaloFutureTrackMatchAlg and inCaloFutureAcceptanceAlg : protect against empty track container
+ - use default HLT locations for the HLT context in all algorithm/tool
+
+
+! 2008-06-26 - Juan PALACIOS
+ - cmt/requirements
+  . Increase version to v4r12
+ - src/CaloFuturePhotonEstimatorTool.cpp
+ - src/CaloFutureSingleGammaTool.cpp
+ - src/Linear.h
+  . Change all Gaudi::XYZLine and Gaudi::Line for Gaudi::Math::XYZLine and
+    Gaudi::Math::XYZLine respectively (adapting to Kernel/LHCbMath v3)
+
+!========================== CaloFuturePIDs v4r11 2008-06-04 =========================
+! 2008-06-04 - Marco Cattaneo
+ - Fix doxygen warning
+
+! 2008-06-03 Olivier Deschamps
+ - change incident type EndEvent to BeginEvent in CaloFutureEnergyForTrack.cpp
+
+!========================== CaloFuturePIDs v4r10 2008-05-13 =========================
+! 2008-05-13 Olivier Deschamps
+- restore void _setProperty(..) instead of StatusCode setProperty(...)
+
+!========================== CaloFuturePIDs v4r9 2008-01-24 ===================
+! 2008-01-24 - Victor Egorychev
+- _setProperty was changed to setProperty
+- fixed mistypo with AddNeigbours instead AddNeibours
+- version was incremented to v4r9
+
+!========================== CaloFuturePIDs v4r8 2007-09-20 ===================
+! 2007-08-24 - Olivier Deschamps
+ - Fix most of the unchecked StatusCodes
+
+!========================== CaloFuturePIDs v4r7 2007-05-31 ===================
+! 2007-05-31 - Marco Cattaneo
+ - Fix doxygen warnings
+
+! 2007-05-26 - Victor Egorychev
+- DLL hist (DC06) for different BremPID added, needs ParamFiles v6r1 
+- src/BremPIDeAlg.cpp
+  - new PIDs from DC06 added
+ - cmt/requirements 
+    version increment to v4r7
+
+!========================== CaloFuturePIDs v4r6 2007-03-02 ==========================
+! 2007-03-02 - Marco Cattaneo
+ - Remove LHCbDefinitions includes
+ - Remove obsolete CaloFuturePIDs_load.cpp file
+ - Fix doxygen warnings and other minor cleanups
+
+!========================== CaloFuturePIDs v4r5p1 2006-11-27 ===================
+! 2006-11-27 - Victor Egorychev
+ - src/CaloFutureID2DLL.cpp Warning " ... very priliminary version ... " was
+   removed
+
+!========================== CaloFuturePIDs v4r5 2006-11-07 ===================
+! 2006-11-07 - Marco Cattaneo
+ - Change CALOFUTUREPIDOPTS variable to CALOFUTUREPIDSOPTS, to be standard....
+
+! 2006-11-06 - Victor Egorychev
+- DLL hist (DC06) for different types tracks for PIDe/mu added 
+  (Ecal, Hcal, Prs). For BremPID - still old hist
+- src/FutureEcalPIDeAlg.cpp
+  - new PIDs from DC06 added for Long, Downstream, TTrack tracks
+- src/FutureHcalPIDeAlg.cpp
+  - new PIDs from DC06 added for Long, Downstream, TTrack tracks
+- src/FuturePrsPIDeAlg.cpp
+  - new PIDs from DC06 added for Long, Downstream, TTrack tracks
+- src/FutureEcalPIDmuAlg.cpp
+  - new PIDs from DC06 added for Long, Downstream, TTrack tracks
+- src/FutureHcalPIDmuAlg.cpp
+  - new PIDs from DC06 added for Long, Downstream, TTrack tracks
+- src/BremPIDeAlg.cpp
+  - old PIDs added for Long, Velo, Upstream tracks
+- src/CaloFutureID2DLL.cpp
+  - hist for different track types added
+- src/CaloFutureID2DLL.h
+  - hist for different track types added
+ - cmt/requirements 
+    version increment to v4r5 
+
+! ========================= CaloFuturePIDs v4r4 2006-09-28 ===================
+! 2006-09-28 - Victor Egorychev
+ - src/Linear.h
+    bug fix for invalid linear state extrapolation 
+ - cmt/requirements 
+    version increment to v4r4 
+
+! ========================= CaloFuturePIDs v4r3 2006-08-03 ===================
+! 2006-08-03 - Chris Jones
+ - Add missing data initialisations in CaloFutureElectronMatch and CaloFuturePhotonMatch
+
+!========================== CaloFuturePIDs v4r2 2006-07-19 ===================
+! 2006-07-19 - Marco Cattaneo
+ - ToString.h : remove all templates now in GaudiKernel/ToStream.h
+
+!========================== CaloFuturePIDs v4r1 2006-06-27 ===================
+! 2006-06-27 - Olivier Deschamps 
+  - CaloFutureReco/CaloFuturePIDs repackaging :
+    - add CaloFutureSingleGammaTool/CaloFuturePhotonEstimatorTool from CaloFutureReco/
+    - increment the release number in cmt/requirements 
+
+!========================== CaloFuturePIDs v4r0 2006-06-22 ===================
+! 2006-06-22 - Vanya BELYAEV
+ - fix the inconsistencies in the configuration of 
+   accepted types for "Brem"-related algorithms 
+
+! 2006-06-21 - Vanya BELYAEV
+ - fix the problem for "Brem"-tools.
+   now it tries to get the fixed states:
+      AtTT, EndRich1, BegRich1, EndVelo, 
+   othwrwise it used the state nearest to 2*meter (and x<4*meter).
+   Also use the explicite extrapolation
+ - Linear.h  - explicite linear extrapolator. 
+    The speed-up of BremMatch algorthm is approximately 2 times "9"->"4"
+
+! 2006-06-20 - Olivier Deschamps
+ - minor update (RelationWeighted1D -> 2D to please ChargedProtoPAlg)
+
+! 2006-06-19 - Vanya Belyaev
+ - First version for DC06
+
+!========================== CaloFuturePIDs v3r0 2005-11-04 ===================
+! 2005-11-04 - Olivier Deschamps
+ - Adapt to new Track Event Model (TrackEvent v1r4)
+
+  modified file :  
+   src/CaloFutureTrackPrsEval.h/cpp
+   src/CaloFutureTrackHcalEval.h/cpp
+   src/CaloFutureTrackEval.h/cpp
+   src/CaloFutureTrackEcalEval.h/cpp
+   src/CaloFutureTrack2IdAlg.cpp
+   src/CaloFutureTrack2EstimatorAlg.cpp
+   src/CaloFuturePIDsData.cpp
+   src/CaloFuturePhotonEstimatorTool.h/cpp
+
+ - cmt/requirements 
+   version increment to v3r0
+
+!========================= CaloFuturePIDs v2r6 2005-06-02 ===========================
+! 2005-06-02 - Marco Cattaneo
+ - Adapt Brunel.opts to new phase name Reco instead of BrunelReco
+
+!========================= CaloFuturePIDs v2r5p1 2005-05-23 =========================
+! 2005-05-10 - Vanya BELYAEV
+
+ - src/CaloFuturePIDsData.cpp
+   1) rename "match" -> "mat" as N-Tuple item name to please PAW 
+                                     (thanks to Kirill VORONCHEV) 
+   2) add photon match estimator  
+   3) cosmetic modifications 
+
+ - src/CaloFuturePIDsData.h 
+    remove the file 
+ 
+!========================= CaloFuturePIDs v2r5 2005-05-09 ===========================
+! 2005-05-08 - Vanya BELYAEV
+    Eliminate all *associators*  
+    Now everything works directly with relation tables 
+    (Assuming the proper instrumentation of "Data-On-Demand" service)
+ 
+ - options/CaloFuturePIDsOnDemand.opt
+     new configuration file (TEST-PHASE) for "CaloFuturePIDs-On-Demand"
+     approach
+ - cmt/requirements 
+     version increment to v2r5 
+
+!======================= CaloFuturePIDs v2r4p1 2005-03-08 =====================
+! 2005-03-08 - Marco Cattaneo
+ - Fix some doxygen warnings
+ - Remove unmatched "#pragma print on" in options to avoid resetting print
+   level in higher level options files
+
+!======================== CaloFuturePIDs v2r4 2004-09-08 ======================
+! 2004-09-02 - Vanya BELYAEV
+   make the preparation for HLT/Trigger development 
+ - update for modifier CaloFutureInterfaces 
+ - cmt/requirements 
+   version increment to v2r4 
+
+!======================== CaloFuturePIDs v2r3 2004-04-27 ======================
+! 2004-04-27 - Vanya Belyaev
+ -  src/CaloFuturePIDsData.cpp
+    fix stupid misprint in type name for associator 
+ -  cmt/requirements
+    increment the version to v2r3 
+
+!======================== CaloFuturePIDs v2r2 2004-04-19 ======================
+! 2004-04-19 - Marco Cattaneo
+ - Fix doxygen warnings
+
+! 2004-04-18 - Vanya Belyaev
+ - src/CaloFuturePhotonEstimatorTool.h,.cpp
+   the updated version of PhotonID tool from Frederic Machefert
+ - options/PhotonPDF.opts 
+   the updated file with parameters 
+ - cmt/requirements
+   increment the version to v2r2 
+ 
+!======================== CaloFuturePIDs v2r1 2004-03-18 ======================
+! 2004-03-17 - Vanya BELYAEV
+ - src/CaloFuturePhotonEstimatorTool.h,cpp
+   new tool for photon ID estimate from Frederic Machefert
+   The origina version from Frederic is udapted a bit to 
+   new GaudiTool/CaloFutureTool methods and to 
+   "typo"-fix ICaloFutureLikelyhood -> ICaloFutureLikelihood 
+ - src/CaloFuturePIDsData.h/.cpp  
+   new algorithm to fill NTuple needed to populate 
+   the reference histograms for charged particle ID 
+
+ - src/CaloFuturePIDs_load.cpp - add new tool and new 
+                           algorithm to the list of 
+                           known components 
+
+ - cmt/requirements  increment the version to v2r1 
+
+ - options/PhotonPDF.opts 
+   configuration of CaloFuturePhotonEstimatorTool/PhotonPID 
+   ********** ATTENTION: tool name is choosen to be 'PhotonPID' *********
+
+!======================== CaloFuturePIDs v2r0 2004-03-08 ======================
+! 2004-03-08 - Marco Cattaneo
+ - In CaloFutureTrack2Estimator.h/.cpp, CaloFutureTrack2Idalg.h/.cpp
+   . rename m_upstream to m_downstream
+   . rename UseUpstream property to UseDownstream 
+   . use new isDownstream() method of TrStoredTrack instead of upstream()
+
+ - In *.opts
+   . rename UseUpstream property to UseDownstream 
+
+! 2004-02-17 - Vanya BELYAEV
+
+   -  update for reading the input histograms from 
+
+      $PARAMFILEROOT/data/CaloFuturePIDs.root  
+        or 
+      $PARAMFILEROOT/data/CaloFuturePIDs.root 
+
+  -   remove 'text' histograms from options directory 
+
+  -   cmt/requirements increment teh MAJOR version 
+
+!======================== CaloFuturePIDs v1r2 2003-12-11 ======================
+! 2003-12-11 - Marco Cattaneo
+ - Move to Gaudi v13:
+   . requirements:        use CaloFutureInterfaces v3r*
+   . CaloFutureTrack2IdAlg.cpp: adapt to AIDA 3.0 
+
+!======================== CaloFuturePIDs v1r1 2003-07-17 ======================
+! 2003-07-17 - Ivan BELYAEV
+ - src/CaloFutureTrackEval.cpp 
+   fix an error (return m_bad valeu for zero energy deposition) 
+ - cmt/requirements  increase the version 
+
+! 2003-07-17 - Ivan BELYAEV
+ - minor change if algorithms to speed-up a code a little bit 
+ - options introduce a low/high limits for estimators to skip 
+   'bad' records 
+
+!======================== CaloFuturePIDs v1r0 2003-04-17 ======================
+! 2003-04-17 - Marco Cattaneo
+ - Remove "#" from "#include" when it appears in doxygen comment lines of job 
+   options, as this breaks the production tools
+
+! 2003-03-13 - Vanya BELYAEV
+ - new package 
diff --git a/CaloFuture/CaloFuturePIDs/python/CaloFuturePIDs/Configuration.py b/CaloFuture/CaloFuturePIDs/python/CaloFuturePIDs/Configuration.py
new file mode 100644
index 0000000000000000000000000000000000000000..e29e2e0e5830225b6775c6bff5bea540e32a779d
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/python/CaloFuturePIDs/Configuration.py
@@ -0,0 +1,191 @@
+#!/usr/bin/env gaudirun.py
+# =============================================================================
+## Configurable for CaloFuturerimeter PID 
+#  @author Vanya BELYAEV Ivan.Belyaev@nikhe.nl
+#  @date 2008-07-17
+# =============================================================================
+"""
+Configurable for CaloFuturerimeter PID
+"""
+# =============================================================================
+__author__  = "Vanya BELYAEV Ivan.Belyaev@nikhef.nl"
+__version__ = "CVS tag $Name: not supported by cvs2svn $, version $Revision: 1.4 $"
+# =============================================================================
+__all__   = (
+    'HltCaloFuturePIDsConf'     ,
+    'OffLineCaloFuturePIDsConf' ,
+    'CaloFuturePIDsConf'
+    )
+# =============================================================================
+
+from LHCbKernel.Configuration import *
+from Configurables            import HistogramSvc
+
+from CaloKernel.ConfUtils     import ( addAlgs        ,
+                                       printOnDemand  ,
+                                       prntCmp        ,
+                                       hltContext     ,
+                                       setTheProperty ) 
+from CaloFuturePIDs.PIDs            import caloPIDs
+from CaloFuturePIDs.PIDs            import referencePIDs
+import logging
+_log = logging.getLogger ('CaloFuturePIDs')
+
+# =============================================================================
+## @class CaloFuturePIDsConf
+#  Configurable for CaloFuturerimeter PID
+#  @author Vanya BELYAEV Ivan.Belyaev@nikhef.nl
+#  @date 2008-07-17
+class CaloFuturePIDsConf(LHCbConfigurableUser):
+    """
+    Class/Configurable to define the calorimeter PID
+    """
+    ## define the slots
+    __slots__ = {
+        ##
+        "Context"              : ''   # The context within which to run
+        , "MeasureTime"        : False       # Measure the time for sequencers
+        , "OutputLevel"        : INFO        # The global output level
+        ##
+        , 'Sequence'           : ''          # The sequencer to add the CALOFUTURE reconstruction algorithms to
+        , 'PIDList'            : ['InAcceptance',
+                                  'Match',
+                                  'Energy',
+                                  'Chi2',
+                                  'DLL',
+                                  'NeutralPID'
+                                  ] # List of PID fragments to be included (alternative full sequence per technique : [ 'EcalPID', 'BremPID', 'HcalPID', 'PrsPID', 'SpdPID', 'NeutralPID' ] )
+
+        , 'EnablePIDsOnDemand' : False       # enable Reco-On-Demand
+        ##
+        , 'DataType'           : 'MC09'      # Data type  
+        , 'TrackLocation'      : ''          # track location to be used (default use CaloFutureAlgUtils default)
+        , 'ClMatchTrTypes'     : []          # Track types for Cluster matching (if not set the alg. default is used i.e. Long + Downstream + TTracks)  
+        , 'CaloFuturePIDTrTypes'      : []         # Track types for CaloFuturePID (if not set the alg. default is used i.e. Long + Downstream + TTracks)
+        , 'BremPIDTrTypes'      : []         # Track types for BremPID (if not set the alg. default is used i.e. Long + Upstream + Velo)
+        , 'SkipNeutrals'       : False       # skip neutralID (already run in CaloFutureRecoConf by default)
+        , 'SkipCharged'        : False       # skip chargedID 
+        , 'FastPID'            : False       # speed-up PID (lighter sequence)
+        , 'ExternalClusters'   : ''          # use non-default cluster container
+        , 'NoSpdPrs'           : False       # Upgrade configuration without Spd/Prs
+        , 'Verbose'            : False
+        }
+    
+    ## Configure recontruction of CaloFuture Charged  PIDs  
+    def caloPIDs ( self ) :
+        """
+        Configure recontruction of CaloFuture Charged  PIDs 
+        """
+        cmp = caloPIDs ( self.getProp( 'Context'            )  ,
+                         self.getProp( 'EnablePIDsOnDemand' )  ,
+                         self.getProp('PIDList'),
+                         self.getProp('TrackLocation'),
+                         self.getProp('ClMatchTrTypes'),
+                         self.getProp('CaloFuturePIDTrTypes'),
+                         self.getProp('BremPIDTrTypes'),                       
+                         self.getProp('SkipNeutrals'),
+                         self.getProp('SkipCharged'),
+                         self.getProp('FastPID'),
+                         self.getProp('ExternalClusters'),
+                         self.getName(),
+                         self.getProp('NoSpdPrs')                       
+                         ) 
+
+        referencePIDs( self.getProp("DataType" ) )
+
+        _log.info ('Configured CaloFuture PIDs           : %s ' % cmp.name()  )
+        ##
+        return cmp 
+    
+    ## Check the configuration
+    def checkConfiguration ( self ) :
+        """
+        Check the configuration
+        """
+        _log.debug('CaloFuturePIDsConf: Configuration is not checked!')
+    
+
+
+    def printConf(self,verbose=False) :
+        if self.getProp('NoSpdPrs') :
+            _log.info("CaloFuturePIDsConf : upgrade configuration without Spd/Prs")
+        if self.getProp('Verbose') or verbose:
+            _log.info ( self )
+
+
+   ## CaloFuturerimeter PID Configuration
+    def applyConf ( self ) :
+        """
+        CaloFuturerimeter PID Configuration
+        """
+
+        self.printConf()
+
+        pids = self.caloPIDs()
+        
+        setTheProperty ( pids , 'Context'     , self.getProp('Context'    ) )
+        setTheProperty ( pids , 'MeasureTime' , self.getProp('MeasureTime') )
+        if self.isPropertySet("OutputLevel") :
+            setTheProperty ( pids , 'OutputLevel' , self.getProp('OutputLevel') )
+
+        if self.getProp ( 'Sequence' ) :
+            addAlgs  ( self.Sequence , pids ) 
+            _log.info ('Configure main CaloFuture PIDs Sequence  : %s '% self.Sequence.name() )
+            if self.getProp('Verbose') :
+                _log.info ( prntCmp ( self.Sequence ) ) 
+        else :
+            _log.info ('Configure CaloFuturerimeter PIDs blocks ' )            
+            if self.getProp('Verbose') :
+                _log.info ( prntCmp ( pids ) )
+            
+                    
+        if self.getProp( 'EnablePIDsOnDemand')  :
+            _log.info ( printOnDemand () )             
+
+
+
+
+# =============================================================================
+## @class HltCaloFuturePIDsConf
+#  Configurable for CaloFuturerimeter PID
+#  @author Vanya BELYAEV Ivan.Belyaev@nikhef.nl
+#  @date 2008-07-17
+class HltCaloFuturePIDsConf(CaloFuturePIDsConf):
+    """
+    Class/Configurable to define the calorimeter PID for Hlt 
+    """
+    __slots__ = {}
+    
+    ## Check the configuration
+    def checkConfiguration ( self ) :
+        """
+        Check the configuration
+        """
+        if not hltContext ( self.getProp('Context') ) :
+            raise AttributeError, 'Invalid context for HltCaloFuturePIDsConf'
+        
+# =============================================================================
+## @class OffLineCaloFuturePIDsConf
+#  Configurable for CaloFuturerimeter PID
+#  @author Vanya BELYAEV Ivan.Belyaev@nikhef.nl
+#  @date 2008-07-17
+class OffLineCaloFuturePIDsConf(CaloFuturePIDsConf):
+    """
+    Class/Configurable to define the calorimeter PID for Off-Line 
+    """
+    __slots__ = {}
+    
+    ## Check the configuration
+    def checkConfiguration ( self ) :
+        """
+        Check the configuration
+        """
+        if hltContext ( self.getProp('Context') ) :
+            raise AttributeError, 'Invalid context for OffLineCaloFuturePIDsConf'
+        
+
+
+        
+# =============================================================================
+# The END
+# =============================================================================
diff --git a/CaloFuture/CaloFuturePIDs/python/CaloFuturePIDs/PIDs.py b/CaloFuture/CaloFuturePIDs/python/CaloFuturePIDs/PIDs.py
new file mode 100644
index 0000000000000000000000000000000000000000..a1a6f303bcdb5b33f30a6d0a7e138f4b1228d9f7
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/python/CaloFuturePIDs/PIDs.py
@@ -0,0 +1,522 @@
+#!/usr/bin/env python
+# =============================================================================
+# $Id: PIDs.py,v 1.4 2010/03/08 01:31:33 odescham Exp $
+# =============================================================================
+## The major building blocks of CaloFuturerimeter PID
+#  @author Vanya BELYAEV Ivan.Belyaev@nikhe.nl
+#  @date 2008-07-17
+# =============================================================================
+"""
+The major building blocks of CaloFuturerimeter PID
+"""
+# =============================================================================
+__author__  = "Vanya BELYAEV Ivan.Belyaev@nikhef.nl"
+__version__ = "CVS tag $Name: v5r6 $, version $Revision: 1.4 $"
+# =============================================================================
+from Gaudi.Configuration  import *
+    
+from Configurables        import    GaudiSequencer
+
+from CaloKernel.ConfUtils import ( hltContext          ,
+                                   getAlgo             ,
+                                   setTheProperty      ,
+                                   addAlgs
+                                   )
+
+
+
+# =============================================================================
+## define "PhotonID" algorithm
+def PhotonID ( context , enableRecoOnDemand, useTracks = True ) :
+    """
+    define 'PhotonID' algorithm
+    """
+    
+    
+    from Configurables import   CaloFuturePhotonIdAlg
+    
+    ## photonID
+    pid = getAlgo ( CaloFuturePhotonIdAlg,
+                    "PhotonID", 
+                    context,
+                    "Rec/Calo/PhotonID",
+                    enableRecoOnDemand
+                    )
+    
+    pid.Type = 'PhotonID'
+    pid.Tracking = useTracks 
+    return pid
+
+# =============================================================================
+## define "MergedID" algorithm
+def MergedID ( context , enableRecoOnDemand, useTracks = True ) :
+    """
+    define 'MergedID' algorithm
+    """
+    
+    from Configurables import   CaloFuturePhotonIdAlg
+    
+    ## photonID
+    mid = getAlgo ( CaloFuturePhotonIdAlg,
+                    "MergedID", 
+                    context,
+                    "Rec/Calo/MergedID",
+                    enableRecoOnDemand
+                    )
+    
+    mid.Type = 'MergedID'    
+    mid.Tracking = useTracks
+    return mid
+
+# =============================================================================
+## define "MergedID" algorithm
+def PhotonFromMergedID ( context , enableRecoOnDemand, useTracks = True ) :
+    """
+    define 'PhotonFromMergedID' algorithm
+    """
+    
+    from Configurables import   CaloFuturePhotonIdAlg
+    
+    ## photonID
+    pmid = getAlgo ( CaloFuturePhotonIdAlg    ,
+                     "PhotonFromMergedID", 
+                     context,
+                     "Rec/Calo/PhotonFromMergedID",
+                     enableRecoOnDemand
+                     )
+    
+    pmid.Type = 'PhotonFromMergedID'    
+    pmid.Tracking = useTracks
+    return pmid
+
+# =============================================================================
+## define "inEcalAcceptance" algorithm
+def inEcalAcc ( context , enableRecoOnDemand, trackLocation = "", matchTrTypes=[]) :
+    """
+    
+    define 'inEcalFutureAcceptance' algorithm
+    
+    """
+
+    from Configurables import  ( InEcalFutureAcceptance        , 
+                                 InEcalFutureAcceptanceAlg ) 
+    
+    ## check if the track is in Ecal acceptance 
+    inEcal = getAlgo ( InEcalFutureAcceptanceAlg  ,
+                       'InECALFuture'             ,
+                       context              ,
+                       "Rec/Calo/InAccEcal" ,
+                       enableRecoOnDemand   )
+
+    if trackLocation :
+        inEcal.Inputs   = trackLocation
+ 
+    if matchTrTypes != [] :
+        inEcal.AcceptedType=matchTrTypes
+        
+    return inEcal
+
+## ============================================================================
+## define the minimal track match sequnce for photon recontruction
+def trackMatch ( context , enableRecoOnDemand, trackLocation = "" , matchTrTypes=[], fastReco = False , clusterLocation = "" ) :
+    """
+
+    Define the minimal track match sequnce for photon reconstruction
+
+    """
+
+    from Configurables import FuturePhotonMatchAlg      
+    
+    seq = getAlgo ( GaudiSequencer , 'CaloFutureTrackMatch' , context )
+
+
+    ## perform the actual track <-> cluster match 
+    clmatch = getAlgo  (  FuturePhotonMatchAlg          ,
+                          'FutureClusterMatch'          ,
+                          context                 ,
+                          'Rec/Calo/ClusterMatch' ,
+                          enableRecoOnDemand      )
+
+    if clusterLocation != '' :
+        clmatch.Calos = clusterLocation 
+    
+
+#    log.info(" ========= trackLocation = " + trackLocation ) 
+
+    ## check if the track is in Ecal acceptance 
+    inEcal = inEcalAcc ( context , enableRecoOnDemand , trackLocation,matchTrTypes) 
+    
+    seq.Members = [ inEcal , clmatch ] 
+
+    setTheProperty ( seq , 'Context' , context )
+
+    if matchTrTypes != [] :
+        clmatch.AcceptedType=matchTrTypes
+
+
+    if trackLocation :
+        clmatch.Tracks = trackLocation
+        
+    log.debug ( "Configure Cluster Track Match : '%s' for  '%s'" %(seq.name(), context) )
+
+
+    return seq
+
+
+# =================================================================================
+## define various CaloFuture PIDs evaluation
+def caloPIDs ( context , enableRecoOnDemand , list , trackLocation = ''   , matchTrTypes=[] , caloTrTypes=[] , bremTrTypes=[],
+               skipNeutrals = False , skipCharged = False , fastPID = False , clusterLocation = '', name = '', noSpdPrs=False) :
+    """
+    Define various CaloFuture PIDs evaluation
+    """
+
+
+    from Configurables import ( InSpdFutureAcceptance     ,
+                                InSpdFutureAcceptanceAlg  ,
+                                InPrsFutureAcceptance     ,
+                                InPrsFutureAcceptanceAlg  ,
+                                InEcalFutureAcceptance    ,
+                                InEcalFutureAcceptanceAlg ,
+                                InBremFutureAcceptance    ,
+                                FutureInBremFutureAcceptanceAlg , 
+                                InHcalFutureAcceptance    ,
+                                InHcalFutureAcceptanceAlg ) 
+    
+    from Configurables import ( FutureElectronMatchAlg    ,
+                                BremMatchAlgFuture        )    
+    
+    from Configurables import ( FutureTrack2SpdEAlg       ,
+                                FutureTrack2PrsEAlg       ,
+                                FutureTrack2EcalEAlg      ,
+                                FutureTrack2HcalEAlg      )
+    
+    
+    from Configurables import ( FutureEcalChi22ID         ,
+                                BremChi22IDFuture         ,
+                                FutureClusChi22ID         ,
+                                FuturePrsPIDeAlg          ,
+                                FutureEcalPIDeAlg         ,
+                                BremPIDeAlgFuture         ,
+                                FutureHcalPIDeAlg         ,
+                                FutureEcalPIDmuAlg        ,
+                                FutureHcalPIDmuAlg        ,
+                                CaloFuturePhotonIdAlg
+                                )
+
+    ##  SANITY CHECK FOR TRACK TYPES (caloTrTypes must be included  in matchTrTypes)
+    defMatchTrTypes = [3,5,6]  # Long / Downstream / TTracks
+    if matchTrTypes != [] :
+        defMatchTrTypes = matchTrTypes
+    for item in caloTrTypes :
+        if item not in defMatchTrTypes :
+            raise AttributeError, 'TrackTypes for ClusterMatching must include CaloFuturePID TrackTypes'
+        
+    if matchTrTypes != [] :
+        log.info(" ! Will use track types = % s for matching" % matchTrTypes)
+    if caloTrTypes != [] :
+        log.info(" ! Will use track types = % s for caloPID" % caloTrTypes)
+    if bremTrTypes != [] :
+        log.info(" ! Will use track types = % s for bremPID" % bremTrTypes)
+                 
+
+
+    ## global PID sequence
+    _name = 'CaloFuturePIDs'
+    if name != context or context.upper() == 'OFFLINE': _name = _name+name
+    seq = getAlgo ( GaudiSequencer, _name, context )
+    seq.Members = []
+
+    ## add Charged
+    if not skipCharged :
+        _name = 'ChargedPIDs'
+        if name != context or context.upper() == 'OFFLINE': _name = _name+name
+
+        charged = getAlgo( GaudiSequencer , _name , context )
+
+        # inAcceptance
+        inAcc = getAlgo ( GaudiSequencer , 'InCaloFutureAcceptance' , context )
+
+        inECAL = inEcalAcc ( context , enableRecoOnDemand , trackLocation , matchTrTypes )         
+        inHCAL = getAlgo ( InHcalFutureAcceptanceAlg  ,
+                           'InHCALFuture'             , 
+                           context              ,
+                           "Rec/Calo/InAccHcal" ,
+                           enableRecoOnDemand   )
+        inBREM = getAlgo ( FutureInBremFutureAcceptanceAlg  ,
+                           'InBREMFuture'             , 
+                           context              ,
+                           "Rec/Calo/InAccBrem" ,
+                           enableRecoOnDemand   )
+        inAcc.Members = [ inECAL , inHCAL , inBREM ]
+
+        if not noSpdPrs :
+            inSPD = getAlgo ( InSpdFutureAcceptanceAlg    ,
+                              'InSPD'               , 
+                              context               ,
+                              "Rec/Calo/InAccSpd"   ,
+                              enableRecoOnDemand    )
+            inPRS = getAlgo ( InPrsFutureAcceptanceAlg    ,
+                              'InPRS'               , 
+                              context               ,
+                              "Rec/Calo/InAccPrs"   ,
+                              enableRecoOnDemand    )             
+            inAcc.Members += [ inSPD  , inPRS  ]
+        else :
+            log.info('remove Spd/Prs from acceptance')
+
+
+            
+
+        # matching
+        match    = getAlgo ( GaudiSequencer  ,
+                             'CaloFutureMatch'     ,
+                             context         )
+        cluster  = trackMatch ( context , enableRecoOnDemand , trackLocation, matchTrTypes, fastPID,clusterLocation)
+
+        electron = getAlgo ( FutureElectronMatchAlg         ,
+                             "ElectronMatchFuture"          ,
+                             context                  ,
+                             'Rec/Calo/ElectronMatch' ,
+                             enableRecoOnDemand       ) 
+        brem     = getAlgo ( BremMatchAlgFuture             ,
+                             "BremMatchFuture"              ,
+                             context                  ,
+                             'Rec/Calo/BremMatch'     ,
+                             enableRecoOnDemand       )
+
+        match.Members = [cluster  , electron, brem ]
+
+        # energy
+        energy = getAlgo ( GaudiSequencer ,
+                           'CaloFutureEnergy'   ,
+                           context        )
+        ecalE  = getAlgo ( FutureTrack2EcalEAlg     ,
+                           'EcalEFuture'            , 
+                           context            ,
+                           'Rec/Calo/EcalE'   ,
+                           enableRecoOnDemand )
+        hcalE  = getAlgo ( FutureTrack2HcalEAlg     ,
+                           'HcalEFuture'            , 
+                           context            ,
+                           'Rec/Calo/HcalE'   ,
+                           enableRecoOnDemand )
+   
+
+        energy.Members = [ ecalE , hcalE ]
+        if not noSpdPrs :
+            spdE   = getAlgo ( FutureTrack2SpdEAlg      ,
+                               'SpdEFuture'             , 
+                               context            ,
+                               'Rec/Calo/SpdE'    ,
+                               enableRecoOnDemand )
+            prsE   = getAlgo ( FutureTrack2PrsEAlg      ,
+                               'PrsEFuture'             , 
+                               context            ,
+                               'Rec/Calo/PrsE'    ,
+                           enableRecoOnDemand )
+
+            energy.Members += [ spdE , prsE ]
+        else :
+            log.info('remove Spd/Prs from energy estimators')
+
+
+        # Chi2's
+        chi2  = getAlgo ( GaudiSequencer , 'CaloFutureChi2', context        )
+        eChi2 = getAlgo ( FutureEcalChi22ID, 'FutureEcalChi22ID' , context, 'Rec/Calo/EcalChi2', enableRecoOnDemand   ) 
+        bChi2 = getAlgo ( BremChi22IDFuture, 'BremChi22IDFuture' , context, 'Rec/Calo/BremChi2', enableRecoOnDemand   ) 
+        cChi2 = getAlgo ( FutureClusChi22ID, 'FutureClusChi22ID' , context, 'Rec/Calo/ClusChi2', enableRecoOnDemand   )
+        chi2.Members = [ eChi2, bChi2 , cChi2 ]
+
+
+        # DLL
+        dlle  = getAlgo ( GaudiSequencer ,
+                          'CaloFutureDLLeFuture'     ,
+                          context        )
+        dllmu  = getAlgo ( GaudiSequencer ,
+                          'CaloFutureDLLmuFuture'     ,
+                          context        )
+        ecale=getAlgo ( FutureEcalPIDeAlg          ,
+                        'EcalPIDeFuture'           ,
+                        context              ,
+                        'Rec/Calo/EcalPIDe'  ,
+                        enableRecoOnDemand   )
+        breme=getAlgo ( BremPIDeAlgFuture          ,
+                        'BremPIDeFuture'           ,
+                        context              ,
+                        'Rec/Calo/BremPIDe'  ,
+                        enableRecoOnDemand   ) 
+        hcale=getAlgo ( FutureHcalPIDeAlg          ,
+                        'HcalPIDeFuture'           ,
+                        context              ,
+                        'Rec/Calo/HcalPIDe'  ,
+                        enableRecoOnDemand   ) 
+        ecalmu=getAlgo ( FutureEcalPIDmuAlg         ,
+                         'EcalPIDmuFuture'          ,
+                         context              ,
+                         'Rec/Calo/EcalPIDmu' ,
+                         enableRecoOnDemand   ) 
+        hcalmu=getAlgo ( FutureHcalPIDmuAlg         ,
+                         'HcalPIDmuFuture'          ,
+                         context              ,
+                         'Rec/Calo/HcalPIDmu' ,
+                         enableRecoOnDemand   )
+
+        
+        dllmu.Members = [ ecalmu, hcalmu ]
+        dlle.Members  = [ ecale , breme , hcale ]
+        if not noSpdPrs :
+            prse=getAlgo ( FuturePrsPIDeAlg           ,
+                           'PrsPIDe'            ,
+                           context              ,
+                           'Rec/Calo/PrsPIDe'   ,
+                           enableRecoOnDemand   ) 
+
+            dlle.Members  += [ prse ]
+        else :
+            log.info('remove Spd/Prs from dlle')
+
+
+
+        # alternative sequence (per caloPID technique)
+        ecalT  = getAlgo ( GaudiSequencer ,'EcalPIDFuture'     , context        )
+        ecalT.Members = [ inECAL,  cluster, electron, ecalE, eChi2, cChi2, ecale, ecalmu ]
+
+        hcalT  = getAlgo ( GaudiSequencer ,'HcalPIDFuture'     , context        )
+        hcalT.Members = [ inHCAL,  hcalE, hcale, hcalmu ]
+
+
+        if not noSpdPrs :
+            prsT  = getAlgo ( GaudiSequencer ,'PrsPIDFuture'     , context        )
+            prsT.Members = [ inPRS,  prsE, prse ]
+ 
+            spdT  = getAlgo ( GaudiSequencer ,'SpdPIDFuture'     , context        )
+            spdT.Members = [ inSPD,  spdE ]
+ 
+        bremT  = getAlgo ( GaudiSequencer ,'BremPIDFuture'     , context        )
+        bremT.Members = [ inBREM,  brem, bChi2, breme ]
+
+
+        # === Redefine accepted track types ===
+        # matchTrTypes propagated to the relevant modules (inEcalAcc & clusterMatch)
+        if caloTrTypes != [] :
+            electron.AcceptedType  = caloTrTypes
+            cChi2.AcceptedType     = caloTrTypes
+            eChi2.AcceptedType     = caloTrTypes
+            ecalE.AcceptedType     = caloTrTypes
+            ecale.AcceptedType     = caloTrTypes
+            ecalmu.AcceptedType    = caloTrTypes
+            inHCAL.AcceptedType    = caloTrTypes        
+            hcalE.AcceptedType     = caloTrTypes
+            hcale.AcceptedType     = caloTrTypes
+            hcalmu.AcceptedType    = caloTrTypes
+            if not noSpdPrs :
+                inSPD.AcceptedType = caloTrTypes
+                spdE.AcceptedType  = caloTrTypes
+                inPRS.AcceptedType = caloTrTypes          
+                prsE.AcceptedType  = caloTrTypes
+                prse.AcceptedType  = caloTrTypes
+        if bremTrTypes != [] :
+            inBREM.AcceptedType = bremTrTypes            
+            brem.AcceptedType   = bremTrTypes
+            bChi2.AcceptedType  = bremTrTypes
+            breme.AcceptedType  = bremTrTypes
+
+        # === Override CaloFutureAlgUtils default track location ===
+        if  trackLocation :
+            electron.Tracks = trackLocation
+            brem.Tracks     = trackLocation
+            inBREM.Inputs   = trackLocation
+            inHCAL.Inputs   = trackLocation
+            eChi2.Tracks    = trackLocation
+            bChi2.Tracks    = trackLocation
+            cChi2.Tracks    = trackLocation
+            ecalE.Inputs    = trackLocation
+            hcalE.Inputs    = trackLocation            
+            if not noSpdPrs :
+                inPRS.Inputs    = trackLocation
+                inSPD.Inputs    = trackLocation
+                spdE.Inputs     = trackLocation
+                prsE.Inputs     = trackLocation
+
+        charged.Members = []
+        # updatXe global sequence with charged
+        if 'InAcceptance' in list : charged.Members += [ inAcc  ]
+        if 'Match' in list : charged.Members        += [ match  ]
+        if 'Energy' in list : charged.Members       += [ energy ]
+        if 'Chi2' in list : charged.Members         += [ chi2   ]
+        if 'DLL' in list or 'DLLe' in list : charged.Members          += [ dlle   ]
+        if 'DLL' in list or 'DLLmu' in list : charged.Members         += [ dllmu  ]
+
+        # alternative full sequence per technique
+        if 'EcalPID' in list :  charged.Members        += [ ecalT  ]
+        if 'BremPID' in list :  charged.Members        += [ bremT  ]
+        if 'HcalPID' in list :  charged.Members        += [ hcalT  ]
+        if 'PrsPID' in list and not noSpdPrs :  charged.Members         += [ prsT   ]
+        if 'SpdPID' in list and not noSpdPrs :  charged.Members         += [ spdT   ]
+        if charged.Members : addAlgs( seq , charged )
+        
+
+    ## Add Neutrals (! No neutralID so far for the noSpdPrs configuration )
+    if not skipNeutrals  and not noSpdPrs:
+        _name = 'NeutralPIDs'
+        if name != context or context.upper() == 'OFFLINE': _name = _name+name
+        neutrals = getAlgo( GaudiSequencer , _name , context )
+        photonID = PhotonID( context , enableRecoOnDemand )
+        mergedID = MergedID( context , enableRecoOnDemand )
+        photonFromMergedID = PhotonFromMergedID( context , enableRecoOnDemand )
+        # update global sequence with neutrals
+        neutrals.Members = []
+        if 'PhotonID' in list or 'NeutralPID' in list            : neutrals.Members += [ photonID  ]
+        if 'MergedID' in list  or 'NeutralPID' in list           : neutrals.Members += [ mergedID  ]
+        if 'PhotonFromMergedID' in list  or 'NeutralPID' in list : neutrals.Members += [ photonFromMergedID ]
+        if neutrals.Members : addAlgs( seq , neutrals )
+
+
+
+    setTheProperty ( seq , 'Context' , context )
+    
+    log.debug ( 'Configure CaloFuture PIDs  Reco : %s    for context : %s' %( seq.name() , context) )
+        
+    return seq
+
+
+
+def referencePIDs( dataType='' ) :
+
+    """
+    Define various reference Histograms on THS
+    """
+    hsvc = HistogramSvc ( 'HistogramDataSvc' )
+    inputs = hsvc.Input 
+     
+    # photon PDF default
+    pfound  = False   
+    for line in inputs : 
+        if 0 == line.find ( 'CaloFutureNeutralPIDs') : pfound = True 
+
+    if pfound : 
+        log.info ("CaloFuturePIDsConf: LUN 'CaloFutureNeutralPIDs' has been defined already")  
+    else: 
+        hsvc.Input += [ "CaloFutureNeutralPIDs DATAFILE='$PARAMFILESROOT/data/PhotonPdf.root' TYP='ROOT'" ] 
+
+
+    # charged PDF default 
+    found  = False   
+    for line in inputs : 
+        if 0 == line.find ( 'CaloFuturePIDs') : found = True 
+        
+    if found : 
+        log.info ("CaloFuturePIDsConf: LUN 'CaloFuturePIDs' has been defined already") 
+    elif 'DC06' == dataType : 
+        hsvc.Input += [ "CaloFuturePIDs DATAFILE='$PARAMFILESROOT/data/CaloPIDs_DC06_v2.root' TYP='ROOT'" ]
+    else: 
+        hsvc.Input += [ "CaloFuturePIDs DATAFILE='$PARAMFILESROOT/data/CaloPIDs_DC09_v1.root' TYP='ROOT'" ] 
+
+    return
+
+    
+# =============================================================================
+if '__main__' == __name__ :
+    print __doc__
+    
diff --git a/CaloFuture/CaloFuturePIDs/python/CaloFuturePIDs/__init__.py b/CaloFuture/CaloFuturePIDs/python/CaloFuturePIDs/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/CaloFuture/CaloFuturePIDs/src/BremChi22IDFuture.cpp b/CaloFuture/CaloFuturePIDs/src/BremChi22IDFuture.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..271322efccf3f34fa90fa0eb0744d7713dcc3bcf
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/BremChi22IDFuture.cpp
@@ -0,0 +1,34 @@
+// Include files
+#include "CaloFutureChi22ID.h"
+#include "ToVector.h"
+
+// ============================================================================
+/** @class BremChi22IDFuture BremChi22IDFuture.cpp
+ *  The preconfigured instance of class CaloFutureChi22ID
+ *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
+ */
+// ============================================================================
+using TABLEI = LHCb::RelationWeighted2D<LHCb::CaloHypo, LHCb::Track, float>;
+using TABLEO = LHCb::Relation1D<LHCb::Track, float>;
+
+struct BremChi22IDFuture final : public CaloFutureChi22ID<TABLEI,TABLEO> {
+  static_assert(
+      std::is_base_of<LHCb::CaloFuture2Track::IHypoTrTable2D, TABLEI>::value,
+      "TABLEI must inherit from IHypoTrTable2D");
+  BremChi22IDFuture(const std::string& name, ISvcLocator* pSvc)
+    : CaloFutureChi22ID<TABLEI,TABLEO>(name, pSvc) {
+    using LHCb::CaloFutureAlgUtils::CaloFutureIdLocation;
+    Gaudi::Functional::updateHandleLocation(*this,  "Input", CaloFutureIdLocation("BremMatch", context()));
+    Gaudi::Functional::updateHandleLocation(*this, "Output", CaloFutureIdLocation("BremChi2", context()));
+    // @todo it must be in agrement with "Threshold" for BremMatchAlgFuture
+    _setProperty("CutOff", "10000");
+    // track types:
+    _setProperty("AcceptedType", Gaudi::Utils::toString<int>(
+                                   LHCb::Track::Types::Velo, LHCb::Track::Types::Long,
+                                   LHCb::Track::Types::Upstream));
+  };
+};
+
+// ============================================================================
+
+DECLARE_COMPONENT( BremChi22IDFuture )
diff --git a/CaloFuture/CaloFuturePIDs/src/BremMatchAlgFuture.cpp b/CaloFuture/CaloFuturePIDs/src/BremMatchAlgFuture.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ff3a871d20628f8d4a85eb257d1cc5ce2cd17b22
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/BremMatchAlgFuture.cpp
@@ -0,0 +1,36 @@
+// Include files
+#include "CaloFutureTrackMatchAlg.h"
+
+// =============================================================================
+/** @class BremMatchAlgFuture
+ *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
+ *  @date 2006-06-16
+ */
+// =============================================================================
+using TABLE = LHCb::RelationWeighted2D<LHCb::CaloHypo, LHCb::Track, float>;
+using CALOFUTURETYPES = LHCb::CaloHypos;
+
+struct BremMatchAlgFuture final : CaloFutureTrackMatchAlg<TABLE,CALOFUTURETYPES> {
+  static_assert(std::is_base_of<LHCb::CaloFuture2Track::IHypoTrTable2D, TABLE>::value,
+                "TABLE must inherit from IHypoTrTable2D");
+  
+  BremMatchAlgFuture(const std::string& name, ISvcLocator* pSvc)
+      : CaloFutureTrackMatchAlg<TABLE,CALOFUTURETYPES>(name, pSvc) {
+    Gaudi::Functional::updateHandleLocation(*this, "Calos",  LHCb::CaloFutureAlgUtils::CaloFutureHypoLocation("Photons",context()));
+    Gaudi::Functional::updateHandleLocation(*this, "Output", LHCb::CaloFutureAlgUtils::CaloFutureIdLocation("BremMatch",context()));
+    Gaudi::Functional::updateHandleLocation(*this, "Filter", LHCb::CaloFutureAlgUtils::CaloFutureIdLocation("InBrem",context()));
+
+    _setProperty("Tool", "CaloFutureBremMatch/BremMatchFuture");
+    _setProperty("Threshold", "10000");
+    // track types:
+    _setProperty("AcceptedType", Gaudi::Utils::toString<int>(
+                                     LHCb::Track::Types::Velo, LHCb::Track::Types::Long,
+                                     LHCb::Track::Types::Upstream));
+    _setProperty("TableSize", "1000");
+  }
+
+};
+
+// =============================================================================
+
+DECLARE_COMPONENT( BremMatchAlgFuture )
diff --git a/CaloFuture/CaloFuturePIDs/src/BremPIDeAlgFuture.cpp b/CaloFuture/CaloFuturePIDs/src/BremPIDeAlgFuture.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..bae0e92c00c0925469d0a6cec20a67f17856d106
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/BremPIDeAlgFuture.cpp
@@ -0,0 +1,50 @@
+// Include files
+#include "CaloFutureID2DLL.h"
+
+// ============================================================================
+/** @class BremPIDeAlgFuture  BremPIDeAlgFuture.cpp
+ *  The preconfigured instance of class CaloFutureID2DLL
+ *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
+ *  @date 2006-06-18
+ */
+// ============================================================================
+
+class BremPIDeAlgFuture final : public CaloFutureID2DLL {
+ public:
+  /// Standard protected constructor
+  BremPIDeAlgFuture(const std::string& name, ISvcLocator* pSvc)
+      : CaloFutureID2DLL(name, pSvc) {
+    using LHCb::CaloFutureAlgUtils::CaloFutureIdLocation;
+
+    Gaudi::Functional::updateHandleLocation(
+        *this, "Input", CaloFutureIdLocation("BremChi2", context()));
+    Gaudi::Functional::updateHandleLocation(
+        *this, "Output", CaloFutureIdLocation("BremPIDe", context()));
+
+    _setProperty("nVlong" , Gaudi::Utils::toString(200));
+    _setProperty("nVvelo" , Gaudi::Utils::toString(200));
+    _setProperty("nVupstr", Gaudi::Utils::toString(200));
+    _setProperty("nMlong" , Gaudi::Utils::toString(50 * Gaudi::Units::GeV));
+    _setProperty("nMvelo" , Gaudi::Utils::toString(50 * Gaudi::Units::GeV));
+    _setProperty("nMupstr", Gaudi::Utils::toString(50 * Gaudi::Units::GeV));
+
+    _setProperty("HistogramU"   , "DLL_Long");
+    _setProperty("HistogramL"   , "DLL_Long");
+    _setProperty("HistogramV"   , "DLL_Long");
+    _setProperty("ConditionName", "Conditions/ParticleID/Calo/BremPIDe");
+
+    _setProperty("HistogramU_THS", "CaloFuturePIDs/CALO/BREMPIDE/h3");
+    _setProperty("HistogramL_THS", "CaloFuturePIDs/CALO/BREMPIDE/h3");
+    _setProperty("HistogramV_THS", "CaloFuturePIDs/CALO/BREMPIDE/h3");
+
+    _setProperty("AcceptedType", Gaudi::Utils::toString<int>(
+                                     LHCb::Track::Types::Velo, LHCb::Track::Types::Long,
+                                     LHCb::Track::Types::Upstream));
+  };
+};
+
+// ============================================================================
+
+DECLARE_COMPONENT( BremPIDeAlgFuture )
+
+// ============================================================================
diff --git a/CaloFuture/CaloFuturePIDs/src/CaloFutureBremMatch.cpp b/CaloFuture/CaloFuturePIDs/src/CaloFutureBremMatch.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..41900ffe2cb641b2ee6bd04443421e666c77f3ed
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/CaloFutureBremMatch.cpp
@@ -0,0 +1,165 @@
+// Include files
+#include "CaloFutureInterfaces/ICaloFutureTrackMatch.h"
+#include "Event/Track.h"
+#include "Event/CaloPosition.h"
+#include "CaloFutureTrackMatch.h"
+#include "Linear.h"
+
+// ============================================================================
+/** @file
+ *  Implementation file for class CaloFutureBremMatch
+ *  @date 2006-05-29
+ *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
+ */
+// ============================================================================
+
+class CaloFutureBremMatch final : public virtual ICaloFutureTrackMatch,
+                            public CaloFutureTrackMatch {
+ public:
+  /// initialize the tool
+  StatusCode initialize() override {
+    StatusCode sc = CaloFutureTrackMatch::initialize();
+    if ( sc.isFailure() ) { return sc ; }
+    m_showerMax = calo()->plane(CaloPlane::ShowerMax);
+    return StatusCode::SUCCESS;
+  }
+
+ public:
+  /** the main matching method
+   *  @see ICaloFutureTrackMatch
+   *  @param caloObj  pointer to "calorimeter" object (position)
+   *  @param trObj    pointer to tracking object (track)
+   *  @param chi2     returned value of chi2 of the matching
+   *  @return status code for matching procedure
+   */
+  StatusCode match(const LHCb::CaloPosition* caloObj, const LHCb::Track* trObj,
+                   double& chi2) override;
+
+  /** The main matching method (Stl interface)
+   *  @see ICaloFutureTrackMatch
+   *  @param caloObj  pointer to "calorimeter" object (position)
+   *  @param trObj    pointer to tracking object (track)
+   *  @return pair of status code/chi2  for matching procedure
+   */
+  MatchingPair operator()(const LHCb::CaloPosition* caloObj,
+                          const LHCb::Track* trObj) override {
+    double chi2;
+    StatusCode sc = match(caloObj, trObj, chi2);
+    return std::make_pair(sc, chi2);
+  }
+
+  /** extract the TrState which was actually used for last matching
+   *  @attention TrState is owned by the tool itself
+   *  The better solution could be to return the pointer
+   *  to TrStateP
+   *  @return pointer to the state actually used for last matching
+   */
+  const LHCb::State* state() const override { return &_state(); }
+
+  CaloFutureBremMatch(const std::string& type, const std::string& name,
+                const IInterface* parent)
+      : CaloFutureTrackMatch(type, name, parent) {
+    declareInterface<ICaloFutureTrackMatch>(this);
+    _setProperty("CalorimeterFuture", DeCalorimeterLocation::Ecal);
+    _setProperty("Tolerance", "10");            // 10 millimeters
+    _setProperty("zForFastExtrapolator", "0");  // 0  meters
+  }
+
+ private:
+  typedef CaloFutureTrackMatch::Match_<2> Match;
+  //
+  Match m_caloMatch;
+  Match m_trackMatch;
+  Gaudi::Plane3D m_showerMax;
+  const LHCb::CaloPosition* m_cBad = nullptr;
+  const LHCb::Track* m_tBad = nullptr;
+};
+
+// ============================================================================
+
+DECLARE_COMPONENT( CaloFutureBremMatch )
+
+// ============================================================================
+/// the main matching method
+// ============================================================================
+
+StatusCode CaloFutureBremMatch::match(const LHCb::CaloPosition* caloObj,
+                                const LHCb::Track* trObj, double& chi2) {
+  chi2 = bad();  // reset chi2
+
+  // check the stored values!
+  if (m_cBad == caloObj || m_tBad == trObj) {
+    return StatusCode::FAILURE;
+  }
+
+  if (caloObj == nullptr) {
+    return Error("match(): CaloPosition* points to NULL");
+  }
+
+  if (!use(trObj)) {
+    return Error("match(): track is not OK");
+  }
+
+  if (updateCaloFuturePos(m_position, caloObj)) {
+    // if ( m_position != caloObj ){
+    // update the position
+    StatusCode sc = fillBrem(*caloObj, m_caloMatch);
+    if (sc.isFailure()) {
+      m_cBad = caloObj;
+      return Warning("match(): Error from fill(2D) ", sc, 0);
+    }
+    // find the proper plane in the detector
+    const LHCb::CaloPosition::Center& par = caloObj->center();
+    const Gaudi::XYZPoint point(par(0), par(1), caloObj->z());
+    if (tolerance() < m_plane.Distance(point)) {
+      m_plane = calo()->plane(point);
+    }
+    // keep the track of the position
+    m_position = caloObj;
+  }
+  //
+  // get the correct state
+  const LHCb::State* state = nullptr;
+  {  // get the correct state at TT
+    state = CaloFutureTrackTool::state(*trObj, LHCb::State::Location::AtTT);
+    if (state == nullptr) {
+      state = CaloFutureTrackTool::state(*trObj, LHCb::State::Location::EndRich1);
+    }
+    if (state == nullptr) {
+      state = CaloFutureTrackTool::state(*trObj, LHCb::State::Location::BegRich1);
+    }
+    if (state == nullptr) {
+      state = CaloFutureTrackTool::state(*trObj, LHCb::State::Location::EndVelo);
+    }
+    // no appropriate state is found
+    if (state == nullptr) {
+      // get the closest state to some artificial value
+      state = &(trObj->closestState(2.0 * Gaudi::Units::meter));
+      // allowed z ?
+      if (state->z() > 4.0 * Gaudi::Units::meter) {
+        if (msgLevel(MSG::DEBUG)) print(debug(), trObj);
+        m_tBad = trObj;
+        return Warning("No appropriate states are found, see 'debug'");
+      }
+    }
+    // use the linear extrapolator
+    // StatusCode sc = propagate ( _state() , m_plane );
+    StatusCode sc = Utils::Linear::propagate(*state, m_plane, _state());
+    if (sc.isFailure()) {
+      m_tBad = trObj;
+      return Warning("match(): failure from propagate (1) ", sc);
+    }
+  }
+
+  StatusCode sc = fill(_state(), m_trackMatch);
+  if (sc.isFailure()) {
+    return Warning("match(): error for fill(2D)");
+  }
+
+  // make a real evaluation
+  chi2 = CaloFutureTrackMatch::chi2(m_caloMatch, m_trackMatch);
+
+  return StatusCode::SUCCESS;
+}
+
+// ============================================================================
diff --git a/CaloFuture/CaloFuturePIDs/src/CaloFutureChi22ID.cpp b/CaloFuture/CaloFuturePIDs/src/CaloFutureChi22ID.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0f004dd8bc7f9b0105b3ee6cc5a40791bb18a3ec
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/CaloFutureChi22ID.cpp
@@ -0,0 +1,51 @@
+// Include files
+#include "CaloFutureChi22ID.h"
+
+// =============================================================================
+/** @file
+ *  Implementation file for class CaloFutureChi22ID
+ *  @date 2006-06-18
+ *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
+ */
+// =============================================================================
+
+//DECLARE_COMPONENT( CaloFutureChi22ID )
+
+// =============================================================================
+/// Standard protected constructor
+// =============================================================================
+template <typename TABLEI, typename TABLEO>
+CaloFutureChi22ID<TABLEI,TABLEO>::CaloFutureChi22ID(const std::string& name, ISvcLocator* pSvcLocator)
+    : base_type(name, pSvcLocator, {KeyValue{"Tracks",""},KeyValue{"Input",""}},KeyValue{"Output",""}) {
+  // context-dependent default track container
+  Gaudi::Functional::updateHandleLocation(*this, "Tracks", LHCb::CaloFutureAlgUtils::TrackLocations(context()).front());
+}
+
+// =============================================================================
+/// algorithm execution
+// =============================================================================
+template <typename TABLEI, typename TABLEO>
+TABLEO CaloFutureChi22ID<TABLEI,TABLEO>::operator()(const LHCb::Tracks& tracks, const TABLEI& input) const {
+
+  TABLEO output(input.relations().size()+10);
+  for(auto const& track : tracks){
+    if( !use(track) ) continue;
+    auto links = input.inverse()->relations( track );
+    // fill the relation table
+    auto chi2 = links.empty() ? m_large.value() : links.front().weight();
+    output.i_push( track,chi2 );
+  }
+  /// MANDATORY: i_sort after i_push
+  output.i_sort();
+
+  m_nTracks+= tracks.size();
+  m_nLinks += output.i_relations().size();
+
+  return output;
+}
+
+// =============================================================================
+
+template class CaloFutureChi22ID<LHCb::RelationWeighted2D<LHCb::CaloHypo, LHCb::Track, float>,LHCb::Relation1D<LHCb::Track,float>>;
+template class CaloFutureChi22ID<LHCb::RelationWeighted2D<LHCb::CaloCluster, LHCb::Track, float>,LHCb::Relation1D<LHCb::Track,float>>;
+
diff --git a/CaloFuture/CaloFuturePIDs/src/CaloFutureChi22ID.h b/CaloFuture/CaloFuturePIDs/src/CaloFutureChi22ID.h
new file mode 100644
index 0000000000000000000000000000000000000000..52f206af2db4c2fc944acb2d3a920da69530d690
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/CaloFutureChi22ID.h
@@ -0,0 +1,48 @@
+#ifndef CALOFUTUREPIDS_CALOFUTURECHI22ID_H
+#define CALOFUTUREPIDS_CALOFUTURECHI22ID_H 1
+
+// Include files
+#include "CaloFutureTrackAlg.h"
+#include "CaloFutureUtils/CaloFuture2Track.h"
+#include "CaloFutureUtils/CaloFutureAlgUtils.h"
+#include "Event/CaloCluster.h"
+#include "Event/CaloHypo.h"
+#include "Event/Track.h"
+#include "GaudiAlg/Transformer.h"
+#include "GaudiKernel/Counters.h"
+#include "Relations/Relation1D.h"
+#include "Relations/RelationWeighted2D.h"
+
+// ============================================================================
+/** @class CaloFutureChi22ID CaloFutureChi22ID.h
+ *
+ *
+ *  @author Ivan BELYAEV
+ *  @date   2006-06-18
+ */
+// ============================================================================
+template <typename TABLEI, typename TABLEO>
+class CaloFutureChi22ID : public Gaudi::Functional::Transformer<TABLEO(const LHCb::Tracks&,const TABLEI&), Gaudi::Functional::Traits::BaseClass_t<CaloFutureTrackAlg> > 
+{
+  public:
+    using CaloFutureTrackAlg::context;
+    using CaloFutureTrackAlg::use;
+    using CaloFutureTrackAlg::getProperty;
+    using CaloFutureTrackAlg::_setProperty;
+    using base_type = Gaudi::Functional::Transformer<TABLEO(const LHCb::Tracks&,const TABLEI&),Gaudi::Functional::Traits::BaseClass_t<CaloFutureTrackAlg> >;
+    using KeyValue  = typename base_type::KeyValue;
+
+    // standard constructor
+    CaloFutureChi22ID(const std::string& name, ISvcLocator* pSvc);
+
+    /// algorithm execution
+    TABLEO operator()(const LHCb::Tracks& tracks, const TABLEI& input) const override;
+
+  protected:
+    Gaudi::Property<float> m_large{ this, "CutOff", 10000, "large value"};
+
+    mutable Gaudi::Accumulators::StatCounter<>  m_nLinks {this, "#links in table"};
+    mutable Gaudi::Accumulators::StatCounter<>  m_nTracks {this, "#total tracks"};
+};
+#endif  // CALOFUTURECHI22ID_H
+// ============================================================================
diff --git a/CaloFuture/CaloFuturePIDs/src/CaloFutureElectronMatch.cpp b/CaloFuture/CaloFuturePIDs/src/CaloFutureElectronMatch.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7144ae0de0e9663e19d72a755085c266749a2e66
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/CaloFutureElectronMatch.cpp
@@ -0,0 +1,162 @@
+// Include files
+#include "CaloFutureInterfaces/ICaloFutureTrackMatch.h"
+#include "Event/Track.h"
+#include "Event/CaloPosition.h"
+#include "CaloFutureTrackMatch.h"
+
+// ============================================================================
+/** @file
+ *  Implementation file for class CaloFutureElectronMatch
+ *  @date 2006-05-29
+ *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
+ */
+// ============================================================================
+
+class CaloFutureElectronMatch final : public virtual ICaloFutureTrackMatch,
+                                public CaloFutureTrackMatch {
+ public:
+  /// initialize the tool
+  StatusCode initialize() override {
+    StatusCode sc = CaloFutureTrackMatch::initialize();
+    if (sc.isFailure()) { return sc; }
+    m_showerMax = calo()->plane(CaloPlane::ShowerMax);
+    return StatusCode::SUCCESS;
+  };
+
+ public:
+  /** the main matching method
+   *  @see ICaloFutureTrackMatch
+   *  @param caloObj  pointer to "calorimeter" object (position)
+   *  @param trObj    pointer to tracking object (track)
+   *  @param chi2     returned value of chi2 of the matching
+   *  @return status code for matching procedure
+   */
+  StatusCode match(const LHCb::CaloPosition* caloObj, const LHCb::Track* trObj,
+                   double& chi2) override;
+
+  /** The main matching method (Stl interface)
+   *  @see ICaloFutureTrackMatch
+   *  @param caloObj  pointer to "calorimeter" object (position)
+   *  @param trObj    pointer to tracking object (track)
+   *  @return pair of status code/chi2  for matching procedure
+   */
+  MatchingPair operator()(const LHCb::CaloPosition* caloObj,
+                          const LHCb::Track* trObj) override {
+    double chi2;
+    StatusCode sc = match(caloObj, trObj, chi2);
+    return std::make_pair(sc, chi2);
+  };
+
+  /** extract the TrState which was actually used for last matching
+   *  @attention TrState is owned by the tool itself
+   *  The better solution could be to return the pointer
+   *  to TrStateP
+   *  @return pointer to the state actually used for last matching
+   */
+  const LHCb::State* state() const override { return &_state(); };
+
+  CaloFutureElectronMatch(const std::string& type, const std::string& name,
+                    const IInterface* parent)
+      : CaloFutureTrackMatch(type, name, parent) {
+    declareInterface<ICaloFutureTrackMatch>(this);
+    _setProperty("CalorimeterFuture", DeCalorimeterLocation::Ecal);
+    _setProperty("Tolerance", "5");  // 5 millimeters
+  };
+
+ private:
+  typedef CaloFutureTrackMatch::Match_<3> Match;
+  //
+  Match m_caloMatch;
+  Match m_trackMatch;
+  Gaudi::Plane3D m_showerMax;
+  const LHCb::CaloPosition* m_cBad = nullptr;
+  const LHCb::Track* m_tBad = nullptr;
+};
+
+// ============================================================================
+
+DECLARE_COMPONENT( CaloFutureElectronMatch )
+
+// ============================================================================
+/// the main matching method
+// ============================================================================
+
+StatusCode CaloFutureElectronMatch::match(const LHCb::CaloPosition* caloObj,
+                                    const LHCb::Track* trObj, double& chi2) {
+  using namespace LHCb;
+
+  chi2 = bad();  // reset chi2
+  //
+  // check the stored values!
+  if (m_cBad == caloObj || m_tBad == trObj) {
+    return StatusCode::FAILURE;
+  }
+
+  if (caloObj == nullptr) {
+    return Error("match(): CaloPosition* points to NULL");
+  }
+
+  if (!use(trObj)) {
+    return Error("match(): track is not OK");
+  }
+
+  if (updateCaloFuturePos(m_position, caloObj)) {
+    // update the position
+    StatusCode sc = fill(*caloObj, m_caloMatch);
+    if (sc.isFailure()) {
+      m_cBad = caloObj;
+      return Warning("match(): Error from fill(2D) ", sc, 0);
+    }
+    // find the proper plane in detector
+    const LHCb::CaloPosition::Center& par = caloObj->center();
+    const Gaudi::XYZPoint point(par(0), par(1), caloObj->z());
+    if (tolerance() < m_plane.Distance(point)) {
+      m_plane = calo()->plane(point);
+    }
+    // keep the track of the position
+    m_position = caloObj;
+  }
+  //
+  // get the correct state
+  const LHCb::State* st = nullptr;
+  {
+    st = CaloFutureTrackTool::state(*trObj, LHCb::State::Location::ECalShowerMax);
+    if (st == nullptr) {
+      StatusCode sc = propagate(*trObj, m_showerMax, _state());
+      if (sc.isFailure()) {
+        m_tBad = trObj;
+        return Warning("match(): failure from propagate (1) ", sc);
+      }
+      _state().setLocation(LHCb::State::Location::ECalShowerMax);
+      const_cast<LHCb::Track*>(trObj)->addToStates(_state());
+      st = CaloFutureTrackTool::state(*trObj, LHCb::State::Location::ECalShowerMax);
+    }
+    // check the validity of the state
+    if (tolerance() < ::fabs(m_plane.Distance(st->position())))
+    // if ( 1 * Gaudi::Units::mm < ::fabs( caloObj->z() - st->position().z() ) )
+    // // let's decrease z-tolerance here to 1 mm
+    {
+      _state() = *st;
+      StatusCode sc = propagate(_state(), m_plane);
+      // StatusCode sc = propagate ( _state() , caloObj->z() );
+      if (sc.isFailure()) {
+        m_tBad = trObj;
+        return Warning("match(): failure from propagate (2) ", sc);
+      }
+      st = &_state();
+    }
+  }
+
+  Assert(st != nullptr, "LHCb::State* points to NULL!");
+  StatusCode sc = fill(*st, m_trackMatch);
+  if (sc.isFailure()) {
+    return Warning("match(): error for fill(3D)");
+  }
+
+  // make a real evaluation
+  chi2 = CaloFutureTrackMatch::chi2(m_caloMatch, m_trackMatch);
+
+  return StatusCode::SUCCESS;
+}
+
+// ============================================================================
diff --git a/CaloFuture/CaloFuturePIDs/src/CaloFutureEnergyForTrack.cpp b/CaloFuture/CaloFuturePIDs/src/CaloFutureEnergyForTrack.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..cb17cc42acf896f7472d76c2e72cdb9bebf2ab07
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/CaloFutureEnergyForTrack.cpp
@@ -0,0 +1,328 @@
+// Include files
+#include "CaloFutureEnergyForTrack.h"
+#include <set>
+#include "CaloFutureInterfaces/ICaloFutureTrackIdEval.h"
+#include "CaloFutureUtils/CaloFutureNeighbours.h"
+#include "Event/CaloDigit.h"
+#include "Event/Track.h"
+#include "GaudiKernel/IIncidentListener.h"
+#include "GaudiKernel/IIncidentSvc.h"
+
+// ============================================================================
+// constructor
+// ============================================================================
+
+CaloFutureEnergyForTrack::CaloFutureEnergyForTrack(const std::string &type,
+                                       const std::string &name,
+                                       const IInterface *parent)
+    : CaloFuture::CaloFutureTrackTool(type, name, parent) {
+  declareInterface <ICaloFutureTrackIdEval>   ( this ) ;
+  declareInterface <ICaloFutureDigits4Track>  ( this ) ;
+  declareInterface <IIncidentListener>  ( this ) ;
+}
+
+// ============================================================================
+// initialize the tool
+// ============================================================================
+
+StatusCode CaloFutureEnergyForTrack::initialize() {
+  StatusCode sc = CaloFuture::CaloFutureTrackTool::initialize();
+  if (sc.isFailure()) {
+    return sc;
+  }
+  if (m_address.empty()) {
+    return Error("Invalid 'DataAddress'");
+  }
+  auto isvc = service<IIncidentSvc>("IncidentSvc", true);
+  isvc->addListener(this, IncidentType::BeginEvent);
+  //
+  std::string det = detectorName();
+  const long caloID = CaloCellCode::CaloNumFromName(det.c_str());
+  switch (caloID) {
+    case 0:
+      // SPD
+      m_location = LHCb::State::Location::Spd;
+      m_planes = {calo()->plane(CaloPlane::Middle)};
+      break;  // BREAK
+    case 1:
+      // PRS
+      m_location = LHCb::State::Location::Prs;
+      m_planes = {calo()->plane(CaloPlane::Middle)};
+      break;
+    case 2:
+      // ECAL
+      m_location = LHCb::State::Location::ECalShowerMax;
+      m_planes = {
+          calo()->plane(CaloPlane::Front), calo()->plane(CaloPlane::ShowerMax),
+          calo()->plane(CaloPlane::Middle), calo()->plane(CaloPlane::Back)};
+      break;
+    case 3:
+      // HCAL
+      m_location = LHCb::State::Location::MidHCal;
+      m_planes = {calo()->plane(CaloPlane::Front),
+                  calo()->plane(CaloPlane::Middle),
+                  calo()->plane(CaloPlane::Back)};
+      break;
+    default:
+      return Error("Invald calorimeter TYPE! '" + detectorName() + "'");
+  }
+  //
+  if (propsPrint() || msgLevel(MSG::DEBUG)) {
+    info() << "State Location is set to '" << m_location << "'" << endmsg;
+  }
+  //
+  if (m_planes.empty()) {
+    return Error("Empty list of CaloFuture-planes");
+  }
+  //
+  return StatusCode::SUCCESS;
+}
+
+// ============================================================================
+/*  collect the cellID-s along the line
+ *  @param line   (INPUT)  the line
+ *  @param cells  (OUTPUT) the container of cells
+ *  @return status code
+ */
+// ============================================================================
+
+StatusCode CaloFutureEnergyForTrack::collect(const CaloFutureEnergyForTrack::Line& line,
+                                       LHCb::CaloCellID::Set& cells) const {
+  cells.clear();
+
+  // get the interesection points of the line with the planes
+  Points points;
+  {
+    points.reserve(m_planes.size() + m_morePlanes);
+    // get the intersection points
+    for (const auto plane: m_planes){
+      double mu = 0;
+      Gaudi::XYZPoint point;
+      Gaudi::Math::intersection(line, plane, point, mu);
+      points.push_back(point);
+    }
+    // add some additional points (if requested)
+    if (2 <= points.size() && 0 < m_morePlanes) {
+      // the same line but in another reparameterization:
+      const auto l2 = Line(points.front(), points.back() - points.front());
+      const double dmu = 1.0 / (1.0 + m_morePlanes);
+      for (unsigned short i = 0; i < m_morePlanes; ++i) {
+        points.push_back(l2.position(dmu * (i + 1.0)));
+      }
+    }
+  }
+  // get all touched calorimeter cells: convert points to cells
+  for (const auto point: points){
+    // get the cell !
+    const auto callParam = calo()->Cell_(point);
+    /// skip invalid cells
+    if (callParam == nullptr || !callParam->valid()) {
+      continue;
+    }
+    // collect all valid cells
+    cells.insert(callParam->cellID());
+  }
+
+  // add neighbours
+  if (0 < m_addNeighbors) {
+    LHCb::CaloFutureFunctors::neighbours(cells, m_addNeighbors, calo());
+  }
+
+  return StatusCode::SUCCESS;
+}
+// ============================================================================
+/*  collect the cellID-s along the line
+ *  @param line   (INPUT)  the line
+ *  @param cells  (OUTPUT) the container of cells
+ *  @return status code
+ */
+// ============================================================================
+StatusCode CaloFutureEnergyForTrack::collect(const CaloFutureEnergyForTrack::Line& line,
+                                       LHCb::CaloCellID::Vector& cells) const {
+  cells.clear();
+  Cells _cells;
+  StatusCode sc = collect(line, _cells);
+  if (sc.isFailure()) {
+    return sc;
+  }
+  cells.insert(cells.end(), _cells.begin(), _cells.end());
+  return StatusCode::SUCCESS;
+}
+// ============================================================================
+/*  collect the cellID-s along the path of the tracks
+ *  @param track  (INPUT)  the track
+ *  @param cells  (OUTPUT) the container of cells
+ *  @return status code
+ */
+// ============================================================================
+StatusCode CaloFutureEnergyForTrack::collect(const LHCb::Track* track,
+                                       LHCb::CaloCellID::Set& cells) const {
+  cells.clear();
+
+  // get the correct state
+  auto state = CaloFutureTrackTool::state(*track, m_location);
+  if (state == nullptr) {
+    // propagate it!
+    StatusCode sc = propagate(*track, m_planes.front(), m_state);
+    if (sc.isFailure()) {
+      return Error("process(): failure from propagate,  return 'bad'", sc);
+    }
+    // initialize the state
+    state = &m_state;
+  }
+  // get the line from the state:
+  const auto l1 = line(*state);
+  return collect(l1, cells);
+}
+// ============================================================================
+/*  collect the cellID-s along the path of the tracks
+ *  @param track  (INPUT)  the track
+ *  @param cells  (OUTPUT) the container of cells
+ *  @return status code
+ */
+// ============================================================================
+StatusCode CaloFutureEnergyForTrack::collect(const LHCb::Track* track,
+                                       LHCb::CaloCellID::Vector& cells) const {
+  cells.clear();
+  Cells _cells;
+  StatusCode sc = collect(track, _cells);
+  if (sc.isFailure()) {
+    return Error("Error from collect(set)", sc);
+  }
+  cells.insert(cells.end(), _cells.begin(), _cells.end());
+  return StatusCode::SUCCESS;
+}
+// ==========================================================================
+/*  collect the fired digits along the path of the tracks
+ *  @param line   (INPUT)  the line
+ *  @param hits   (OUTPUT) the container of digits
+ *  @return status code
+ */
+// ==========================================================================
+StatusCode CaloFutureEnergyForTrack::collect(const CaloFutureEnergyForTrack::Line& line,
+                                       LHCb::CaloDigit::Set& hits) const {
+  hits.clear();
+  Cells cells;
+  StatusCode sc = collect(line, cells);
+  if (sc.isFailure()) {
+    return Error("Error from collect(cells)", sc);
+  }
+  // convert cells into digits:
+  if (!cells.empty()) {
+    const Digits* data = digits();
+    for (const auto cell: cells){
+      // get the gidit
+      const auto digit = data->object(cell);
+      // accumulate good fired cells
+      if (digit != nullptr) {
+        hits.insert(digit);
+      }
+    }
+  }
+  return StatusCode::SUCCESS;
+}
+// ============================================================================
+/*  collect the fired digits along the line
+ *  @param line   (INPUT)  the line
+ *  @param digits (OUTPUT) the container of digits
+ *  @return status code
+ */
+// ============================================================================
+StatusCode CaloFutureEnergyForTrack::collect(const CaloFutureEnergyForTrack::Line& line,
+                                       LHCb::CaloDigit::Vector& hits) const {
+  hits.clear();
+  LHCb::CaloDigit::Set _hits;
+  StatusCode sc = collect(line, _hits);
+  if (sc.isFailure()) {
+    return Error("Error from collect(set)", sc);
+  }
+  hits.insert(hits.end(), _hits.begin(), _hits.end());
+  return StatusCode::SUCCESS;
+}
+// ============================================================================
+/*  collect the digits from the given calorimeter along the track
+ *  @param  track  (INPUT)  pointer to the object to be processed
+ *  @param  digits (OUTPUT) the conatiner of collected digits
+ *  @return status code
+ */
+// ============================================================================
+StatusCode CaloFutureEnergyForTrack::collect(const LHCb::Track* track,
+                                       LHCb::CaloDigit::Set& hits) const {
+  hits.clear();
+  Cells cells;
+  StatusCode sc = collect(track, cells);
+  if (sc.isFailure()) {
+    return Error("Error from collect(cells)", sc);
+  }
+  // convert cells into digits:
+  if (!cells.empty()) {
+    const auto data = digits();
+    for (const auto cell: cells){
+      // get the gidit
+      const auto digit = data->object(cell);
+      // accumulate good fired cells
+      if (digit != nullptr) {
+        hits.insert(digit);
+      }
+    }
+  }
+  return StatusCode::SUCCESS;
+}
+// ============================================================================
+/*  collect the digits from the given calorimeter along the track
+ *  @param  track  (INPUT)  pointer to the object to be processed
+ *  @param  digits (OUTPUT) the conatiner of collected digits
+ *  @return status code
+ */
+// ============================================================================
+StatusCode CaloFutureEnergyForTrack::collect(const LHCb::Track* track,
+                                       LHCb::CaloDigit::Vector& hits) const {
+  hits.clear();
+  LHCb::CaloDigit::Set _hits;
+  StatusCode sc = collect(track, _hits);
+  if (sc.isFailure()) {
+    return Error("Error from collect(set)", sc);
+  }
+  hits.insert(hits.end(), _hits.begin(), _hits.end());
+  return StatusCode::SUCCESS;
+}
+// ============================================================================
+// The main processing method
+// ============================================================================
+StatusCode CaloFutureEnergyForTrack::process(const LHCb::Track* track,
+                                       double& value) const {
+  value = m_bad;
+  LHCb::CaloDigit::Set hits;
+  StatusCode sc = collect(track, hits);
+  if (sc.isFailure()) {
+    return Error("Error from 'collect(set)'", sc);
+  }
+
+  // accumulate the energy from all touched cells
+  double energy = 0;
+  for (const auto digit: hits){
+    if (digit != nullptr) {
+      energy += digit->e();
+    }
+  }
+  //
+  value = energy;  // RESULT
+  //
+  return StatusCode::SUCCESS;
+}
+// ============================================================================
+// The main processing method (functor interface)
+// ============================================================================
+double CaloFutureEnergyForTrack::operator()(const LHCb::Track* track) const {
+  double value = m_bad;
+  StatusCode sc = process(track, value);
+  Assert(sc.isSuccess(), "Failure from process():", sc);
+  return value;
+}
+// ============================================================================
+/// factory
+// ============================================================================
+DECLARE_COMPONENT( CaloFutureEnergyForTrack )
+// ============================================================================
+// The END
+// ============================================================================
diff --git a/CaloFuture/CaloFuturePIDs/src/CaloFutureEnergyForTrack.h b/CaloFuture/CaloFuturePIDs/src/CaloFutureEnergyForTrack.h
new file mode 100644
index 0000000000000000000000000000000000000000..74cb3f68eeba9148b303df3ccc35a4c15573ee20
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/CaloFutureEnergyForTrack.h
@@ -0,0 +1,153 @@
+#ifndef CALOFUTUREENERGYFORTRACK_H
+#define CALOFUTUREENERGYFORTRACK_H 1
+
+// Include files
+#include <set>
+#include "GaudiKernel/IIncidentSvc.h"
+#include "GaudiKernel/IIncidentListener.h"
+#include "CaloFutureInterfaces/ICaloFutureTrackIdEval.h"
+#include "CaloFutureInterfaces/ICaloFutureDigits4Track.h"
+#include "Event/Track.h"
+#include "Event/CaloDigit.h"
+#include "CaloFutureTrackTool.h"
+
+// ============================================================================
+/** @class CaloFutureEnergyForTrack
+ *  tool which accumulates the energy for the given track
+ *  along the track line
+ *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
+ */
+class CaloFutureEnergyForTrack : public virtual ICaloFutureTrackIdEval,
+                           public virtual ICaloFutureDigits4Track,
+                           public virtual IIncidentListener,
+                           public CaloFuture::CaloFutureTrackTool {
+ public:
+  typedef LHCb::CaloDigit::Container Digits;
+  typedef ICaloFutureDigits4Track::Line Line;
+
+  /// Inform that a new incident has occured @see IIncidentListener
+  void handle(const Incident&) override { m_digits = 0; }
+
+  StatusCode initialize() override;
+
+  /** The main processing method
+   *  It evaluated the Track ID estimators using the calorimeter information
+   *  @param  track  pointer to the object to be processed
+   *  @param  value  (return) the value of the estimator
+   *  @return status code
+   */
+  StatusCode process(const LHCb::Track* track, double& value) const override;
+
+  /** The main processing method (functor interface)
+   *  It evaluated the Track ID estimators using the calorimeter information
+   *  @param  track  pointer to the object to be processed
+   */
+  double operator()(const LHCb::Track* track) const override;
+
+  /** collect the cellID-s along the line
+   *  @param line   (INPUT)  the line
+   *  @param cells  (OUTPUT) the container of cells
+   *  @return status code
+   */
+  StatusCode collect(const Line& line,
+                     LHCb::CaloCellID::Vector& cells) const override;
+
+  /** collect the cellID-s along the line
+   *  @param line   (INPUT)  the line
+   *  @param cells  (OUTPUT) the container of cells
+   *  @return status code
+   */
+  StatusCode collect(const Line& line,
+                     LHCb::CaloCellID::Set& cells) const override;
+
+  /** collect the cellID-s along the path of the tracks
+   *  @param track  (INPUT)  the track
+   *  @param cells  (OUTPUT) the container of cells
+   *  @return status code
+   */
+  StatusCode collect(const LHCb::Track* track,
+                     LHCb::CaloCellID::Vector& cells) const override;
+
+  /** collect the cellID-s along the path of the tracks
+   *  @param track  (INPUT)  the track
+   *  @param cells  (OUTPUT) the container of cells
+   *  @return status code
+   */
+  StatusCode collect(const LHCb::Track* track,
+                     LHCb::CaloCellID::Set& cells) const override;
+
+  /** collect the fired digits along the line
+   *  @param line   (INPUT)  the line
+   *  @param digits (OUTPUT) the container of digits
+   *  @return status code
+   */
+  StatusCode collect(const Line& line,
+                     LHCb::CaloDigit::Vector& digits) const override;
+
+  /** collect the fired digits along the path of the tracks
+   *  @param line   (INPUT)  the line
+   *  @param digits (OUTPUT) the container of digits
+   *  @return status code
+   */
+  StatusCode collect(const Line& line,
+                     LHCb::CaloDigit::Set& digits) const override;
+
+  /** collect the fired digits along the path of the tracks
+   *  @param track  (INPUT)  the track
+   *  @param digits (OUTPUT) the container of digits
+   *  @return status code
+   */
+  StatusCode collect(const LHCb::Track* track,
+                     LHCb::CaloDigit::Vector& digits) const override;
+
+  /** collect the fired digits along the path of the tracks
+   *  @param track  (INPUT)  the track
+   *  @param digits (OUTPUT) the container of digits
+   *  @return status code
+   */
+  StatusCode collect(const LHCb::Track* track,
+                     LHCb::CaloDigit::Set& digits) const override;
+
+  CaloFutureEnergyForTrack(const std::string& type, const std::string& name,
+                     const IInterface* parent);
+
+ protected:
+  // get the data form TES
+  inline const Digits* digits() const;
+
+  typedef std::vector<Gaudi::Plane3D> Planes;
+  typedef std::vector<Gaudi::XYZPoint> Points;
+  typedef std::vector<LHCb::State*> States;
+  typedef LHCb::CaloCellID::Set Cells;
+
+ private:
+  mutable const Digits* m_digits = nullptr;
+  mutable LHCb::State m_state;
+
+  Gaudi::Property<std::string> m_address
+    {this, "DataAddress", "", "TES-location of corresponding CaloDigits"};
+
+  Gaudi::Property<double> m_bad
+    {this, "BadValue", 1e+10, "The bad value to be returned"};
+
+  LHCb::State::Location       m_location = LHCb::State::Location::Spd;
+  Planes                      m_planes;
+  Gaudi::Property<unsigned short> m_morePlanes   {this, "MorePlanes", 0};
+  Gaudi::Property<unsigned short> m_addNeighbors {this, "AddNeighbours", 0};
+
+};
+
+// ============================================================================
+// get the data form TES
+// ============================================================================
+
+inline const CaloFutureEnergyForTrack::Digits* CaloFutureEnergyForTrack::digits() const {
+  if (m_digits == nullptr) {
+    m_digits = get<Digits>(m_address);
+  }
+  return m_digits;
+}
+
+// ============================================================================
+#endif  // CALOFUTUREENERGYFORTRACK_H
+// ============================================================================
diff --git a/CaloFuture/CaloFuturePIDs/src/CaloFutureID2DLL.cpp b/CaloFuture/CaloFuturePIDs/src/CaloFutureID2DLL.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6c0c9cf454bc7b0d42b213b761cc4432522baa45
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/CaloFutureID2DLL.cpp
@@ -0,0 +1,200 @@
+// Include files
+#include <type_traits>
+#include "GaudiKernel/ITHistSvc.h"
+#include "DetDesc/HistoParam.h"
+#include "CaloFutureID2DLL.h"
+#include "GaudiUtils/Aida2ROOT.h"
+
+// ============================================================================
+/** @file
+ *  Implementation file for class CaloFutureID2DLL
+ *  @date 2006-06-18
+ *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
+ */
+// ============================================================================
+
+DECLARE_COMPONENT( CaloFutureID2DLL )
+
+// ============================================================================
+/// standard proected constructor
+// ============================================================================
+
+CaloFutureID2DLL::CaloFutureID2DLL(const std::string &name, ISvcLocator *pSvcLocator)
+    : Transformer(name, pSvcLocator, KeyValue{"Input", ""}, KeyValue{"Output", ""}) {
+  // track types
+  _setProperty("AcceptedType", Gaudi::Utils::toString<int>(
+                                   LHCb::Track::Types::Long, 
+                                   LHCb::Track::Types::Ttrack,
+                                   LHCb::Track::Types::Downstream
+                                   ));
+}
+
+//==============================================================================
+// Algorithm initialization
+//==============================================================================
+
+StatusCode CaloFutureID2DLL::initialize() {
+  StatusCode sc = Transformer::initialize();
+  if (sc.isFailure())
+    return sc;
+
+  if (!existDet<DataObject>(detSvc(), m_conditionName)) {
+    warning() << "Initialise: Condition '" << m_conditionName
+              << "' not found -- switch to reading the DLLs from THS!"
+              << endmsg;
+    m_useCondDB = false;
+  }
+
+  sc = m_useCondDB ? initializeWithCondDB() : initializeWithoutCondDB();
+  return sc;
+}
+
+// ============================================================================
+
+StatusCode CaloFutureID2DLL::initializeWithCondDB()
+{
+  info() << "init with CondDB, m_conditionName = " << m_conditionName.value() << endmsg;
+  try {
+    registerCondition(m_conditionName, m_cond, &CaloFutureID2DLL::i_updateDLL);
+  } catch (GaudiException &e) {
+    fatal() << e << endmsg;
+    return StatusCode::FAILURE;
+  }
+  StatusCode sc = runUpdate(); // load the conditions
+  return sc;
+}
+
+// ============================================================================
+
+StatusCode CaloFutureID2DLL::initializeWithoutCondDB() {
+  info() << "init w/o CondDB (read the 2D DLL histograms from a root file "
+            "through THS)"
+         << endmsg;
+
+  // locate the histogram
+  if (!m_title_lt_ths.empty()) {
+    AIDA::IHistogram2D *aida =
+        get<AIDA::IHistogram2D>(histoSvc(), m_title_lt_ths);
+    m_histo_lt = Gaudi::Utils::Aida2ROOT::aida2root(aida);
+  }
+
+  if (!m_title_dt_ths.empty()) {
+    AIDA::IHistogram2D *aida =
+        get<AIDA::IHistogram2D>(histoSvc(), m_title_dt_ths);
+    m_histo_dt = Gaudi::Utils::Aida2ROOT::aida2root(aida);
+  }
+
+  if (!m_title_tt_ths.empty()) {
+    AIDA::IHistogram2D *aida =
+        get<AIDA::IHistogram2D>(histoSvc(), m_title_tt_ths);
+    m_histo_tt = Gaudi::Utils::Aida2ROOT::aida2root(aida);
+  }
+
+  if (!m_title_vt_ths.empty()) {
+    AIDA::IHistogram2D *aida =
+        get<AIDA::IHistogram2D>(histoSvc(), m_title_vt_ths);
+    m_histo_vt = Gaudi::Utils::Aida2ROOT::aida2root(aida);
+  }
+
+  if (!m_title_ut_ths.empty()) {
+    AIDA::IHistogram2D *aida =
+        get<AIDA::IHistogram2D>(histoSvc(), m_title_ut_ths);
+    m_histo_ut = Gaudi::Utils::Aida2ROOT::aida2root(aida);
+  }
+
+  if (msgLevel(MSG::DEBUG))
+    debug() << "\nLong:        '" << m_title_lt_ths << "' -> "
+            << (void *)m_histo_lt << "\nDownstream:  '" << m_title_dt_ths
+            << "' -> " << (void *)m_histo_dt << "\nTTuricensis: '"
+            << m_title_tt_ths << "' -> " << (void *)m_histo_tt
+            << "\nUpstream:    '" << m_title_ut_ths << "' -> "
+            << (void *)m_histo_ut << "\nVelo:        '" << m_title_vt_ths
+            << "' -> " << (void *)m_histo_vt << endmsg;
+
+  return StatusCode::SUCCESS;
+}
+
+// ============================================================================
+/// Algorithm execution
+// ============================================================================
+
+Table CaloFutureID2DLL::operator()(const Table &input) const {
+
+  // create and register the output ocntainer
+  const auto links = input.relations();
+  auto table = Table(links.size());
+
+  // loop over all links
+  for (const auto link : links) {
+    const auto track = link.from();
+    const double value = link.to();
+    if (!use(track)) {
+      continue;
+    }
+
+    // convert value to DLL
+    const double DLL = dLL(track->p(), value, track->type());
+
+    // fill the relation table
+    table.i_push(track, (float)DLL); // NB!: i_push
+  };
+  /// MANDATORY: i_sort after i_push
+  table.i_sort();
+
+  if (counterStat->isQuiet())
+    counter(inputLocation() + "=>" + outputLocation()) +=
+        table.i_relations().size();
+
+  return table;
+}
+
+// ============================================================================
+
+StatusCode CaloFutureID2DLL::i_updateDLL() {
+  if (msgLevel(MSG::DEBUG))
+    debug() << "i_updateDLL() called" << endmsg;
+  if (!m_cond)
+    return StatusCode::FAILURE;
+
+  try {
+    if (!m_title_lt.empty()) {
+      m_histo_lt = reinterpret_cast<TH2D *>(
+          &m_cond->param<DetDesc::Params::Histo2D>(m_title_lt));
+    }
+
+    if (!m_title_dt.empty()) {
+      m_histo_dt = reinterpret_cast<TH2D *>(
+          &m_cond->param<DetDesc::Params::Histo2D>(m_title_dt));
+    }
+
+    if (!m_title_tt.empty()) {
+      m_histo_tt = reinterpret_cast<TH2D *>(
+          &m_cond->param<DetDesc::Params::Histo2D>(m_title_tt));
+    }
+
+    if (!m_title_ut.empty()) {
+      m_histo_ut = reinterpret_cast<TH2D *>(
+          &m_cond->param<DetDesc::Params::Histo2D>(m_title_ut));
+    }
+
+    if (!m_title_vt.empty()) {
+      m_histo_vt = reinterpret_cast<TH2D *>(
+          &m_cond->param<DetDesc::Params::Histo2D>(m_title_vt));
+    }
+  } catch (GaudiException &exc) {
+    fatal() << "DLL update failed! msg ='" << exc << "'" << endmsg;
+    return StatusCode::FAILURE;
+  }
+
+  if (msgLevel(MSG::DEBUG))
+    debug() << "\nLong:        '" << m_title_lt << "' -> " << (void *)m_histo_lt
+            << "\nDownstream:  '" << m_title_dt << "' -> " << (void *)m_histo_dt
+            << "\nTTuricensis: '" << m_title_tt << "' -> " << (void *)m_histo_tt
+            << "\nUpstream:    '" << m_title_ut << "' -> " << (void *)m_histo_ut
+            << "\nVelo:        '" << m_title_vt << "' -> " << (void *)m_histo_vt
+            << endmsg;
+
+  return StatusCode::SUCCESS;
+}
+
+// ============================================================================
diff --git a/CaloFuture/CaloFuturePIDs/src/CaloFutureID2DLL.h b/CaloFuture/CaloFuturePIDs/src/CaloFutureID2DLL.h
new file mode 100644
index 0000000000000000000000000000000000000000..d3856d4b088dac7be5ad58b017e0dc3f9d2b8bcf
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/CaloFutureID2DLL.h
@@ -0,0 +1,147 @@
+#ifndef CALOFUTUREPIDS_CALOFUTUREID2DLL_H
+#define CALOFUTUREPIDS_CALOFUTUREID2DLL_H 1
+
+// Include files
+#include <cmath>
+#include "GaudiKernel/VectorMap.h"
+#include "GaudiAlg/Transformer.h"
+#include "AIDA/IHistogram2D.h"
+#include "Relations/IRelation.h"
+#include "Relations/Relation1D.h"
+#include "Event/Track.h"
+#include "CaloFutureUtils/CaloFuture2Track.h"
+#include "CaloFutureTrackAlg.h"
+#include "CaloFutureUtils/CaloFutureAlgUtils.h"
+#include "ToString.h"
+#include "ToVector.h"
+#include "DetDesc/Condition.h"
+#include "TH2D.h"
+
+
+class ITHistSvc;
+
+// ============================================================================
+/** @class CaloFutureID2DLL CaloFutureID2DLL.h
+ *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
+ *  @date   2006-06-18
+ */
+// ============================================================================
+
+using Table = LHCb::Relation1D<LHCb::Track, float>;
+
+class CaloFutureID2DLL : public Gaudi::Functional::Transformer<
+                       Table(const Table &),
+                       Gaudi::Functional::Traits::BaseClass_t<CaloFutureTrackAlg>> {
+public:
+  StatusCode initialize() override;
+  Table operator()(const Table& input) const override;
+
+  /// callback function invoked by the UpdateManagerSvc
+  StatusCode i_updateDLL();
+  StatusCode dumpDLLsToFile();
+
+  CaloFutureID2DLL(const std::string &name, ISvcLocator *pSvc);
+
+protected:
+  inline double dLL(const double p, const double v,
+                    const LHCb::Track::Types t) const;
+
+private:
+  StatusCode initializeWithCondDB();
+  StatusCode initializeWithoutCondDB();
+
+protected:
+  // histogram title
+  Gaudi::Property<std::string> m_title_lt {this, "HistogramL", "", "histogram title long"  };
+  Gaudi::Property<std::string> m_title_dt {this, "HistogramD", "", "histogram title down"  };
+  Gaudi::Property<std::string> m_title_tt {this, "HistogramT", "", "histogram title TTrack"};
+  Gaudi::Property<std::string> m_title_ut {this, "HistogramU", "", "histogram title upstr" };
+  Gaudi::Property<std::string> m_title_vt {this, "HistogramV", "", "histogram title velo"  };
+
+  Gaudi::Property<std::string> m_title_lt_ths {this, "HistogramL_THS", "", "histogram title long if DLLs are read from a root file via THS"};
+  Gaudi::Property<std::string> m_title_dt_ths {this, "HistogramD_THS", "", "histogram title down if DLLs are read from a root file via THS"};
+  Gaudi::Property<std::string> m_title_tt_ths {this, "HistogramT_THS", "", "histogram title TTrack if DLLs are read from a root file via THS"};
+  Gaudi::Property<std::string> m_title_ut_ths {this, "HistogramU_THS", "", "histogram title upstr if DLLs are read from a root file via THS"};
+  Gaudi::Property<std::string> m_title_vt_ths {this, "HistogramV_THS", "", "histogram title velo if DLLs are read from a root file via THS"};
+
+  Gaudi::Property<float> m_pScale_lt {this, "nMlong"  , -1, "scale for mom long"};
+  Gaudi::Property<float> m_pScale_dt {this, "nMdown"  , -1, "scale for mom down"};
+  Gaudi::Property<float> m_pScale_tt {this, "nMTtrack", -1, "scale for mom TT"};
+  Gaudi::Property<float> m_pScale_ut {this, "nMupstr" , -1, "scale for val upstr"};
+  Gaudi::Property<float> m_pScale_vt {this, "nMvelo"  , -1, "scale for val velo"};
+
+  Gaudi::Property<float> m_vScale_lt {this, "nVlong"  , -1, "scale for val long"};
+  Gaudi::Property<float> m_vScale_dt {this, "nVdown"  , -1, "scale for val down"};
+  Gaudi::Property<float> m_vScale_tt {this, "nVTtrack", -1, "scale for val TT"};
+  Gaudi::Property<float> m_vScale_ut {this, "nVupstr" , -1, "scale for val upstr"};
+  Gaudi::Property<float> m_vScale_vt {this, "nVvelo"  , -1, "scale for val velo"};
+
+private:
+
+  const TH2D *m_histo_lt = nullptr;
+  const TH2D *m_histo_dt = nullptr;
+  const TH2D *m_histo_tt = nullptr;
+  const TH2D *m_histo_ut = nullptr;
+  const TH2D *m_histo_vt = nullptr;
+
+  Gaudi::Property<bool> m_useCondDB
+    {this, "UseCondDB", true, "if true - use CondDB, otherwise get the DLLs via THS from a root file"};
+
+  Gaudi::Property<std::string> m_conditionName {this, "ConditionName"};
+  Condition * m_cond = nullptr;
+};
+
+// ============================================================================
+
+inline double CaloFutureID2DLL::dLL(const double p, const double v,
+                              const LHCb::Track::Types t) const {
+  const TH2D *histo = nullptr;
+  double pScale = -1.;
+  double vScale = -1.;
+
+  switch (t) {
+    case LHCb::Track::Types::Long:
+      histo = m_histo_lt;
+      pScale = m_pScale_lt;
+      vScale = m_vScale_lt;
+      break;
+    case LHCb::Track::Types::Downstream:
+      histo = m_histo_dt;
+      pScale = m_pScale_dt;
+      vScale = m_vScale_dt;
+      break;
+    case LHCb::Track::Types::Upstream:
+      histo = m_histo_ut;
+      pScale = m_pScale_ut;
+      vScale = m_vScale_ut;
+      break;
+    case LHCb::Track::Types::Velo:
+      histo = m_histo_vt;
+      pScale = m_pScale_vt;
+      vScale = m_vScale_vt;
+      break;
+    case LHCb::Track::Types::Ttrack:
+      histo = m_histo_tt;
+      pScale = m_pScale_tt;
+      vScale = m_vScale_tt;
+      break;
+    default:
+    Error ("Injvald track type, return 0").ignore();
+      return 0;
+  }
+
+  if ( 0 == histo )
+  {
+    Error ("Histogram is not specified return 0").ignore();
+    return 0;
+  }
+
+  const double _x = ::tanh(p / pScale);
+  const double _y = ::tanh(v / vScale);
+  const int ii = const_cast<TH2D *>(histo)->FindBin(_x, _y);
+  return histo->GetBinContent(ii);
+}
+
+// ============================================================================
+#endif  // CALOFUTUREID2DLL_H
+// ============================================================================
diff --git a/CaloFuture/CaloFuturePIDs/src/CaloFuturePhotonIdAlg.cpp b/CaloFuture/CaloFuturePIDs/src/CaloFuturePhotonIdAlg.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..15374f48eac51c2a523750bdc0588b4444da122e
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/CaloFuturePhotonIdAlg.cpp
@@ -0,0 +1,407 @@
+// Include files
+#include "CaloFuturePhotonIdAlg.h"
+#include "DetDesc/HistoParam.h"
+#include <GaudiUtils/Aida2ROOT.h>
+#include <math.h>
+
+//------------------------------------------------------------------------------
+// Implementation file for class : CaloFuturePhotonIdAlg
+//
+// 2010-02-27 : Olivier Deschamps
+//------------------------------------------------------------------------------
+
+DECLARE_COMPONENT( CaloFuturePhotonIdAlg )
+
+//==============================================================================
+// Standard constructor, initializes variables
+//==============================================================================
+
+CaloFuturePhotonIdAlg::CaloFuturePhotonIdAlg(const std::string &name,
+                                 ISvcLocator *pSvcLocator)
+    : MergingTransformer(name, pSvcLocator, {"Inputs", {}}, {"Output", {}}) {
+  // TODO : split PID estimator (Prs-Spd-Ecal(Chi2, seed/cluster) + add
+  // estimator ( E4/E9, Hcal/Ecal, shower-shape,  ...)
+  // and let NeutralProtoParticle to combine ...
+}
+
+//==============================================================================
+// Initialization
+//==============================================================================
+StatusCode CaloFuturePhotonIdAlg::initialize() {
+  StatusCode sc = MergingTransformer::initialize();
+  if (sc.isFailure())
+    return sc;
+  if (msgLevel(MSG::DEBUG))
+    debug() << "==> Initialize" << endmsg;
+
+  // Retrieve tools
+  m_counterStat.retrieve();
+  sc = m_estimator.retrieve();
+  if (sc.isFailure())
+    return sc;
+
+  // Report
+  if (m_dlnL) {
+    info() << "PhotonId : Delta Log Likelihood calculation." << endmsg;
+  } else {
+    info() << "PhotonId : Likelihood estimator." << endmsg;
+  }
+  // Initialize histogram access
+  if (m_useCondDB && !existDet<DataObject>(detSvc(), m_conditionName)) {
+    warning() << "Initialise: Condition '" << m_conditionName
+              << "' not found -- switch to reading the DLLs from THS!"
+              << endmsg;
+    m_useCondDB = false;
+  }
+
+  sc = m_useCondDB ? initializeWithCondDB() : initializeWithoutCondDB();
+
+  // context-dependent inputs/output (if not defined via options)
+  using LHCb::CaloFutureAlgUtils::CaloFutureHypoLocation;
+  using LHCb::CaloFutureAlgUtils::CaloFutureIdLocation;
+
+  // Update inputs to this default if null
+  if (getProperty("Inputs").toString() == "[  ]"){
+    std::string loc;
+    if (m_type == "MergedID") {
+      loc = "MergedPi0s";
+    } else if (m_type == "PhotonID") {
+      loc = "Photons";
+    } else if (m_type == "PhotonFromMergedID") {
+      loc = "SplitPhotons";
+    }
+    std::vector<std::string> inputs = {CaloFutureHypoLocation(loc, context())};
+    Gaudi::Functional::updateHandleLocations(*this, "Inputs", inputs);
+  }
+  // Update output to this default if null
+  if (getProperty("Output").toString() == ""){
+    std::string output = CaloFutureIdLocation(m_type, context());
+    Gaudi::Functional::updateHandleLocation(*this, "Output", output);
+  }
+
+
+  // Warning : the algorithm settings overwrite the caloHypo2CaloFuture default
+  // settings
+  std::string seed = m_seed ? "true" : "false";
+  std::string line = m_extrapol ? "true" : "false";
+  std::string neig = m_neig ? "true" : "false";
+  m_estimator->hypo2CaloFuture()->_setProperty("Seed", seed).ignore();
+  m_estimator->hypo2CaloFuture()->_setProperty("PhotonLine", line).ignore();
+  m_estimator->hypo2CaloFuture()->_setProperty("AddNeighbors", neig).ignore();
+  m_estimator->_setProperty("SkipNeutralID", "true").ignore(); // avoid loop
+
+  return sc;
+}
+
+//==============================================================================
+
+Table CaloFuturePhotonIdAlg::operator()(const HyposList &hyposlist) const {
+
+// StatusCode CaloFuturePhotonIdAlg::execute() {
+  if (msgLevel(MSG::DEBUG))
+    debug() << "==> Execute" << endmsg;
+
+  // create the table
+  auto table = Table(200);
+
+  // fill the table
+  for (const auto hypos : hyposlist) {
+    // Skip if null
+    if (!hypos) {
+      if (m_counterStat->isQuiet())
+        counter("Empty location ") += 1;
+      continue;
+    }
+    // Retrieve location on TES
+    const auto loc = hypos->registry()->identifier();
+    if (m_counterStat->isVerbose())
+      counter("#Hypos in " + loc) += hypos->size();
+
+    // Loop over hypos
+    for (const auto hypo : *hypos){
+      if (hypo == nullptr) {
+        if (m_counterStat->isQuiet())
+          counter("hypo points to NULL in " + loc) += 1;
+        continue;
+      }
+      const double l = m_isRunnable ? likelihood(hypo) : -999.;
+      if (m_counterStat->isVerbose())
+        counter("likelihood") += l;
+      table.i_push(hypo, (float)(l));
+    }
+  }
+  table.i_sort();
+
+  // statistics
+  if (m_counterStat->isQuiet()){
+    const auto inputs = getProperty("Inputs").toString();
+    const auto output = getProperty("Output").toString();
+    counter(inputs + " ==> " + output) += table.i_relations().size();
+  }
+
+  return table;
+}
+
+//==============================================================================
+
+double CaloFuturePhotonIdAlg::likelihood(const LHCb::CaloHypo *hypo) const {
+  // Get the relevant information - basic checks
+  if (0 == hypo) {
+    Warning("CaloHypo points to NULL", StatusCode::SUCCESS).ignore();
+    if (m_counterStat->isQuiet())
+      counter("Null hypo") += 1;
+    return -999.;
+  }
+
+  double energy, et, eSeed, ePrs;
+  int nSpd;
+  unsigned int area;
+
+  double chi2 = -999.;
+
+  // parameter evaluation
+  if (evalParam(hypo, energy, et, eSeed, nSpd, ePrs, area).isFailure())
+    return -999.;
+
+  // get chi2
+  chi2 = -999.;
+  if (m_tracking)
+    chi2 = m_estimator->data(hypo, CaloFutureDataType::ClusterMatch, +999.);
+  // evaluate
+  return evalLikelihood(energy, et, eSeed, nSpd, ePrs, chi2, area);
+}
+
+//==============================================================================
+
+StatusCode CaloFuturePhotonIdAlg::evalParam(const LHCb::CaloHypo *hypo,
+                                      double &energy, double &et, double &eSeed,
+                                      int &nSpd, double &ePrs,
+                                      unsigned int &area) const {
+  using namespace CaloFutureDataType;
+  energy = m_estimator->data(hypo, HypoE);
+  et = m_estimator->data(hypo, HypoEt);
+  eSeed = m_estimator->data(hypo, E1Hypo);
+  nSpd = (int)m_estimator->data(hypo, ToSpdM);
+  ePrs = m_estimator->data(hypo, ToPrsE);
+  area = LHCb::CaloCellID(
+             (LHCb::CaloCellID::ContentType)m_estimator->data(hypo, CellID))
+             .area();
+  if (!m_estimator->status())
+    return StatusCode::FAILURE;
+  return StatusCode::SUCCESS;
+}
+
+//==============================================================================
+
+double CaloFuturePhotonIdAlg::evalLikelihood(double energy, double et, double eSeed,
+                                       int nSpd, double ePrs, double chi2,
+                                       unsigned int area) const {
+  // Initialization
+  double estimator;
+  double signal, backgr;
+  const double epsilon = 1.e-20;
+  // SPD Hit
+
+  signal = epsilon;
+  backgr = epsilon;
+
+  if (nSpd == 0) {
+    signal = CaloFuturePhotonIdAlg::dLL(energy, ePrs, chi2, eSeed,
+                                  CaloFuturePhotonIdAlg::SIGNAL, area);
+    if (m_isRunnable) {
+      backgr = CaloFuturePhotonIdAlg::dLL(energy, ePrs, chi2, eSeed,
+                                    CaloFuturePhotonIdAlg::BACKGROUND, area);
+    }
+  } else {
+    signal = CaloFuturePhotonIdAlg::dLL(energy, ePrs, chi2, eSeed,
+                                  CaloFuturePhotonIdAlg::SIGNAL_SPD, area);
+    if (m_isRunnable) {
+      backgr = CaloFuturePhotonIdAlg::dLL(energy, ePrs, chi2, eSeed,
+                                    CaloFuturePhotonIdAlg::BACKGROUND_SPD, area);
+    }
+  }
+
+  if (m_dlnL) {
+    if (m_isRunnable) {
+      if (signal < epsilon)
+        signal = epsilon;
+      if (backgr < epsilon)
+        backgr = epsilon;
+      estimator = log(signal) - log(backgr);
+    } else
+      estimator = -999.;
+  } else {
+    if (m_isRunnable) {
+      estimator = (signal + backgr > 0.) ? signal / (signal + backgr) : -1.;
+    } else {
+      estimator = -999.;
+    }
+  }
+
+  if (msgLevel(MSG::DEBUG)) {
+    debug() << "Photon Candidate :" << endmsg;
+    debug() << " -E         =" << energy << endmsg;
+    debug() << " -Et        =" << et << endmsg;
+    debug() << " -#Spd hits =" << nSpd << endmsg;
+    debug() << " -EPrs      =" << ePrs << endmsg;
+    debug() << " -Chi2      =" << chi2 << endmsg;
+    debug() << " -ESeed     =" << eSeed << endmsg;
+    if (m_dlnL)
+      debug() << "      => DlnL     = " << estimator << endmsg;
+    else
+      debug() << "      => estimator= " << estimator << endmsg;
+  }
+
+  return estimator;
+}
+
+//==============================================================================
+
+StatusCode CaloFuturePhotonIdAlg::initializeWithCondDB() {
+  info() << "init with CondDB, m_conditionName = " << m_conditionName.value() << endmsg;
+  try {
+    registerCondition(m_conditionName, m_cond, &CaloFuturePhotonIdAlg::i_updateDLL);
+  } catch (GaudiException &e) {
+    fatal() << e << endmsg;
+    m_isRunnable = false;
+    return StatusCode::FAILURE;
+  }
+  StatusCode sc = runUpdate(); // load the conditions
+  return sc;
+}
+
+//==============================================================================
+
+StatusCode CaloFuturePhotonIdAlg::initializeWithoutCondDB() {
+  info() << "init w/o CondDB, pdf histos path is " << m_histo_path << endmsg;
+
+  m_Sig_EPrs_10 = locateHistoOnDisk(m_title_Sig_EPrs_10);
+  m_Sig_EPrs_11 = locateHistoOnDisk(m_title_Sig_EPrs_11);
+  m_Sig_EPrs_12 = locateHistoOnDisk(m_title_Sig_EPrs_12);
+  m_Sig_EPrs_15 = locateHistoOnDisk(m_title_Sig_EPrs_15);
+  m_Sig_EPrs_16 = locateHistoOnDisk(m_title_Sig_EPrs_16);
+  m_Sig_EPrs_17 = locateHistoOnDisk(m_title_Sig_EPrs_17);
+
+  m_Sig_Chi2_20 = locateHistoOnDisk(m_title_Sig_Chi2_20);
+  m_Sig_Chi2_21 = locateHistoOnDisk(m_title_Sig_Chi2_21);
+  m_Sig_Chi2_22 = locateHistoOnDisk(m_title_Sig_Chi2_22);
+  m_Sig_Chi2_25 = locateHistoOnDisk(m_title_Sig_Chi2_25);
+  m_Sig_Chi2_26 = locateHistoOnDisk(m_title_Sig_Chi2_26);
+  m_Sig_Chi2_27 = locateHistoOnDisk(m_title_Sig_Chi2_27);
+
+  m_Sig_Seed_30 = locateHistoOnDisk(m_title_Sig_Seed_30);
+  m_Sig_Seed_31 = locateHistoOnDisk(m_title_Sig_Seed_31);
+  m_Sig_Seed_32 = locateHistoOnDisk(m_title_Sig_Seed_32);
+  m_Sig_Seed_35 = locateHistoOnDisk(m_title_Sig_Seed_35);
+  m_Sig_Seed_36 = locateHistoOnDisk(m_title_Sig_Seed_36);
+  m_Sig_Seed_37 = locateHistoOnDisk(m_title_Sig_Seed_37);
+
+  m_Bkg_EPrs_110 = locateHistoOnDisk(m_title_Bkg_EPrs_110);
+  m_Bkg_EPrs_111 = locateHistoOnDisk(m_title_Bkg_EPrs_111);
+  m_Bkg_EPrs_112 = locateHistoOnDisk(m_title_Bkg_EPrs_112);
+  m_Bkg_EPrs_115 = locateHistoOnDisk(m_title_Bkg_EPrs_115);
+  m_Bkg_EPrs_116 = locateHistoOnDisk(m_title_Bkg_EPrs_116);
+  m_Bkg_EPrs_117 = locateHistoOnDisk(m_title_Bkg_EPrs_117);
+
+  m_Bkg_Chi2_120 = locateHistoOnDisk(m_title_Bkg_Chi2_120);
+  m_Bkg_Chi2_121 = locateHistoOnDisk(m_title_Bkg_Chi2_121);
+  m_Bkg_Chi2_122 = locateHistoOnDisk(m_title_Bkg_Chi2_122);
+  m_Bkg_Chi2_125 = locateHistoOnDisk(m_title_Bkg_Chi2_125);
+  m_Bkg_Chi2_126 = locateHistoOnDisk(m_title_Bkg_Chi2_126);
+  m_Bkg_Chi2_127 = locateHistoOnDisk(m_title_Bkg_Chi2_127);
+
+  m_Bkg_Seed_130 = locateHistoOnDisk(m_title_Bkg_Seed_130);
+  m_Bkg_Seed_131 = locateHistoOnDisk(m_title_Bkg_Seed_131);
+  m_Bkg_Seed_132 = locateHistoOnDisk(m_title_Bkg_Seed_132);
+  m_Bkg_Seed_135 = locateHistoOnDisk(m_title_Bkg_Seed_135);
+  m_Bkg_Seed_136 = locateHistoOnDisk(m_title_Bkg_Seed_136);
+  m_Bkg_Seed_137 = locateHistoOnDisk(m_title_Bkg_Seed_137);
+
+  return StatusCode::SUCCESS;
+}
+
+//==============================================================================
+
+StatusCode CaloFuturePhotonIdAlg::i_updateDLL() {
+  if (msgLevel(MSG::DEBUG))
+    debug() << "i_updateDLL() called" << endmsg;
+  if (!m_cond)
+    return StatusCode::FAILURE;
+
+  try {
+    m_Sig_EPrs_10 = locateHistoOnDB(m_title_Sig_EPrs_10);
+    m_Sig_EPrs_11 = locateHistoOnDB(m_title_Sig_EPrs_11);
+    m_Sig_EPrs_12 = locateHistoOnDB(m_title_Sig_EPrs_12);
+    m_Sig_EPrs_15 = locateHistoOnDB(m_title_Sig_EPrs_15);
+    m_Sig_EPrs_16 = locateHistoOnDB(m_title_Sig_EPrs_16);
+    m_Sig_EPrs_17 = locateHistoOnDB(m_title_Sig_EPrs_17);
+
+    m_Sig_Chi2_20 = locateHistoOnDB(m_title_Sig_Chi2_20);
+    m_Sig_Chi2_21 = locateHistoOnDB(m_title_Sig_Chi2_21);
+    m_Sig_Chi2_22 = locateHistoOnDB(m_title_Sig_Chi2_22);
+    m_Sig_Chi2_25 = locateHistoOnDB(m_title_Sig_Chi2_25);
+    m_Sig_Chi2_26 = locateHistoOnDB(m_title_Sig_Chi2_26);
+    m_Sig_Chi2_27 = locateHistoOnDB(m_title_Sig_Chi2_27);
+
+    m_Sig_Seed_30 = locateHistoOnDB(m_title_Sig_Seed_30);
+    m_Sig_Seed_31 = locateHistoOnDB(m_title_Sig_Seed_31);
+    m_Sig_Seed_32 = locateHistoOnDB(m_title_Sig_Seed_32);
+    m_Sig_Seed_35 = locateHistoOnDB(m_title_Sig_Seed_35);
+    m_Sig_Seed_36 = locateHistoOnDB(m_title_Sig_Seed_36);
+    m_Sig_Seed_37 = locateHistoOnDB(m_title_Sig_Seed_37);
+
+    m_Bkg_EPrs_110 = locateHistoOnDB(m_title_Bkg_EPrs_110);
+    m_Bkg_EPrs_111 = locateHistoOnDB(m_title_Bkg_EPrs_111);
+    m_Bkg_EPrs_112 = locateHistoOnDB(m_title_Bkg_EPrs_112);
+    m_Bkg_EPrs_115 = locateHistoOnDB(m_title_Bkg_EPrs_115);
+    m_Bkg_EPrs_116 = locateHistoOnDB(m_title_Bkg_EPrs_116);
+    m_Bkg_EPrs_117 = locateHistoOnDB(m_title_Bkg_EPrs_117);
+
+    m_Bkg_Chi2_120 = locateHistoOnDB(m_title_Bkg_Chi2_120);
+    m_Bkg_Chi2_121 = locateHistoOnDB(m_title_Bkg_Chi2_121);
+    m_Bkg_Chi2_122 = locateHistoOnDB(m_title_Bkg_Chi2_122);
+    m_Bkg_Chi2_125 = locateHistoOnDB(m_title_Bkg_Chi2_125);
+    m_Bkg_Chi2_126 = locateHistoOnDB(m_title_Bkg_Chi2_126);
+    m_Bkg_Chi2_127 = locateHistoOnDB(m_title_Bkg_Chi2_127);
+
+    m_Bkg_Seed_130 = locateHistoOnDB(m_title_Bkg_Seed_130);
+    m_Bkg_Seed_131 = locateHistoOnDB(m_title_Bkg_Seed_131);
+    m_Bkg_Seed_132 = locateHistoOnDB(m_title_Bkg_Seed_132);
+    m_Bkg_Seed_135 = locateHistoOnDB(m_title_Bkg_Seed_135);
+    m_Bkg_Seed_136 = locateHistoOnDB(m_title_Bkg_Seed_136);
+    m_Bkg_Seed_137 = locateHistoOnDB(m_title_Bkg_Seed_137);
+  } catch (GaudiException &exc) {
+    fatal() << "DLL update failed! msg ='" << exc << "'" << endmsg;
+    return StatusCode::FAILURE;
+  }
+  return StatusCode::SUCCESS;
+}
+
+//==============================================================================
+
+TH2D *CaloFuturePhotonIdAlg::locateHistoOnDisk(std::string histoname) const {
+  TH2D *histo = nullptr;
+  if (!histoname.empty()) {
+    AIDA::IHistogram2D *aida =
+        get<AIDA::IHistogram2D>(histoSvc(), m_histo_path + histoname);
+    if (aida == nullptr) {
+      warning() << "Could not find AIDA::IHistogram2D* "
+                << m_histo_path + histoname << "." << endmsg;
+      m_isRunnable = false;
+      return nullptr;
+    }
+    histo = Gaudi::Utils::Aida2ROOT::aida2root(aida);
+  }
+  return histo;
+}
+
+//==============================================================================
+
+TH2D *CaloFuturePhotonIdAlg::locateHistoOnDB(std::string histoname) const {
+  TH2D *histo = nullptr;
+  if (!histoname.empty()) {
+    histo = reinterpret_cast<TH2D *>(
+        &m_cond->param<DetDesc::Params::Histo2D>(histoname));
+  }
+  return histo;
+}
diff --git a/CaloFuture/CaloFuturePIDs/src/CaloFuturePhotonIdAlg.h b/CaloFuture/CaloFuturePIDs/src/CaloFuturePhotonIdAlg.h
new file mode 100644
index 0000000000000000000000000000000000000000..7a36b8ab4ff89d0b1cc398449b47b5290073a4f6
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/CaloFuturePhotonIdAlg.h
@@ -0,0 +1,327 @@
+#ifndef CALOFUTUREPHOTONIDALG_H
+#define CALOFUTUREPHOTONIDALG_H 1
+
+// Include files
+#include "AIDA/IHistogram2D.h"
+#include "CaloFutureInterfaces/ICaloFutureHypoEstimator.h"
+#include "CaloFutureInterfaces/IFutureCounterLevel.h"
+#include "CaloFutureUtils/CaloFuture2Track.h"
+#include "CaloFutureUtils/CaloFutureAlgUtils.h"
+#include "CaloFutureUtils/ClusterFunctors.h"
+#include "DetDesc/Condition.h"
+#include "GaudiAlg/MergingTransformer.h"
+#include "Relations/IRelationWeighted.h"
+#include "Relations/Relation1D.h"
+#include "TH2D.h"
+#include "boost/static_assert.hpp"
+#include <GaudiUtils/Aida2ROOT.h>
+
+// =============================================================================
+/** @class CaloFuturePhotonIdAlg CaloFuturePhotonIdAlg.h
+ *  @author Olivier Deschamps
+ *  @date   2010-02-27
+ */
+
+using Hypos = LHCb::CaloHypos;
+using HyposList = Gaudi::Functional::vector_of_const_<Hypos*>;
+using Table = LHCb::Relation1D<LHCb::CaloHypo, float>;
+
+class CaloFuturePhotonIdAlg final
+    : public Gaudi::Functional::MergingTransformer<Table(const HyposList &)> {
+public:
+  static_assert(std::is_base_of<LHCb::CaloFuture2Track::IHypoEvalTable, Table>::value,
+                "Table must inherit from IHypoEvalTable");
+
+  enum TYPE { SIGNAL, BACKGROUND, SIGNAL_SPD, BACKGROUND_SPD };
+
+  /// Standard constructor
+  CaloFuturePhotonIdAlg(const std::string &name, ISvcLocator *pSvcLocator);
+
+  /// C++11 non-copyable idiom
+  CaloFuturePhotonIdAlg() = delete;
+  CaloFuturePhotonIdAlg(const CaloFuturePhotonIdAlg &) = delete;
+  CaloFuturePhotonIdAlg &operator=(const CaloFuturePhotonIdAlg &) = delete;
+
+  StatusCode initialize() override;
+  Table operator()(const HyposList &hyposlist) const override;
+
+  /// callback function invoked by the UpdateManagerSvc
+  StatusCode i_updateDLL();
+
+protected:
+  StatusCode initializeWithCondDB();
+  StatusCode initializeWithoutCondDB();
+
+private:
+  double likelihood(const LHCb::CaloHypo *hypo) const;
+
+  inline double dLL(const double, const double, const double, const double,
+                    const CaloFuturePhotonIdAlg::TYPE, const int) const;
+
+  StatusCode evalParam(const LHCb::CaloHypo *, double &, double &, double &,
+                       int &, double &, unsigned int &) const;
+
+  double evalLikelihood(double, double, double, int, double, double,
+                        unsigned int) const;
+
+  TH2D *locateHistoOnDisk(std::string) const;
+  TH2D *locateHistoOnDB(std::string) const;
+
+private:
+
+  ToolHandle<IFutureCounterLevel> m_counterStat {"FutureCounterLevel"};
+
+  mutable ToolHandle<ICaloFutureHypoEstimator> m_estimator 
+    {"CaloFutureHypoEstimator/CaloFutureHypoEstimator", this};
+
+  bool m_extrapol = true;
+  bool m_seed = false;
+  bool m_neig = false;
+  mutable bool m_isRunnable = true;
+
+  Condition * m_cond = nullptr;
+
+  Gaudi::Property<std::string> m_type {this, "Type", "PhotonID"};
+
+  Gaudi::Property<bool> m_tracking {this, "Tracking", true};
+  Gaudi::Property<bool> m_pdfEPrs  {this, "PdfEPrs" , true};
+  Gaudi::Property<bool> m_pdfChi2  {this, "PdfChi2" , true};
+  Gaudi::Property<bool> m_pdfSeed  {this, "PdfSeed" , true};
+  Gaudi::Property<bool> m_dlnL     {this, "DlnL"    , true};
+
+
+  // Condition dbase
+  Gaudi::Property<bool> m_useCondDB 
+    {this, "UseCondDB", true, 
+    "if true - use CondDB, otherwise get the DLLs via THS from a root file"};
+  
+  Gaudi::Property<std::string> m_conditionName
+    {this, "ConditionName", "Conditions/ParticleID/Calo/PhotonID"};
+  
+  std::string m_histo_path = "CaloFutureNeutralPIDs/PhotonID/";
+
+  // Photon Pdf
+
+  std::string m_title_Sig_EPrs_10 = "Signal_Prs_noSpdHit_10";
+  std::string m_title_Sig_EPrs_11 = "Signal_Prs_noSpdHit_11";
+  std::string m_title_Sig_EPrs_12 = "Signal_Prs_noSpdHit_12";
+  std::string m_title_Sig_EPrs_15 = "Signal_Prs_SpdHit_15";
+  std::string m_title_Sig_EPrs_16 = "Signal_Prs_SpdHit_16";
+  std::string m_title_Sig_EPrs_17 = "Signal_Prs_SpdHit_17";
+
+  std::string m_title_Sig_Chi2_20 = "Signal_Chi2Tk_noSpdHit_20";
+  std::string m_title_Sig_Chi2_21 = "Signal_Chi2Tk_noSpdHit_21";
+  std::string m_title_Sig_Chi2_22 = "Signal_Chi2Tk_noSpdHit_22";
+  std::string m_title_Sig_Chi2_25 = "Signal_Chi2Tk_SpdHit_25";
+  std::string m_title_Sig_Chi2_26 = "Signal_Chi2Tk_SpdHit_26";
+  std::string m_title_Sig_Chi2_27 = "Signal_Chi2Tk_SpdHit_27";
+
+  std::string m_title_Sig_Seed_30 = "Signal_ESeed_noSpdHit_30";
+  std::string m_title_Sig_Seed_31 = "Signal_ESeed_noSpdHit_31";
+  std::string m_title_Sig_Seed_32 = "Signal_ESeed_noSpdHit_32";
+  std::string m_title_Sig_Seed_35 = "Signal_ESeed_SpdHit_35";
+  std::string m_title_Sig_Seed_36 = "Signal_ESeed_SpdHit_36";
+  std::string m_title_Sig_Seed_37 = "Signal_ESeed_SpdHit_37";
+
+  std::string m_title_Bkg_EPrs_110 = "Background_Prs_noSpdHit_110";
+  std::string m_title_Bkg_EPrs_111 = "Background_Prs_noSpdHit_111";
+  std::string m_title_Bkg_EPrs_112 = "Background_Prs_noSpdHit_112";
+  std::string m_title_Bkg_EPrs_115 = "Background_Prs_SpdHit_115";
+  std::string m_title_Bkg_EPrs_116 = "Background_Prs_SpdHit_116";
+  std::string m_title_Bkg_EPrs_117 = "Background_Prs_SpdHit_117";
+
+  std::string m_title_Bkg_Chi2_120 = "Background_Chi2Tk_noSpdHit_120";
+  std::string m_title_Bkg_Chi2_121 = "Background_Chi2Tk_noSpdHit_121";
+  std::string m_title_Bkg_Chi2_122 = "Background_Chi2Tk_noSpdHit_122";
+  std::string m_title_Bkg_Chi2_125 = "Background_Chi2Tk_SpdHit_125";
+  std::string m_title_Bkg_Chi2_126 = "Background_Chi2Tk_SpdHit_126";
+  std::string m_title_Bkg_Chi2_127 = "Background_Chi2Tk_SpdHit_127";
+
+  std::string m_title_Bkg_Seed_130 = "Background_ESeed_noSpdHit_130";
+  std::string m_title_Bkg_Seed_131 = "Background_ESeed_noSpdHit_131";
+  std::string m_title_Bkg_Seed_132 = "Background_ESeed_noSpdHit_132";
+  std::string m_title_Bkg_Seed_135 = "Background_ESeed_SpdHit_135";
+  std::string m_title_Bkg_Seed_136 = "Background_ESeed_SpdHit_136";
+  std::string m_title_Bkg_Seed_137 = "Background_ESeed_SpdHit_137";
+
+  const TH2D *m_Sig_EPrs_10 = nullptr;
+  const TH2D *m_Sig_EPrs_11 = nullptr;
+  const TH2D *m_Sig_EPrs_12 = nullptr;
+  const TH2D *m_Sig_EPrs_15 = nullptr;
+  const TH2D *m_Sig_EPrs_16 = nullptr;
+  const TH2D *m_Sig_EPrs_17 = nullptr;
+
+  const TH2D *m_Sig_Chi2_20 = nullptr;
+  const TH2D *m_Sig_Chi2_21 = nullptr;
+  const TH2D *m_Sig_Chi2_22 = nullptr;
+  const TH2D *m_Sig_Chi2_25 = nullptr;
+  const TH2D *m_Sig_Chi2_26 = nullptr;
+  const TH2D *m_Sig_Chi2_27 = nullptr;
+
+  const TH2D *m_Sig_Seed_30 = nullptr;
+  const TH2D *m_Sig_Seed_31 = nullptr;
+  const TH2D *m_Sig_Seed_32 = nullptr;
+  const TH2D *m_Sig_Seed_35 = nullptr;
+  const TH2D *m_Sig_Seed_36 = nullptr;
+  const TH2D *m_Sig_Seed_37 = nullptr;
+
+  const TH2D *m_Bkg_EPrs_110 = nullptr;
+  const TH2D *m_Bkg_EPrs_111 = nullptr;
+  const TH2D *m_Bkg_EPrs_112 = nullptr;
+  const TH2D *m_Bkg_EPrs_115 = nullptr;
+  const TH2D *m_Bkg_EPrs_116 = nullptr;
+  const TH2D *m_Bkg_EPrs_117 = nullptr;
+
+  const TH2D *m_Bkg_Chi2_120 = nullptr;
+  const TH2D *m_Bkg_Chi2_121 = nullptr;
+  const TH2D *m_Bkg_Chi2_122 = nullptr;
+  const TH2D *m_Bkg_Chi2_125 = nullptr;
+  const TH2D *m_Bkg_Chi2_126 = nullptr;
+  const TH2D *m_Bkg_Chi2_127 = nullptr;
+
+  const TH2D *m_Bkg_Seed_130 = nullptr;
+  const TH2D *m_Bkg_Seed_131 = nullptr;
+  const TH2D *m_Bkg_Seed_132 = nullptr;
+  const TH2D *m_Bkg_Seed_135 = nullptr;
+  const TH2D *m_Bkg_Seed_136 = nullptr;
+  const TH2D *m_Bkg_Seed_137 = nullptr;
+};
+
+// ============================================================================
+
+inline double CaloFuturePhotonIdAlg::dLL(const double energy, const double eprs,
+                                   const double chi2, const double seed,
+                                   const CaloFuturePhotonIdAlg::TYPE type,
+                                   const int area) const {
+  const TH2D *histo_eprs = nullptr;
+  const TH2D *histo_chi2 = nullptr;
+  const TH2D *histo_seed = nullptr;
+
+  const double epsilon = 1.e-20;
+
+  switch (area) {
+  case 0:
+    switch (type) {
+    case SIGNAL:
+      histo_eprs = m_Sig_EPrs_10;
+      histo_chi2 = m_Sig_Chi2_20;
+      histo_seed = m_Sig_Seed_30;
+      break;
+    case SIGNAL_SPD:
+      histo_eprs = m_Sig_EPrs_15;
+      histo_chi2 = m_Sig_Chi2_25;
+      histo_seed = m_Sig_Seed_35;
+      break;
+    case BACKGROUND:
+      histo_eprs = m_Bkg_EPrs_110;
+      histo_chi2 = m_Bkg_Chi2_120;
+      histo_seed = m_Bkg_Seed_130;
+      break;
+    case BACKGROUND_SPD:
+      histo_eprs = m_Bkg_EPrs_115;
+      histo_chi2 = m_Bkg_Chi2_125;
+      histo_seed = m_Bkg_Seed_135;
+      break;
+    default:
+      Error("Invalid cluster type").ignore();
+      return epsilon;
+    }
+    break;
+  case 1:
+    switch (type) {
+    case SIGNAL:
+      histo_eprs = m_Sig_EPrs_11;
+      histo_chi2 = m_Sig_Chi2_21;
+      histo_seed = m_Sig_Seed_31;
+      break;
+    case SIGNAL_SPD:
+      histo_eprs = m_Sig_EPrs_16;
+      histo_chi2 = m_Sig_Chi2_26;
+      histo_seed = m_Sig_Seed_36;
+      break;
+    case BACKGROUND:
+      histo_eprs = m_Bkg_EPrs_111;
+      histo_chi2 = m_Bkg_Chi2_121;
+      histo_seed = m_Bkg_Seed_131;
+      break;
+    case BACKGROUND_SPD:
+      histo_eprs = m_Bkg_EPrs_116;
+      histo_chi2 = m_Bkg_Chi2_126;
+      histo_seed = m_Bkg_Seed_136;
+      break;
+    default:
+      Error("Invalid cluster type").ignore();
+      return epsilon;
+    }
+    break;
+  case 2:
+    switch (type) {
+    case SIGNAL:
+      histo_eprs = m_Sig_EPrs_12;
+      histo_chi2 = m_Sig_Chi2_22;
+      histo_seed = m_Sig_Seed_32;
+      break;
+    case SIGNAL_SPD:
+      histo_eprs = m_Sig_EPrs_17;
+      histo_chi2 = m_Sig_Chi2_27;
+      histo_seed = m_Sig_Seed_37;
+      break;
+    case BACKGROUND:
+      histo_eprs = m_Bkg_EPrs_112;
+      histo_chi2 = m_Bkg_Chi2_122;
+      histo_seed = m_Bkg_Seed_132;
+      break;
+    case BACKGROUND_SPD:
+      histo_eprs = m_Bkg_EPrs_117;
+      histo_chi2 = m_Bkg_Chi2_127;
+      histo_seed = m_Bkg_Seed_137;
+      break;
+    default:
+      Error("Invalid cluster type").ignore();
+      return epsilon;
+    }
+    break;
+  default:
+    Error("Invalid area").ignore();
+    return epsilon;
+  }
+
+  if (histo_eprs == nullptr) {
+    warning() << "Histogram EPrs is not found." << endmsg;
+    warning() << "Stop evaluating the Dll." << endmsg;
+    m_isRunnable = false;
+    return -9999.;
+  }
+  if (histo_chi2 == nullptr) {
+    warning() << "Histogram Chi2 is not found." << endmsg;
+    warning() << "Stop evaluating the Dll." << endmsg;
+    m_isRunnable = false;
+    return -9999.;
+  }
+  if (histo_seed == nullptr) {
+    warning() << "Histogram Seed is not found." << endmsg;
+    warning() << "Stop evaluating the Dll." << endmsg;
+    m_isRunnable = false;
+    return -9999.;
+  }
+
+  if (energy < epsilon)
+    return epsilon;
+  double e = log(1.4 * energy) - 6.2;
+  if (e > 5.5)
+    e = 5.5;
+
+  const int ieprs = const_cast<TH2D *>(histo_eprs)->FindBin(eprs, e);
+  const int ichi2 = const_cast<TH2D *>(histo_chi2)->FindBin(chi2, e);
+  const int iseed = const_cast<TH2D *>(histo_seed)->FindBin(seed, e);
+
+  double tmp =
+      histo_eprs->GetBinContent(ieprs) * histo_seed->GetBinContent(iseed);
+
+  if (m_tracking)
+    tmp *= histo_chi2->GetBinContent(ichi2);
+
+  return tmp;
+}
+
+#endif // CALOFUTUREPHOTONIDALG_H
diff --git a/CaloFuture/CaloFuturePIDs/src/CaloFuturePhotonMatch.cpp b/CaloFuture/CaloFuturePIDs/src/CaloFuturePhotonMatch.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4f303a236a492567f0e7a9c7bef04d1a613425ed
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/CaloFuturePhotonMatch.cpp
@@ -0,0 +1,166 @@
+// Include files
+#include "CaloFutureInterfaces/ICaloFutureTrackMatch.h"
+#include "Event/Track.h"
+#include "Event/CaloPosition.h"
+#include "CaloFutureTrackMatch.h"
+
+// ============================================================================
+/** @file
+ *  Implementation file for class CaloFuturePhotonMatch
+ *  @date 2006-05-29
+ *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
+ */
+// ============================================================================
+
+class CaloFuturePhotonMatch final : public virtual ICaloFutureTrackMatch,
+                              public CaloFutureTrackMatch {
+ public:
+  /// initialize the tool
+  StatusCode initialize() override {
+    StatusCode sc = CaloFutureTrackMatch::initialize();
+    if (sc.isFailure()) { return sc; }
+    if (calo()->index() == CaloCellCode::EcalCalo) {
+      m_showerMaxLocation = LHCb::State::Location::ECalShowerMax;
+      m_showerMax = calo()->plane(CaloPlane::ShowerMax);
+    } else if (calo()->index() == CaloCellCode::HcalCalo) {
+      m_showerMaxLocation = LHCb::State::Location::MidHCal;
+      m_showerMax = calo()->plane(CaloPlane::Middle);
+    } else {
+      return Error("initialize: calorimeter niether Ecal nor Hcal");
+    }
+    return StatusCode::SUCCESS;
+  };
+
+ public:
+  /** the main matching method
+   *  @see ICaloFutureTrackMatch
+   *  @param caloObj  pointer to "calorimeter" object (position)
+   *  @param trObj    pointer to tracking object (track)
+   *  @param chi2     returned value of chi2 of the matching
+   *  @return status code for matching procedure
+   */
+  StatusCode match(const LHCb::CaloPosition* caloObj, const LHCb::Track* trObj,
+                   double& chi2) override;
+  /** The main matching method (Stl interface)
+   *  @see ICaloFutureTrackMatch
+   *  @param caloObj  pointer to "calorimeter" object (position)
+   *  @param trObj    pointer to tracking object (track)
+   *  @return pair of status code/chi2  for matching procedure
+   */
+  MatchingPair operator()(const LHCb::CaloPosition* caloObj,
+                          const LHCb::Track* trObj) override {
+    double chi2;
+    StatusCode sc = match(caloObj, trObj, chi2);
+    return std::make_pair(sc, chi2);
+  };
+  /** extract the TrState which was actually used for last matching
+   *  @attention TrState is owned by the tool itself
+   *  The better solution could be to return the pointer
+   *  to TrStateP
+   *  @return pointer to the state actually used for last matching
+   */
+  const LHCb::State* state() const override { return &_state(); };
+
+  CaloFuturePhotonMatch(const std::string& type,  // ?
+                  const std::string& name, const IInterface* parent)
+      : CaloFutureTrackMatch(type, name, parent) {
+    declareInterface<ICaloFutureTrackMatch>(this);
+    _setProperty("CalorimeterFuture", DeCalorimeterLocation::Ecal);
+    _setProperty("Tolerance", "15");  // 15 millimeters
+  };
+
+ private:
+  typedef CaloFutureTrackMatch::Match_<2> Match;
+  Match m_caloMatch;
+  Match m_trackMatch;
+  Gaudi::Plane3D m_showerMax;
+  const LHCb::CaloPosition* m_cBad = nullptr;
+  const LHCb::Track* m_tBad = nullptr;
+  LHCb::State::Location m_showerMaxLocation;
+};
+
+// ============================================================================
+
+DECLARE_COMPONENT( CaloFuturePhotonMatch )
+
+// ============================================================================
+/// the main matching method
+// ============================================================================
+
+StatusCode CaloFuturePhotonMatch::match(const LHCb::CaloPosition* caloObj,
+                                  const LHCb::Track* trObj, double& chi2) {
+  using namespace LHCb;
+
+  chi2 = bad();  // reset chi2
+  //
+  if (m_cBad == caloObj || m_tBad == trObj) {
+    return StatusCode::FAILURE;
+  }
+  //
+  if (caloObj == nullptr) {
+    return Error("match(): CaloPosition* points to NULL");
+  }
+
+  if (!use(trObj)) {
+    return Error("match(): track is not OK");
+  }
+
+  if (updateCaloFuturePos(m_position, caloObj)) {
+    // if ( m_position != caloObj ){
+    // update the position
+    StatusCode sc = fill(*caloObj, m_caloMatch);
+    if (sc.isFailure()) {
+      m_cBad = caloObj;
+      m_position = nullptr;
+      return Warning("match(): Error from fill(2D) -- ", StatusCode::FAILURE,
+                     0);
+    }
+    // find the proper plane in detector
+    const LHCb::CaloPosition::Center& par = caloObj->center();
+    const Gaudi::XYZPoint point(par(0), par(1), caloObj->z());
+    if (tolerance() < m_plane.Distance(point)) {
+      m_plane = calo()->plane(point);
+    }
+    // keep the track of the position
+    m_position = caloObj;
+  }
+
+  // get the correct state
+  const LHCb::State* st = nullptr;
+  {
+    st = CaloFutureTrackTool::state(*trObj, m_showerMaxLocation);
+    if (st == nullptr) {
+      StatusCode sc = propagate(*trObj, m_showerMax, _state());
+      if (sc.isFailure()) {
+        m_tBad = trObj;
+        return Warning("match(): failure from propagate (1) ", sc);
+      }
+      _state().setLocation(m_showerMaxLocation);
+      // ugly, but efficient
+      const_cast<LHCb::Track*>(trObj)->addToStates(_state());
+      st = CaloFutureTrackTool::state(*trObj, m_showerMaxLocation);
+    }
+    // check the state, propagate if needed
+    if (tolerance() < ::fabs(m_plane.Distance(st->position()))) {
+      _state() = *st;
+      StatusCode sc = propagate(_state(), m_plane);
+      if (sc.isFailure()) {
+        m_tBad = trObj;
+        return Warning("match(): failure from propagate (2) ", sc);
+      }
+      st = &_state();
+    }
+  }
+
+  Assert(st != nullptr, "LHCb::State* points to NULL!");
+  StatusCode sc = fill(*st, m_trackMatch);
+  if (sc.isFailure()) {
+    return Warning("match(): error for fill(2D)");
+  }
+
+  // make a real evaluation
+  chi2 = CaloFutureTrackMatch::chi2(m_caloMatch, m_trackMatch);
+  return StatusCode::SUCCESS;
+}
+
+// ============================================================================
diff --git a/CaloFuture/CaloFuturePIDs/src/CaloFutureTrack2IDAlg.cpp b/CaloFuture/CaloFuturePIDs/src/CaloFutureTrack2IDAlg.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..64b1019344740838d4a3662e33a4343a7898cbe1
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/CaloFutureTrack2IDAlg.cpp
@@ -0,0 +1,66 @@
+// Include files
+#include "CaloFutureTrack2IDAlg.h"
+#include <type_traits>
+
+// ============================================================================
+
+DECLARE_COMPONENT( CaloFutureTrack2IDAlg )
+
+// ============================================================================
+/// Standard protected constructor
+// ============================================================================
+
+CaloFutureTrack2IDAlg::CaloFutureTrack2IDAlg(const std::string &name, ISvcLocator *pSvc)
+    : Transformer(name, pSvc, {KeyValue{"Inputs",""},KeyValue{"Filter",""}}, KeyValue{"Output",""}) {
+  _setProperty("StatPrint", "false");
+  // track types:
+  _setProperty("AcceptedType", Gaudi::Utils::toString<int>(
+                                   LHCb::Track::Types::Long, 
+                                   LHCb::Track::Types::Downstream,
+                                   LHCb::Track::Types::Ttrack));
+
+  // context-dependent default track container
+  Gaudi::Functional::updateHandleLocation(*this, "Inputs", LHCb::CaloFutureAlgUtils::TrackLocations(context()).front());
+}
+
+// ============================================================================
+/// standard algorithm execution
+// ============================================================================
+Table CaloFutureTrack2IDAlg::operator()(const LHCb::Tracks& tracks, const Filter& filter) const {
+  static_assert(std::is_base_of<LHCb::CaloFuture2Track::ITrEvalTable, Table>::value, "Table must inherit from ITrEvalTable");
+
+  Table table(100);
+
+  // loop over all tracks
+  for (const auto& track : tracks) {
+    // use the track ?
+    if (!use(track)) {
+      continue;
+    } // CONTINUE
+    // use filter ?
+    const auto r = filter.relations(track);
+    // no positive information? skip!
+    if (r.empty() || !r.front().to()) {
+      continue;
+    } // CONTINUE
+    double value = 0;
+    StatusCode sc = m_tool->process(track, value);
+    if (sc.isFailure()) {
+      Warning(" Failure from the tool, skip the track!", sc).ignore();
+      continue;
+    }
+    // make a relations (fast, efficient, call for i_sort is mandatory!)
+    table.i_push(track, value); // NB! i_push
+  }
+  // MANDATORY after i_push! // NB! i_sort
+  table.i_sort();
+
+  m_nTracks += tracks.size();
+  auto links = table.i_relations();
+  m_nLinks  += links.size();
+  //for( const auto& link : links) m_nEnergy += link.to() / Gaudi::Units::GeV;
+  auto c = m_nEnergy.buffer();
+  for(const auto& link : links) c += link.to() / Gaudi::Units::GeV;
+
+  return table;
+}
diff --git a/CaloFuture/CaloFuturePIDs/src/CaloFutureTrack2IDAlg.h b/CaloFuture/CaloFuturePIDs/src/CaloFutureTrack2IDAlg.h
new file mode 100644
index 0000000000000000000000000000000000000000..32be663d0ae73dfe55072e6118a24b05021e5344
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/CaloFutureTrack2IDAlg.h
@@ -0,0 +1,41 @@
+#ifndef CALOFUTUREPIDS_CALOFUTURETRACK2IDALG_H
+#define CALOFUTUREPIDS_CALOFUTURETRACK2IDALG_H 1
+
+// Include files
+#include "CaloFutureTrackAlg.h"
+#include "CaloFutureInterfaces/ICaloFutureTrackIdEval.h"
+#include "CaloFutureUtils/CaloFuture2Track.h"
+#include "CaloFutureUtils/CaloFutureAlgUtils.h"
+#include "Event/Track.h"
+#include "GaudiAlg/Transformer.h"
+#include "GaudiKernel/Counters.h"
+#include "Relations/Relation1D.h"
+#include "ToVector.h"
+
+// ============================================================================
+/** @class CaloFutureTrack2IDAlg CaloFutureTrack2IDAlg.h
+ *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
+ *  @date   2006-06-15
+ */
+
+using Table  = LHCb::Relation1D<LHCb::Track,float>;
+using Filter = LHCb::Relation1D<LHCb::Track,bool>;
+
+class CaloFutureTrack2IDAlg : public Gaudi::Functional::Transformer<Table(const LHCb::Tracks&,const Filter&),Gaudi::Functional::Traits::BaseClass_t<CaloFutureTrackAlg> > {
+  static_assert(std::is_base_of<LHCb::CaloFuture2Track::ITrAccTable,Filter>::value,"Filter must inherit from ITrAccTable");
+  public:
+    CaloFutureTrack2IDAlg(const std::string& name, ISvcLocator* pSvc);
+    Table operator()(const LHCb::Tracks&,const Filter&) const override;
+
+  private:
+    // tool to be used for evaluation
+    ToolHandle<ICaloFutureTrackIdEval> m_tool{this, "Tool", "<NOT DEFINED>"};
+
+    mutable Gaudi::Accumulators::StatCounter<> m_nTracks{this, "#total tracks"};
+    mutable Gaudi::Accumulators::StatCounter<> m_nLinks {this, "#links in table"};
+    mutable Gaudi::Accumulators::StatCounter<double> m_nEnergy{this, "#total energy"};
+};
+
+// ============================================================================
+#endif  // CALOFUTURETRACK2IDALG_H
+// ============================================================================
diff --git a/CaloFuture/CaloFuturePIDs/src/CaloFutureTrackAlg.cpp b/CaloFuture/CaloFuturePIDs/src/CaloFutureTrackAlg.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4dc3914d008e17524346128540cd5ceb472f5fe9
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/CaloFutureTrackAlg.cpp
@@ -0,0 +1,57 @@
+// Include files
+#include "CaloFutureTrackAlg.h"
+#include "CaloFutureUtils/CaloFutureAlgUtils.h"
+#include "Event/Track.h"
+
+// ============================================================================
+/** @file
+ *
+ *  Implementation file for class CaloCluster2TrackAlg
+ *  @see CaloCluster2TrackAlg
+ *
+ *  @author Vanya Belyaev Ivan.Belyaev@itep.ru
+ *  @date 02/11/2001
+ */
+// ============================================================================
+
+CaloFutureTrackAlg::CaloFutureTrackAlg(const std::string& name, ISvcLocator* svcloc)
+    : GaudiAlgorithm(name, svcloc) {
+  //
+  _setProperty("CheckTracks", "true");
+  std::vector<int> stat = {LHCb::Track::FitStatus::Fitted};
+  if (LHCb::CaloFutureAlgUtils::hltContext(context()))
+    stat.push_back(LHCb::Track::FitStatus::FitStatusUnknown);
+  setProperty("AcceptedFitStatus", stat).ignore();
+}
+
+// =============================================================================
+// standard algorithm initialization
+// =============================================================================
+
+StatusCode CaloFutureTrackAlg::initialize() {
+  StatusCode sc = GaudiAlgorithm::initialize();
+  if (sc.isFailure()) {
+    return sc;
+  }
+  // Retrieve tools
+  sc = counterStat.retrieve();
+  if (sc.isFailure()) {
+    return sc;
+  }
+  //
+  if (propsPrint() || msgLevel(MSG::DEBUG) || m_use.check()) {
+    info() << m_use << endmsg;
+  };
+  //
+  return StatusCode::SUCCESS;
+}
+
+// =============================================================================
+
+void CaloFutureTrackAlg::_setProperty(const std::string& p, const std::string& v) {
+  StatusCode sc = setProperty(p, v);
+  if (!sc.isSuccess()) {
+    warning() << " setting Property " << p << " to " << v << " FAILED"
+              << endmsg;
+  }
+}
diff --git a/CaloFuture/CaloFuturePIDs/src/CaloFutureTrackAlg.h b/CaloFuture/CaloFuturePIDs/src/CaloFutureTrackAlg.h
new file mode 100644
index 0000000000000000000000000000000000000000..4c87fd5e1eb11b8a6531e99a48ed0415259eb7b6
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/CaloFutureTrackAlg.h
@@ -0,0 +1,86 @@
+#ifndef CALOFUTUREUTILS_CALOFUTURETrackAlg_H
+#define CALOFUTUREUTILS_CALOFUTURETrackAlg_H 1
+
+// Include files
+#include <string>
+#include "GaudiAlg/GaudiAlgorithm.h"
+#include "CaloFutureInterfaces/IFutureCounterLevel.h"
+#include "Event/TrackUse.h"
+
+// ============================================================================
+/** @class CaloFutureTrackAlg CaloFutureTrackAlg.h
+ *
+ *  Helper base algorithm form implementation 'track'-related algorithms
+ *
+ *  It helps to select the appropriate tracks for further processing
+ *  Track is 'selected' if it fullfills
+ *
+ *   - general features
+ *   - category
+ *   - "algorithm"
+ *
+ *  @see TrackUse
+ *
+ *  @see CaloFutureAlgorithm
+ *  @see     Algorithm
+ *  @see    IAlgorithm
+ *
+ *  @author Vanya BELYAEV belyaev@lapp.in2p3.fr
+ *  @date   2004-10-26
+ */
+// ============================================================================
+
+class TrackUse;
+class Track;
+
+class CaloFutureTrackAlg : public GaudiAlgorithm {
+ public:
+  /// standard algorithm initialization
+  StatusCode initialize() override;
+
+  void _setProperty(const std::string& p, const std::string& v);
+
+  /// C++11 non-copyable idiom
+  CaloFutureTrackAlg() = delete;
+  CaloFutureTrackAlg(const CaloFutureTrackAlg&) = delete;
+  CaloFutureTrackAlg& operator=(const CaloFutureTrackAlg&) = delete;
+
+ protected:
+  /// Standard constructor
+  CaloFutureTrackAlg(const std::string& name, ISvcLocator* svcloc);
+
+  virtual ~CaloFutureTrackAlg(){};
+  
+  /// check if the track to be used @see TrackUse
+  inline bool use(const LHCb::Track* track) const { return m_use(track); }
+  /// print the short infomration about track flags
+  inline MsgStream& print(MsgStream& stream, const LHCb::Track* track) const;
+  /// print the short infomration about track flags
+  inline MsgStream& print(const LHCb::Track* track,
+                          const MSG::Level level = MSG::INFO) const;
+
+  ToolHandle<IFutureCounterLevel> counterStat{"FutureCounterLevel"};
+  TrackUse m_use { *this };
+};
+
+// ============================================================================
+/// print the short infomration about track flags
+// ============================================================================
+
+inline MsgStream& CaloFutureTrackAlg::print(MsgStream& stream,
+                                      const LHCb::Track* track) const {
+  return stream.isActive() ? m_use.print(stream, track) : stream;
+}
+
+// ============================================================================
+/// print the short infomration about track flags
+// ============================================================================
+
+inline MsgStream& CaloFutureTrackAlg::print(const LHCb::Track* track,
+                                      const MSG::Level level) const {
+  return print(msgStream(level), track);
+}
+
+// ============================================================================
+#endif  // CALOFUTURETrackAlg_H
+// ============================================================================
diff --git a/CaloFuture/CaloFuturePIDs/src/CaloFutureTrackMatch.cpp b/CaloFuture/CaloFuturePIDs/src/CaloFutureTrackMatch.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..fada31a33796c692abdee2ebd7bfa39ffa64704c
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/CaloFutureTrackMatch.cpp
@@ -0,0 +1,97 @@
+// Include files
+#include "CaloFutureTrackMatch.h"
+#include "GaudiKernel/IIncidentListener.h"
+#include "GaudiKernel/IIncidentSvc.h"
+
+// ============================================================================
+/** @file
+ *  Implementation file for class CaloFutureTrackMatch
+ *
+ *  Properties of the class:
+ *  BadValue - bad value of the chi2,
+ *  ConditionName - string with the path to the file containing e- and e+ X-correction condition parameters,
+ *  AlphaPOut - track-cluster matching X-correction parameters for Outer zone of the ECAL in case (q*polarity) > 0
+ *  AlphaNOut - track-cluster matching X-correction parameters for Outer zone of the ECAL in case (q*polarity) < 0
+ *  AlphaPMid - track-cluster matching X-correction parameters for Middle zone of the ECAL in case (q*polarity) > 0
+ *  AlphaNMid - track-cluster matching X-correction parameters for Middle zone of the ECAL in case (q*polarity) < 0
+ *  AlphaPInn - track-cluster matching X-correction parameters for Inner zone of the ECAL in case (q*polarity) > 0
+ *  AlphaNInn - track-cluster matching X-correction parameters for Inner zone of the ECAL in case (q*polarity) < 0
+ *
+ *  @author Oleg STENYAKIN  oleg.stenyakin@cern.ch
+ *  @date   2014-03-03
+ *
+ */
+
+// ============================================================================
+/// standard constructor
+// ============================================================================
+
+CaloFutureTrackMatch::CaloFutureTrackMatch(const std::string& type, const std::string& name,
+                               const IInterface* parent)
+    : CaloFuture::CaloFutureTrackTool(type, name, parent) {
+  declareInterface<IIncidentListener>(this);
+}
+
+// ============================================================================
+
+StatusCode CaloFutureTrackMatch::i_updateAlpha() {
+  // allow a user to disable the CondDB and reset the x-corrections with
+  // setProperty on the fly (if ever needed)
+  if ( m_conditionName.empty() ){
+    if( msgLevel(MSG::DEBUG) )
+      debug() << "attempt to update X-correction parameters by UpdMgrSvc while CondDB access disabled" << endmsg;
+    return StatusCode::SUCCESS;
+  }
+
+  // safety protection against SIGSEGV
+  if ( !m_cond ){ fatal() << "CaloFutureTrackMatch::i_updateAlpha m_cond == 0" << endmsg; return StatusCode::FAILURE; }
+  try {
+    m_alphaPOut.value() = m_cond->paramAsDoubleVect( "alphaPOut" );
+    m_alphaNOut.value() = m_cond->paramAsDoubleVect( "alphaNOut" );
+    m_alphaPMid.value() = m_cond->paramAsDoubleVect( "alphaPMid" );
+    m_alphaNMid.value() = m_cond->paramAsDoubleVect( "alphaNMid" );
+    m_alphaPInn.value() = m_cond->paramAsDoubleVect( "alphaPInn" );
+    m_alphaNInn.value() = m_cond->paramAsDoubleVect( "alphaNInn" );
+  }
+  catch ( GaudiException &exc ){
+    fatal() << "X-correction update failed! msg ='" << exc << "'" << endmsg;
+    return StatusCode::FAILURE;
+  }
+  if ( msgLevel(MSG::DEBUG) )
+    debug() << "CondDB update of CaloFutureTrackMatch X-correction parameters with '" << m_conditionName << "':"
+            <<"\nalphaPOut: "<< Gaudi::Utils::toString ( m_alphaPOut.value() )
+            <<" alphaNOut: " << Gaudi::Utils::toString ( m_alphaNOut.value() )
+            <<"\nalphaPMid: "<< Gaudi::Utils::toString ( m_alphaPMid.value() )
+            <<" alphaNMid: " << Gaudi::Utils::toString ( m_alphaNMid.value() )
+            <<"\nalphaPInn: "<< Gaudi::Utils::toString ( m_alphaPInn.value() )
+            <<" alphaNInn: " << Gaudi::Utils::toString ( m_alphaNInn.value() ) << endmsg;
+
+  return StatusCode::SUCCESS;
+}
+
+// =============================================================================
+
+StatusCode CaloFutureTrackMatch::initialize(){
+  StatusCode sc = CaloFuture::CaloFutureTrackTool::initialize();
+  if ( sc.isFailure() ) { return sc ; }
+  IIncidentSvc* isvc = svc<IIncidentSvc>( "IncidentSvc" , true ) ;
+  isvc->addListener ( this , IncidentType::BeginEvent ) ;
+
+  if (! existDet<DataObject>(detSvc(), m_conditionName) ){
+    if( msgLevel(MSG::DEBUG) ) debug() << "Condition '" << m_conditionName << "' not found -- switch off the use of the CondDB for CaloFutureTrackMatch!" << endmsg;
+    m_conditionName = "";
+  }
+
+  if ( ! m_conditionName.empty() ){
+    registerCondition(m_conditionName, m_cond, &CaloFutureTrackMatch::i_updateAlpha);
+    sc = runUpdate();  // ask UpdateManagerSvc to load the condition w/o waiting for the next BeginEvent incident
+  }
+  else
+    if( msgLevel(MSG::DEBUG) ) debug() << "ConditionName empty -- reading of the CaloFutureTrackMatch X-correction parameters from the CondDB has been disabled!" << endmsg;
+
+  m_magFieldSvc = svc<ILHCbMagnetSvc>( "MagneticFieldSvc", true ) ;
+
+  return StatusCode::SUCCESS;
+}
+
+// ============================================================================
diff --git a/CaloFuture/CaloFuturePIDs/src/CaloFutureTrackMatch.h b/CaloFuture/CaloFuturePIDs/src/CaloFutureTrackMatch.h
new file mode 100644
index 0000000000000000000000000000000000000000..f7a4a574d59150c2f7ec89ef8e0d5ae67ecbe2ed
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/CaloFutureTrackMatch.h
@@ -0,0 +1,406 @@
+#ifndef CALOFUTUREUTILS_CALOFUTURETRACKMATCH_H
+#define CALOFUTUREUTILS_CALOFUTURETRACKMATCH_H 1
+
+// Include files
+#include "GaudiKernel/IIncidentSvc.h"
+#include "GaudiKernel/IIncidentListener.h"
+#include "GaudiKernel/GenericVectorTypes.h"
+#include "GaudiKernel/SymmetricMatrixTypes.h"
+#include "Event/CaloPosition.h"
+#include "Event/State.h"
+#include "CaloFutureTrackTool.h"
+#include "DetDesc/Condition.h"
+#include "Kernel/ILHCbMagnetSvc.h"
+
+// ============================================================================
+/** @class CaloFutureTrackMatch CaloFutureTrackMatch.h
+ *  Description of the use of the track-cluster matching X-correction
+ *  parameters for electrons and positrons.
+ *
+ *  The X-correction part of the code has been designed with the kind help from
+ *  Vanya BELYAEV and Dmitry GOLUBKOV.
+ *
+ *  Common form of the X-correction between the X-position of the state
+ *  of track and barycentre of the CaloHypo object is:
+ *  dX = a0*p + a1 + a2/p + a3/p^2 + ...
+ *  where p - momentum of the track in GeV/$c$,
+ *  parameter vectors for each zone of the ECAL
+ *  m_alphaN<Area>[3] = {a0, a1, a2, a3, ...}
+ *  for e- MagUp and e+ MagDown: (q*polarity) < 0
+ *  and
+ *  m_alphaP<Area>[3] = {a0, a1, a2, a3, ...}
+ *  for e- MagDown and e+ MagUp: (q*polarity) > 0
+ *
+ *  By default the X-correction parameters are read from the CondDB
+ *  path '/dd/Conditions/ParticleID/Calo/ElectronXCorrection'.
+ *
+ *  In the case when the CondDB is switched off or reading
+ *  of the X-correction parameters from the CondDB is disabled
+ *  the X-correction is not implemented and all X-correction parameters
+ *  are equal to zero.
+ *
+ *  Usage of the X-correction parameters in Bender scripts:
+ *  def configure ( ) :
+ *      """
+ *      Job configuration
+ *      """
+ *      ...
+ *      from Configurables import CaloFutureElectronMatch
+ *      my_tool = CaloFutureElectronMatch()
+ *      ## disable use of the CondDB to apply correction coefficients
+ *      ## from the Options
+ *      my_tool.ConditionName = ""
+ *      ## Set the X-correction parameters for the Outer zone
+ *      ## of the ECAL in case (q*polarity) < 0
+ *      my_tool.AlphaNOut = [ 0.0, -18.92, 83.46, -292.4 ]
+ *
+ *  For more info see talk by O. Stenyakin
+ *  at 2014/02/20 Moscow student meeting
+ *  https://indico.cern.ch/event/302695/
+ *  or
+ *  at 2014/01/24 CaloFuture Objects meeting
+ *  https://indico.cern.ch/event/296617/
+ *
+ *  @author Oleg STENYAKIN oleg.stenyakin@cern.ch
+ *  @date   2014-03-03
+ */
+// ============================================================================
+
+class CaloFutureTrackMatch : public CaloFuture::CaloFutureTrackTool,
+                       public virtual IIncidentListener {
+ public:
+  /// initialization
+  StatusCode initialize() override;
+  StatusCode i_updateAlpha();
+  void handle(const Incident&) override {
+    m_position = nullptr;
+    m_plane = Gaudi::Plane3D();
+  }
+
+ protected:
+  /// Standard constructor
+  CaloFutureTrackMatch(const std::string& type, const std::string& name,
+                 const IInterface* parent);
+
+  virtual ~CaloFutureTrackMatch(){};
+
+ protected:
+  /// helper internal structure to simplify matrix calculations
+  template <unsigned D>
+  class Match_ {
+   public:
+    using Vector = ROOT::Math::SVector<double, D>;
+    using Matrix = ROOT::Math::SMatrix<double, D, D, ROOT::Math::MatRepSym<double, D> >;
+
+   public:
+    /// constructor
+    Match_(const Vector& params, const Matrix& matrix)
+        : m_params(params), m_matrix(matrix), m_ok(true), m_inverted(false){};
+    Match_() : m_params(), m_matrix(), m_ok(true), m_inverted(false){};
+
+   public:
+    inline const Vector& params() const { return m_params; }
+    inline const Matrix& matrix() const { return m_matrix; }
+    inline bool ok() const { return m_ok; }
+    inline bool inverted() const { return m_inverted; }
+
+   public:
+    double& operator()(const unsigned int ind) { return m_params(ind); }
+    double& operator()(const unsigned int ind1, const unsigned int ind2) {
+      return m_matrix(ind1, ind2);
+    }
+
+   public:
+    Match_& set(const Matrix& m) {
+      m_matrix = m;
+      return *this;
+    }
+    Match_& set(const Vector& v) {
+      m_params = v;
+      return *this;
+    }
+    Match_& setOK(const bool e) {
+      m_ok = e;
+      return *this;
+    }
+    Match_& setInverted(const bool i) {
+      m_inverted = i;
+      return *this;
+    }
+
+   public:
+    // invert the matrix
+    bool invert() {
+      if (m_inverted) {
+        return m_ok;
+      }  // RETURN
+      m_ok = m_matrix.Invert();
+      if (m_ok) {
+        m_inverted = true;
+      }
+      return ok();
+    };
+
+   private:
+    Match_(const Match_&);
+    Match_& operator=(const Match_&);
+
+   private:
+    // the vector of parameters x,y(,e)
+    Vector m_params;
+    // the (inverse) covariance matrix of parameters
+    Matrix m_matrix;
+    // flag for errors
+    bool m_ok = true;
+    // flag to indicate that matrix is already inverted
+    bool m_inverted = false;
+  };
+
+ protected:
+  inline bool updateCaloFuturePos(const LHCb::CaloPosition* p1,
+                            const LHCb::CaloPosition* p2) {
+    return (p1 != p2);
+  }
+
+  template <unsigned int D>
+  inline double chi2(const Match_<D>& m1, const Match_<D>& m2) const {
+    typedef typename Match_<D>::Vector Vector;
+    typedef typename Match_<D>::Matrix Matrix;
+
+    if (!m1.inverted() || !m1.ok() || !m2.inverted() || !m2.ok()) {
+      Warning("chi2(): invalid data are detected - return bad chi2").ignore();
+      return 99999999.;
+    }
+
+    // local storage to avoid the dynamic allocation
+    static Matrix s_cov;
+    // evaluate the overall covariance matrix
+    s_cov = m1.matrix() + m2.matrix();
+    if (!s_cov.Invert()) {
+      Warning("chi2(): can not invert the matrix - return bad chi2").ignore();
+      return 99999999.;
+    }
+
+    // get the weighted and mean parameters
+    // Note: Cannot use `auto` here
+    Vector pw = m1.matrix()*m1.params() + m2.matrix()*m2.params() ;
+    Vector pm = s_cov * pw ;
+
+    // evaluate chi2
+    const double temp = ROOT::Math::Similarity(pm - m1.params(), m1.matrix()) +
+                        ROOT::Math::Similarity(pm - m2.params(), m2.matrix());
+    return temp;
+  }
+
+  /// get 2D-infomration form CaloPosition
+  inline StatusCode fill(const LHCb::CaloPosition& c, Match_<2>& match) const {
+    const auto par = c.center();
+    const auto cov = c.spread();
+    match(0) = par(0);
+    match(1) = par(1);
+    match(0, 0) = cov(0, 0);
+    match(0, 1) = cov(0, 1);
+    match(1, 1) = cov(1, 1);
+    match.setInverted(false);
+    match.setOK(true);
+    if (!match.invert()) {
+      if (msgLevel(MSG::DEBUG)) {
+        debug() << "CaloPosition:" << c << endmsg;
+      }
+      return Warning("match(): Could not invert '2D-calo' matrix, see debug",
+                     StatusCode::FAILURE, 0);
+    }
+    return StatusCode::SUCCESS;
+  };
+
+  // get 2D-information from State
+  inline StatusCode fill(const LHCb::State& s, Match_<2>& match) const {
+    const auto par = s.stateVector();
+    const auto cov = s.covariance();
+    match(0) = par(0);
+    match(1) = par(1);
+    match(0, 0) = cov(0, 0);
+    match(0, 1) = cov(0, 1);
+    match(1, 1) = cov(1, 1);
+    match.setInverted(false);
+    match.setOK(true);
+    if (!match.invert()) {
+      if (msgLevel(MSG::DEBUG)) {
+        debug() << "State:" << s << endmsg;
+      }
+      return Warning("match(): Could not invert 'track' matrix",
+                     StatusCode::FAILURE);
+    }
+    return StatusCode::SUCCESS;
+  };
+
+  /// get 3D-infomration form CaloPosition
+  inline StatusCode fill(const LHCb::CaloPosition& c, Match_<3>& match) const {
+    const auto par = c.parameters();
+    const auto cov = c.covariance();
+    match(0) = par(LHCb::CaloPosition::Index::X);
+    match(1) = par(LHCb::CaloPosition::Index::Y);
+    match(2) = par(LHCb::CaloPosition::Index::E);
+    match(0, 0) = cov(LHCb::CaloPosition::Index::X, LHCb::CaloPosition::Index::X);
+    match(0, 1) = cov(LHCb::CaloPosition::Index::X, LHCb::CaloPosition::Index::Y);
+    match(0, 2) = cov(LHCb::CaloPosition::Index::X, LHCb::CaloPosition::Index::E);
+    match(1, 1) = cov(LHCb::CaloPosition::Index::Y, LHCb::CaloPosition::Index::Y);
+    match(1, 2) = cov(LHCb::CaloPosition::Index::Y, LHCb::CaloPosition::Index::E);
+    match(2, 2) = cov(LHCb::CaloPosition::Index::E, LHCb::CaloPosition::Index::E);
+    match.setInverted(false);
+    match.setOK(true);
+    if (!match.invert()) {
+      if (msgLevel(MSG::DEBUG)) {
+        debug() << "CaloPosition:" << c << endmsg;
+      }
+      return Warning("match(): Could not invert '3D-calo' matrix",
+                     StatusCode::FAILURE);
+    }
+    return StatusCode::SUCCESS;
+  };
+
+  /// get 2D-infomration from CaloPosition for Bremstrahlung
+  inline StatusCode fillBrem(const LHCb::CaloPosition& c,
+                             Match_<2>& match) const {
+    const auto par = c.parameters();
+    const auto cov = c.covariance();
+    match(0) = par(LHCb::CaloPosition::Index::X);
+    match(1) = par(LHCb::CaloPosition::Index::Y);
+    match(0, 0) = cov(LHCb::CaloPosition::Index::X, LHCb::CaloPosition::Index::X);
+    match(0, 1) = cov(LHCb::CaloPosition::Index::X, LHCb::CaloPosition::Index::Y);
+    match(1, 1) = cov(LHCb::CaloPosition::Index::Y, LHCb::CaloPosition::Index::Y);
+    match.setInverted(false);
+    match.setOK(true);
+    if (!match.invert()) {
+      if (msgLevel(MSG::DEBUG)) {
+        debug() << "CaloPosition:" << c << endmsg;
+      }
+      return Warning("match(): Could not invert '2D-calobrem' matrix",
+                     StatusCode::FAILURE);
+    }
+    return StatusCode::SUCCESS;
+  };
+
+  // get 3D-information from State
+  inline StatusCode fill(const LHCb::State& s, Match_<3>& match) const {
+    const auto par = s.stateVector();
+    const double q = 0 < par(4) ? 1. : -1.;  // charge
+    const double mom =
+        ::fabs(1.0 / par(4) / Gaudi::Units::GeV);  // momentum in GeV
+
+    // find calo area corresponding to the input LHCb::State &s;
+    const auto cell =
+        calo()->Cell_(s.position()); // cell parameters (null if point is
+                                     // outside the CalorimeterFuture)
+    unsigned int area = 4;           // initialize with some invalid area number
+    if (cell)  // protection against tracks pointing outside the CalorimeterFuture
+      area = cell->cellID().area();  // 0:Outer, 1:Middle, 2:Inner
+    else  // roughly assign the area around the beam hole to the Inner,
+          // everything outside CaloFuture -- to the Outer
+      area = (fabs(s.position().x()) < 2. * Gaudi::Units::m &&
+              fabs(s.position().y()) < 2. * Gaudi::Units::m)
+                 ? 2
+                 : 0;  // |x,y| < > 2m
+
+    const float polarity = m_magFieldSvc->isDown() ? -1 : +1;
+    const bool qpolarity = (q * polarity >
+                      0);  // true : (q*polarity) > 0, false : (q*polarity) < 0
+
+    const std::vector<double>* alpha = nullptr;
+    switch (area)  // symbolic names only declaread as "the private part" of
+                   // namespace CaloFutureCellCode in CaloFutureCellCode.cpp
+    {
+    case 0 : // Outer  ECAL
+      alpha = qpolarity ? &m_alphaPOut.value() : &m_alphaNOut.value();
+      break;
+    case 1 : // Middle ECAL
+      alpha = qpolarity ? &m_alphaPMid.value() : &m_alphaNMid.value();
+      break;
+    case 2 : // Inner  ECAL
+      alpha = qpolarity ? &m_alphaPInn.value() : &m_alphaNInn.value();
+      break;
+    }
+    Assert(alpha,
+           "electron track pointing to an impossible CaloFuture area outside 0..2 "
+           "range");
+
+    match(0) = par(0);
+    // now add the correction series dX = a0*p + a1 + a2/p + a3/p^2 + ...
+    if (!alpha->empty()) {
+      double mmm = mom;                               // p, 1, 1/p, 1/p^2, ...
+      double inv = fabs(par(4) * Gaudi::Units::GeV);  // abs(1/p) in GeV
+
+      for (const auto it: *alpha){
+        match(0) += it * mmm;
+        mmm *= inv;  // [1/p]^k, k=-1, 0, ... size(alpha)-2
+      }
+    }
+
+    match(1) = par(1);
+    match(2) = ::fabs(1.0 / par(4));              /// @todo check it!
+    const double f = -1.0 * q / par(4) / par(4);  // d(p)/d(Q/p)
+    const auto cov = s.covariance();
+    match(0, 0) = cov(0, 0);          // (x,x)
+    match(0, 1) = cov(0, 1);          // (x,y)
+    match(1, 1) = cov(1, 1);          // (y,y)
+    match(0, 2) = f * cov(0, 4);      // (x,p)
+    match(1, 2) = f * cov(1, 4);      // (y,p)
+    match(2, 2) = f * cov(4, 4) * f;  // (p,p)
+    match.setInverted(false);
+    match.setOK(true);
+    if (!match.invert()) {
+      if (msgLevel(MSG::DEBUG)) {
+        debug() << "State:" << s << endmsg;
+      }
+      return Warning("match(): Could not invert 'track' matrix",
+                     StatusCode::FAILURE);
+    }
+    return StatusCode::SUCCESS;
+  };
+
+ protected:
+  inline       double        bad    () const { return m_bad   ; }
+  inline       LHCb::State& _state  ()       { return m_state ; }
+  inline const LHCb::State& _state  () const { return m_state ; }
+
+  Condition* m_cond;
+  Gaudi::Property<std::string> m_conditionName
+    {this, "ConditionName", 
+    "/dd/Conditions/ParticleID/Calo/ElectronXCorrection",
+    "set this property to an empty string to disable the use of CondDB"};
+
+  ILHCbMagnetSvc* m_magFieldSvc;
+
+  const LHCb::CaloPosition* m_position = nullptr;
+
+  Gaudi::Plane3D m_plane;
+
+private:
+  LHCb::State m_state;
+  
+  Gaudi::Property<double> m_bad 
+    {this, "BadValue", 1.e+10, "bad value for chi2"};
+
+  Gaudi::Property<std::vector<double>> m_alphaPOut
+    {this, "AlphaPOut", {}, "electron X-correction params for (q*polarity) > 0 Outer" };
+
+  Gaudi::Property<std::vector<double>> m_alphaNOut
+    {this, "AlphaNOut", {}, "electron X-correction params for (q*polarity) < 0 Outer" };
+
+  Gaudi::Property<std::vector<double>> m_alphaPMid
+    {this, "AlphaPMid", {}, "electron X-correction params for (q*polarity) > 0 Middle"};
+
+  Gaudi::Property<std::vector<double>> m_alphaNMid
+    {this, "AlphaNMid", {}, "electron X-correction params for (q*polarity) < 0 Middle"};
+
+  Gaudi::Property<std::vector<double>> m_alphaPInn
+    {this, "AlphaPInn", {}, "electron X-correction params for (q*polarity) > 0 Inner" };
+
+  Gaudi::Property<std::vector<double>> m_alphaNInn
+    {this, "AlphaNInn", {}, "electron X-correction params for (q*polarity) < 0 Inner" };
+
+};
+
+// ============================================================================
+#endif  // CALOFUTUREUTILS_CALOFUTURETRACKMATCH_H
+// ============================================================================
diff --git a/CaloFuture/CaloFuturePIDs/src/CaloFutureTrackMatchAlg.cpp b/CaloFuture/CaloFuturePIDs/src/CaloFutureTrackMatchAlg.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..63c645fe761bd411bbea9598c33b0c74fcf29b5a
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/CaloFutureTrackMatchAlg.cpp
@@ -0,0 +1,74 @@
+// Include files
+#include "CaloFutureTrackMatchAlg.h"
+
+// ============================================================================
+/** @file
+ *  Implementation file for class CaloFutureTrackMatchAlg
+ *  @date 2006-06-16
+ *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
+ */
+// ============================================================================
+/// Standard protected constructor
+// ============================================================================
+
+template <typename TABLE, typename CALOFUTURETYPES>
+CaloFutureTrackMatchAlg<TABLE,CALOFUTURETYPES>::CaloFutureTrackMatchAlg(const std::string& name, ISvcLocator* pSvc)
+    : base_type(name, pSvc, {KeyValue{"Tracks",""},KeyValue{"Calos",""},KeyValue{"Filter",""}}, KeyValue{"Output",""})
+{
+  // context-dependent default track container
+  Gaudi::Functional::updateHandleLocation(*this, "Tracks", LHCb::CaloFutureAlgUtils::TrackLocations(context()).front());
+}
+
+// ============================================================================
+/// standard algorithm execution
+// ============================================================================
+template <typename TABLE, typename CALOFUTURETYPES>
+TABLE CaloFutureTrackMatchAlg<TABLE,CALOFUTURETYPES>::operator()(const LHCb::Tracks& tracks, const CALOFUTURETYPES& calos, const Filter& filter) const {
+
+  LHCb::Track::ConstVector good_tracks;
+  good_tracks.reserve(100);
+  std::copy_if( tracks.begin(), tracks.end(), std::back_inserter(good_tracks),
+	  [&](const auto& track){
+	    if(!this->use(track)) return false;
+	    const auto& r = filter.relations(track);
+	    return !r.empty() && r.front().to();
+	  }
+	  );
+  const size_t nTracks = good_tracks.size();
+  if(0==nTracks) if(msgLevel(MSG::DEBUG)) debug() << "No good tracks have been selected" << endmsg;
+
+  TABLE table(m_tablesize);
+  size_t nOverflow = 0;
+   
+  // loop over the calo objects
+  for(const auto& calo : calos){
+    const auto caloPos = position(calo);
+    for(const auto& track : good_tracks){
+      double chi2 = 0;
+      StatusCode sc = m_tool->match( caloPos, track, chi2);
+      if (sc.isFailure() ){
+        if (msgLevel(MSG::DEBUG)) debug() << "Failure from Tool::match, skip" << endmsg;
+        m_nMatchFailure += 1;
+        continue;
+      }
+      if( m_threshold < chi2 ){++nOverflow; continue;}
+      table.i_push(calo,track,chi2);
+    }
+  }//calos
+  // MANDATORY: i_sort after i_push
+  table.i_sort();  // NB: i_sort
+  
+  const auto links = table.i_relations();
+  m_nLinks    += links.size();
+  m_nTracks   += nTracks;
+  m_nCalos    += calos.size();
+  m_nOverflow += nOverflow;
+  auto b = m_chi2.buffer();
+  for(const auto& l : links) b += l.weight();
+
+  return table;
+}
+
+template class CaloFutureTrackMatchAlg<LHCb::RelationWeighted2D<LHCb::CaloCluster, LHCb::Track, float>,LHCb::CaloClusters>;
+template class CaloFutureTrackMatchAlg<LHCb::RelationWeighted2D<LHCb::CaloHypo, LHCb::Track, float>,LHCb::CaloHypos>;
+
diff --git a/CaloFuture/CaloFuturePIDs/src/CaloFutureTrackMatchAlg.h b/CaloFuture/CaloFuturePIDs/src/CaloFutureTrackMatchAlg.h
new file mode 100644
index 0000000000000000000000000000000000000000..7eb513caa5a003cf33abfd8b4b2c47c0725d88b7
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/CaloFutureTrackMatchAlg.h
@@ -0,0 +1,77 @@
+#ifndef CALOFUTURETRACKMATCHALG_H
+#define CALOFUTURETRACKMATCHALG_H 1
+
+// Include files
+#include "CaloFutureTrackAlg.h"
+#include "CaloFutureUtils/CaloFuture2Track.h"
+#include "CaloFutureUtils/CaloFutureAlgUtils.h"
+#include "Event/CaloCluster.h"
+#include "Event/CaloHypo.h"
+#include "Event/Track.h"
+#include "CaloFutureInterfaces/ICaloFutureTrackMatch.h"
+#include "Relations/Relation1D.h"
+#include "Relations/RelationWeighted2D.h"
+#include "GaudiAlg/Transformer.h"
+#include "GaudiKernel/Counters.h"
+#include "ToVector.h"
+
+// ============================================================================
+/** @class CaloFutureTrackMatchAlg CaloFutureTrackMatchAlg.h
+ *
+ *
+ *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
+ *  @date   2006-06-16
+ */
+
+using Filter = LHCb::Relation1D<LHCb::Track,bool>; 
+
+template <typename TABLE, typename CALOFUTURETYPES>
+class CaloFutureTrackMatchAlg 
+    : public Gaudi::Functional::Transformer<
+               TABLE(const LHCb::Tracks&, const CALOFUTURETYPES&, const Filter&), 
+               Gaudi::Functional::Traits::BaseClass_t<CaloFutureTrackAlg> >
+{
+  static_assert(std::is_base_of<LHCb::CaloFuture2Track::ITrAccTable,Filter>::value,"Filter must inherit from ITrAccTable");
+  public:
+    using CaloFutureTrackAlg::context;
+    using CaloFutureTrackAlg::msgLevel;
+    using CaloFutureTrackAlg::debug;
+    using CaloFutureTrackAlg::use;
+    using CaloFutureTrackAlg::getProperty;
+    using CaloFutureTrackAlg::_setProperty;
+    using base_type = Gaudi::Functional::Transformer<TABLE(const LHCb::Tracks&,const CALOFUTURETYPES&,const Filter&),
+                                                     Gaudi::Functional::Traits::BaseClass_t<CaloFutureTrackAlg> >;
+    using KeyValue = typename base_type::KeyValue;
+
+    // standard constructor
+    CaloFutureTrackMatchAlg(const std::string& name, ISvcLocator* pSvc);
+
+    // standard execution
+    TABLE operator()(const LHCb::Tracks& tracks, const CALOFUTURETYPES& calos, const Filter& filter) const override;
+
+
+  protected:
+
+    Gaudi::Property<float> m_threshold {this, "Threshold", 10000., "threshold"};
+    Gaudi::Property<int>   m_tablesize {this, "TableSize", 100,    "table size"};
+
+    // the tool for matching
+    // **TODO**: update tool CaloFutureTrackMatch 
+    mutable ToolHandle<ICaloFutureTrackMatch> m_tool {this, "Tool", "<NOT DEFINED>"};
+
+    // a bit of statistics
+    mutable Gaudi::Accumulators::StatCounter<>  m_nMatchFailure {this, "#match failure"};
+    mutable Gaudi::Accumulators::StatCounter<>  m_nLinks {this, "#links in table"};
+    mutable Gaudi::Accumulators::StatCounter<>  m_nTracks {this, "#good tracks"};
+    mutable Gaudi::Accumulators::StatCounter<>  m_nCalos {this, "#total calos"};
+    mutable Gaudi::Accumulators::StatCounter<>  m_nOverflow {this, "#above threshold"};
+    mutable Gaudi::Accumulators::StatCounter<float> m_chi2 {this, "#chi2"};
+
+  private:
+    const LHCb::CaloPosition* position(const LHCb::CaloCluster* c) const { return &c->position();}
+    const LHCb::CaloPosition* position(const LHCb::CaloHypo* c) const { return c->position();}
+};
+
+// ============================================================================
+#endif  // CALOFUTURETRACKMATCHALG_H
+// ============================================================================
diff --git a/CaloFuture/CaloFuturePIDs/src/CaloFutureTrackTool.cpp b/CaloFuture/CaloFuturePIDs/src/CaloFutureTrackTool.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2a4e4bb692bca5cca71f8bcbf12c5d0ddba04914
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/CaloFutureTrackTool.cpp
@@ -0,0 +1,55 @@
+// Include files
+#include "CaloFutureTrackTool.h"
+
+// ============================================================================
+/** @file
+ *  Implementation file for class CaloFuture::CaloFutureTrackTool
+ *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
+ *  @date 2006-05-28
+ */
+// ============================================================================
+/// standard constructor
+// ============================================================================
+CaloFuture::CaloFutureTrackTool::CaloFutureTrackTool( const std::string& type   , // ?
+                                    const std::string& name   ,
+                                    const IInterface*  parent )
+  : GaudiTool ( type , name , parent )
+{
+  _setProperty("CheckTracks", "false");
+  declareProperty("Extrapolator", m_extrapolator);
+}
+
+//==============================================================================
+/// initialize the tool
+//==============================================================================
+
+StatusCode CaloFuture::CaloFutureTrackTool::initialize() {
+  StatusCode sc = GaudiTool::initialize();
+  if ( sc.isFailure() ) { return sc ; }
+  //
+  if ( propsPrint() || msgLevel ( MSG::DEBUG ) || m_use.check() )
+  { info () << m_use << endmsg ; } ;
+  //
+  if ( !m_detectorName.empty() )
+  { m_calo = getDet<DeCalorimeter> ( detectorName()  ); }
+  else { Warning("empty detector name!"); }
+
+  // Retrieve tools
+  sc = m_extrapolator.retrieve();
+  if (sc.isFailure()) {return sc;}
+  sc = m_fastExtrapolator.retrieve();
+  if (sc.isFailure()) {return sc;}
+
+  return StatusCode::SUCCESS ;
+}
+
+//==============================================================================
+
+void CaloFuture::CaloFutureTrackTool::_setProperty(const std::string &p,
+                                       const std::string &v) {
+  StatusCode sc = setProperty(p, v);
+  if (!sc) {
+    warning() << " setting Property " << p << " to " << v << " FAILED"
+              << endmsg;
+  }
+}
diff --git a/CaloFuture/CaloFuturePIDs/src/CaloFutureTrackTool.h b/CaloFuture/CaloFuturePIDs/src/CaloFutureTrackTool.h
new file mode 100644
index 0000000000000000000000000000000000000000..44ec7b065f5b5fec60d1909f2ea1cd7d0d068ed9
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/CaloFutureTrackTool.h
@@ -0,0 +1,315 @@
+#ifndef CALOFUTUREUTILS_CALOFUTURE_CALOFUTURETRACKTOOL_H
+#define CALOFUTUREUTILS_CALOFUTURE_CALOFUTURETRACKTOOL_H 1
+
+// Include files
+#include <vector>
+#include <string>
+#include <algorithm>
+#include "GaudiAlg/GaudiTool.h"
+#include "LHCbMath/GeomFun.h"
+#include "LHCbMath/Line.h"
+#include "Event/Track.h"
+#include "Event/TrackFunctor.h"
+#include "Event/State.h"
+#include "Event/TrackUse.h"
+#include "CaloFutureInterfaces/ICaloFutureTrackMatch.h"
+#include "CaloFutureInterfaces/ICaloFutureDigits4Track.h"
+#include "TrackInterfaces/ITrackExtrapolator.h"
+#include "CaloDet/DeCalorimeter.h"
+
+//==============================================================================
+
+namespace CaloFuture
+{
+  /** @class CaloFuture::CaloFutureTrackTool CaloFutureTrackTool.h
+   *
+   *
+   *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
+   *  @date   2006-05-28
+   */
+  class CaloFutureTrackTool : public GaudiTool
+  {
+  public:
+    using TrackTypes = std::vector<LHCb::Track::Types>;
+    using Line = ICaloFutureDigits4Track::Line;
+
+    /// initialize the tool
+    StatusCode initialize() override;
+
+    // Internal version. Raise warning if failure
+    void _setProperty(const std::string& p ,const std::string& v);
+
+    /// the default constructor is disabled ;
+    CaloFutureTrackTool() = delete;
+
+  protected:
+    /// standard constructor
+    CaloFutureTrackTool
+    ( const std::string& type   ,
+      const std::string& name   ,
+      const IInterface*  parent ) ;
+
+    /// protected destructor
+    virtual ~CaloFutureTrackTool() {}
+
+    inline ITrackExtrapolator* extrapolator      () const ;
+    inline ITrackExtrapolator* fastExtrapolator  () const ;
+
+    /// Propagate track to a given 3D-place
+    inline StatusCode propagate
+    ( const LHCb::Track&      track ,
+      const Gaudi::Plane3D&   plane ,
+      LHCb::State&            state ,
+      const LHCb::Tr::PID pid = LHCb::Tr::PID::Pion() ) const ;
+
+    /// Propagate state to a given 3D-place
+    inline StatusCode propagate
+    ( LHCb::State&            state ,
+      const Gaudi::Plane3D&   plane ,
+      const LHCb::Tr::PID pid = LHCb::Tr::PID::Pion() ) const ;
+
+    /// Propagate state to a given Z
+    inline StatusCode propagate
+    ( LHCb::State&            state ,
+      const double            z     ,
+      const LHCb::Tr::PID pid = LHCb::Tr::PID::Pion() ) const ;
+
+    /// construct the straight line from the state
+    inline Line line ( const LHCb::State& state ) const
+    { return Line ( state.position() , state.slopes () ) ; } ;
+
+    /** get  a pointer to the satte for the given track at given location
+     *  it shodul be faster then double usage of
+     *  LHCb::Track::hasStateAt ( location )  and LHCb::stateAt ( location )
+     *  In addition it scans the list of states fro the end -
+     *  it is good for calorimeter
+     */
+    inline const LHCb::State* state
+    ( const LHCb::Track&          track ,
+      const LHCb::State::Location loc   ) const ;
+
+    /** get  a pointer to the satte for the given track at given location
+     *  it shodul be faster then double usage of
+     *  LHCb::Track::hasStateAt ( location )  and LHCb::stateAt ( location )
+     *  In addition it scans the list of states fro the end -
+     *  it is good for calorimeter
+     */
+    inline       LHCb::State* state
+    ( LHCb::Track&                track ,
+      const LHCb::State::Location loc   ) const ;
+
+    /// check if the track to be used @see TrackUse
+    inline bool use  ( const LHCb::Track* track ) const { return m_use( track) ; }
+
+    /// print the short infomration about track flags
+    inline MsgStream& print
+    ( MsgStream&         stream ,
+      const LHCb::Track* track  ) const ;
+    
+    /// print the short infomration about track flags
+    inline MsgStream& print
+    ( const LHCb::Track* track             ,
+      const MSG::Level   level = MSG::INFO ) const ;
+
+    double tolerance() const { return m_tolerance ; }
+    const std::string& detectorName() const { return m_detectorName ; }
+    const DeCalorimeter* calo() const { return m_calo ; }
+
+  private:
+
+    // extrapolator
+    mutable ToolHandle<ITrackExtrapolator> m_extrapolator
+      {"TrackRungeKuttaExtrapolator/Regular", this};
+
+    // fast extrapolator
+    mutable ToolHandle<ITrackExtrapolator> m_fastExtrapolator
+      {"TrackLinearExtrapolator/Linear"};
+
+    Gaudi::Property<float> m_fastZ
+      {this, "zForFastExtrapolator", 
+      10.0 * Gaudi::Units::meter, 
+      "z-position of 'linear' extrapolation"};
+
+    Gaudi::Property<float> m_tolerance
+      {this, "Tolerance", 
+      2.0 * Gaudi::Units::mm, 
+      "plane extrapolation tolerance"};
+
+    Gaudi::Property<float> m_cosTolerance
+      {this, "CosTolerance", 
+      ::cos( 0.1 * Gaudi::Units::mrad ), 
+      "plane extrapolation angular tolerance"};
+
+    Gaudi::Property<unsigned int> m_maxIter
+      {this, "MaxPlaneIterations", 5, 
+      "maximal number of iterations"};
+
+    Gaudi::Property<std::string> m_detectorName 
+      {this, "CalorimeterFuture"};
+
+    // detector element
+    const DeCalorimeter* m_calo = nullptr;
+
+    // track selector
+    TrackUse m_use { *this };
+
+    // local storages
+    mutable Gaudi::XYZPoint  m_pos;
+    mutable Gaudi::XYZVector m_mom;
+  };
+}
+
+// ============================================================================
+// get the extrapolator
+// ============================================================================
+
+inline ITrackExtrapolator *CaloFuture::CaloFutureTrackTool::extrapolator() const {
+  return m_extrapolator.get();
+}
+
+// ============================================================================
+// get the fast extrapolator
+// ============================================================================
+
+inline ITrackExtrapolator *CaloFuture::CaloFutureTrackTool::fastExtrapolator() const {
+  return m_fastExtrapolator.get();
+}
+
+// ============================================================================
+// Propagate track to a given 3D-place
+// ============================================================================
+
+inline StatusCode
+CaloFuture::CaloFutureTrackTool::propagate
+( const LHCb::Track&      track ,
+  const Gaudi::Plane3D&   plane ,
+  LHCb::State&            state ,
+  const LHCb::Tr::PID pid   ) const
+{
+  state = track.closestState ( plane ) ;
+  if ( ::fabs( plane.Distance ( state.position() ) ) < tolerance() )
+  { return StatusCode::SUCCESS ; }
+  return propagate ( state , plane , pid ) ;
+}
+
+// ============================================================================
+// Propagate state to a given 3D-place
+// ============================================================================
+
+inline StatusCode
+CaloFuture::CaloFutureTrackTool::propagate
+( LHCb::State&            state ,
+  const Gaudi::Plane3D&   plane ,
+  const LHCb::Tr::PID pid   ) const
+{
+  // check the plane: if it is "almost Z=const"-plane
+  const Gaudi::XYZVector& normal = plane.Normal() ;
+  if ( m_cosTolerance < ::fabs ( normal.Z() ) )
+  {
+    // use the standard method
+    const double Z =  -1*plane.HesseDistance()/normal.Z() ;
+    return propagate (  state , Z , pid ) ;
+  }
+  Gaudi::XYZPoint point ;
+  for ( unsigned int iter = 0 ; iter < m_maxIter ; ++iter )
+  {
+    const double distance = ::fabs ( plane.Distance( state.position() ) );
+    if ( distance <m_tolerance ) { return StatusCode::SUCCESS ; }   // RETURN
+    double mu = 0.0 ;
+    if ( !Gaudi::Math::intersection ( line ( state ) , plane , point , mu ) )
+    { return Warning ( "propagate: line does not cross the place" ) ; }// RETURN
+    StatusCode sc = propagate ( state , point.Z() , pid ) ;
+    if ( sc.isFailure() )
+    { return Warning ( "propagate: failure from propagate" , sc  ) ; } // RETURN
+  }
+  return Warning ( "propagate: no convergency has been reached" ) ;
+}
+
+// ============================================================================
+// Propagate state to a given Z
+// ============================================================================
+
+inline StatusCode
+CaloFuture::CaloFutureTrackTool::propagate
+( LHCb::State&            state ,
+  const double            z     ,
+  const LHCb::Tr::PID pid   ) const
+{
+  if      ( std::max ( state.z() , z ) <  m_fastZ )
+  { // use the regular extrapolator
+    return extrapolator     () -> propagate ( state , z , pid ) ;
+  }
+  else if ( std::min ( state.z() , z ) > m_fastZ  )
+  { // use the fast (linear) extrapolator
+    return fastExtrapolator () -> propagate ( state , z , pid ) ;
+  }
+  // use the pair of extrapolators
+  StatusCode sc1 ;
+  StatusCode sc2 ;
+  if ( state.z () < z )
+  {
+    sc1 = extrapolator     () -> propagate ( state  , m_fastZ , pid ) ;
+    sc2 = fastExtrapolator () -> propagate ( state  , z       , pid ) ;
+  }
+  else
+  {
+    sc2 = fastExtrapolator () -> propagate ( state  , m_fastZ , pid ) ;
+    sc1 = extrapolator     () -> propagate ( state  , z       , pid ) ;
+  }
+
+  StatusCode sc = StatusCode::SUCCESS;
+  std::string errMsg;
+  if ( sc2.isFailure() )
+  {
+    errMsg = "Error from FastExtrapolator";
+    sc = sc2;
+  }
+  if ( sc1.isFailure() )
+  {
+    errMsg = "Error from extrapolator";
+    sc = sc1;
+  }
+  //
+  return  sc.isFailure() ? Warning( errMsg, sc ) : sc;
+}
+
+// ============================================================================
+// print the short infomration about track flags
+// ============================================================================
+
+inline MsgStream&
+CaloFuture::CaloFutureTrackTool::print
+( MsgStream&         stream ,
+  const LHCb::Track* track  ) const
+{ return stream.isActive() ? m_use.print ( stream , track ) : stream ; }
+
+// ============================================================================
+// print the short infomration about track flags
+// ============================================================================
+
+inline MsgStream&
+CaloFuture::CaloFutureTrackTool::print
+( const LHCb::Track* track ,
+  const MSG::Level   level ) const
+{ return print ( msgStream ( level ) , track ) ; }
+
+// ============================================================================
+// get  a pointer to the state for the given track at given location
+// ============================================================================
+
+inline const LHCb::State*
+CaloFuture::CaloFutureTrackTool::state
+( const LHCb::Track& track , const LHCb::State::Location loc   ) const
+{
+  const auto& states = track.states()  ;
+  // loop in reverse order: for calo should be a bit more efficient
+  auto found = std::find_if( states.rbegin(), states.rend(),
+                             [&](const LHCb::State* s)
+                             { return s->checkLocation(loc); } );
+  //
+  return found != states.rend() ? *found : nullptr ;           // RETURN
+}
+
+// ============================================================================
+#endif // CALOFUTUREUTILS_CALOFUTURE_CALOFUTURETRACKTOOL_H
+// ============================================================================
diff --git a/CaloFuture/CaloFuturePIDs/src/FutureClusChi22ID.cpp b/CaloFuture/CaloFuturePIDs/src/FutureClusChi22ID.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1bdea136791bd47bb8a9bd88494a829918d1c3bf
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/FutureClusChi22ID.cpp
@@ -0,0 +1,29 @@
+// Include files
+#include "CaloFutureChi22ID.h"
+#include "ToVector.h"
+
+// ============================================================================
+using TABLEI = LHCb::RelationWeighted2D<LHCb::CaloCluster, LHCb::Track, float>;
+using TABLEO = LHCb::Relation1D<LHCb::Track, float>;
+
+struct FutureClusChi22ID final: public CaloFutureChi22ID<TABLEI,TABLEO> {
+  static_assert(
+      std::is_base_of<LHCb::CaloFuture2Track::IClusTrTable2D, TABLEI>::value,
+      "TABLEI must inherit from IClusTrTable2D");
+
+  FutureClusChi22ID(const std::string& name, ISvcLocator* pSvc)
+      : CaloFutureChi22ID<TABLEI,TABLEO>(name, pSvc) {
+    using LHCb::CaloFutureAlgUtils::CaloFutureIdLocation;
+    Gaudi::Functional::updateHandleLocation(*this,  "Input", CaloFutureIdLocation("ClusterMatch", context()));
+    Gaudi::Functional::updateHandleLocation(*this, "Output", CaloFutureIdLocation("ClusChi2", context()));
+    // @todo it must be in agrement with "Threshold" for PhotonMatchAlg
+    _setProperty("CutOff", "1000");  //
+    // track types:
+    _setProperty("AcceptedType", Gaudi::Utils::toString<int>(
+                                     LHCb::Track::Types::Long, LHCb::Track::Types::Ttrack,
+                                     LHCb::Track::Types::Downstream));
+  };
+};
+// ============================================================================
+
+DECLARE_COMPONENT( FutureClusChi22ID )
diff --git a/CaloFuture/CaloFuturePIDs/src/FutureEcalChi22ID.cpp b/CaloFuture/CaloFuturePIDs/src/FutureEcalChi22ID.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..fa7a3a0f3b944287b42db0b6e458b204824bd03b
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/FutureEcalChi22ID.cpp
@@ -0,0 +1,33 @@
+// Include files
+#include "CaloFutureChi22ID.h"
+#include "ToVector.h"
+
+// ============================================================================
+/** @class FutureEcalChi22ID FutureEcalChi22ID.cpp
+ *  The preconfigured instance of class CaloFutureChi22ID
+ *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
+ */
+// ============================================================================
+using TABLEI = LHCb::RelationWeighted2D<LHCb::CaloHypo, LHCb::Track, float>;
+using TABLEO = LHCb::Relation1D<LHCb::Track, float>;
+
+struct FutureEcalChi22ID final : public CaloFutureChi22ID<TABLEI,TABLEO> {
+  static_assert(
+      std::is_base_of<LHCb::CaloFuture2Track::IHypoTrTable2D, TABLEI>::value,
+      "TABLEI must inherit from IHypoTrTable2D");
+  FutureEcalChi22ID(const std::string& name, ISvcLocator* pSvc)
+    : CaloFutureChi22ID<TABLEI,TABLEO>(name, pSvc) {
+    using LHCb::CaloFutureAlgUtils::CaloFutureIdLocation;
+    Gaudi::Functional::updateHandleLocation(*this,  "Input", CaloFutureIdLocation("ElectronMatch", context()));
+    Gaudi::Functional::updateHandleLocation(*this, "Output", CaloFutureIdLocation("EcalChi2", context()));
+    // @todo it must be in agrement with "Threshold" for ElectonMatchAlg
+    _setProperty("CutOff", "10000");
+    // track types:
+    _setProperty("AcceptedType", Gaudi::Utils::toString<int>(
+                                   LHCb::Track::Types::Long, LHCb::Track::Types::Ttrack,
+                                   LHCb::Track::Types::Downstream));
+  };
+};
+
+// ============================================================================
+DECLARE_COMPONENT( FutureEcalChi22ID )
diff --git a/CaloFuture/CaloFuturePIDs/src/FutureEcalEnergyForTrack.cpp b/CaloFuture/CaloFuturePIDs/src/FutureEcalEnergyForTrack.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6acd0ea723fd18133bad0ee40bcad6caafc0a1e7
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/FutureEcalEnergyForTrack.cpp
@@ -0,0 +1,27 @@
+// Include files
+#include "CaloFutureEnergyForTrack.h"
+
+// ============================================================================
+/** @class FutureEcalEnergyForTrack
+ *  The concrete preconfigured insatnce for CaloFutureEnergyForTrack tool
+ *  along the track line
+ *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
+ */
+// ============================================================================
+
+class FutureEcalEnergyForTrack final : public CaloFutureEnergyForTrack {
+ public:
+  FutureEcalEnergyForTrack(const std::string& type, const std::string& name,
+                     const IInterface* parent)
+      : CaloFutureEnergyForTrack(type, name, parent) {
+    setProperty("DataAddress", LHCb::CaloDigitLocation::Ecal).ignore();
+    setProperty("MorePlanes", 3).ignore();  /// 3 additional planes
+    setProperty("AddNeigbours", 0).ignore();
+    setProperty("Tolerance", 5 * Gaudi::Units::mm).ignore();
+    setProperty("CalorimeterFuture", DeCalorimeterLocation::Ecal).ignore();
+  }
+};
+
+// ============================================================================
+
+DECLARE_COMPONENT( FutureEcalEnergyForTrack )
diff --git a/CaloFuture/CaloFuturePIDs/src/FutureEcalPIDeAlg.cpp b/CaloFuture/CaloFuturePIDs/src/FutureEcalPIDeAlg.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b94b4e896e823c91b87995cddacf3b4dfdbe58d0
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/FutureEcalPIDeAlg.cpp
@@ -0,0 +1,49 @@
+// Include files
+#include "CaloFutureID2DLL.h"
+
+// ============================================================================
+/** @class FutureEcalPIDeAlg  FutureEcalPIDeAlg.cpp
+ *  The preconfigured instance of class CaloFutureID2DLL
+ *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
+ *  @date 2006-06-18
+ */
+// ============================================================================
+
+class FutureEcalPIDeAlg final : public CaloFutureID2DLL {
+ public:
+  FutureEcalPIDeAlg(const std::string& name, ISvcLocator* pSvc)
+      : CaloFutureID2DLL(name, pSvc) {
+    using LHCb::CaloFutureAlgUtils::CaloFutureIdLocation;
+
+    Gaudi::Functional::updateHandleLocation(
+        *this, "Input", CaloFutureIdLocation("EcalChi2", context()));
+    Gaudi::Functional::updateHandleLocation(
+        *this, "Output", CaloFutureIdLocation("EcalPIDe", context()));
+
+    _setProperty("nVlong"  , Gaudi::Utils::toString(2500));
+    _setProperty("nVdown"  , Gaudi::Utils::toString(2500));
+    _setProperty("nVTtrack", Gaudi::Utils::toString(2500));
+    _setProperty("nMlong"  , Gaudi::Utils::toString(100 * Gaudi::Units::GeV));
+    _setProperty("nMdown"  , Gaudi::Utils::toString(100 * Gaudi::Units::GeV));
+    _setProperty("nMTtrack", Gaudi::Utils::toString(100 * Gaudi::Units::GeV));
+
+    _setProperty("HistogramL"   , "DLL_Long");
+    _setProperty("HistogramD"   , "DLL_Downstream");
+    _setProperty("HistogramT"   , "DLL_Ttrack");
+    _setProperty("ConditionName", "Conditions/ParticleID/Calo/EcalPIDe");
+
+    _setProperty("HistogramL_THS", "CaloFuturePIDs/CALO/ECALPIDE/h3");
+    _setProperty("HistogramD_THS", "CaloFuturePIDs/CALO/ECALPIDE/h5");
+    _setProperty("HistogramT_THS", "CaloFuturePIDs/CALO/ECALPIDE/h6");
+
+    _setProperty("AcceptedType", Gaudi::Utils::toString<int>(
+                                     LHCb::Track::Types::Long, LHCb::Track::Types::Ttrack,
+                                     LHCb::Track::Types::Downstream));
+  };
+};
+
+// ============================================================================
+
+DECLARE_COMPONENT( FutureEcalPIDeAlg )
+
+// ============================================================================
diff --git a/CaloFuture/CaloFuturePIDs/src/FutureEcalPIDmuAlg.cpp b/CaloFuture/CaloFuturePIDs/src/FutureEcalPIDmuAlg.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e4dc653f990a2f67e890ea4983e5b3d773428726
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/FutureEcalPIDmuAlg.cpp
@@ -0,0 +1,49 @@
+// Include files
+#include "CaloFutureID2DLL.h"
+
+// ============================================================================
+/** @class FutureEcalPIDmuAlg  FutureEcalPIDmuAlg.cpp
+ *  The preconfigured instance of class CaloFutureID2DLL
+ *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
+ *  @date 2006-06-18
+ */
+// ============================================================================
+
+class FutureEcalPIDmuAlg final : public CaloFutureID2DLL {
+ public:
+  FutureEcalPIDmuAlg(const std::string& name, ISvcLocator* pSvc)
+      : CaloFutureID2DLL(name, pSvc) {
+    using LHCb::CaloFutureAlgUtils::CaloFutureIdLocation;
+
+    Gaudi::Functional::updateHandleLocation(
+        *this, "Input", CaloFutureIdLocation("EcalE", context()));
+    Gaudi::Functional::updateHandleLocation(
+        *this, "Output", CaloFutureIdLocation("EcalPIDmu", context()));
+
+    _setProperty("nVlong"  , Gaudi::Utils::toString(5 * Gaudi::Units::GeV));
+    _setProperty("nVdown"  , Gaudi::Utils::toString(5 * Gaudi::Units::GeV));
+    _setProperty("nVTtrack", Gaudi::Utils::toString(5 * Gaudi::Units::GeV));
+    _setProperty("nMlong"  , Gaudi::Utils::toString(25 * Gaudi::Units::GeV));
+    _setProperty("nMdown"  , Gaudi::Utils::toString(25 * Gaudi::Units::GeV));
+    _setProperty("nMTtrack", Gaudi::Utils::toString(25 * Gaudi::Units::GeV));
+
+    _setProperty("HistogramL"   , "DLL_Long");
+    _setProperty("HistogramD"   , "DLL_Downstream");
+    _setProperty("HistogramT"   , "DLL_Ttrack");
+    _setProperty("ConditionName", "Conditions/ParticleID/Calo/EcalPIDmu");
+
+    _setProperty("HistogramL_THS", "CaloFuturePIDs/CALO/ECALPIDM/h3");
+    _setProperty("HistogramD_THS", "CaloFuturePIDs/CALO/ECALPIDM/h5");
+    _setProperty("HistogramT_THS", "CaloFuturePIDs/CALO/ECALPIDM/h6");
+
+    _setProperty("AcceptedType", Gaudi::Utils::toString<int>(
+                                     LHCb::Track::Types::Long, LHCb::Track::Types::Ttrack,
+                                     LHCb::Track::Types::Downstream));
+  };
+};
+
+// ============================================================================
+
+DECLARE_COMPONENT( FutureEcalPIDmuAlg )
+
+// ============================================================================
diff --git a/CaloFuture/CaloFuturePIDs/src/FutureElectronMatchAlg.cpp b/CaloFuture/CaloFuturePIDs/src/FutureElectronMatchAlg.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2144b1608ea067f42f9c197b071dfb6ad60fd5b1
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/FutureElectronMatchAlg.cpp
@@ -0,0 +1,37 @@
+// Include files
+#include "CaloFutureTrackMatchAlg.h"
+
+// ============================================================================
+/** @class FutureElectronMatchAlg
+ *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
+ *  @date 2006-06-16
+ */
+// ============================================================================
+using TABLE = LHCb::RelationWeighted2D<LHCb::CaloHypo, LHCb::Track, float>;
+using CALOFUTURETYPES = LHCb::CaloHypos;
+
+struct FutureElectronMatchAlg final : CaloFutureTrackMatchAlg<TABLE,CALOFUTURETYPES> {
+  static_assert(std::is_base_of<LHCb::CaloFuture2Track::IHypoTrTable2D, TABLE>::value,
+                "Table must inherit from IHypoTrTable2D");
+
+  FutureElectronMatchAlg(const std::string& name, ISvcLocator* pSvc)
+      : CaloFutureTrackMatchAlg<TABLE,CALOFUTURETYPES>(name, pSvc) {
+    Gaudi::Functional::updateHandleLocation(*this, "Calos",  LHCb::CaloFutureAlgUtils::CaloFutureHypoLocation("Electrons",context()));
+    Gaudi::Functional::updateHandleLocation(*this, "Output", LHCb::CaloFutureAlgUtils::CaloFutureIdLocation("ElectronMatch",context()));
+    Gaudi::Functional::updateHandleLocation(*this, "Filter", LHCb::CaloFutureAlgUtils::CaloFutureIdLocation("InEcal",context()));
+
+    _setProperty("Tool", "CaloFutureElectronMatch/ElectronMatchFuture");
+    _setProperty("Threshold", "10000");
+    // track types:
+    _setProperty("AcceptedType", Gaudi::Utils::toString<int>(
+                                     LHCb::Track::Types::Long, LHCb::Track::Types::Downstream,
+                                     LHCb::Track::Types::Ttrack));
+    _setProperty("TableSize", "1000");
+  }
+
+};
+
+// ============================================================================
+
+DECLARE_COMPONENT( FutureElectronMatchAlg )
+
diff --git a/CaloFuture/CaloFuturePIDs/src/FutureHcalEnergyForTrack.cpp b/CaloFuture/CaloFuturePIDs/src/FutureHcalEnergyForTrack.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1e94a9666e152c86100bce619c8395488c04e0b1
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/FutureHcalEnergyForTrack.cpp
@@ -0,0 +1,27 @@
+// Include files
+#include "CaloFutureEnergyForTrack.h"
+
+// ============================================================================
+/** @class FutureHcalEnergyForTrack
+ *  The concrete preconfigured insatnce for CaloFutureEnergyForTrack tool
+ *  along the track line
+ *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
+ */
+// ============================================================================
+
+class FutureHcalEnergyForTrack final : public CaloFutureEnergyForTrack {
+ public:
+  FutureHcalEnergyForTrack(const std::string& type, const std::string& name,
+                     const IInterface* parent)
+      : CaloFutureEnergyForTrack(type, name, parent) {
+    setProperty("DataAddress", LHCb::CaloDigitLocation::Hcal).ignore();
+    setProperty("CalorimeterFuture", DeCalorimeterLocation::Hcal).ignore();
+    setProperty("MorePlanes", 5).ignore();
+    setProperty("AddNeigbours", 0).ignore();
+    setProperty("Tolerance", 15.0 * Gaudi::Units::mm).ignore();
+  }
+};
+
+// ============================================================================
+
+DECLARE_COMPONENT( FutureHcalEnergyForTrack )
diff --git a/CaloFuture/CaloFuturePIDs/src/FutureHcalPIDeAlg.cpp b/CaloFuture/CaloFuturePIDs/src/FutureHcalPIDeAlg.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4484ef2371674d4df0dbc15cd457c20458649391
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/FutureHcalPIDeAlg.cpp
@@ -0,0 +1,49 @@
+// Include files
+#include "CaloFutureID2DLL.h"
+
+// ============================================================================
+/** @class FutureHcalPIDeAlg  FutureHcalPIDeAlg.cpp
+ *  The preconfigured instance of class CaloFutureID2DLL
+ *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
+ *  @date 2006-06-18
+ */
+// ============================================================================
+
+class FutureHcalPIDeAlg final : public CaloFutureID2DLL {
+ public:
+  FutureHcalPIDeAlg(const std::string& name, ISvcLocator* pSvc)
+      : CaloFutureID2DLL(name, pSvc) {
+    using LHCb::CaloFutureAlgUtils::CaloFutureIdLocation;
+
+    Gaudi::Functional::updateHandleLocation(
+        *this, "Input", CaloFutureIdLocation("HcalE", context()));
+    Gaudi::Functional::updateHandleLocation(
+        *this, "Output", CaloFutureIdLocation("HcalPIDe", context()));
+
+    _setProperty("nVlong"  , Gaudi::Utils::toString(5 * Gaudi::Units::GeV));
+    _setProperty("nVdown"  , Gaudi::Utils::toString(5 * Gaudi::Units::GeV));
+    _setProperty("nVTtrack", Gaudi::Utils::toString(5 * Gaudi::Units::GeV));
+    _setProperty("nMlong"  , Gaudi::Utils::toString(100 * Gaudi::Units::GeV));
+    _setProperty("nMdown"  , Gaudi::Utils::toString(100 * Gaudi::Units::GeV));
+    _setProperty("nMTtrack", Gaudi::Utils::toString(100 * Gaudi::Units::GeV));
+
+    _setProperty("HistogramL"   , "DLL_Long");
+    _setProperty("HistogramD"   , "DLL_Downstream");
+    _setProperty("HistogramT"   , "DLL_Ttrack");
+    _setProperty("ConditionName", "Conditions/ParticleID/Calo/HcalPIDe");
+
+    _setProperty("HistogramL_THS", "CaloFuturePIDs/CALO/HCALPIDE/h3");
+    _setProperty("HistogramD_THS", "CaloFuturePIDs/CALO/HCALPIDE/h5");
+    _setProperty("HistogramT_THS", "CaloFuturePIDs/CALO/HCALPIDE/h6");
+
+    _setProperty("AcceptedType", Gaudi::Utils::toString<int>(
+                                     LHCb::Track::Types::Long, LHCb::Track::Types::Ttrack,
+                                     LHCb::Track::Types::Downstream));
+  };
+};
+
+// ============================================================================
+
+DECLARE_COMPONENT( FutureHcalPIDeAlg )
+
+// ============================================================================
diff --git a/CaloFuture/CaloFuturePIDs/src/FutureHcalPIDmuAlg.cpp b/CaloFuture/CaloFuturePIDs/src/FutureHcalPIDmuAlg.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ec5160837fc348abe289c67e181ebe1a605cb7be
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/FutureHcalPIDmuAlg.cpp
@@ -0,0 +1,49 @@
+// Include files
+#include "CaloFutureID2DLL.h"
+
+// ============================================================================
+/** @class FutureHcalPIDmuAlg  FutureHcalPIDmuAlg.cpp
+ *  The preconfigured instance of class CaloFutureID2DLL
+ *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
+ *  @date 2006-06-18
+ */
+// ============================================================================
+
+class FutureHcalPIDmuAlg final : public CaloFutureID2DLL {
+ public:
+  FutureHcalPIDmuAlg(const std::string& name, ISvcLocator* pSvc)
+      : CaloFutureID2DLL(name, pSvc) {
+    using LHCb::CaloFutureAlgUtils::CaloFutureIdLocation;
+
+    Gaudi::Functional::updateHandleLocation(
+        *this, "Input", CaloFutureIdLocation("HcalE", context()));
+    Gaudi::Functional::updateHandleLocation(
+        *this, "Output", CaloFutureIdLocation("HcalPIDmu", context()));
+
+    _setProperty("nVlong"  , Gaudi::Utils::toString(10 * Gaudi::Units::GeV));
+    _setProperty("nVdown"  , Gaudi::Utils::toString(10 * Gaudi::Units::GeV));
+    _setProperty("nVTtrack", Gaudi::Utils::toString(10 * Gaudi::Units::GeV));
+    _setProperty("nMlong"  , Gaudi::Utils::toString(25 * Gaudi::Units::GeV));
+    _setProperty("nMdown"  , Gaudi::Utils::toString(25 * Gaudi::Units::GeV));
+    _setProperty("nMTtrack", Gaudi::Utils::toString(25 * Gaudi::Units::GeV));
+
+    _setProperty("HistogramL"   , "DLL_Long");
+    _setProperty("HistogramD"   , "DLL_Downstream");
+    _setProperty("HistogramT"   , "DLL_Ttrack");
+    _setProperty("ConditionName", "Conditions/ParticleID/Calo/HcalPIDmu");
+
+    _setProperty("HistogramL_THS", "CaloFuturePIDs/CALO/HCALPIDM/h3");
+    _setProperty("HistogramD_THS", "CaloFuturePIDs/CALO/HCALPIDM/h5");
+    _setProperty("HistogramT_THS", "CaloFuturePIDs/CALO/HCALPIDM/h6");
+
+    _setProperty("AcceptedType", Gaudi::Utils::toString<int>(
+                                     LHCb::Track::Types::Long, LHCb::Track::Types::Ttrack,
+                                     LHCb::Track::Types::Downstream));
+  };
+};
+
+// ============================================================================
+
+DECLARE_COMPONENT( FutureHcalPIDmuAlg )
+
+// ============================================================================
diff --git a/CaloFuture/CaloFuturePIDs/src/FuturePhotonMatchAlg.cpp b/CaloFuture/CaloFuturePIDs/src/FuturePhotonMatchAlg.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..615d8faa9eea5e12453f3063a1bec42101337632
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/FuturePhotonMatchAlg.cpp
@@ -0,0 +1,37 @@
+// Include files
+#include "CaloFutureTrackMatchAlg.h"
+
+
+// ============================================================================
+/** @class FuturePhotonMatchAlg
+ *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
+ *  @date 2006-06-16
+ */
+// ============================================================================
+using TABLE = LHCb::RelationWeighted2D<LHCb::CaloCluster, LHCb::Track, float>;
+using CALOFUTURETYPES = LHCb::CaloClusters;
+
+struct FuturePhotonMatchAlg final: CaloFutureTrackMatchAlg<TABLE,CALOFUTURETYPES> {
+  static_assert(std::is_base_of<LHCb::CaloFuture2Track::IClusTrTable2D, TABLE>::value,
+                "TABLE must inherit from IClusTrTable2D");
+  FuturePhotonMatchAlg(const std::string& name, ISvcLocator* pSvc)
+      : CaloFutureTrackMatchAlg<TABLE,CALOFUTURETYPES>(name, pSvc) {
+    Gaudi::Functional::updateHandleLocation(*this, "Calos",  LHCb::CaloFutureAlgUtils::CaloFutureClusterLocation("Ecal",context()));
+    Gaudi::Functional::updateHandleLocation(*this, "Output", LHCb::CaloFutureAlgUtils::CaloFutureIdLocation("ClusterMatch",context()));
+    Gaudi::Functional::updateHandleLocation(*this, "Filter", LHCb::CaloFutureAlgUtils::CaloFutureIdLocation("InEcal",context()));
+
+    _setProperty("Tool", "CaloFuturePhotonMatch/FuturePhotonMatch");
+    _setProperty("Threshold", "1000");
+    // track types:
+    _setProperty("AcceptedType", Gaudi::Utils::toString<int>(
+                                     LHCb::Track::Types::Long, LHCb::Track::Types::Downstream,
+                                     LHCb::Track::Types::Ttrack));
+    _setProperty("TableSize", "5000");
+  }
+
+};
+
+// ============================================================================
+
+DECLARE_COMPONENT( FuturePhotonMatchAlg )
+
diff --git a/CaloFuture/CaloFuturePIDs/src/FuturePrsEnergyForTrack.cpp b/CaloFuture/CaloFuturePIDs/src/FuturePrsEnergyForTrack.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..146865e24ad7138e04ebb4d7bd3f904a47a38e73
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/FuturePrsEnergyForTrack.cpp
@@ -0,0 +1,25 @@
+// Include files
+#include "CaloFutureEnergyForTrack.h"
+
+// ============================================================================
+/** @class FuturePrsEnergyForTrack
+ *  The concrete preconfigured insatnce for CaloFutureEnergyForTrack tool
+ *  along the track line
+ *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
+ */
+// ============================================================================
+
+class FuturePrsEnergyForTrack final : public CaloFutureEnergyForTrack {
+ public:
+  FuturePrsEnergyForTrack(const std::string& type, const std::string& name,
+                    const IInterface* parent)
+      : CaloFutureEnergyForTrack(type, name, parent) {
+    _setProperty("DataAddress", LHCb::CaloDigitLocation::Prs);
+    _setProperty("Tolerance", "2");  /// 2 * Gaudi::Units::mm
+    _setProperty("CalorimeterFuture", DeCalorimeterLocation::Prs);
+  };
+};
+
+// ============================================================================
+
+DECLARE_COMPONENT( FuturePrsEnergyForTrack )
diff --git a/CaloFuture/CaloFuturePIDs/src/FuturePrsPIDeAlg.cpp b/CaloFuture/CaloFuturePIDs/src/FuturePrsPIDeAlg.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a9d5b2d1ed93e53df2409eec3acaa3204b74243a
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/FuturePrsPIDeAlg.cpp
@@ -0,0 +1,49 @@
+// Include files
+#include "CaloFutureID2DLL.h"
+
+// ============================================================================
+/** @class FuturePrsPIDeAlg  FuturePrsPIDeAlg.cpp
+ *  The preconfigured instance of class CaloFutureID2DLL
+ *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
+ *  @date 2006-06-18
+ */
+// ============================================================================
+
+class FuturePrsPIDeAlg final : public CaloFutureID2DLL {
+ public:
+  FuturePrsPIDeAlg(const std::string& name, ISvcLocator* pSvc)
+      : CaloFutureID2DLL(name, pSvc) {
+    using LHCb::CaloFutureAlgUtils::CaloFutureIdLocation;
+
+    Gaudi::Functional::updateHandleLocation(
+        *this, "Input", CaloFutureIdLocation("PrsE", context()));
+    Gaudi::Functional::updateHandleLocation(
+        *this, "Output", CaloFutureIdLocation("PrsPIDe", context()));
+
+    _setProperty("nVlong"  , Gaudi::Utils::toString(100 * Gaudi::Units::MeV));
+    _setProperty("nVdown"  , Gaudi::Utils::toString(100 * Gaudi::Units::MeV));
+    _setProperty("nVTtrack", Gaudi::Utils::toString(100 * Gaudi::Units::MeV));
+    _setProperty("nMlong"  , Gaudi::Utils::toString(100 * Gaudi::Units::GeV));
+    _setProperty("nMdown"  , Gaudi::Utils::toString(100 * Gaudi::Units::GeV));
+    _setProperty("nMTtrack", Gaudi::Utils::toString(100 * Gaudi::Units::GeV));
+
+    _setProperty("HistogramL"   , "DLL_Long");
+    _setProperty("HistogramD"   , "DLL_Downstream");
+    _setProperty("HistogramT"   , "DLL_Ttrack");
+    _setProperty("ConditionName", "Conditions/ParticleID/Calo/PrsPIDe");
+
+    _setProperty("HistogramL_THS", "CaloFuturePIDs/CALO/PRSPIDE/h3");
+    _setProperty("HistogramD_THS", "CaloFuturePIDs/CALO/PRSPIDE/h5");
+    _setProperty("HistogramT_THS", "CaloFuturePIDs/CALO/PRSPIDE/h6");
+
+    _setProperty("AcceptedType", Gaudi::Utils::toString<int>(
+                                     LHCb::Track::Types::Long, LHCb::Track::Types::Ttrack,
+                                     LHCb::Track::Types::Downstream));
+  };
+};
+
+// ============================================================================
+
+DECLARE_COMPONENT( FuturePrsPIDeAlg )
+
+// ============================================================================
diff --git a/CaloFuture/CaloFuturePIDs/src/FutureSpdEnergyForTrack.cpp b/CaloFuture/CaloFuturePIDs/src/FutureSpdEnergyForTrack.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d60beaf3e712278f1c46d5f071d399a640d4b488
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/FutureSpdEnergyForTrack.cpp
@@ -0,0 +1,25 @@
+// Include files
+#include "CaloFutureEnergyForTrack.h"
+
+// ============================================================================
+/** @class FutureSpdEnergyForTrack
+ *  The concrete preconfigured insatnce for CaloFutureEnergyForTrack tool
+ *  along the track line
+ *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
+ */
+// ============================================================================
+
+class FutureSpdEnergyForTrack final : public CaloFutureEnergyForTrack {
+ public:
+  FutureSpdEnergyForTrack(const std::string& type, const std::string& name,
+                    const IInterface* parent)
+      : CaloFutureEnergyForTrack(type, name, parent) {
+    _setProperty("DataAddress", LHCb::CaloDigitLocation::Spd);
+    _setProperty("Tolerance", "2");  /// 2 * Gaudi::Units::mm
+    _setProperty("CalorimeterFuture", DeCalorimeterLocation::Spd);
+  };
+};
+
+// ============================================================================
+
+DECLARE_COMPONENT( FutureSpdEnergyForTrack )
diff --git a/CaloFuture/CaloFuturePIDs/src/FutureTrack2EcalEAlg.cpp b/CaloFuture/CaloFuturePIDs/src/FutureTrack2EcalEAlg.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..dba435804ddaf6f7fb1c3dbcc62ed22594fff187
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/FutureTrack2EcalEAlg.cpp
@@ -0,0 +1,24 @@
+// Include files
+#include "CaloFutureTrack2IDAlg.h"
+
+// ============================================================================
+/** @class FutureTrack2EcalEAlg FutureTrack2EcalEAlg.cpp
+ *  preconfigured instance of class  CaloFutureTrack2IDAlg
+ *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
+ *  @date   2006-06-15
+ */
+struct FutureTrack2EcalEAlg final : public CaloFutureTrack2IDAlg {
+  FutureTrack2EcalEAlg(const std::string& name, ISvcLocator* pSvc)
+      : CaloFutureTrack2IDAlg(name, pSvc) {
+    using LHCb::CaloFutureAlgUtils::CaloFutureIdLocation;
+    _setProperty("Output", CaloFutureIdLocation("EcalE", context()));
+    _setProperty("Filter", CaloFutureIdLocation("InEcal", context()));
+    _setProperty("Tool", "FutureEcalEnergyForTrack/EcalEFuture");
+  }
+};
+
+// ============================================================================
+
+DECLARE_COMPONENT( FutureTrack2EcalEAlg )
+
+// ============================================================================
diff --git a/CaloFuture/CaloFuturePIDs/src/FutureTrack2HcalEAlg.cpp b/CaloFuture/CaloFuturePIDs/src/FutureTrack2HcalEAlg.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f55b2a7b66b0dc0742a9017a348b8adf5ad7dc80
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/FutureTrack2HcalEAlg.cpp
@@ -0,0 +1,24 @@
+// Include files
+#include "CaloFutureTrack2IDAlg.h"
+
+// ============================================================================
+/** @class FutureTrack2HcalEAlg FutureTrack2HcalEAlg.cpp
+ *  preconfigured instance of class  CaloFutureTrack2IDAlg
+ *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
+ *  @date   2006-06-15
+ */
+struct FutureTrack2HcalEAlg final : public CaloFutureTrack2IDAlg {
+  FutureTrack2HcalEAlg(const std::string& name, ISvcLocator* pSvc)
+      : CaloFutureTrack2IDAlg(name, pSvc) {
+    using LHCb::CaloFutureAlgUtils::CaloFutureIdLocation;
+    _setProperty("Output", CaloFutureIdLocation("HcalE", context()));
+    _setProperty("Filter", CaloFutureIdLocation("InHcal", context()));
+    _setProperty("Tool", "FutureHcalEnergyForTrack/HcalEFuture");
+  }
+};
+
+// ============================================================================
+
+DECLARE_COMPONENT( FutureTrack2HcalEAlg )
+
+// ============================================================================
diff --git a/CaloFuture/CaloFuturePIDs/src/FutureTrack2PrsEAlg.cpp b/CaloFuture/CaloFuturePIDs/src/FutureTrack2PrsEAlg.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0d42c1e6d4c8c8a64ee1b98eebec5301655c1c1e
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/FutureTrack2PrsEAlg.cpp
@@ -0,0 +1,24 @@
+// Include files
+#include "CaloFutureTrack2IDAlg.h"
+
+// ============================================================================
+/** @class FutureTrack2PrsEAlg FutureTrack2PrsEAlg.cpp
+ *  preconfigured instance of class  CaloFutureTrack2IDAlg
+ *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
+ *  @date   2006-06-15
+ */
+struct FutureTrack2PrsEAlg final : public CaloFutureTrack2IDAlg {
+  FutureTrack2PrsEAlg(const std::string& name, ISvcLocator* pSvc)
+      : CaloFutureTrack2IDAlg(name, pSvc) {
+    using LHCb::CaloFutureAlgUtils::CaloFutureIdLocation;
+    _setProperty("Output", CaloFutureIdLocation("PrsE", context()));
+    _setProperty("Filter", CaloFutureIdLocation("InPrs", context()));
+    _setProperty("Tool", "FuturePrsEnergyForTrack/PrsE");
+  }
+};
+
+// ============================================================================
+
+DECLARE_COMPONENT( FutureTrack2PrsEAlg )
+
+// ============================================================================
diff --git a/CaloFuture/CaloFuturePIDs/src/FutureTrack2SpdEAlg.cpp b/CaloFuture/CaloFuturePIDs/src/FutureTrack2SpdEAlg.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..58f646402d45c3058604ececa734342c52fd5fa0
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/FutureTrack2SpdEAlg.cpp
@@ -0,0 +1,24 @@
+// Include files
+#include "CaloFutureTrack2IDAlg.h"
+
+// ============================================================================
+/** @class FutureTrack2SpdEAlg FutureTrack2SpdEAlg.cpp
+ *  preconfigured instance of class  CaloFutureTrack2IDAlg
+ *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
+ *  @date   2006-06-15
+ */
+struct FutureTrack2SpdEAlg final : public CaloFutureTrack2IDAlg {
+  FutureTrack2SpdEAlg(const std::string& name, ISvcLocator* pSvc)
+      : CaloFutureTrack2IDAlg(name, pSvc) {
+    using LHCb::CaloFutureAlgUtils::CaloFutureIdLocation;
+    _setProperty("Output", CaloFutureIdLocation("SpdE", context()));
+    _setProperty("Filter", CaloFutureIdLocation("InSpd", context()));
+    _setProperty("Tool", "FutureSpdEnergyForTrack/SpdE");
+  }
+};
+
+// ============================================================================
+
+DECLARE_COMPONENT( FutureTrack2SpdEAlg )
+
+// ============================================================================
diff --git a/CaloFuture/CaloFuturePIDs/src/InBremFutureAcceptance.cpp b/CaloFuture/CaloFuturePIDs/src/InBremFutureAcceptance.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..db0d74f04fa363a77c2d26bd1d04941a4fada338
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/InBremFutureAcceptance.cpp
@@ -0,0 +1,79 @@
+// Include files
+#include "InCaloFutureAcceptance.h"
+#include "LHCbMath/GeomFun.h"
+#include "LHCbMath/Line.h"
+#include "Linear.h"
+
+// ============================================================================
+/** @class InBremFutureAcceptance
+ *  The preconfigured instance of InCaloFutureAcceptance Tool
+ *  @author Victor EGORYCHEV Victor.Egorychev@cern.ch
+ *  @author Vanya  BELYAEV    ibelyaev@phsycis.syr.edu
+ *  @date   2006-05-28
+ */
+// ============================================================================
+
+struct InBremFutureAcceptance final : InCaloFutureAcceptance {
+  /// standard constructor
+  InBremFutureAcceptance(const std::string& type, const std::string& name,
+                   const IInterface* parent)
+      : InCaloFutureAcceptance(type, name, parent) {
+    _setProperty("CalorimeterFuture", DeCalorimeterLocation::Ecal);
+  }
+
+  /// C++11 non-copyable idiom
+  InBremFutureAcceptance() = delete;
+  InBremFutureAcceptance(const InBremFutureAcceptance&) = delete;
+  InBremFutureAcceptance& operator=(const InBremFutureAcceptance&) = delete;
+
+  // ==========================================================================
+  /** check the track is in acceptance of given calorimeter
+   *  @see IInAcceptance
+   *  @param  track track to be checked
+   *  @return true if the track is in acceptance
+   */
+  bool inAcceptance(const LHCb::Track* track) const override;
+};
+
+// ============================================================================
+
+DECLARE_COMPONENT( InBremFutureAcceptance )
+
+// ============================================================================
+// check the expected bremstrahlung photon is in acceptance of Ecal
+// ============================================================================
+
+bool InBremFutureAcceptance::inAcceptance(const LHCb::Track* track) const {
+  // check the goodness of the tarck
+  if (!use(track)) {
+    return false;
+  }  // RETURN
+  //
+  // find the appropriate state
+  const LHCb::State* state = nullptr;
+  for (const auto& loc : {LHCb::State::Location::AtTT, LHCb::State::Location::EndRich1,
+                          LHCb::State::Location::BegRich1, LHCb::State::Location::EndVelo}) {
+    state = CaloFutureTrackTool::state(*track, loc);
+    if (state) break;
+  }
+  if (!state) {
+    // get the closest state to some artificial value
+    state = &(track->closestState(2.0 * Gaudi::Units::meter));
+    // allowed z ?
+    if (state->z() > 4.0 * Gaudi::Units::meter) {
+      Error("No appropriate states are found, see 'debug'").ignore();
+      if (msgLevel(MSG::DEBUG)) print(debug(), track);
+      return false;
+    }
+  }
+  // get the line form the state
+  const Line l = line(*state);
+  // get the point of intersection of the line with the plane
+  Gaudi::XYZPoint point;
+  double mu = 0;
+  Gaudi::Math::intersection(l, plane(), point, mu);
+  //
+  return ok(point);
+}
+
+// ============================================================================
diff --git a/CaloFuture/CaloFuturePIDs/src/InBremFutureAcceptanceAlg.cpp b/CaloFuture/CaloFuturePIDs/src/InBremFutureAcceptanceAlg.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..de10fbe1837d201042a54f2f2f81662801b817c4
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/InBremFutureAcceptanceAlg.cpp
@@ -0,0 +1,33 @@
+// Include files
+#include "InCaloFutureAcceptanceAlg.h"
+
+// ============================================================================
+/** @class FutureInBremFutureAcceptanceAlg FutureInBremFutureAcceptanceAlg.cpp
+ *  the preconfigured instance of InCaloFutureAcceptanceAlg
+ *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
+ *  @date   2006-06-17
+ */
+// ============================================================================
+
+struct FutureInBremFutureAcceptanceAlg final : InCaloFutureAcceptanceAlg {
+  /// Standard constructor
+  FutureInBremFutureAcceptanceAlg(const std::string& name, ISvcLocator* pSvc)
+      : InCaloFutureAcceptanceAlg(name, pSvc) {
+    using LHCb::CaloFutureAlgUtils::CaloFutureIdLocation;
+
+    Gaudi::Functional::updateHandleLocation(
+        *this, "Output", CaloFutureIdLocation("InBrem", context()));
+
+    _setProperty("Tool", "InBremFutureAcceptance/InBremFuture");
+    // track types:
+    _setProperty("AcceptedType", Gaudi::Utils::toString<int>(
+                                     LHCb::Track::Types::Velo, LHCb::Track::Types::Long,
+                                     LHCb::Track::Types::Upstream));
+  }
+};
+
+// ============================================================================
+
+DECLARE_COMPONENT( FutureInBremFutureAcceptanceAlg )
+
+// ============================================================================
diff --git a/CaloFuture/CaloFuturePIDs/src/InCaloFutureAcceptance.cpp b/CaloFuture/CaloFuturePIDs/src/InCaloFutureAcceptance.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9f175dec429375db56a2962ac50348611af58924
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/InCaloFutureAcceptance.cpp
@@ -0,0 +1,110 @@
+// Include files
+#include "Event/Track.h"
+#include "GaudiKernel/Point3DTypes.h"
+#include "GaudiKernel/Vector3DTypes.h"
+#include "GaudiKernel/Plane3DTypes.h"
+#include "Kernel/CaloCellCode.h"
+#include "CaloDet/DeCalorimeter.h"
+#include "CaloFutureTrackAlg.h"
+#include "InCaloFutureAcceptance.h"
+
+// ============================================================================
+/** @file
+ *  Implementation file for class InCaloFutureAcceptance
+ *  @see InAccpetance
+ *
+ *  @author Victor EGORYCHEV Victor.Egorychev@cern.ch
+ *  @author Vanya  BELYAEV    ibelyaev@phsycis.syr.edu
+ *  @date   2006-05-28
+ */
+// ============================================================================
+
+DECLARE_COMPONENT( InCaloFutureAcceptance )
+
+// ============================================================================
+//  Standard constructor, initializes variables
+// ============================================================================
+
+InCaloFutureAcceptance::InCaloFutureAcceptance(const std::string& type,
+                                   const std::string& name,
+                                   const IInterface* parent)
+    : CaloFuture::CaloFutureTrackTool(type, name, parent) {
+  declareInterface<IInAcceptance>(this);
+}
+
+// ============================================================================
+// initialization @see IAlgTool
+// ============================================================================
+
+StatusCode InCaloFutureAcceptance::initialize() {
+  StatusCode sc = CaloFuture::CaloFutureTrackTool::initialize();
+  if (sc.isFailure()) {
+    return sc;
+  }
+  // check the detector
+  if (calo() == nullptr) {
+    return Error("Invalid Detector");
+  }
+  // select the plane
+  const int check_calorimeter_id =
+      CaloCellCode::CaloNumFromName(detectorName());
+  switch (check_calorimeter_id) {
+    case 0:
+      // SPD
+      m_loc = LHCb::State::Location::Spd;
+      m_plane = calo()->plane(CaloPlane::Middle);
+      break;  // BREAK
+    case 1:
+      // PRS
+      m_loc = LHCb::State::Location::Prs;
+      m_plane = calo()->plane(CaloPlane::Middle);
+      break;  // BREAK
+    case 2:
+      // ECAL
+      m_loc = LHCb::State::Location::ECalShowerMax;
+      m_plane = calo()->plane(CaloPlane::ShowerMax);
+      break;  // BREAK
+    case 3:
+      // HCAL
+      m_loc = LHCb::State::Location::MidHCal;
+      m_plane = calo()->plane(CaloPlane::Middle);
+      break;  // BREAK
+    default:
+      return Error("Invalid calorimeter TYPE! '" + detectorName() + "'");
+  }
+  //
+  if (propsPrint() || msgLevel(MSG::DEBUG)) {
+    info() << "State to be used for aceptance check is '" << m_loc << "'"
+           << endmsg;
+  }
+  return StatusCode::SUCCESS;
+}
+
+// ============================================================================
+// check the track is in acceptance of the given calorimeter
+// ============================================================================
+
+bool InCaloFutureAcceptance::inAcceptance(const LHCb::Track* track) const {
+  // check the goodness of the tarck
+  if (!use(track)) {
+    return false;
+  }  // RETURN
+
+  // find the appropriate state
+  auto state = CaloFuture::CaloFutureTrackTool::state(*track, m_loc);
+  if (state == nullptr) {
+    // if there is no proper state - add it into the track!
+    StatusCode sc = propagate(*track, plane(), m_state);
+    if (sc.isFailure()) {
+      Error("failure from propagate()", sc).ignore();
+      return false;  // RETURN
+    }
+    m_state.setLocation(m_loc);
+    const_cast<LHCb::Track*>(track)->addToStates(m_state);
+    state = &m_state;
+  }
+  // check the point
+  return ok(state->position());
+}
+
+// ============================================================================
diff --git a/CaloFuture/CaloFuturePIDs/src/InCaloFutureAcceptance.h b/CaloFuture/CaloFuturePIDs/src/InCaloFutureAcceptance.h
new file mode 100644
index 0000000000000000000000000000000000000000..d857709866bf8edb1af14b0668fee44af6f784db
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/InCaloFutureAcceptance.h
@@ -0,0 +1,86 @@
+#ifndef CALOFUTUREPIDS_INCALOFUTUREACCEPTANCE_H
+#define CALOFUTUREPIDS_INCALOFUTUREACCEPTANCE_H 1
+
+// Include files
+#include "GaudiAlg/GaudiTool.h"
+#include "CaloFutureTrackTool.h"
+#include "TrackInterfaces/IInAcceptance.h"
+#include "TrackInterfaces/ITrackExtrapolator.h"
+
+// ============================================================================
+
+/** @class InCaloFutureAcceptance InCaloFutureAcceptance.h
+ *
+ *  The general tool to determine if the reconstructed charged track
+ *  "is in CalorimeterFuture acceptance"
+ *
+ *  @author Victor EGORYCHEV Victor.Egorychev@cern.ch
+ *  @author Vanya  BELYAEV    ibelyaev@phsycis.syr.edu
+ *  @date   2006-05-28
+ */
+class InCaloFutureAcceptance : public virtual IInAcceptance,
+                         public CaloFuture::CaloFutureTrackTool {
+ public:
+  /// initialization @see IAlgTool
+  StatusCode initialize() override;
+
+  /** check the track is in acceptance of given calorimeter
+   *  @see IInAcceptance
+   *  @param  track track to be checked
+   *  @return true if the track is in acceptance
+   */
+  bool inAcceptance(const LHCb::Track* track) const override;
+
+ protected:
+  /// check if the point "is in acceptance"
+  inline bool ok(const Gaudi::XYZPoint& point) const;
+  /// get the plane
+  const Gaudi::Plane3D& plane() const { return m_plane; }
+
+ public:
+  InCaloFutureAcceptance(const std::string& type, const std::string& name,
+                   const IInterface* parent);
+
+private:
+  /// use fiducial volume or real volume ?
+  Gaudi::Property<bool> m_fiducial {this, "UseFiducial", true};
+  LHCb::State::Location m_loc   ;
+  ///
+  Gaudi::Plane3D m_plane;
+  /// Local storage
+  mutable LHCb::State m_state;
+};
+
+// ============================================================================
+/// check if the point "is in acceptance"
+// ============================================================================
+
+inline bool InCaloFutureAcceptance::ok(const Gaudi::XYZPoint& point) const {
+  const CellParam* cell = calo()->Cell_(point);
+  if (cell==nullptr || !cell->valid()) {
+    return false;
+  }
+  // check for fiducial volume ?
+  if (!m_fiducial) {
+    return true;
+  }
+  // check for neighbors
+  const CaloNeighbors& neighbors = cell->neighbors();
+  // regular cell: >= 8 valid neighbours
+  if (8 <= neighbors.size()) {
+    return true;
+  }
+  // incomplete neibors: border of 2 zones ?
+  const unsigned int area = cell->cellID().area();
+  for (auto inei = neighbors.begin() + 1; neighbors.end() != inei; ++inei) {
+    if (area != inei->area()) {
+      return true;
+    }
+  }
+  // finally
+  return false;
+}
+
+// ===========================================================================
+#endif  // CALOFUTUREPIDS_INCALOFUTUREACCEPTANCE_H
+// ============================================================================
diff --git a/CaloFuture/CaloFuturePIDs/src/InCaloFutureAcceptanceAlg.cpp b/CaloFuture/CaloFuturePIDs/src/InCaloFutureAcceptanceAlg.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8bed031722f7001026778e1ce46847c52094b5d1
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/InCaloFutureAcceptanceAlg.cpp
@@ -0,0 +1,65 @@
+// include files
+#include <type_traits>
+#include "Relations/Relation1D.h"
+#include "InCaloFutureAcceptanceAlg.h"
+
+// ============================================================================
+/** @file
+ *  Implementation file for class InCaloFutureAcceptanceAlg
+ *  @Date 2006-06-17
+ *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
+ */
+// ============================================================================
+
+DECLARE_COMPONENT( InCaloFutureAcceptanceAlg )
+
+// ============================================================================
+/// Standard protected constructor
+// ============================================================================
+
+InCaloFutureAcceptanceAlg::InCaloFutureAcceptanceAlg(const std::string& name,
+                                         ISvcLocator* pSvc)
+    : Transformer(name, pSvc, KeyValue{"Inputs", ""}, KeyValue{"Output", ""}) {
+  // context-dependent default track container
+  // (Context only available after baseclass is contructed)
+  Gaudi::Functional::updateHandleLocation(*this, "Inputs", LHCb::CaloFutureAlgUtils::TrackLocations(context()).front());
+}
+
+// ============================================================================
+// algorithm execution
+// ============================================================================
+
+Table InCaloFutureAcceptanceAlg::operator()(const LHCb::Tracks& tracks) const {
+  // a trivial check
+  Assert(m_tool, "InAcceptance-tool  is invalid!");
+
+  if (0 == tracks.size()) {
+    if (msgLevel(MSG::DEBUG))
+      debug() << "No tracks retrieved from container" << endmsg;
+  }
+
+  Table table(100);
+
+  size_t nAccept = 0;
+  // loop over all tracks in the container
+  for (const auto& track : tracks) {
+    if (!use(track)) {
+      continue;
+    }  // CONTINUE
+    const bool result = m_tool->inAcceptance(track);
+    // fill the relation table
+    table.i_push(track, result);  // ATTENTION: i-push is used
+    if (result) {
+      ++nAccept;
+    }
+  }
+  // MANDATORY: i_sort after i_push
+  table.i_sort();
+
+  // a bit of statistics
+  m_nTracks += tracks.size();
+  m_nAccept += nAccept;
+  m_nLinks  += table.i_relations().size();
+
+  return table;
+}
diff --git a/CaloFuture/CaloFuturePIDs/src/InCaloFutureAcceptanceAlg.h b/CaloFuture/CaloFuturePIDs/src/InCaloFutureAcceptanceAlg.h
new file mode 100644
index 0000000000000000000000000000000000000000..f3833956d5ba195d62fe87094cb7e7397891ab68
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/InCaloFutureAcceptanceAlg.h
@@ -0,0 +1,52 @@
+#ifndef CALOFUTUREPIDS_INCALOFUTUREACCEPTANCEALG_H 
+#define CALOFUTUREPIDS_INCALOFUTUREACCEPTANCEALG_H 1
+
+// Include files
+#include "CaloFutureTrackAlg.h"
+#include "CaloFutureUtils/CaloFuture2Track.h"
+#include "CaloFutureUtils/CaloFutureAlgUtils.h"
+#include "Event/Track.h"
+#include "GaudiAlg/Transformer.h"
+#include "GaudiKernel/Counters.h"
+#include "TrackInterfaces/IInAcceptance.h"
+#include "Relations/Relation1D.h"
+#include "ToVector.h"
+
+// ============================================================================
+/** @class InCaloFutureAcceptanceAlg InCaloFutureAcceptanceAlg.h
+ *
+ *  the trivial algorithm to fill "InCaloFutureAcceptance" table 
+ *
+ *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
+ *  @date   2006-06-17
+ */
+// ============================================================================
+
+using Table =  LHCb::Relation1D<LHCb::Track,bool>;
+
+class InCaloFutureAcceptanceAlg
+    : public Gaudi::Functional::Transformer<
+          Table(const LHCb::Tracks&),
+          Gaudi::Functional::Traits::BaseClass_t<CaloFutureTrackAlg> >
+{
+  // check the proper convertability
+  static_assert(std::is_base_of<LHCb::CaloFuture2Track::ITrAccTable, Table>::value,
+                "Table must inherit from ITrAccTable");
+
+  public:
+    /// Standard constructor
+    InCaloFutureAcceptanceAlg(const std::string& name, ISvcLocator* pSvc);
+    /// algorithm execution
+    Table operator()(const LHCb::Tracks&) const override;
+
+    ToolHandle<IInAcceptance> m_tool {this, "Tool", "<NOT DEFINED>"};
+
+    // counter
+    mutable Gaudi::Accumulators::StatCounter<> m_nTracks{this, "#total tracks"};
+    mutable Gaudi::Accumulators::StatCounter<> m_nAccept{this, "#tracks in acceptance"};
+    mutable Gaudi::Accumulators::StatCounter<> m_nLinks {this, "#links in table"};
+};
+
+// ============================================================================
+#endif  // CALOFUTUREPIDS_INCALOFUTUREACCEPTANCEALG_H
+// ============================================================================
diff --git a/CaloFuture/CaloFuturePIDs/src/InEcalFutureAcceptance.cpp b/CaloFuture/CaloFuturePIDs/src/InEcalFutureAcceptance.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..47e9687c88154dd1b3f238749f25636cc9d35399
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/InEcalFutureAcceptance.cpp
@@ -0,0 +1,33 @@
+// Include files
+#include "InCaloFutureAcceptance.h"
+
+// ============================================================================
+/** @class InEcalFutureAcceptance    
+ *  The precofigured instance of InCaloFutureAcceptance Tool
+ *  @author Victor EGORYCHEV Victor.Egorychev@cern.ch
+ *  @author Vanya  BELYAEV    ibelyaev@phsycis.syr.edu
+ *  @date   2006-05-28
+ */
+// ============================================================================
+
+struct InEcalFutureAcceptance     final : InCaloFutureAcceptance {
+  /// standard constructor
+  InEcalFutureAcceptance(const std::string& type, const std::string& name,
+                   const IInterface* parent)
+      : InCaloFutureAcceptance(type, name, parent) {
+    _setProperty("CalorimeterFuture", DeCalorimeterLocation::Ecal);
+    _setProperty("UseFiducial", "true");
+    _setProperty("Tolerance", "5");  /// 5 * Gaudi::Units::mm
+  };
+
+  /// C++11 non-copyable idiom
+  InEcalFutureAcceptance() = delete;
+  InEcalFutureAcceptance(const InEcalFutureAcceptance&) = delete;
+  InEcalFutureAcceptance& operator=(const InEcalFutureAcceptance&) = delete;
+};
+
+// ============================================================================
+
+DECLARE_COMPONENT( InEcalFutureAcceptance )
+
+// ============================================================================
diff --git a/CaloFuture/CaloFuturePIDs/src/InEcalFutureAcceptanceAlg.cpp b/CaloFuture/CaloFuturePIDs/src/InEcalFutureAcceptanceAlg.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e9de2804a30853a52800b67ee60007bc8d8c0861
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/InEcalFutureAcceptanceAlg.cpp
@@ -0,0 +1,32 @@
+// Include files
+#include "InCaloFutureAcceptanceAlg.h"
+
+// ============================================================================
+/** @class InEcalFutureAcceptance    Alg InEcalFutureAcceptance    Alg.cpp
+ *  the preconfigured instance of InCaloFutureAcceptanceAlg
+ *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
+ *  @date   2006-06-17
+ */
+// ============================================================================
+
+struct InEcalFutureAcceptanceAlg final : InCaloFutureAcceptanceAlg {
+  /// Standard constructor
+  InEcalFutureAcceptanceAlg(const std::string& name, ISvcLocator* pSvc)
+      : InCaloFutureAcceptanceAlg(name, pSvc) {
+    using LHCb::CaloFutureAlgUtils::CaloFutureIdLocation;
+    Gaudi::Functional::updateHandleLocation(
+        *this, "Output", CaloFutureIdLocation("InEcal", context()));
+
+    _setProperty("Tool", "InEcalFutureAcceptance/InEcalFuture");
+    // track types:
+    _setProperty("AcceptedType", Gaudi::Utils::toString<int>(
+                                     LHCb::Track::Types::Long, LHCb::Track::Types::Downstream,
+                                     LHCb::Track::Types::Ttrack));
+  }
+};
+
+// ============================================================================
+
+DECLARE_COMPONENT( InEcalFutureAcceptanceAlg )
+
+// ============================================================================
diff --git a/CaloFuture/CaloFuturePIDs/src/InHcalFutureAcceptance.cpp b/CaloFuture/CaloFuturePIDs/src/InHcalFutureAcceptance.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d6e4c9b7f90922785c7e0fd53575493a25f61875
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/InHcalFutureAcceptance.cpp
@@ -0,0 +1,33 @@
+// Include files
+#include "InCaloFutureAcceptance.h"
+
+// ============================================================================
+/** @class InHcalFutureAcceptance    
+ *  The precofigured instance of InCaloFutureAcceptance Tool
+ *  @author Victor EGORYCHEV Victor.Egorychev@cern.ch
+ *  @author Vanya  BELYAEV    ibelyaev@phsycis.syr.edu
+ *  @date   2006-05-28
+ */
+// ============================================================================
+
+struct InHcalFutureAcceptance     final : InCaloFutureAcceptance {
+  /// standard constructor
+  InHcalFutureAcceptance(const std::string& type, const std::string& name,
+                   const IInterface* parent)
+      : InCaloFutureAcceptance(type, name, parent) {
+    _setProperty("CalorimeterFuture", DeCalorimeterLocation::Hcal);
+    _setProperty("UseFiducial", "true");
+    _setProperty("Tolerance", "10");  /// 10 * Gaudi::Units::mm
+  };
+
+  /// C++11 non-copyable idiom
+  InHcalFutureAcceptance() = delete;
+  InHcalFutureAcceptance(const InHcalFutureAcceptance&) = delete;
+  InHcalFutureAcceptance& operator=(const InHcalFutureAcceptance&) = delete;
+};
+
+// ============================================================================
+
+DECLARE_COMPONENT( InHcalFutureAcceptance     )
+
+// ============================================================================
diff --git a/CaloFuture/CaloFuturePIDs/src/InHcalFutureAcceptanceAlg.cpp b/CaloFuture/CaloFuturePIDs/src/InHcalFutureAcceptanceAlg.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b44299fddd8c42d93e9f392d11bdb95a5c2572b6
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/InHcalFutureAcceptanceAlg.cpp
@@ -0,0 +1,33 @@
+// Include files
+#include "InCaloFutureAcceptanceAlg.h"
+
+// ============================================================================
+/** @class InHcalFutureAcceptanceAlg InHcalFutureAcceptanceAlg.cpp
+ *  the preconfigured instance of InCaloFutureAcceptanceAlg
+ *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
+ *  @date   2006-06-17
+ */
+// ============================================================================
+
+struct InHcalFutureAcceptanceAlg final : InCaloFutureAcceptanceAlg {
+  /// Standard constructor
+  InHcalFutureAcceptanceAlg(const std::string& name, ISvcLocator* pSvc)
+      : InCaloFutureAcceptanceAlg(name, pSvc) {
+    using LHCb::CaloFutureAlgUtils::CaloFutureIdLocation;
+
+    Gaudi::Functional::updateHandleLocation(
+        *this, "Output", CaloFutureIdLocation("InHcal", context()));
+
+    _setProperty("Tool", "InHcalFutureAcceptance/InHcalFuture");
+    // track types:
+    _setProperty("AcceptedType", Gaudi::Utils::toString<int>(
+                                     LHCb::Track::Types::Long, LHCb::Track::Types::Downstream,
+                                     LHCb::Track::Types::Ttrack));
+  }
+};
+
+// ============================================================================
+
+DECLARE_COMPONENT( InHcalFutureAcceptanceAlg )
+
+// ============================================================================
diff --git a/CaloFuture/CaloFuturePIDs/src/InPrsFutureAcceptance.cpp b/CaloFuture/CaloFuturePIDs/src/InPrsFutureAcceptance.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0d0ddcea85ec848d19bbd0f083471a7679d63de6
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/InPrsFutureAcceptance.cpp
@@ -0,0 +1,33 @@
+// Include files
+#include "InCaloFutureAcceptance.h"
+
+// ============================================================================
+/** @class InPrsFutureAcceptance     
+ *  The precofigured instance of InCaloFutureAcceptance Tool
+ *  @author Victor EGORYCHEV Victor.Egorychev@cern.ch
+ *  @author Vanya  BELYAEV    ibelyaev@phsycis.syr.edu
+ *  @date   2006-05-28
+ */
+// ============================================================================
+
+struct InPrsFutureAcceptance final : InCaloFutureAcceptance {
+  /// standard constructor
+  InPrsFutureAcceptance(const std::string& type, const std::string& name,
+                  const IInterface* parent)
+      : InCaloFutureAcceptance(type, name, parent) {
+    _setProperty("CalorimeterFuture", DeCalorimeterLocation::Prs);
+    _setProperty("UseFiducial", "false");
+    _setProperty("Tolerance", "10");  /// 10 * Gaudi::Units::mm
+  };
+
+  /// C++11 non-copyable idiom
+  InPrsFutureAcceptance() = delete;
+  InPrsFutureAcceptance(const InPrsFutureAcceptance&) = delete;
+  InPrsFutureAcceptance& operator=(const InPrsFutureAcceptance&) = delete;
+};
+
+// ============================================================================
+
+DECLARE_COMPONENT( InPrsFutureAcceptance )
+
+// ============================================================================
diff --git a/CaloFuture/CaloFuturePIDs/src/InPrsFutureAcceptanceAlg.cpp b/CaloFuture/CaloFuturePIDs/src/InPrsFutureAcceptanceAlg.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4b606a247629cdc4260706a432302f16b966e674
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/InPrsFutureAcceptanceAlg.cpp
@@ -0,0 +1,33 @@
+// Include files
+#include "InCaloFutureAcceptanceAlg.h"
+
+// ============================================================================
+/** @class InPrsFutureAcceptanceAlg InPrsFutureAcceptanceAlg.cpp
+ *  the preconfigured instance of InCaloFutureAcceptanceAlg
+ *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
+ *  @date   2006-06-17
+ */
+// ============================================================================
+
+struct InPrsFutureAcceptanceAlg final : InCaloFutureAcceptanceAlg {
+  /// Standard constructor
+  InPrsFutureAcceptanceAlg(const std::string& name, ISvcLocator* pSvc)
+      : InCaloFutureAcceptanceAlg(name, pSvc) {
+    using LHCb::CaloFutureAlgUtils::CaloFutureIdLocation;
+
+    Gaudi::Functional::updateHandleLocation(*this, "Output",
+                                            CaloFutureIdLocation("InPrs", context()));
+
+    _setProperty("Tool", "InPrsFutureAcceptance/InPrs");
+    // track types:
+    _setProperty("AcceptedType", Gaudi::Utils::toString<int>(
+                                     LHCb::Track::Types::Long, LHCb::Track::Types::Downstream,
+                                     LHCb::Track::Types::Ttrack));
+  }
+};
+
+// ============================================================================
+
+DECLARE_COMPONENT( InPrsFutureAcceptanceAlg )
+
+// ============================================================================
diff --git a/CaloFuture/CaloFuturePIDs/src/InSpdFutureAcceptance.cpp b/CaloFuture/CaloFuturePIDs/src/InSpdFutureAcceptance.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f5b6f78cd82baa0285af6a8d58853c0492f8f5f5
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/InSpdFutureAcceptance.cpp
@@ -0,0 +1,33 @@
+// Include files
+#include "InCaloFutureAcceptance.h"
+
+// ============================================================================
+/** @class InSpdFutureAcceptance     
+ *  The precofigured instance of InCaloFutureAcceptance Tool
+ *  @author Victor EGORYCHEV Victor.Egorychev@cern.ch
+ *  @author Vanya  BELYAEV    ibelyaev@phsycis.syr.edu
+ *  @date   2006-05-28
+ */
+// ============================================================================
+
+struct InSpdFutureAcceptance final : InCaloFutureAcceptance {
+  /// standard constructor
+  InSpdFutureAcceptance(const std::string& type, const std::string& name,
+                  const IInterface* parent)
+      : InCaloFutureAcceptance(type, name, parent) {
+    _setProperty("CalorimeterFuture", DeCalorimeterLocation::Spd);
+    _setProperty("UseFiducial", "false");
+    _setProperty("Tolerance", "1");  /// 1 * Gaudi::Units::mm
+  };
+
+  /// C++11 non-copyable idiom
+  InSpdFutureAcceptance() = delete;
+  InSpdFutureAcceptance(const InSpdFutureAcceptance&) = delete;
+  InSpdFutureAcceptance& operator=(const InSpdFutureAcceptance&) = delete;
+};
+
+// ============================================================================
+
+DECLARE_COMPONENT( InSpdFutureAcceptance      )
+
+// ============================================================================
diff --git a/CaloFuture/CaloFuturePIDs/src/InSpdFutureAcceptanceAlg.cpp b/CaloFuture/CaloFuturePIDs/src/InSpdFutureAcceptanceAlg.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..488ebad43787908ae72893a410a009694469f6e1
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/InSpdFutureAcceptanceAlg.cpp
@@ -0,0 +1,33 @@
+// Include files
+#include "InCaloFutureAcceptanceAlg.h"
+
+// ============================================================================
+/** @class InSpdFutureAcceptanceAlg InSpdFutureAcceptanceAlg.cpp
+ *  the preconfigured instance of InCaloFutureAcceptanceAlg
+ *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
+ *  @date   2006-06-17
+ */
+// ============================================================================
+
+struct InSpdFutureAcceptanceAlg final : InCaloFutureAcceptanceAlg {
+  /// Standard constructor
+  InSpdFutureAcceptanceAlg(const std::string& name, ISvcLocator* pSvc)
+      : InCaloFutureAcceptanceAlg(name, pSvc) {
+    using LHCb::CaloFutureAlgUtils::CaloFutureIdLocation;
+
+    Gaudi::Functional::updateHandleLocation(*this, "Output",
+                                            CaloFutureIdLocation("InSpd", context()));
+
+    _setProperty("Tool", "InSpdFutureAcceptance/InSpd");
+    // track types:
+    _setProperty("AcceptedType", Gaudi::Utils::toString<int>(
+                                     LHCb::Track::Types::Long, LHCb::Track::Types::Downstream,
+                                     LHCb::Track::Types::Ttrack));
+  }
+};
+
+// ============================================================================
+
+DECLARE_COMPONENT( InSpdFutureAcceptanceAlg )
+
+// ============================================================================
diff --git a/CaloFuture/CaloFuturePIDs/src/Linear.h b/CaloFuture/CaloFuturePIDs/src/Linear.h
new file mode 100644
index 0000000000000000000000000000000000000000..7e615c709c1a06a55b3339850a49027c148d457a
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/Linear.h
@@ -0,0 +1,155 @@
+// ============================================================================
+#ifndef CALOFUTUREPIDS_LINEAR_H 
+#define CALOFUTUREPIDS_LINEAR_H 1
+// ============================================================================
+// Include files
+// ============================================================================
+// Event 
+// ============================================================================
+#include "Event/State.h"
+#include "Event/TrackTypes.h"
+// ============================================================================
+// LHCbMath 
+// ============================================================================
+#include "LHCbMath/Line.h"
+#include "LHCbMath/GeomFun.h"
+// ============================================================================
+// Math Definitions
+// ============================================================================
+#include "GaudiKernel/Plane3DTypes.h"
+// ============================================================================
+
+namespace Utils
+{
+  namespace Linear
+  {  
+    /** make a linear extrapiolation of the state to a certain Z 
+     *  @param state (input/output) state to be extrapolated 
+     *  @param newZ (input) z-position
+     *  @return status code 
+     */
+    inline 
+    StatusCode propagate 
+    ( LHCb::State& state , 
+      const double newZ  )
+    {
+      // make a linear extrapolation of state to new Z-position 
+      if ( newZ == state.z() ) { return StatusCode::SUCCESS ; }
+      // 
+      const double dz = newZ - state.z() ;
+      // correct the positions:
+      state.setZ ( newZ ) ;
+      Gaudi::TrackVector& vct = state.stateVector();
+
+      vct[0] += dz*vct[2] ;
+      vct[1] += dz*vct[3];
+
+      // correct the covarinaces:
+      Gaudi::TrackSymMatrix& cov = state.covariance() ;
+      // 
+      const double dz2  = dz * dz ;
+      //
+      enum { 
+        X  = 0 , 
+        Y  = 1 , 
+        TX = 2 , 
+        TY = 3 , 
+        QP = 4 
+      } ;
+      //
+      const double _cxx    = cov (  X ,  X ) ;
+      const double _cxy    = cov (  X ,  Y ) ;
+      const double _cxtx   = cov (  X , TX ) ;
+      const double _cxty   = cov (  X , TY ) ;
+      const double _cxqp   = cov (  X , QP ) ;
+      //
+      const double _cyy    = cov (  Y ,  Y ) ;
+      const double _cytx   = cov (  Y , TX ) ;
+      const double _cyty   = cov (  Y , TY ) ;
+      const double _cyqp   = cov (  Y , QP ) ;
+      //
+      const double _ctxtx  = cov ( TX , TX ) ;
+      const double _ctxty  = cov ( TX , TY ) ;
+      const double _ctxqp  = cov ( TX , QP ) ;
+      //
+      const double _ctyty  = cov ( TY , TY ) ;
+      const double _ctyqp  = cov ( TY , QP ) ;
+      //
+      // const double _cqpqp  = cov ( QP , QP ) ;
+      //
+      // update the matrix 
+      //
+      cov (  X ,  X ) = _cxx   + 2*dz*_cxtx       + dz2 * _ctxtx ;
+      cov (  X ,  Y ) = _cxy   + dz*(_cxty+_cytx) + dz2 * _ctxty ;
+      cov (  X , TX ) = _cxtx  +                    dz  * _ctxtx ;
+      cov (  X , TY ) = _cxty  +                    dz  * _ctxty ;
+      cov (  X , QP ) = _cxqp  +                    dz  * _ctxqp ;
+      //
+      cov (  Y ,  Y ) = _cyy   + 2*dz*_cyty       + dz2 * _ctyty ;
+      cov (  Y , TX ) = _cytx  +                    dz  * _ctxty ;
+      cov (  Y , TY ) = _cyty  +                    dz  * _ctyty ;
+      cov (  Y , QP ) = _cyqp  +                    dz  * _ctyqp ;
+      //
+      //
+      return StatusCode::SUCCESS ;
+    }
+    /** make a linear extrapiolation of the state to a certain Z 
+     *  @param s1 (input) state to be extrapolated 
+     *  @param newZ (input) z-position
+     *  @param s2 (output) extrapoalted state 
+     *  @return status code 
+     */
+    inline StatusCode propagate 
+    ( const LHCb::State& s1   , 
+      const double       newZ ,
+      LHCb::State&       s2   ) 
+    {
+      // copy the state 
+      s2 = s1 ;
+      // propagate it 
+      return propagate ( s2 , newZ ) ;
+    }
+    /** make a linear extrapolation of the state to a certain 3D-plane 
+     *  @param state (input/output) state to be extrapolated 
+     *  @param plane (input) plane 
+     *  @return status code 
+     */    
+    inline StatusCode propagate 
+    ( LHCb::State&          state , 
+      const Gaudi::Plane3D& plane ) 
+    {
+      typedef Gaudi::Math::Line<Gaudi::XYZPoint,Gaudi::XYZVector> Line ;
+      // construct the line form the state 
+      const Line line = Line( state.position() , state.slopes () ) ;
+      Gaudi::XYZPoint point ;
+      double mu = 0 ;
+      // find the interseciton of the line with plane 
+      if ( !Gaudi::Math::intersection ( line , plane , point , mu ) )
+      { return StatusCode::FAILURE ; }
+      // propagate to a certain Z 
+      return propagate ( state , point.Z() ) ;
+    }
+    /** make a linear extrapolation of the state to a certain 3D-plane 
+     *  @param s1 (input) state to be extrapolated 
+     *  @param pl (input) plane 
+     *  @param s2 (output) extrapoalted state 
+     *  @return status code 
+     */
+    inline StatusCode propagate 
+    ( const LHCb::State&    s1 , 
+      const Gaudi::Plane3D& pl ,
+      LHCb::State&          s2 )  
+    {
+      // copy the state 
+      s2 = s1 ;
+      // propagate it 
+      return propagate ( s2 , pl ) ;
+    }
+  }
+}
+
+// ============================================================================
+// The END 
+// ============================================================================
+#endif // LINEAR_H
+// ============================================================================
diff --git a/CaloFuture/CaloFuturePIDs/src/ToString.h b/CaloFuture/CaloFuturePIDs/src/ToString.h
new file mode 100644
index 0000000000000000000000000000000000000000..f7e987254ebef3033d0ce5dbc720724b13f6aa6f
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/ToString.h
@@ -0,0 +1,27 @@
+// ============================================================================
+#ifndef CALOFUTUREPIDS_TOSTRING_H 
+#define CALOFUTUREPIDS_TOSTRING_H 1
+// ============================================================================
+// Include files
+// ============================================================================
+// STD & STL
+// ============================================================================
+#include <vector>
+#include <sstream>
+#include "GaudiKernel/ToStream.h"
+// ============================================================================
+namespace Gaudi
+{
+  namespace Utils 
+  {
+    inline std::string toString ( const std::string& o ) 
+    { return "\"" + o + "\"" ; }
+  } // end of namespace Utils 
+} // end of namespace Gaudi 
+// ============================================================================
+
+// ============================================================================
+// The END 
+// ============================================================================
+#endif // CALOFUTUREPIDS_TOSTRING_H
+// ============================================================================
diff --git a/CaloFuture/CaloFuturePIDs/src/ToVector.h b/CaloFuture/CaloFuturePIDs/src/ToVector.h
new file mode 100644
index 0000000000000000000000000000000000000000..538fc148d082100f00af167ddfac9f4d35517996
--- /dev/null
+++ b/CaloFuture/CaloFuturePIDs/src/ToVector.h
@@ -0,0 +1,41 @@
+// ============================================================================
+#ifndef CALOFUTUREPIDS_TOVECTOR_H 
+#define CALOFUTUREPIDS_TOVECTOR_H 1
+// ============================================================================
+// Include files
+// ============================================================================
+// STD & STL 
+// ============================================================================
+#include <vector>
+#include <type_traits>
+#include <string>
+// ============================================================================
+// Local 
+// ============================================================================
+#include "ToString.h"
+// ============================================================================
+
+namespace Gaudi
+{
+  namespace Utils 
+  {
+    // ========================================================================
+    template <typename... TYPE>
+    std::vector<typename std::common_type<TYPE...>::type> toVector( const TYPE&... o )
+    { return { o... }; }
+    // ========================================================================
+    
+    // ========================================================================
+    template <typename... TYPE> 
+    std::string toString( const TYPE&... o )
+    { return toString( toVector( o... ) ) ; }
+    // ========================================================================
+    
+  } // end of namespace Utils 
+} // end of namespace Gaudi 
+
+// ============================================================================
+// The END 
+// ============================================================================
+#endif // TOVECTOR_H
+// ============================================================================
diff --git a/CaloFuture/CaloFutureReco/CMakeLists.txt b/CaloFuture/CaloFutureReco/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..468b2640d250d44fbfb926accf532eb0aa6bf3b3
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/CMakeLists.txt
@@ -0,0 +1,24 @@
+################################################################################
+# Package: CaloFutureReco
+################################################################################
+gaudi_subdir(CaloFutureReco v5r28)
+
+gaudi_depends_on_subdirs(CaloFuture/CaloFutureDAQ
+                         CaloFuture/CaloFutureInterfaces
+                         CaloFuture/CaloFuturePIDs
+                         CaloFuture/CaloFutureUtils
+                         Kernel/Relations)
+
+find_package(Boost)
+find_package(ROOT)
+include_directories(SYSTEM ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS})
+
+gaudi_add_module(CaloFutureReco
+                 src/*.cpp
+                 INCLUDE_DIRS CaloFuture/CaloFutureDAQ
+                 LINK_LIBRARIES CaloFutureUtils RelationsLib)
+
+gaudi_install_python_modules()
+
+gaudi_env(SET CALOFUTURERECOOPTS \${CALOFUTURERECOROOT}/options)
+
diff --git a/CaloFuture/CaloFutureReco/doc/release.notes b/CaloFuture/CaloFutureReco/doc/release.notes
new file mode 100755
index 0000000000000000000000000000000000000000..0c2ee2ef0314eb8b21bca44024e544b9c19d2ac7
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/doc/release.notes
@@ -0,0 +1,1277 @@
+! -----------------------------------------------------------------------------
+! Package     : CaloFuture/CaloFutureReco
+! Responsible : Olivier Deschamps odescham@in2p3.fr 
+! Purpose     : Main Package for CaloFuturerimeter Reconstruction Software 
+! -----------------------------------------------------------------------------
+
+! 2017-08-10 - O.Deschamps
+  - reduce verbosity in CaloFutureShowerOverlapTool and CaloFutureECorrection (HLT request)
+
+! 2016-08-16 - Olivier Deschamps
+  - implement counter() switch based on FutureCounterLevel tool
+  - Configurable : propagate counter() switch to all CaloFuture sequences
+  - CaloFutureCorrectionBase : CaloFuture HLT Speed update (from G. Raven - see  LHCBPS-1620)
+
+ -06-04 - Olivier Deschamps
+  - CaloFutureCorrectionBase : add protection to avoid repeated Condition registration when running TCK in Moore
+
+
+!========================= CaloFutureReco v5r28 2016-03-17 =========================
+! 2016-03-05 - Olivier Deschamps
+  - CaloFutureProcessor configurables :  add slots to configure the Accepted Track::Types at CaloFuturePID level
+
+! 2016-02-25 - Olivier Deschamps
+  - fix a clang warning
+
+! 2016-02-24 - Olivier Deschamps
+  - fix clang warning in friend declarations of ToolFactory (class->struct)
+
+! 2016-02-18 - Olivier Deschamps
+ - CaloFutureMergedPi0 : replace setOuputLevel with setProperty("OutputLevel", ...) to please Gaudi_HEAD
+
+! 2016-02-17 - Olivier Deschamps
+ - Configuration.py : - fix :  propagate cluster mask to  SplitClusters
+                      - revert change done in 2015-12-05 :  the exception handling to check TES was done on purpose - to avoid triggering the splitcluster onDemand with another instance 
+                      of the same algorithm !
+
+
+! 2016-02-02 - Olivier Deschamps
+ - Fix EnergyTags & PositionTags property setting in configurable.
+
+!========================= CaloFutureReco v5r27 2016-01-28 =========================
+! 2015-12-16 - Marco Cattaneo
+ - CaloFutureCorrectionBase.cpp: add workaround to prevent wierd FPE with clang
+
+! 2015-12-05 - Gerhard Raven
+ - avoid the use of exception handling to find out whether there already is an 
+   object on the TES...
+
+!========================= CaloFutureReco v5r26 2015-10-23 ==========================
+
+! 2015-10-16 - Olivier Deschamps
+ - python configurable : propagate same Et threshold for mergedPi0 and for splitCluster production
+
+!========================= CaloFutureReco v5r25p1 2015-10-13 =========================
+! 2015-08-12 - Gerhard Raven
+ - remove #include of obsolete Gaudi headers
+
+!========================= CaloFutureReco v5r25 2015-04-21 =========================
+! 2015-04-15 - Olivier Deschamps
+ - python/CaloFutureReco/Configuration : in CaloFutureProcessor : give CaloFutureProcessor-name-dependent naming for the neutralProtoPAlg
+
+!========================= CaloFutureReco v5r24 2015-03-31 =========================
+! 2015-03-30 - Olivier Deschamps
+ - python/CaloFutureReco/Configuration : in CaloFutureProcessor : give CaloFutureProcessor-name-dependent naming for the algorithms updating charged ProtoP
+
+! 2015-03-29 - Roel Aaij
+ - Fix bad assert.
+
+! 2015-03-26 - Gerhard Raven
+  -  CaloFutureCorrectionBase::getParams: 
+   o don't create an empty vector if it won't be needed
+   o cache counters by (type, areaName) instead of creating a string containing
+      both every single time, and then looking them up by string
+   This reduces the # of calls to new/delete in the HLT by ~10% (!), and speeds up 
+   the HLT (in its preliminary 2015 configuration) by ~1%.
+
+!========================= CaloFutureReco v5r23 2015-02-23 =========================
+! 2015-01-21 - Daria Savrina
+ - Corrected a typo in CaloFuture/CaloFutureReco/python/CaloFutureReco/Reconstruction.py, line 160
+   (there were too few arguments to format a string)
+
+! 2015-01-15 - Olivier Deschamps
+ - CaloFutureCorrectionBase : add boolean method to flag condition update (hasConditionChanged())
+ - FutureClusterCovarianceMatrixTool : update parameters via BeginEvent incident only when condition changed
+
+!========================= CaloFutureReco v5r22 2014-12-11 =========================
+! 2014-11-26 - Marco Cattaneo
+ - Fix unprotected debug in CaloFutureSCorrection.cpp
+
+!========================= CaloFutureReco v5r21p1 2014-09-28 =========================
+! 2014-09-28
+  - CaloFutureMergedPi0 : fix bug that affect sub-seed definition in some configuration
+  - Configuration.py : decrease MergedPi0Pt threshold from 2 GeV to 1.5 GeV 
+     (applies on cluster pT before merged hypothesis is fully reconstructed)
+
+!========================= CaloFutureReco v5r21 2014-09-08 =========================
+! 2014-08-22 - Gerhard Raven
+ - various CPU performance improvements.
+
+! 2014-07-26 - Dima Golubkov
+  - CaloFutureECorrection.cpp, CaloFutureSCorrection.cpp : correct defaults for missing correction functions in CondDB and add more protection
+
+! 2014-07-23 - Olivier Deschamps for Dima
+  - CaloFutureCorrectionBase/CaloFutureECorrection/CaloFutureSCorrection : implement correction propagation to Covariance
+
+
+!========================= CaloFutureReco v5r20 2014-07-14 =========================
+! 2014-07-11 - Olivier Deschamps
+  - CaloFutureECorrection/CaloFutureCorrectionBase :  add energy offset correction (allowing sin(theta) dependency to have transverse energy correction)
+
+
+! 2014-07-08 - Olivier Deschamps
+  - CaloFutureECorrection :  fix unapplied correction
+
+! 2014-07-08 - Olivier Deschamps
+  - CaloFutureCorrectionBase/CaloFutureECorrection : add possible non-linear dependency to Prs corrections
+
+! 2014-07-03 - Olivier Deschamps
+  - FutureClusterCovarianceMatrixTool : allow for covariance parametrization per CaloFuture area - improve DB access
+  - FutureSubClusterSelectorTool      : improve DB access
+  - add Hcal default settings for Jet-related reconstruction
+  
+! 2014-07-02 - Olivier Deschamps
+  - CaloFutureShowerOverlapTool : add protection in case of missing ShowerProfile
+  - CaloFutureMergedPi0 : add minimal ET cut on splitPhoton (applied to both cluster and corrected CaloFutureHypo)
+  - CaloFutureXCorrection : skip correction in case of negative energy
+
+! 2014-07-01 - Olivier Deschamps
+  - Photon/Electron/MergedPi0 CaloFutureHypos : skip CaloFutureHypos with negative energy (if any) 
+
+! 2014-06-30 - Olivier Deschamps
+  - Reconstruction.py : skip single-cell "clusters" for CaloFutureHypo building
+  - CaloFutureSelectCluster : add a cut on entries.size()
+  - CaloFutureMergedPi0 : fix property name causing a crash in Moore 
+
+! 2014-06-30 - Marco Cattaneo
+  - fix verbosity of CaloFuture{L,E,S}Correction.cpp constructor
+
+! 2014-06-30 - Olivier Deschamps
+  - fix electronPt/photonPt cluster thresholds for CaloFutureHypo production
+
+! 2014-06-29 - Olivier Deschamps
+  - fix default parameters for Covariance estimation
+
+! 2014-06-29 - Olivier Deschamps
+  - fix FPE's, compilation warnings & verbosity excess
+
+! 2014-06-27 - Olivier Deschamps
+	- add new specific ClusterSelector's : FutureSubClusterSelector2x2 , FutureSubClusterSelectorSwissCross.h
+  - and a generic tool to access condDB and tag the clusters  : FutureSubClusterSelectorTool.h
+  - src/CaloFutureShowerOverlapTool : new tool to substract overlap energy in cluster pair (note : CaloFutureSharedCellAlg.cpp is now obsolete)
+  - src/CaloFutureMergedPi0 & CaloFutureShowerOverlap  : mergePi0 reconstruction and ClusterOverlap based on the above tool (note : CaloFutureMergedPi0Alg is now obsolete)
+
+  - adapt to change in cluster masking : CaloFutureClusterizationTool, FutureSubClusterSelectorBase, CaloFutureClusterCovarianceAlg, FutureSubClusterSelector3x3, FutureClusterCovarianceMatrixTool
+  - CaloFutureCorrectionBase  : map new corrections and implement generic DB access for cluster masks                   
+  - CaloFutureSCorrection.cpp : add new Alexis' correction
+
+  - python/CaloFutureReco/Configuration.py  : new slots to select cluster masks :  ClusterEnergyMasks and ClusterPositionMasks (default : get mask setting from DB) 
+  - python/CaloFutureReco/Reconstruction.py : propagate masks to ClusterCovariance , ClusterOverlap & MergedPi0
+                                      : use CaloFutureMergedPi0     (replacing the now obsolete CaloFutureMergedPi0Alg)
+                                      : use CaloFutureShowerOverlap (replacing the now obsolete CaloFutureSharedCellAlg)  
+
+
+
+!========================= CaloFutureReco v5r19 2014-03-18 =========================
+! 2014-03-06 - Olivier Deschamps
+ -  python/Configuration.py : propagate OutputLevel value to calo sequences only when the property is explicity set
+
+! 2014-03-05 - Olivier Deschamps
+ -  python/Configuration.py : dactivate Spd/Prs Decoders in DecoderDB when noSpdPrs=True
+ -  add DAQSys dependency
+
+! 2014-02-27 - Olivier Deschamps
+ -  CaloFutureMergedPi0Alg : remove default tools property triggering Prs/Spd decoding
+
+!========================= CaloFutureReco v5r18 2013-12-10 =========================
+! 2013-10-30 - Olivier Deschamps
+ -  python/CaloFutureReco/Configuration.py : fix typo in CaloFutureLines method.
+
+!========================= CaloFutureReco v5r17 2013-10-24 =========================
+! 2013-10-09 - Olivier Deschamps
+ -  python/CaloFutureReco/*.py : 
+        - possibility to set-up a configuration without active Spd/Prs  (NoSpdPrs = <False> flag)
+                - configure the caloReco/Pids algorithms in order they don't access Prs/Spd detectorElement nor Digits
+                - remove any component related to Prs/Spd  in the reconstruction sequence : 
+                         digits decoding via CaloFutureDigitsConf, cluster filtering, photonID, pi0/gamma separation, neutral/charged ID
+        - NoSpdPrs flag propagated to CaloFuturePIDs configuration via CaloFutureProcessor and CaloFutureDigitsConf configured with [Ecal,Hcal] only 
+
+ -  src/CaloFutureMergedPi0AlgAlg :  protect against accessing Prs/Spd digits when they don't exist
+
+!========================= CaloFutureReco v5r16p1 2013-06-03 =======================
+! 2013-05-27 - Marco Cattaneo
+ - Fix clang32 warnings
+
+!========================= CaloFutureReco v5r16 2012-11-28 =========================
+! 2012-11-22 - Marco Clemencic
+ - Added CMake configuration file.
+
+! 2012-10-08 - Marco Cattaneo
+ - In Brunel.opts, remove setting of MeasureTime=true in sequencers,
+   should not be the default, and should in any case use TimingAuditor.
+
+! 2012-10-08 - Olivier Deschamps
+  - fix coverity problems
+
+!========================= CaloFutureReco v5r15 2012-06-25 ========================= 
+! 2012-06-24 - Olivier Deschamps
+  - FutureClusterCovarianceMatrixTool : get covariance parameters from condDB when
+    available
+
+! 2012-06-23 - Olivier Deschamps
+  - CaloFutureMergedPi0Alg : add covariance matrix for SplitClusters & SplitPhotons
+    (assume no correlation)
+  - CaloFutureECorrection  : allow spd-dependent PileUp subtraction 
+
+! 2011-12-10 - Olivier Deschamps
+  - Configurable CaloFutureLine : add ClusterizationLevel tag for L0CaloFuture2CaloFuture
+   (set to 2 by default)
+
+!========================= CaloFutureReco v5r14 2012-02-28 =========================
+! 2012-02-27 - Marco Cattaneo
+ - CaloFutureMergedPi0Alg: Fix potential memory leak, probably never fired
+   (Coverity defect 17572)
+ - Fix UNINIT_CTOR defects
+ - Fix trivial icc remarks  
+
+!========================= CaloFutureReco v5r13 2011-11-26 =========================
+! 2011-11-25 - Olivier Deschamps
+  - CaloFutureMergedPi0Rec : fix abusive 'return 0'
+
+!========================= CaloFutureReco v5r12 2011-08-29 =========================
+! 2011-08-27 - Olivier Deschamps
+	- fix tracks list reset in CaloFutureProcessor.XXSequence when called from CaloFutureLines
+	- python/Configuration.py : remove dependency on GlobalRecoConf (was producing loop in configurable).
+															TrackTypes & TrackCuts is now private property with the same default 
+															as in GlobalRecoConf so far
+
+
+!========================= CaloFutureReco v5r11 2011-07-27 =========================
+! 2011-07-27 - Marco Cattaneo
+ - Protect unprotected MSG::DEBUG, also using UNLIKELY macro
+
+! 2011-07-08 - Albert Puig
+  - python/Configuration.py : correctly propagate track locations in CaloFutureLines.
+
+! 2011-07-04 - Olivier Deschamps
+  - python/Configuration.py : apply default GlobalRecoConf settings for
+    chargedProtoPMaker (when activated on-demand in CaloFutureProcessor)
+
+!========================= CaloFutureReco v5r10 2011-06-15 =========================
+! 2011-06-06 - Olivier Deschamps
+  - python/Configuration.py :  consolid sequencer() methods
+                               new configurable : CaloFutureLines for HLT fast reconstruction
+
+  - src/CaloFutureClusterizationTool : limit the number of clusterization pass to 10
+
+! 2011-05-16 - Olivier Deschamps
+  - CaloFutureClusterizationTool : fix interfacing with L0CaloFuture2CaloFutureTool
+
+! 2011-05-09 - Olivier Deschamps
+  - fix protoP maker DoD in CaloFutureProcessor (no DoD setting by default)
+
+!========================= CaloFutureReco v5r9p1 2011-05-09 =========================
+! 2011-05-09 -  Gerhard Raven
+ - do not check Hlt context, but honour the EnableOnDemand property of the
+   Configurable instead (i.e. as it was in v5r8!)
+
+! 2011-05-09 -  Roel Aaij
+ - Add check for Hlt context before adding to DoD in CaloFutureProcessor.
+
+!========================= CaloFutureReco v5r9 2011-04-27 =========================
+! 2011-04-24 - Olivier Deschamps
+  - update CaloFutureProcessor configurable with 'MakeExternalClustersWithTag' slot
+
+! 2011-04-24 - Olivier Deschamps
+  - update CaloFutureProcessor configurable with 'ExternalClusters' slot
+
+!========================= CaloFutureReco v5r8p1 2011-01-28 ========================
+
+! 2011-02-23 - Olivier Deschamps
+ - CaloFutureCorrectionBase : add missing protection
+ - remove obsolete CellularAutomaton.cpp
+
+! 2011-02-17 - Olivier Deschamps
+ - clean CaloFutureClusterisationTool
+ - remove obsolete CellularAutomaton.cpp
+
+! 2011-02-17 - Marco Clemencic
+ - Fixed an infinite loop with associated memory leak.
+
+! 2011-02-17 - Chris Jones
+ - Some trivial coverity and icc fixes
+
+! 2011-07-02 - Olivier Deschamps
+	- CaloFutureECorrection : cluster energy offset via CaloFutureDAQ/ICaloFutureDigitFilterTool
+	- Add : digit masking/offset in Cluster sequence (Brunel.opts/Reconstruction.py)
+	- Add : Et threshold in cluster selection for hypo building
+	- few protections here and ther requirements : add depencency on CaloFutureUtils
+
+!========================= CaloFutureReco v5r8 2011-01-17 ========================
+
+- 2010-12-20 - Olivier Deschamps
+ - reduce verbosity and fix untested StatusCode 
+
+- 2010-12-16 - Olivier Deschamps :
+ - Update CaloFutureCorrectionBase to handle S/L-corrections + ShowerProfile parametrisation from condDB
+ - Update CaloFutureSCorrection, CaloFutureLCorrection and CaloFutureMergedPi0Alg to get parameters from DB.
+ - updates options/python accordingly
+
+!========================= CaloFutureReco v5r7p1 2010-10-28 =========================
+- 2010-10-15 - Olivier Deschamps :
+ - Clean obsolete options file
+
+
+!========================== CaloFutureReco v5r7  2010-09-24 =======================
+- 2010-09-24 - Olivier Deschamps :
+ - Uncomment correction
+
+- 2010-09-23 - Olivier Deschamps :
+ - SinglePhotonAlg : fix typo in default setting
+
+- 2010-09-23 - Olivier Deschamps :
+  - CaloFutureCorrection : 
+    - add new functions in CaloFutureCorrectionBase
+    - adapt CaloFutureLCorrection to the new correction framework (adapt options and configurable)
+    - CaloFutureECorrection : allow for beta_prs  dependency with energy
+
+
+! 2010-09-20 - Olivier Deschamps
+  - CaloFutureMergedPi0Alg : fix window compilation warning
+
+! 2010-09-03 - Olivier Deschamps
+ - Configuration.py : fix interference between unpack/calo sequence DoD setting
+ - CaloFutureMergedPi0Alg : paranoid protection against already existing SplitCluster container
+
+! 2010-08-27 - Olivier Deschamps
+ - CaloFutureMergedPi0Alg : add extraDigit tool to both mergedPi0 and splitPhotons + update python/Reconstruction.py (and old style options)
+
+!========================== CaloFutureReco v5r6  2010-06-01 =======================
+! 2010-08-17 - Olivier Deschamps
+ - python/Configuration.py : CaloFutureProcessor adapted to change in CaloFuturePIDs (PIDList) + consolidation of the configurables 
+
+
+!========================== CaloFutureReco v5r5p2  2010-06-01 =======================
+! 2010-06-01 - Gerhard Raven
+ - suppress printout of another error from CaloFutureClusterCovarianceAlg, but keep
+   summary at the end of the job
+
+!========================== CaloFutureReco v5r5p1  2010-05-27 ========================
+! 2010-05-27 - Olivier Deschamps
+	- CaloFutureCorrectionBase : reduce verbosity
+
+! 2010-05-26 - Olivier Deschamps
+	- python/Configuration.py : set correctly the charged protop location in combinedProtoP algo
+
+!========================== CaloFutureReco v5r5  2010-05-21 ========================
+! 2010-05-21 - Olivier Deschamps
+	- python/Configuration.py : full protoP reprocessing (incl. combination) in protoSequence
+
+! 2010-05-20 - Olivier Deschamps
+
+	- CaloFutureCorrectionBase : new base algorithm for CaloFutureCorrections (access to dataBase, handling parameters)
+	   - adapt CaloFutureECorrection.h/cpp : use (new) condDB table for correction parameters - if not use options driven parametrization
+		 - adap CaloFutureECorrection.opts & python/Correction.py to the new property syntax
+
+		 - so far options contains parametrization for MC data. Data correction should be defined via new table in condDB.
+		 - TODO : 
+			- adapt CaloFutureSCorrection and CaloFutureLCorrection accordingly
+		  - review parametrization for MC2010
+			- adapt CaloFutureMergedPi0Rec parametrization
+
+
+	- CaloFutureSelect** tools : add summary counters
+
+	- Brunel.opts : add missing setting for MergedID/SplitPhotonID
+
+	- python/Configuration : fix bug in ElectronRec setting (Chi2(track-cluster) selection was not applied
+				--> size of CaloFutureHypo container for electron should be reduced (factor ~2 ?)
+
+! 2010-05-19 - Gerhard Raven
+ - suppress printout of error from CaloFutureClusterCovarianceAlg, but keep
+   summary at the end of the job (see http://savannah.cern.ch/bugs/?67077)
+
+! 2010-04-29 - Olivier Deschamps
+	  - Reconstruction.py : fix splitCluster onDemand setting
+	  - fix Brunel.opts
+
+!========================== CaloFutureReco v5r4p2  2010-04-09 ========================
+! 2010-03-27 - Olivier Deschamps
+  - add missing Prs threshold in Standalone Electron selection (CaloFutureStandaloneClusterSelection.opts)
+
+
+!========================== CaloFutureReco v5r4p1  2010-03-31 =========================
+! 2010-03-27 - V. Gligorov
+  - Fix incorrect configuration of CaloFuturePIDsConf and CaloFutureDigitsConf in Configuration.py
+    Please see (https://savannah.cern.ch/task/index.php?12691) for futuredetails 
+
+
+!========================== CaloFutureReco v5r4  2010-03-19 =========================
+! 2010-03-13 - Olivier Deschamps
+ - CaloFutureSharedCellAlg : fix non-reproducible processing (additional sort -> small impact on processing time)
+
+
+! 2010-03-10 - Olivier Deschamps
+ - CaloFutureProcessor CU : 
+    - add neutralProtoSequence() + chargedProtoSequence
+    -  all sequence() : add ProtoPrefixLocation as argument
+    - Context have the priority over instanceName when set. If not Context = instance
+    - problem with NeutralID OnDemand : neutralID activated only in CaloFuturePIDs
+
+
+
+! 2010-03-09 - Marco Cattaneo
+ - In requirements, add dependencies on CaloFuture/CaloFuturePIDs and CaloFuture/CaloFutureDAQ, due to
+   build time dependencies on CaloFuturePIDsConf and CaloFutureDigitConf in Configuration.py
+
+! 2010-03-08 - Olivier Deschamps
+ - Configurables : 
+   - adapt to changes in CaloKernel/ConfUtils
+   - make all component context-dependent
+   - add few slots (SkipNeutral, usePrs, ...)
+   - new CU : 
+     - CaloFutureProcessor() : produce CaloFutureRecoPID / CaloFuture-ProtoPUpdate / Full sequencers for a given track location(s)
+     - fully instantiable
+     - to be used for HLT2's processings
+     - syntax  examples :
+        from Configurables import CaloFutureProcessor
+        _tracks = ['Rec/Track/Best]
+        CaloFutureProcessor('Repro').sequence( _tracks )   ## returns a full (Reco/Pid/ProtoUpdate) sequence for context = 'Repro'
+        CaloFutureProcessor('Hlt2/Fitted').caloSequence( _tracks )   ## returns the calo (Reco/Pid) sequence for context = 'Hlt2/Fitted'
+        CaloFutureProcessor('Hlt2').protoSequence(_tracks) ## return the proto Update sequence for context = 'Hlt2'
+        CaloFutureProcessor('Partial', SkipNeutrals = True , CaloFuturePIDs = False ).sequence() ## return Charged Reco only for default track locations
+
+
+   - properly configure SplitCluster on-demand
+   - add missing 'CaloFutureStandalone' mode
+
+ - options :
+   - clean options (remove obsolete)
+   - add temporarly NeutralPIDs.opts (config to be passed via condD asap)
+
+ - src :
+   - CaloFutureSelectCluster : add Et cut
+
+ - TODO : 
+   - Configurables : special Hlt's settings to speed up the processing (Cluster Et cut , Et cut of electron before track match, ...)
+   - CaloFutureProcessor() CU : split ProtoP update by CaloFuturePID technique (to be synchronized with CaloFuturePIDsConf)
+   - CellularAutomaton : EtCut + level !=0 to be active simultaneously
+
+!========================== CaloFutureReco v5r3  2009-11-13 =========================
+! 2009-11-13 - Rob Lambert
+ - Tagged v5r3
+
+! 2009-11-09 - Marco Cattaneo
+ - In CaloFutureReco configurable, propagate OutputLevel to CaloFutureDigitConf
+
+! 2009-11-05 - Dmitry GOLUBKOV
+ - CaloFutureClusterizationTool.cpp,h : remove look_neigh(), use CaloFutureFunctors::neighbours()
+
+! 2009-10-30 - Dmitry GOLUBKOV
+ - CaloFutureClusterizationTool.cpp : fix uninitialized neighbour cell list for level=1
+
+! 2009-10-27 - Vanya Belyaev
+ - make usage off CaloFutureDigitConf configurable to access digits 
+
+! 2009-10-26 - Olivier Deschamps
+  - CaloFutureRecoOnDemand : CaloFutureDigitsSeq imported from CaloFutureDAQ 
+  - CaloFutureElectronAlg  : fix hypothesis setting (uncorrect since a while!)
+
+!========================== CaloFutureReco v5r2  2009-10-22 =========================
+! 2009-10-22 - Marco Cattaneo
+ - Fix python import problems causing errors in make
+
+! 2009-10-15 - Marco Cattaneo
+ - Remove CaloFuturePacking.py, moved to GaudiConf
+
+! 2009-10-10 - Vanya Belyaev
+ - CaloFutureReco/CaloFuturePacking.py 
+    new function to control packing/unpacking of CaloFuturerimeter objects on DST 
+
+! 2009-09-28 - Vanya Belyaev
+ - add the possibility to use both Tracks and Spd ( in *OR* mode) 
+   as neutrality criterion for clusters  
+
+! 2009-09-26 - Juan Palacios
+ - python/CaloFutureReco/Reconstruction.py
+  . Bug fix from Gerhard Raven: unpack the digits.
+ - cmt/requirements
+  . Increase version to v5r1p1
+
+! 2009-09-17 - Olivier Deschamps 
+ - CaloFutureStandaloneClusterSelection.opts : fix bug in Photon selection
+
+! 2009-09-14 - Olivier Deschamps 
+ - Brunel.opts, HltCaloFutureSeq.opts, python/Reconstruction.py :
+   remove CaloFutureGetterInit/CaloFutureDigitGetter (no longer needed)
+
+!========================== CaloFutureReco v5r1  2009-09-04 =========================
+! 2009-09-04 - Olivier Deschamps 
+ - remove Warning verbosity in CaloFutureElectronAlg initialize
+
+! 2009-09-01 - Vanya BELYAEV
+ - fix warnings for Configurables 
+ - cmt/requirements
+     version increment to v5r1 
+
+!========================== CaloFutureReco v5r0  2009-08-31 =========================
+! 2009-08-21 - Olivier Deschamps
+
+  - adapt old syntax .opts to change in CaloFutureReco (public->private tool)
+  - implement generic context-dependent TES I/O
+
+! 2009-08-13 - Chris Jones
+ - Add missing #include <memory> for std::auto_ptr
+
+! 2009-08-10 - Vanya BELYAEV
+ - further polishing of configurables 
+
+! 2009-08-05 - Vanya BELYAEV
+ - add proper configurables for calorimetr recontruction 
+ - version increment to v5r0 
+
+!========================== CaloFutureReco v4r21 2009-07-28 =========================
+! 2009-07-28 - Marco Cattaneo
+ - Remove obsolete file CaloFutureReco_dll.cpp
+
+! 2009-07-24 - Olivier Deschamps 
+ - options/CaloFutureRecoOnDemand.opts : Add digit sequence in CaloFutureCluster-onDemand 
+                                   to please HLT
+
+!========================== CaloFutureReco v4r20 2009-06-30 =======================
+! 2009-06-22 - Marco Cattaneo
+ - Remove unused m_e member from CaloFutureAutoTaggedCell. It was not initialised and
+   was causing FPE on slc4_ia32_gcc34_dbg
+ - Fix WIN32 warning about type conversion
+ - Replace all endreq by endmsg
+ - Fix untested StatusCodes when calling Warning() and Error()
+
+! 2009-06-17 O. Deschamps 
+ - CelAutoTaggedCell : resurrect constructor/destructor
+                       (without the id argument leading to warnings)
+
+! 2009-06-17 O. Deschamps for V. Egorychev
+ - CaloFutureClusterisationTool : prepare for fast HLT clusterisation
+
+!========================== CaloFutureReco v4r19p1 2009-05-25 =======================
+! 2009-05-10 - Vanya Belyaev 
+ - FutureClusterSpreadTool.cpp
+   add (debug) printout of counters for spread-corrected clusters 
+
+ - cmt/requirements 
+   version increment to v4r19p1 
+
+!========================== CaloFutureReco v4r19 2009-05-08 =========================
+! 2008-04-17 - Olivier Deschamps
+ - new alg  CaloFutureGetterInit : create a public instance of CaloFutureGetterTool
+   (from CaloFutureTools) and process the event-update
+ - Brunel.opts/HltCaloFutureSeq.opts : add CaloFutureGetterInit in the reconstruction
+   sequence to have fast access to CaloFutureDigits
+
+! 2009-04-16 - Olivier Deschamps
+ - fix minor bug in HltClusterSelection.opts + adapt to change in CaloFutureTools
+ - CaloFutureClusterisationTool : reduce verbosity
+
+!========================== CaloFutureReco v4r18 2009-03-11 =========================
+! 2009-03-11 - Marco Cattaneo
+ - Added file CaloFuturePIDs-DC06.opts, for DC06 pdf histograms
+ - Brunel.opts no longer includes CaloFuturePIDs.opts. Instead, RecSysConf includes
+   either CaloFuturePIDs.opts or CaloFuturePIDs-DC06.opts
+
+! 2009-03-11 - Victor Egorychev
+ - CaloFuturePIDs_DC09_v1.root file with new PDF for DC09 in BrunelPID.opts and CaloFuturePIDs.opt 
+
+! 2009-03-10 - Marco Cattaneo
+ - Clean up messages in CaloFutureMergedPi0Alg:
+   . Protect debug() with MsgLevel(MSG::DEBUG)
+   . Fix untested status codes from Warning() and Error()
+   . Replace endreq with endmsg
+
+! 2009-03-10 - Olivier Deschamps
+ - Fix FPE occurring in CaloFutureMergedPi0Alg (missing initialization)
+
+! 2009-03-09 - Olivier Deschamps
+ - options/CaloFutureECorrectionParam.opts : 2nd iteration of DC09 tuning (Ecorrection for electron from e/p)
+
+! 2009-03-05 - Olivier Deschamps
+ - options/CaloFutureECorrectionParam.opts : preliminary DC09 tuning
+ - options/UnpackCaloFutureHypoOnDemand.opts : new options to unpack packed CaloFutureHypo on-demand (same as done in DstConf.py)
+
+!========================== CaloFutureReco v4r17p1 2009-02-12 =======================
+! 2009-02-12 - Marco Cattaneo for Vanya
+ - Fix FPE occurring in CaloFutureClusterizationTool on ia32 only
+ - Fix some doxygen warnings
+
+!========================== CaloFutureReco v4r17 2009-01-12 =========================
+! 2009-01-09 Olivier Deschamps
+ - FutureCellularAutomatonAlg.cpp : put cluster container before cluster is sorted -
+   to be bakward compatible with CellularAutomaton (-> if not trouble with calo
+   MC-association for DC06 data reconstruced with CellularAutomaton)
+ - options/Brunel.opts : remove CaloFutureClusterCorrect3x3Position/EcalPosition
+   (obsolete, handled by the clusterisation)
+ - options/HltCaloFutureSeq.opts
+   . use FutureCellularAutomatonAlg as default clusterisation algorithm
+     (as already done for offline sequence)
+   . remove obsolete CaloFutureClusterCorrect3x3Position/EcalPosition 
+     (handled by the clusterisation)
+ - options/(Hlt)ClusterSelection.opts : add default protection against negative
+   cluster energy ( e > threshold = 0 )
+ 
+! 2008-10-02 - Olivier Deschamps
+  - fix typo in (HLT)MergedPi0Rec.opts
+
+!========================== CaloFutureReco v4r16 2008-10-02 =========================
+! 2008-10-02 - Olivier Deschamps
+  - fix bad setting in HltClusterSelection.opts
+
+! 2008-09-14 - Olivier Deschamps
+  - new cluster selection tools : 
+    - CaloFutureSelectCluster  : cluster selection with energy and #entries
+    - CaloFutureSelectClusterWithPrs : cluster selection with Prs energy and multiplicity
+    - CaloFutureSelectNeutralClusterWithSpd : cluster selection with Spd hits multiplicity
+    - CaloFutureSelectNeutralClusterWithTracks (replace CaloFutureSelectNeutralCluster)
+  - CaloFutureExtraDigits : use of the new CaloFutureHypo2CaloFuture tool (located inCaloFutureTools)  
+    as CaloFutureSelectClusterWithPrs & CaloFutureSelectNeutralClusterWithSpd 
+    Bonus : the matching now takes the actual calo alignment into account 
+
+  - CaloFutureElectronAlg : remove hardcoded Prs/Spd criteria (use selection tool instead)
+
+  - CellularAutomaton & FutureCellularAutomatonAlg & CaloFutureClusterizationTool : 
+    - fix problem of incomplete  clusteriwation due to rare digits configuration
+    - add statistics printout in finalize()
+    - complete FutureCellularAutomatonAlg (Level property + missing HLT/CaloFuture context)
+    - include the possibility to select digit for energy computation using 
+     CaloFutureUtils/CellSelector (mask by options)  : default '3x3' mask
+     --> CaloFutureClusterCorrect3x3Energy in principle obsolete. 
+     Could be remove from options (To be checked)
+   
+  - FutureCellularAutomatonAlg is now the default in Brunel options (and on-Demand)
+    and replace 'CellularAutomaton' everywhere 
+    (obsolete now and to be remove in the next release)
+
+  - new options :   
+    - (Hlt)ClusterSelection.opts : based on tracks (default)
+    - CaloFutureStandaloneClusterSelection.opts : based on Prs/Spd
+    - CaloFutureStandalonePartialReco.opts : partial reco (no pid) to be used for commissioning
+    - remove ExtraDigits.opts (default setting now in CaloFutureTools/CaloFutureHypo2CaloFuture) 
+    - Et(cluster)>2GeV is now the default for offline MergedPi0 reconstruction (as for Hlt)
+
+  - adapt here and there to change in CaloFutureUtils & CaloFutureTools
+
+!========================== CaloFutureReco v4r15 2008-09-04 =========================
+! 2008-08-14 - Olivier Deschamps
+ - HltCaloFutureSeq.opts : CaloFutureDigits created via the on-Demand service to avoid
+                     conflict with offline processing.
+
+!========================== CaloFutureReco v4r14 2008-07-18 ===================
+! 2008-07-18 - Olivier Deschamps
+ - make the Hlt stream fully independent of the offline sequence in options/
+ - fix missing prefix in CaloFutureOnDemand.opts
+
+!========================== CaloFutureReco v4r13 2008-07-02 ===================
+! 2008-06-27 - Olivier Deschamps
+ - use default HLT locations for the HLT context in all algorithm/tool
+ - Set default location to run the clusterisation sequence on Hcal (depends on the instance name)
+ - new options : HltCaloFutureSeq with setting to run the Reco/PID within HLT framework
+
+! 2008-06-06 - Victor Egorychev
+ - Fix id warning in CelAutoTaggedCell.h
+ - version was increased
+
+!========================== CaloFutureReco v4r12 2008-06-04 ===================
+! 2008-06-04 - Marco Cattaneo
+ - Fix doxygen warning
+
+! 2008-06-03 Olivier Deschamps
+ - change incident type EndEvent to BeginEvent in CaloFutureSelectNeutralCluster.cpp
+   and CaloFutureExtraDigits.cpp
+
+!========================== CaloFutureReco v4r11 2008-04-22 ===================
+! 2008-04-22 - Marco Cattaneo
+ - In CaloFutureRecoOnDemand.opts, replace DataOnDemandSvc.Algorithms with .AlgMap
+
+! 2008-04-21 - Victor Egorychev
+ - New FutureCellularAutomatonAlg.cpp and CellularAtomatonAlg.h were added
+ - New CaloFutureClusterizationTool.cpp and CaloFutureClustrerizationTool.h were added
+ - version was increased
+
+!========================== CaloFutureReco v4r10 2007-12-20 ===================
+! 2007-12-19 - Olivier Deschamps
+ - Fix unprotected array index in CaloFutureMergedPi0.cpp
+   (causes an infinite loop when running in debug mode on amd64)
+
+!========================== CaloFutureReco v4r9 2007-09-20 ===================
+! 2007-08-24 - Olivier Deschamps
+ - Fix the unchecked StatusCodes
+
+!========================== CaloFutureReco v4r8 2007-05-26 ===================
+! 2007-05-26 - Victor Egorychev
+ - options/Brunel.opts, options/BrunelPIDs.opts
+ - added new DLL hist for CaloFuture PIDe/mu (CaloFuturePIDs_DC06_v2.root) in ECAL, HCAL, Prs
+   and Brem
+ - cmt/requirement 
+   version increment to v4r8 
+
+!========================== CaloFutureReco v4r7 2007-03-05 ==========================
+! 2007-03-05 - Marco Cattaneo
+ - Remove LHCbDefinitions includes
+ - Remove obsolete CaloFutureReco_load.cpp file
+ - Remove obsolete ApplicationMgr.DLLs option
+
+!========================== CaloFutureReco v4r6 2006-12-01 ==========================
+! 2006-12-01 - Olivier Deschamps
+ - update CaloFutureECorrection.cpp & CaloFutureECorrectionParam.opts for electron calibration
+
+! 2006-11-28 - Marco Cattaneo
+ - use DECLARE_xxx_FACTORY macros
+ - Remove unneccessary GaudiKernel includes
+
+! 2006-11-28 - Olivier Deschamps
+ - update CaloFutureMergedPi0Alg and CaloFutureXCorrection tools
+ - update MergedPi0Rec.opts
+ - DC06 tuning for merged pi0
+ - version increment to v4r6
+
+!========================== CaloFutureReco v4r5 2006-11-06 ===================
+! 2006-11-06 - Victor Egorychev
+ - options/Brunel.opts, options/BrunelPIDs.opts
+ - added new DLL hist for CaloFuture PIDe/mu (CaloFuturePIDs_DC06_v1.root) in ECAL, HCAL, Prs
+   for different types of tracks
+ - old hist for Brem PIDe (CaloFuturePIDs.root)
+ - cmt/requirement 
+   version increment to v4r5 
+
+! 2006-10-27 - Olivier Deschamps
+ - Preliminary setting for DC06 (CaloFutureECorrections.opts)
+ - fix Cluster CaloFuturePosition in CaloFutureMergedPi0Alg.cpp
+ (was undefined  when  cluster on-Demand is requested).
+
+!========================== CaloFutureReco v4r4 2006-10-17 ===================
+! 2006-10-17 - Olivier Deschamps
+ - fix CaloFutureMergedPi0Alg 
+! 2006-10-13 - Olivier Deschamps
+ - Modify CaloFutureMergedPi0Alg to allow the separate creation of CaloFutureClusters and CaloFutureHypos
+ - Add DVCaloFutureRecoOnDemand.opts : CaloFutureDigits and CaloFutureClusters on-Demand for DaVinci usage
+
+!========================== CaloFutureReco v4r3 2006-09-08 ===================
+! 2006-09-07 - Olivier Deschamps
+ - Remove CaloFutureBank.opts (moved to CaloFutureDAQ as CaloFutureBanksHandler.opts)
+
+!========================== CaloFutureReco v4r2 2006-07-19 ===================
+! 2006-07-19 - Marco Cattaneo
+ - Fix constructor in CaloFutureClusterCorrect3x3Position, for Gaudi v18r6
+ - Fix Brunel.opts for pedantic new options parser
+
+! 2006-07-18 - Olivier Deschamps
+ - Fix SVector constructor in CaloFutureClusterCorrect3x3Position.cpp
+
+!========================== CaloFutureReco v4r1 2006-06-28 ===================
+! 2006-06-27 - Olivier Deschamps
+  - 3rd step of the migration towards DC06 software : repackaging
+  - remove obsolete tools (CaloFuture-Track matching stuff rewritten in CaloFuturePIDs)
+  - move CaloFutureSingleGammaTool/CaloFuturePhotonEstimatorTool to CaloFuturePIDs/
+  - adapt to change in RecEvent (enums)
+  - simplify the dependency in cmt/requirements (remove TrackXX/LHCbMath dependency)
+  - increment the release number in cmt/requirements 
+
+!========================== CaloFutureReco v4r0 2006-06-22 ===================
+! 2006-06-21 - Vanya BELYAEV
+ - introduce a bit more hierarchy into CaloFuture-sequence.
+
+! 2006-06-20 - Olivier Deschamps
+ - new CaloFutureReco/CaloFuturePIDs sequence in Brunel.opts
+ - add options/UseForwardTracksOnly.opts
+ - THERE ARE OBSOLETE TOOLS SINCE NEW CALOFUTUREPIDS IS AVAILABLE
+   WILL BE REMOVED IN NEXT RELEASE.
+
+! 2006-06-14 - Olivier Deschamps
+ - 2nd step of the migration towards DC06 software : cleaning + debugging
+ - Adapt to changes in LHCb v21r1 
+ - re-implement CaloFutureSinglePhotonAlg tools required by NeutralProtoPAlg
+ - add temporarly CaloFuturePhotonEstimatorTool (moved from CaloFuturePID) + options/PhotonPDF.opts
+   in order NeutralProtoPAlg can run work without CaloFuturePID.
+ - increment release number in cmt/requirements
+ - Final version to be reelased with next CaloFuturePID version.
+
+! 2006-05-29 - Olivier Deschamps
+ - first step of the migration towards DC06 software.
+  - package adapted to new Event Models, new MathLib, 1MHW DAQ, ...
+  - Cleaning of obsolete tools/algorithms
+
+!========================== CaloFutureReco v3r0 2005-11-04 ===================
+! 2005-11-04 - Olivier Deschamps
+ - Adapt to new Track Event Model (TrackEvent v1r4)
+
+  modified file :  
+   src/CaloFutureTrackMatchPhoton.h
+   src/CaloFutureTrackMatchElectron.h
+   src/CaloFutureTrackMatchBremm.h
+   src/CaloFutureTrackMatchBrem2.h
+   src/CaloFutureTrackMatchBase.cpp
+   src/CaloFutureSelectNeutralCluster.h
+   src/CaloFutureCluster2TrackAlg.cpp
+   src/CaloFutureHypo2TrackAlg.cpp
+
+ - cmt/requirements 
+   version increment to v3r0
+!============================ CaloFutureReco v2r9 2005-06-02 ========================
+! 2005-06-02 - Marco Cattaneo
+ - Adapt Brunel.opts to new phase name Reco instead of BrunelReco
+
+!=========================== CaloFutureReco v2r8p2 2005-05-24 =======================
+! 2005-05-24 - P. Koppenburg
+ - options/CaloFutureReCorrections.opts
+   . New options: Moved from DaVinci
+
+!=========================== CaloFutureReco v2r8p1 2005-05-24 =======================
+! 2005-05-24 - P. Koppenburg
+ - options/CaloFutureRecoOnDemand.opts
+   . Fix typo in /Event/Rec/CaloFuture/ElectronMatch (no "n")
+   
+!=========================== CaloFutureReco v2r8 2005-05-09 =========================
+! 2005-05-06 - Vanya BELYAEV
+
+ - src/CaloFutureTrackAlg.h src/CaloFutureTrackAlg.cpp,
+     files are moved into CaloFuture/CaloFutureUtils package 
+ 
+ - src/CaloFutureCluster2TrackAlg.h, 
+     remove this file
+
+ - src/CaloFutureHypo2TrackAlg.h, 
+   src/CaloFutureCluster2TrackAlg.cpp 
+     files are updated for new location of CaloFutureTrackAlg.h
+     and removal of src/CaloFutureCluster2TrackAlg.h
+
+ - options/CaloFutureRecoOnDemand.opts
+     the prototype (INVALID NOW) for future "CaloFuture-Reco-On-Demand"
+
+ - cmt/requirements
+     version incremement to v2r8 
+
+!========================= CaloFutureReco v2r7p1 2005-03-07 ==================
+! 2005-03-07 - Marco Cattaneo
+ - Fix many doxygen warnings
+
+! 2005-02-17 - Vanya BELYAEV
+ - options/NeutralCluster.opts 
+ - options/ChargedCluster.opts 
+           fix for new associators 
+ - cmt/requirements 
+           version incement to v2r7p1 
+
+!========================== CaloFutureReco v2r7 2004-12-13 ===================
+! 2004-12-13 - Marco Cattaneo
+ - Fix some doxygen warnings
+
+! 2004-12-10 - Ivan BELYAEV
+ - add new algorithm: few more steps to 'Fast' (a'la HLT) CaloFuturerimeter 
+   reconstruction 
+     - CaloFutureHypo2TrgTrackAlg.h,.cpp
+     - CaloFutureTrgSelectNeutralCluster.h,.cpp
+ - cmt/requirements 
+    version increment to v2r7 
+
+!========================== CaloFutureReco v2r6 2004-10-27 ===================
+! 2004-10-27 - Vanya BELYAEV
+ - src/CaloFutureTrackAlg.h, src/CaloFutureTrackAlg.cpp
+    the algorithm is modified to take advantage from 
+    new class TrTrackUse from CaloFuture/CaloFutureUtils package 
+ - src/CaloFutureMergedPi0Alg.h, src/CaloFutureMergedPi0Alg.cpp
+
+    new property "EtCut" is added to skip the processing of 
+    clusters with small transverse energy.
+    The default value of this oproperty is -100*GeV
+   (which implies "NO CUT", and "BACKWARD-COMPATIBILITY" 
+    in the sense of absolute reproducibility of results). 
+    The idea comes from Olivier Deschamps and Cristina Carloganu.
+
+    Another new property "MaxIterations" is added to reduce the 
+    number of iterations 
+    The default value (16) is "BACKWARD-COMPATIBLE"
+    The idea comes from Olivier Deschamps and Cristina Carloganu.
+
+    In addition few "tiny" modification are applied:
+      - remove "count" loop 
+      - location of spddigits and prs digits are moved from internal loop
+        to a top level 
+
+    The usage of EtCut=1.5*GeV and MaxIteration=6 togather with 
+    these 'technical' optimizations  
+    speeds up the execution of the algorithm approxmately 20 times.
+
+
+ The package *REQUIRES* : 
+  - CaloFuture/CaloFutureUtils with versions >= v4r8 
+  - CaloFuture/CaloFutureEvent with version  >= v13r6  
+
+
+! 2004-10-26 - Vanya BELYAEV
+ - src/CaloFutureCluster2TrackAlg.h, src/CaloFutureCluster2TrackAlg.cpp
+ - src/CaloFutureHypo2TrackAlg.h, src/CaloFutureHypo2TrackAlg.cpp
+     update in properties for better dealing with track types 
+   it is done with the helper algorithm base CaloFutureTrackAlg,
+   which allow to select/reject a certain track categories 
+   according to 
+      - general criteria (unique?error?),
+      - track categories ( is'*'?)
+      - algorithms ('*'?)
+- options/BremMatch.opts
+- options/Brem2Match.opts
+   update the configuratin files for new property names 
+
+! 2004-10-26 - Vanya BELYAEV
+ - introduce FAST "photon" matching of trigger track (TrgTrach) with 
+   CaloFuturetrimeter clusters. For a moment follow "off-line" phylosophy:
+   perfroam all-to-all mathcing and save result as a relation table 
+   in TES. The supporting algorithm CaloFutureCluster2TrgTrackAlg does this job.
+   The execution is 5-6 times faster than the execution of 
+   "standard" photon matching. The efficiency need to be testes 
+   and studied.
+   In real environment one coudl gain addiitonal factor of 2
+   (since if one uses this "o nly" fo select neutral clusters - "photons")
+   one does not need all-to-all matching (and one does not need to 
+   register the table in TES!),  one just che the existence of 
+   tracks with chi2<cut, which should be "fast" procedure.  
+
+
+! 2004-10-24 - Vanya BELYAEV
+ - src/CaloFutureTrackMatchBrem2.h
+   src/CaloFutureTrackMatchBrem2.cpp
+   src/CaloFutureReco_load.cpp
+     add new 'tool' for (hopefully) improved 'bremstrahlung' matching.
+     the tool need to be tested with *LARGE* statistics 
+ - options/Brem2Match.opts 
+     new file for 'Brem2Match' algorithm configuration 
+ - options/BremMatch.opts
+     add 'include' for new file Brem2Match.opts  
+
+! 2004-10-24 - Vanya BELYAEV
+ -  src/CaloFutureTrackMathcPhotonAlg.cpp
+    src/CaloFutureTrackMathcPhotonAlg.h
+    src/CaloFutureReco_load.cpp
+       remove obsolete algorithm
+ -  src/CaloFutureTrack*.cpp 
+       improve a little bit the error-reporting printout
+
+! 2004-10-22 - Vanya BELYAEV
+ - src/CaloFutureTrackMatchBase.h
+   src/CaloFutureTrackMatchBase.cpp
+
+   1) modify the internal match structure MatchStruct1 
+      to invert the matrix in the constructor 
+   2) modify the internal chi2 method to be more efficient 
+      (eliminate the intermediate matrices) 
+   3) introduce local matrix storage
+   4) itoriducet mtrxOp methods for fast evaluation of matrix products 
+
+       in overall (142) gives >10% impromevent in CPU performance 
+
+   5) introduce new internal structure MatchStruct2 
+   6) introduce set of new "chi2" methods dealing with MatchStruct2 
+  
+        (5) and (6) are the steps toward HLT matching 
+
+ - src/CellularAutomaton.cpp
+   change the Error-Code for 'uclusterized cells' warning message 
+   from FAILURE to SUCCESS to redice a bit the potential confusion 
+ 
+! 2004-10-22 - Vanya BELYAEV
+
+   (requires the recent modifications in Event/CaloFutureEvent  >= 13r6 ) 
+
+ - src/CellularAutomaton.h
+   src/CellularAutomaton.cpp
+   
+     The algorithm gas got 2 new properties 
+   "Sort"     (boolean, default = true ) - the flag which indicates wether 
+                                           the sorting of clusters should 
+                                           be performed
+   "SprtByET" (boolean, default = false) - the flag which indicates 
+                                           which sorting criteria (energy 
+                                           versus transverse energy) is used 
+                                           for sorting
+
+   The default settings corresponds to "backward-compatibility"
+
+  - src/CaloFutureDeleteObject.h, src/CaloDeteleObject.cpp  
+    remove the obsolete algorithm
+      one should use TESFilter algorithm from  Kernel/LHCbAlgs package
+
+  - src/CaloFutureCheckObjects.h, src/CaloFutureCheckObjects.cpp  
+    remove obsolete algorithm
+      one should use TESCheck algorithm from  Kernel/LHCbAlgs package 
+  - src/CaloFutureReco_load.cpp
+    remove the factory instantiations for removed obsolete algorithms 
+
+  - cmt/requirements 
+   version increment to v2r6 
+
+!======================= CaloFutureReco v2r5 2004-09-08 ======================
+! 2004-09-08 - Marco Cattaneo
+ - Remove associator factories from CaloFutureReco_load.cpp, as these have been
+   move to Associators/Associators package
+
+! 2004-09-05 - Vanya BELYAEV
+  - src/CelAutoTaggedCell.h
+    src/CellularAutomaton.h
+    src/CellularAutomaton.cpp
+   trivial modification to obtain 25% CPU gain 
+
+! 2004-09-05 - Vanya BELYAEV
+ - src/CaloFutureCheckObjectsAlg.h(.cpp)
+   new trivial algorithm for checking the existence 
+   (and by product, the loading!) of objects in Gaudi transient store 
+ - src/CaloFutureReco_load.cpp
+   add the decalration of the new algorithm 
+
+! 2004-09-02 - Vanya BELYAEV
+ - prepare for HLT/Trigger developments 
+
+!======================= CaloFutureReco v2r4 2004-07-22 ======================
+! 2004-07-21 - Vanya BELYAEV
+
+ - src/CaloFutureClusterCorrect3x3Position.cpp 
+    1. fix compilation warnings 
+ - src/CaloFuture04ECorrection.cpp 
+    1. fix compilation warnings 
+    2. add 'info' printout for accepter hypos 
+    3. suppress excessive 'INFO' printout 
+    4. add 'EmCharged' to the list of accepted hypos 
+ - src/CaloFuture04SCorrection.cpp 
+    1. fix compilation warnings 
+    2. add 'EmCharged' to the list of accepted hypos 
+    3. add 'info' printout for accepter hypos 
+ - src/CaloFuture04LCorrection.cpp 
+    1. fix compilation warnings 
+    2. add 'info' printout for accepter hypos 
+    3. add 'EmCharged' to the list of accepted hypos 
+
+            ****** ALL MODIFICATIONS ARE BACKWARD COMPATIBLE ****** 
+
+ - cmt/requirements   
+    1. increment the version to v2r4 
+
+! 2004-07-20 - Vanya BELYAEV
+ - CaloFutureMergedPi0Alg.cpp 
+   1. make a fix for segmentation fault for 
+   3-cell cluster at the edge of calorimeter, where 
+   only seed digit has positive energy. 
+   For this case "subrow" and "subcol" values were not defined
+   it result in SubClus[1][1][1] = NULL and a further segmentation 
+   fault. 
+   2.  Few minor fixes to suppress compiler warnings about 
+       the unused variables 
+ - cmt/requirements  increment the version to v2r3p2 
+   
+!======================= CaloFutureReco v2r3p1 2004-06-03 ======================
+! 2004-06-03 - Ivan Belyaev
+ - src/CaloFutureReco_load.cpp
+   . Missing algorithm
+ - tagged as v2r3p1
+!======================== CaloFutureReco v2r3 2004-06-03 =======================
+! 2004-06-03 - Ivan Belyaev
+ - src/CaloFutureE0Correction.cpp
+  new version of energy corrections for DC04 
+ - src/CaloFutureClusterCorrect3x3Position.cpp(.h)
+  position correction for DC04 
+ - options/CaloFuture04ECorrection.opts 
+  updated parameters for corrections 
+ - cmt/requirement  increment teh version to v2r3 
+
+
+!======================== CaloFutureReco v2r2 2004-06-02 =======================
+! 2004-05-11 - Vanya BELYAEV
+
+- src/CaloFuture04ECorrection.cpp 
+   modification of energy correction tool to be used for analysis 
+   of DC04 data (produced with XmlDDDB >= v22r2 ) from Oliver Deschamps
+- options/CaloFuture04*.opts 
+   new parameters foe E/S/L corrections to be used for DC04 data 
+   from Olivier Deschamps 
+- cmt/requirements 
+   increment the version to v2r2 
+ 
+!======================= CaloFutureReco v2r1p1 2004-03-29 ======================
+! 2004-03-29 - Marco Cattaneo
+ - Fix Reco.opts to avoid multiple inclusion of options files
+
+!======================== CaloFutureReco v2r1 2004-03-18 =======================
+! 2004-03-17 - Vanya BELYAEV
+  - add new (04) Correction s from Olivier Deschamps
+  - remove some obsoltee stuff from 'options' directory
+  - few minor fixes 
+  - cmt/requirements increment the version to v2r1 
+
+!======================== CaloFutureReco v2r0 2004-03-08 =======================
+! 2004-03-08 - Marco Cattaneo
+ - In CaloFutureCluster2TrackAlg.h/cpp, CaloFutureHypo2TrackAlg.h/cpp:
+   . rename m_upstream to m_downstream
+   . rename UseUpstream property to UseDownstream 
+   . use new isDownstream() method of TrStoredTrack instead of upstream()
+
+ - In CaloFutureTrackMatchBase.cpp, CaloFutureTrackMatchBremm.cpp, CaloFutureTrackMatchElectron.cpp
+   . use new isDownstream() method of TrStoredTrack instead of upstream()
+
+ - In BremMatch.opts, ElectronMatch.opts, HcalPIDe.opts, PhotonMatch.opts
+   . rename UseUpstream property to UseDownstream 
+
+! 2004-02-17 - Ivan BELYAEV
+ - update for new CaloFuture/CaloKernel and CaloFuture/CaloFutureInterface  
+ - increase teh *MAJOR* version to v2r0 
+
+!======================== CaloFutureReco v1r8 2004-01-13 =======================
+! 2004-01-13 - Vanya BELYAEV
+ - src/CellularAutomaton.cpp 
+ - src/CaloFutureMergedPi0Alg.cpp    
+             1) initialize new data field "seed" for the CaloFutureCluster 
+             2) set version (==2) for new container of Clusters 
+
+!======================== CaloFutureReco v1r7 2003-12-11 =======================
+! 2003-12-11 - Marco Cattaneo
+ - Move to Gaudi v13, VC71 
+   . requirements: use CaloFutureInterfaces v3r0
+   . Remove WIN32 implementations of std::max and std::min
+
+ - Fix some doxygen warnings
+
+!======================= CaloFutureReco v1r6p1 2003-06-23 =======================
+! 2003-11-27 - Marco Cattaneo
+ - Add workarounds for missing != operator in new CaloFutureCellID from Xml
+
+!======================== CaloFutureReco v1r6 2003-06-23 ========================
+! 2003-06-23 - Ivan Belyaev
+ - Few fixes for new compiler 
+
+! 2003-05-15 - Vanya BELYAEV
+ - src/CaloFutureSinglePhotonAlg.cpp 
+ - src/CaloFutureElectronAlg.cpp         
+    in the case of errors in used tools, the cluster/hypo is skipped now 
+    (no error return)   
+ - cmt/requirments                 increase the version 
+
+!====================== CaloFutureReco v1r5 2003-04-30 ==========================
+! 2003-04-11 - Vanya BELYAEV
+   new files:
+ - src/CaloFutureNewECorrection.h,.cpp        new Energy correction from O. Deschamps
+ - src/CaloFutureNewSCorrection.h,.cpp        new S-correctin tool from O.Deschamps 
+ - src/CaloFutureNewLCorrection.h,.cpp        new L-correction tool from O.Deschams
+ - options/CaloFutureNewECorrectionParam.opts parameters
+ - options/CaloFutureNewSCorrectionParam.opts parameters
+ - options/CaloFutureNewLCorrectionParam.opts parameters 
+   modified:
+ - src/CaloFutureReco_load.cpp                add new tools 
+ - cmt/requirements                     increse the version to v1r5 
+
+! 2003-04-08 - Vanya BELYAEV
+ - src/CaloFutureHyposMerge.cpp    Add split photons (CaloFutureHypoLocation::SplitPhotons)
+                             to the default list of "merged" hypos 
+
+!====================== CaloFutureReco v1r4 2003-03-24 ==========================
+! 2003-03-13 - Vanya BELYAEV
+ - move *ALL* PID algorithms and tools into new package CaloFuturePIDs 
+ - increase the version to v1r4 
+ - src/CaloFutureMergedPi0Alg.cpp  -   <<<<<<<<<<< VERY IMPORTANT BUG FIX >>>>>>>>>>>> 
+   For merged pi0s "the first" split photons gets the extra cluster 
+   and "the second one" gets only native/merged cluster 
+ - src/CaloFutureHypoReShuffleAlg.h,.cpp new algorithm to fix the bug 
+ - cmt/requirements          - increase the version 
+
+
+! 2003-02-24 - Richard Beneyton
+ - src/CaloFutureSCorrectionFinal.cpp   - re use covariance DEFINITION for S correction
+                                  - update covariance for border special correction
+
+!======================== CaloFutureReco v1r3p1 2003-02-13 ======================
+! 2003-02-11 - Ivan BELYAEV
+ - src/CaloFutureSingleGammaTool.cpp    - add protection against MergedPi0s, which have no 
+                                    CaloFuturePosition* field and reduce the debug printout 
+ - cmt/requirements               - increase the version number 
+
+!======================== CaloFutureReco v1r3 2003-02-04 ========================
+
+! 2003-02-04 - Ivan BELYAEV
+  - src/CaloFutureSingleGammaTool.h,.cpp - updated version of the tool by Frederic MACHEFERT
+  - src/CaloFuturePrsCorrection.h        - improve calibration formula 
+  - options/PrsCorrE.opts          - new calibration constants for electrons 
+  - options/PrsCorrG.opts          - new calibration constants for photons
+  - options/Brunel.opts            - reshuffling of "PIDs" algorithms 
+  - cmt/requirements               - increase the version 
+
+! 2003-01-31 - Richard Beneyton
+ - src/CaloFutureSCorrectionFinal    - update function, add border and covariance
+ - src/CaloFutureLCorrectionSimplev  - update function
+ - options/LCorrectionSimple   - define parameter 
+ - options/SCorrectionFinal    - define parameter
+
+!======================= CaloFutureReco v1r2p1 2003-01-23 =======================
+! 2003-01-22 - Ivan BELYAEV 
+ - src/CaloFutureExtraDigits.h         - tiny fix 
+                                   remove unused variable
+  
+! 2003-01-19 - Ivan Belyaev
+ - src/CaloFutureTrackEval.cpp       - fix small "memory leak" (1 TrState per job)
+
+
+!========================= CaloFutureReco v1r2 2002-12-09 =====================
+! 2002-12-09 - Ivan Belyaev
+ - Various bug fixes to Electron and Photon Algs
+
+! 2002-11-22 - Florence Ranjard
+ - requirements - use new versions
+
+!======================== CaloFutureReco v1r1 2002-12-02 =====================
+! 2002-11-29 - Ivan Belyaev
+ - cmt/requirements               version update 
+ - src/CaloFutureTrackEval.h,.cpp       new generic tool for Spd/Prs/Ecal/HCal 
+                                  energy evaluation for given track by V.Romanovsky
+                                  default parameters configured for Hcal 
+ - src/CaloFutureTrackMatchBremm.h,.cpp improved error printout 
+ - src/CaloFutureSCorrectionFinal.cpp   check the position before using it 
+  CONFIGURATION
+ - options/PhotonRec.opts         switch OFF S-corrections by R.Beneyton 
+                                  a) no covarioance matrix yet 
+                                  b) no border treatment
+                                  use 2TANH correction from K.Beloous
+ - options/SShape2Tanh.opts       new (tuned) parametrisations from S-corrections
+
+ - options/ElectronRec.opts       switch OFF S-corrections by R.Beneyton 
+                                  use 2TANH correction from K.Beloous
+
+! 2002-11-20 - Richard Beneyton
+ - Add parabolic modilisation in CaloFutureLCorrectionSimple
+   with updated parameters
+
+!======================== CaloFutureReco v1r0 2002-11-18 =====================
+! 2002-11-18 - Marco Cattaneo
+ - Add missing factory for CaloFutureSCorrectionFinal Tool
+ - Add missing factory for CaloFutureHyposMerge algorithm
+
+! 2002-11-18 - Ivan Belyaev
+ - options/Brunel.opts    quick fix to remove Hcal estrimators 
+ - options/PrsPID*.opts   remove "pragma" directives used for debugging 
+
+! 2002-11-17 - Ivan Belyaev 
+  - src/CaloFutureSCorrectionFinal.cpp  - add missing std::max fro WIN32 compilation
+! 2002-11-17 - Ivan Belyaev
+ - src/CaloFutureTrackIdEval.cpp,.h     - remove these prototypes 
+ - CaloFutureTrack2EstimatorAlg.cpp,.h  - new generic algorithm for building the 
+                                    generic relations of tracks and 
+                                    some caloriemter estimators
+                                    (e.g. energy in Hcal or energy in Prs)
+ - CaloFutureTrack2IdAlg.cpp, .h        - new generic algorithm to build 
+                                    the actual PID estimators from 
+                                    measured values using reference 
+                                    "Signal" and "Background" distributions 
+
+ - CaloFutureTrackEcalEval.cpp,.h      - concrete tool, which frm given chi2 table
+                                    gets Ecal estimator 
+ - CaloFutureTrackHcalEval.cpp,.h      - prototype of concrete tool, which evaluates 
+                                   the energy in Hcal for given track 
+ - CaloFutureTrackPrsEval.cpp,.h       - concrete tool, which evaluates 
+                                   the energy in Prs for given track 
+
+ - options/*.opts                - a lot of new configuration options, 
+                                   need to ne tuned next week 
+ 
+! 2002-11-14 - Richard Beneyton
+ - Update L Correction coeff and calcul in CaloFutureLCorrectionSimple
+   with default parameters in code (supressed in option file)
+ - Add CaloFutureSCorrectionFinal with hardcoded default coeff 
+   supressed in option file)
+   rq.: alg not based on CaloFutureSCorrectionSequence due to special 
+    energies definition
+
+! 2002-10-31 - Ivan Belyaev
+ - New package 
+ - All algorithms from CaloFutureAlgs,CaloFutureRec,CaloFutureTools,CaloFutureTrackTools 
+	are grouped together 
diff --git a/CaloFuture/CaloFutureReco/options/Brunel.opts b/CaloFuture/CaloFutureReco/options/Brunel.opts
new file mode 100755
index 0000000000000000000000000000000000000000..88848e4bb00d04f47d4596ddad34a5cebb785c71
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/options/Brunel.opts
@@ -0,0 +1,124 @@
+// $Id: Brunel.opts,v 1.29 2010-04-29 21:13:59 odescham Exp $ 
+// ============================================================================
+// CVS tag $Name: not supported by cvs2svn $, version $Revision: 1.29 $ 
+// ============================================================================
+
+/** @file
+ *  The job-options file to run  CaloFuturerimeter Reconstruction in Brunel
+ *  @author    Olivier Deschamps odescham@in2p3.fr
+ *           & Vanya Belyaev     Ivan.Belyaev@cern.ch
+ *  @date 2006-26-05
+ */
+
+// The main stream :
+RecoCALOFUTURESeq.Members +=     { 	"GaudiSequencer/CaloFutureDigits" ,
+                              //"CaloFutureGetterInit/CaloFutureDigitGetter", // NO LONGER NEEDED
+                              "GaudiSequencer/CaloFutureClusters",
+                              "GaudiSequencer/CaloFutureTrackMatch" ,
+                              "GaudiSequencer/CaloFutureRec",
+                              "GaudiSequencer/CaloFuturePIDs" };
+
+//------ Unpack the rawBanks & create CaloFutureDigit on TES 
+CaloFutureDigits.Members = {  "CaloFutureZSupAlg/FutureEcalZSup",                 
+                        "CaloFutureZSupAlg/FutureHcalZSup",                  
+                        "CaloFutureDigitsFromRaw/FuturePrsFromRaw",        
+                        "CaloFutureDigitsFromRaw/FutureSpdFromRaw"};
+
+
+//------ Clusterize, clean & compute cluster parameters 
+CaloFutureClusters.Members += { "CaloFutureDigitFilterAlg/CaloFutureDigitFilter",
+                          "FutureCellularAutomatonAlg/EcalClust",
+                          "CaloFutureSharedCellAlg/EcalShare",
+                          "CaloFutureClusterCovarianceAlg/EcalCovar"};
+
+//------ Track-Cluster 2D matching for Neutral/Charged cluster selection
+
+CaloFutureTrackMatch.Members +=     { "GaudiSequencer/CaloFutureAcceptance",
+                                "FuturePhotonMatchAlg/ClusterMatch"   } ;
+
+//------ Acceptance Filters
+CaloFutureAcceptance.Members = { "InSpdFutureAcceptance     Alg/InSPD" ,
+                           "InPrsFutureAcceptance     Alg/InPRS" ,
+                           "InEcalFutureAcceptance    Alg/InECAL", 
+                           "InHcalFutureAcceptance    Alg/InHCAL" ,
+                           "FutureInBremFutureAcceptanceAlg/InBREM" };
+
+
+//------ Merged Pi0, Single Photon & Electron reconstruction
+
+CaloFutureRec.Members += {"CaloFutureMergedPi0Alg/MergedPi0Rec", 
+                    "CaloFutureHypoAlg/PhotonFromMergedRec",
+                    "CaloFutureSinglePhotonAlg/SinglePhotonRec",
+                    "CaloFutureElectronAlg/ElectronRec"};
+
+
+#include "$CALOFUTURERECOOPTS/ClusterSelection.opts" 
+#include "$CALOFUTURERECOOPTS/MergedPi0Rec.opts"
+#include "$CALOFUTURERECOOPTS/PhotonFromMergedRec.opts"
+#include "$CALOFUTURERECOOPTS/SinglePhotonRec.opts" 
+#include "$CALOFUTURERECOOPTS/ElectronRec.opts" 
+// Configure Tools
+#include "$CALOFUTURERECOOPTS/CaloFutureECorrectionParam.opts"  
+#include "$CALOFUTURERECOOPTS/CaloFutureSCorrectionParam.opts"  
+#include "$CALOFUTURERECOOPTS/CaloFutureLCorrectionParam.opts"
+
+//------- Track- charged/neutral cluster 3D matching for electron/bremStrahlung evaluation
+
+CaloFuturePIDs.Members +=  
+  { 
+    // 3D Matching	
+		"GaudiSequencer/CaloFutureMatch"
+      // Energy Deposit along track path
+      ,"GaudiSequencer/CaloFutureEnergy"
+      // CaloFutureID DLL's
+      ,"GaudiSequencer/CaloFutureDLLs"
+      // Neutral IDs
+      ,"GaudiSequencer/NeutralPIDs"
+  } ;
+
+NeutralPIDs.Members += {
+  "CaloFuturePhotonIdAlg/PhotonID",
+    "CaloFuturePhotonIdAlg/MergedID",
+    "CaloFuturePhotonIdAlg/SplitPhotonID"
+    };
+
+MergedID.Type = "MergedID";
+SplitPhotonID.Type= "PhotonFromMergedID";
+
+CaloFutureMatch.Members +=
+  {
+    "FutureElectronMatchAlg/ElectronMatch"
+    ,"BremMatchAlg/BremMatch"        
+  };
+CaloFutureEnergy.Members = 
+  {
+    "FutureTrack2SpdEAlg/SpdE"
+    ,"FutureTrack2PrsEAlg/PrsE"
+    ,"FutureTrack2EcalEAlg/EcalE"
+    ,"FutureTrack2HcalEAlg/HcalE"
+  };
+CaloFutureDLLs.Members += 
+  {
+    // convert tables into plain Chi2's
+      "FutureEcalChi22ID"
+    , "BremChi22ID"
+    , "FutureClusChi22ID"
+    // evaluate proper DLL
+    , "FuturePrsPIDeAlg/PrsPIDe" 
+    , "BremPIDeAlg/BremPIDe" 
+    , "FutureEcalPIDeAlg/EcalPIDe" 
+    , "FutureHcalPIDeAlg/HcalPIDe" 
+    , "FutureEcalPIDmuAlg/EcalPIDmu" 
+    , "FutureHcalPIDmuAlg/HcalPIDmu" 
+  };
+
+
+CaloFutureDigits.MeasureTime     = true ;
+CaloFutureClusters.MeasureTime   = true ;
+CaloFutureTrackMatch.MeasureTime = true ;
+CaloFutureRec.MeasureTime        = true ;
+CaloFuturePIDs.MeasureTime       = true ;
+CaloFutureAcceptance.MeasureTime = true ;
+CaloFutureMatch.MeasureTime     = true ;
+CaloFutureEnergy.MeasureTime     = true ;
+CaloFutureDLLs.MeasureTime       = true ;
diff --git a/CaloFuture/CaloFutureReco/options/CaloFutureECorrectionParam.opts b/CaloFuture/CaloFutureReco/options/CaloFutureECorrectionParam.opts
new file mode 100755
index 0000000000000000000000000000000000000000..07c14c15de3423e8cccf817cf3ce5ebcd547c9fc
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/options/CaloFutureECorrectionParam.opts
@@ -0,0 +1,51 @@
+// MC-based paramatrisation for CaloFutureECorrection (to be re-evaluated for recent MC).
+// to be applied on MC data - Real data correction come with condDB
+
+// Single Photon ===========================
+SinglePhotonRec.ECorrection.Parameters += {
+  //              function   #param     params :    outer | middle | inner
+    "alphaG"     : { 0      ,     1    ,               1.0          , 1.0         ,  1.0           },
+    "alphaE"     : { 0      ,     2    ,               1.0105       , 1.0208      ,  1.0325   ,              
+                                                       0.11561E-06  , 0.33802E-07 , -0.28272E-07   },
+    "alphaB"     : { 0      ,     2    ,               1.0159       , 1.0210      ,  1.0256    ,             
+                                                      -0.67500E-01  ,-0.78525E-01 , -0.8901E-01    },
+    "alphaX"     : { 0      ,     2    ,        1,1,1, 0.     , 0.0171 ,  0.0315   },
+    "alphaY"     : { 0      ,     2    ,        1,1,1, 0.     , 0.0362 ,  0.0479   },
+    "beta"       : { 1      ,     1    ,               8.3    , 8.8    ,  9.5      },
+    "globalC"    : { 0      ,     1    ,               0.977  , 0.977  ,  0.977    }
+};
+
+
+// Photon from MergedPi0  ===========================
+PhotonFromMergedRec.ECorrection.Parameters += {
+  //              function   #param     params :    outer | middle | inner
+    "alphaG"     : { 0      ,     1    ,               1.0          , 1.0         ,  1.0           },
+    "alphaE"     : { 0      ,     2    ,               1.0105       , 1.0208      ,  1.0325   ,              
+                                                       0.11561E-06  , 0.33802E-07 , -0.28272E-07   },
+    "alphaB"     : { 0      ,     2    ,               1.0159       , 1.0210      ,  1.0256    ,             
+                                                      -0.67500E-01  ,-0.78525E-01 , -0.8901E-01    },
+    "alphaX"     : { 0      ,     2    ,        1,1,1, 0.     , 0.0171 ,  0.0315   },
+    "alphaY"     : { 0      ,     2    ,        1,1,1, 0.     , 0.0362 ,  0.0479   },
+    "beta"       : { 1      ,     1    ,               8.3    , 8.8    ,  9.5      },
+    "globalC"    : { 0      ,     1    ,               0.977  , 0.977  ,  0.977    }
+};
+
+
+// Single Electron ===========================
+ElectronRec.ECorrection.Parameters += {
+  //              function   #param     params :    outer | middle | inner
+    "alphaG"     : { 0      ,     1    ,               0.988        , 0.988       ,  0.988         },
+    "alphaE"     : { 0      ,     2    ,               1.0105       , 1.0208      ,  1.0325   ,             
+                                                       0.11561E-06  , 0.33802E-07 , -0.28272E-07   },
+    "alphaB"     : { 0      ,     2    ,               1.0159       , 1.0210      ,  1.0256    ,             
+                                                      -0.67500E-01  ,-0.78525E-01 , -0.8901E-01    },
+    "alphaX"     : { 0      ,     2    ,        1,1,1, 0.     , 0.0171 ,  0.0315   },
+    "alphaY"     : { 0      ,     2    ,        1,1,1, 0.     , 0.0362 ,  0.0479   },
+    "beta"       : { 1      ,     1    ,               8.3    , 8.8    ,  9.5      }
+};
+
+
+
+
+
+
diff --git a/CaloFuture/CaloFutureReco/options/CaloFutureECorrectionParam_Data2010.opts b/CaloFuture/CaloFutureReco/options/CaloFutureECorrectionParam_Data2010.opts
new file mode 100644
index 0000000000000000000000000000000000000000..a9beccbace829b63ba66a31dbe48929f1f609ad0
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/options/CaloFutureECorrectionParam_Data2010.opts
@@ -0,0 +1,48 @@
+// paramatrisation for CaloFutureECorrection as extracted from first 2010 DATA (2010/05/20)
+// should come via condDB - keep options file for further development
+
+
+
+// Single Photon ===========================
+SinglePhotonRec.ECorrection.Parameters += {
+  //              function   #param     params :    outer | middle | inner
+    "alphaG"     : { 0      ,     1    ,               1.0353          , 1.0553         ,  1.1000           },
+    "alphaB"     : { 0      ,     2    ,               1.9984          , 1.0106         ,  1.0152     ,             
+                                                      -0.6635E-01      ,-0.7772E-01     , -0.8811E-01       },
+    "alphaX"     : { 0      ,     2    ,        1,1,1, 0.     , 0.0171 ,  0.0315   },
+    "alphaY"     : { 0      ,     2    ,        1,1,1, 0.     , 0.0362 ,  0.0479   },
+    "beta"       : { 1      ,     1    ,               8.7    , 9.7    , 11.0      },
+    "globalC"    : { 1      ,     1    ,              1.0762  , 1.0545 ,  1.0390   }
+};
+
+
+// Photon from MergedPi0  ===========================
+PhotonFromMergedRec.ECorrection.Parameters += {
+  //              function   #param     params :    outer | middle | inner
+    "alphaG"     : { 0      ,     1    ,               1.1110          , 1.1356         ,  1.2152           },
+    "alphaB"     : { 0      ,     2    ,               1.9984          , 1.0106         ,  1.0152     ,             
+                                                      -0.6635E-01      ,-0.7772E-01     , -0.8811E-01       },
+    "alphaX"     : { 0      ,     2    ,        1,1,1, 0.     , 0.0171 ,  0.0315   },
+    "alphaY"     : { 0      ,     2    ,        1,1,1, 0.     , 0.0362 ,  0.0479   },
+    "beta"       : { 1      ,     1    ,               8.7    , 9.7    , 11.0      },
+    "globalC"    : { 1      ,     1    ,              1.0762  , 1.0545 ,  1.0390   }
+};
+
+
+// Single Electron ===========================
+ElectronRec.ECorrection.Parameters += {
+  //              function   #param     params :    outer | middle | inner
+    "alphaG"     : { 0      ,     1    ,               1.0353          , 1.0553         ,  1.1000           },
+    "alphaB"     : { 0      ,     2    ,               1.9984          , 1.0106         ,  1.0152     ,             
+                                                      -0.6635E-01      ,-0.7772E-01     , -0.8811E-01       },
+    "alphaX"     : { 0      ,     2    ,        1,1,1, 0.     , 0.0171 ,  0.0315   },
+    "alphaY"     : { 0      ,     2    ,        1,1,1, 0.     , 0.0362 ,  0.0479   },
+    "beta"       : { 1      ,     1    ,               8.7    , 9.7    , 11.0      },
+    "globalC"    : { 1      ,     1    ,              1.08379 , 1.07990 ,  1.07923   }
+};
+
+
+
+
+
+
diff --git a/CaloFuture/CaloFutureReco/options/CaloFutureLCorrectionParam.opts b/CaloFuture/CaloFutureReco/options/CaloFutureLCorrectionParam.opts
new file mode 100755
index 0000000000000000000000000000000000000000..f9ea09a084098ad6644fd694e789ef5f91fecec1
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/options/CaloFutureLCorrectionParam.opts
@@ -0,0 +1,36 @@
+//SinglePhotonRec.LCorrection.OutputLevel = 2;
+
+
+SinglePhotonRec.LCorrection.Parameters += {
+  //              function   #param     params :    outer | middle | inner
+    "gamma0"     : { 1      ,     1    ,              22.305  , 19.053    , 17.936     },
+    "gammaP"     : { 2      ,     2    ,               2.04   ,  1.53     ,  1.15 ,
+                                                      -0.0281  , -0.455   , -0.0392    },
+    "delta0"     : { 1      ,     1    ,              49.04   ,  51.87    , 45.54      },
+    "deltaP"     : { 2      ,     2    ,               4.38   ,   4.15    ,  4.02 ,     
+                                                      -0.0247 , -0.0597   , -0.0308    }
+};  
+
+
+ElectronRec.LCorrection.Parameters += {
+  //              function   #param     params :    outer | middle | inner
+    "gamma0"     : { 1      ,     1    ,              22.305  , 19.053    , 17.936     },
+    "gammaP"     : { 2      ,     2    ,               2.04   ,  1.53     ,  1.15 ,
+                                                      -0.0281  , -0.455   , -0.0392    },
+    "delta0"     : { 1      ,     1    ,              49.04   ,  51.87    , 45.54      },
+    "deltaP"     : { 2      ,     2    ,               4.38   ,   4.15    ,  4.02  ,    
+                                                      -0.0247 , -0.0597   , -0.0308    }
+};  
+
+PhotonFromMergedRec.LCorrection.Parameters += {
+  //              function   #param     params :    outer | middle | inner
+    "gamma0"     : { 1      ,     1    ,              22.305  , 19.053    , 17.936     },
+    "gammaP"     : { 2      ,     2    ,               2.04   ,  1.53     ,  1.15 ,
+                                                      -0.0281 , -0.455    , -0.0392    },
+    "delta0"     : { 1      ,     1    ,              49.04   ,  51.87    , 45.54      },
+    "deltaP"     : { 2      ,     2    ,               4.38   ,   4.15    ,  4.02  ,    
+                                                      -0.0247 , -0.0597   , -0.0308    }
+};  
+
+
+
diff --git a/CaloFuture/CaloFutureReco/options/CaloFutureRecoOnDemand.opts b/CaloFuture/CaloFutureReco/options/CaloFutureRecoOnDemand.opts
new file mode 100755
index 0000000000000000000000000000000000000000..646ea86c3eef331422dc45df242e89599f9fe27e
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/options/CaloFutureRecoOnDemand.opts
@@ -0,0 +1,29 @@
+//
+// author : Olivier Deschamps odescham@in2p3.fr
+//
+// Setup the CaloFutureReco on-Demand for DaVinci usage
+//
+
+// CaloFutureDigits on-demand
+#include "$CALOFUTUREDAQROOT/options/CaloFutureDigitsOnDemand.opts"
+
+// CaloFutureClusters on-demand 
+DataOnDemandSvc.AlgMap += {
+  "Rec/Calo/EcalClusters"      : "GaudiSequencer/CaloFutureClusterOnDemand"
+ ,"Rec/Calo/EcalSplitClusters" : "CaloFutureMergedPi0Alg/MergedPi0Rec"
+};
+
+// Add digit sequence in CaloFutureCluster-onDemand to please HLT
+CaloFutureClusterOnDemand.Members += {   "GaudiSequencer/CaloFutureDigitsSeq",
+                                   "FutureCellularAutomatonAlg/EcalClust",
+                                   "CaloFutureSharedCellAlg/EcalShare",
+                                   "CaloFutureClusterCovarianceAlg/EcalCovar",
+                                   "CaloFutureClusterCorrect3x3Position/EcalPosition"};
+#include "$CALOFUTUREDAQROOT/options/CaloFutureDigitsSeq.opts"
+
+//
+MergedPi0Rec.CreateSplitClustersOnly = true;
+#include "$CALOFUTURERECOOPTS/MergedPi0Rec.opts"
+
+// Other CaloFuture objects (CaloFutureHypo, CaloFuturePIDs) are available on DST
+// TODO : matching tables ...
diff --git a/CaloFuture/CaloFutureReco/options/CaloFutureSCorrectionParam.opts b/CaloFuture/CaloFutureReco/options/CaloFutureSCorrectionParam.opts
new file mode 100755
index 0000000000000000000000000000000000000000..b531d42b6fdc6bc41c674cbcaedee91919e4714b
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/options/CaloFutureSCorrectionParam.opts
@@ -0,0 +1,61 @@
+ElectronRec.SCorrection.Parameters = {
+  //                    function   #param     params :    outer | middle | inner
+        "shapeX"    : { 5        ,   1     ,              0.102      , 0.129       , 0.144 },
+        "shapeY"    : { 5        ,   1     ,              0.102      , 0.129       , 0.144 },
+        "residual"  : { 1        ,   8     ,             -0.47496E-03, -0.97712E-05, -0.14401E-03,
+                                                          0.44911    ,  0.33898    ,  0.29037,
+                                                         -0.34187E-01,  0.14566E-01,  0.28848E-01,
+                                                         -9.0335     , -5.9958     , -5.1697,
+                                                          0.46190    , -0.13533    , -0.34664,
+                                                         53.041      , 32.711      , 26.885,
+                                                         -1.2801     ,  0.33460E-01,  0.99928,  
+                                                        -97.865      ,-58.743      ,-45.032},
+        "asymP"     : { 1       ,    3     ,              0.24742E-01, 0.28587E-01, 0.19870E-01,
+                                                          0.11487E-01, 0.11557E-01, 0.38043E-02,
+                                                         -0.32640    ,-0.31548    ,-0.21436},
+        "asymM"     : { 1       ,    3     ,             -0.29386E-01,-0.28587E-01,-0.19870E-01,
+                                                          0.11472E-01, 0.11557E-01, 0.38043E-02,
+                                                          0.35928    , 0.31548    , 0.21436}
+};
+
+SinglePhotonRec.SCorrection.Parameters = {
+  //                    function   #param     params :    outer | middle | inner
+        "shapeX"    : { 5        ,   1     ,              0.102      , 0.129       , 0.144 },
+        "shapeY"    : { 5        ,   1     ,              0.102      , 0.129       , 0.144 },
+        "residual"  : { 1        ,   8     ,             -0.47496E-03, -0.97712E-05, -0.14401E-03,
+                                                          0.44911    ,  0.33898    ,  0.29037,
+                                                         -0.34187E-01,  0.14566E-01,  0.28848E-01,
+                                                         -9.0335     , -5.9958     , -5.1697,
+                                                          0.46190    , -0.13533    , -0.34664,
+                                                         53.041      , 32.711      , 26.885,
+                                                         -1.2801     ,  0.33460E-01,  0.99928, 
+                                                        -97.865      ,-58.743      ,-45.032},
+        "asymP"     : { 1       ,    3     ,              0.24742E-01, 0.28587E-01, 0.19870E-01,
+                                                          0.11487E-01, 0.11557E-01, 0.38043E-02,
+                                                         -0.32640    ,-0.31548    ,-0.21436},
+        "asymM"     : { 1       ,    3     ,             -0.29386E-01,-0.28587E-01,-0.19870E-01,
+                                                          0.11472E-01, 0.11557E-01, 0.38043E-02,
+                                                          0.35928    , 0.31548    , 0.21436}
+};
+
+
+PhotonFromMergedRec.SCorrection.Parameters = {
+  //                    function   #param     params :    outer | middle | inner
+        "shapeX"    : { 5        ,   1     ,              0.102      , 0.129       , 0.144 },
+        "shapeY"    : { 5        ,   1     ,              0.102      , 0.129       , 0.144 },
+        "residual"  : { 1        ,   8     ,             -0.47496E-03, -0.97712E-05, -0.14401E-03,
+                                                          0.44911    ,  0.33898    ,  0.29037,
+                                                         -0.34187E-01,  0.14566E-01,  0.28848E-01,
+                                                         -9.0335     , -5.9958     , -5.1697,
+                                                          0.46190    , -0.13533    , -0.34664,
+                                                         53.041      , 32.711      , 26.885,
+                                                         -1.2801     ,  0.33460E-01,  0.99928, 
+                                                        -97.865      ,-58.743      ,-45.032},
+        "asymP"     : { 1       ,    3     ,              0.24742E-01, 0.28587E-01, 0.19870E-01,
+                                                          0.11487E-01, 0.11557E-01, 0.38043E-02,
+                                                         -0.32640    ,-0.31548    ,-0.21436},
+        "asymM"     : { 1       ,    3     ,             -0.29386E-01,-0.28587E-01,-0.19870E-01,
+                                                          0.11472E-01, 0.11557E-01, 0.38043E-02,
+                                                          0.35928    , 0.31548    , 0.21436}
+};
+
diff --git a/CaloFuture/CaloFutureReco/options/CaloFutureStandaloneClusterSelection.opts b/CaloFuture/CaloFutureReco/options/CaloFutureStandaloneClusterSelection.opts
new file mode 100755
index 0000000000000000000000000000000000000000..32352be144c784bde7b11cfa03fce5ca5785cc6e
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/options/CaloFutureStandaloneClusterSelection.opts
@@ -0,0 +1,27 @@
+//-------------------------------------------
+// Select neutral clusters for Photon hypo
+//-------------------------------------------
+SinglePhotonRec.SelectionTools   = { 
+  "CaloFutureSelectCluster/PhotonClusterSelect",
+  "CaloFutureSelectClusterWithPrs/EcalClusterWithPrs",
+  "CaloFutureSelectNeutralClusterWithSpd/EcalClusterWithNoSpd"
+}; 
+SinglePhotonRec.EcalClusterWithPrs.MinEnergy = 10*MeV ;
+SinglePhotonRec.PhotonClusterSelect.MinEnergy = 150;
+//SinglePhotonRec.PhotonClusterSelect.MaxDigits = 99;
+
+
+//-------------------------------------------
+// Select charged clusters for Electron hypo
+//-------------------------------------------
+ElectronRec.SelectionTools  =  { 
+  "CaloFutureSelectCluster/ElectronClusterSelect",
+  "CaloFutureSelectClusterWithPrs/EcalClusterWithPrs",  
+  "CaloFutureSelectChargedClusterWithSpd/EcalClusterWithSpd"
+};
+ElectronRec.EcalClusterWithPrs.MinEnergy = 10*MeV ;
+ElectronRec.ElectronClusterSelect.MinEnergy = 150;
+//ElectronRec.ElectronClusterSelect.MaxDigits = 99;
+
+
+
diff --git a/CaloFuture/CaloFutureReco/options/CaloFutureStandalonePartialReco.opts b/CaloFuture/CaloFutureReco/options/CaloFutureStandalonePartialReco.opts
new file mode 100755
index 0000000000000000000000000000000000000000..f45c2ffc08a2c102fccfea74c024da20c0ab85b0
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/options/CaloFutureStandalonePartialReco.opts
@@ -0,0 +1,38 @@
+
+PartialRecoCALOFUTURESeq.Members +=     { 	"GaudiSequencer/CaloFutureDigits" 
+                                      ,"GaudiSequencer/CaloFutureClusters"
+                                      ,"GaudiSequencer/CaloFutureRec"
+};
+
+//------ Unpack the rawBanks & create CaloFutureDigit on TES 
+CaloFutureDigits.Members = {  "CaloFutureZSupAlg/FutureEcalZSup",                 
+                        "CaloFutureZSupAlg/FutureHcalZSup",                  
+                        "CaloFutureDigitsFromRaw/FuturePrsFromRaw",        
+                        "CaloFutureDigitsFromRaw/FutureSpdFromRaw"};
+
+
+//------ Clusterize, clean & compute cluster parameters 
+CaloFutureClusters.Members += { "FutureCellularAutomatonAlg/EcalClust",
+                          "CaloFutureSharedCellAlg/EcalShare",
+                          "CaloFutureClusterCovarianceAlg/EcalCovar",
+                          "CaloFutureClusterCorrect3x3Position/EcalPosition"};
+
+
+//------ Merged Pi0, Single Photon & Electron reconstruction
+CaloFutureRec.Members += {"CaloFutureMergedPi0Alg/MergedPi0Rec", 
+                    "CaloFutureHypoAlg/PhotonFromMergedRec",
+                    "CaloFutureSinglePhotonAlg/SinglePhotonRec",
+                    "CaloFutureElectronAlg/ElectronRec"};
+
+//EcalClust.CellSelectorForEnergy = "";
+
+#include "$CALOFUTURERECOOPTS/SinglePhotonRec.opts" 
+#include "$CALOFUTURERECOOPTS/ElectronRec.opts" 
+#include "$CALOFUTURERECOOPTS/MergedPi0Rec.opts"
+#include "$CALOFUTURERECOOPTS/PhotonFromMergedRec.opts"
+#include "$CALOFUTURERECOOPTS/CaloFutureStandaloneClusterSelection.opts"
+#include "$CALOFUTURERECOOPTS/CaloFutureECorrectionParam.opts"  
+#include "$CALOFUTURERECOOPTS/CaloFutureSCorrectionParam.opts"  
+#include "$CALOFUTURERECOOPTS/CaloFutureLCorrectionParam.opts"
+
+
diff --git a/CaloFuture/CaloFutureReco/options/ClusterSelection.opts b/CaloFuture/CaloFutureReco/options/ClusterSelection.opts
new file mode 100755
index 0000000000000000000000000000000000000000..a377e4a8697fa4eae93d64f671a3eaac7983fad4
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/options/ClusterSelection.opts
@@ -0,0 +1,28 @@
+//-------------------------------------------
+// Select neutral clusters for Photon hypo
+//-------------------------------------------
+SinglePhotonRec.SelectionTools   = { 
+  "CaloFutureSelectCluster/PhotonClusterSelect",
+  "CaloFutureSelectNeutralClusterWithTracks/NeutralCluster"
+} ;
+SinglePhotonRec.NeutralCluster.MinChi2 = 4 ;
+SinglePhotonRec.PhotonClusterSelect.MinEnergy = 150;
+//SinglePhotonRec.PhotonClusterSelect.MaxDigits = 99;
+
+
+//-------------------------------------------
+// Select charged clusters for Electron hypo
+//-------------------------------------------
+ElectronRec.SelectionTools           =  {  
+  "CaloFutureSelectCluster/ElectronClusterSelect",
+  "CaloFutureSelectChargedClusterWithSpd/ClusterWithSpd",
+  "CaloFutureSelectClusterWithPrs/ClusterWithPrs",
+  "CaloFutureSelectorNOT/ChargedCluster"
+};
+
+ElectronRec.ChargedCluster.SelectorTools =  { "CaloFutureSelectNeutralClusterWithTracks/NotNeutralCluster"} ;
+ElectronRec.ChargedCluster.NotNeutralCluster.MinChi2 = 25 ;
+ElectronRec.ClusterWithPrs.MinEnergy = 10.*MeV;
+ElectronRec.ElectronClusterSelect.MinEnergy = 150;
+//ElectronRec.ElectronClusterSelect.MaxDigits = 99;
+
diff --git a/CaloFuture/CaloFutureReco/options/ElectronRec.opts b/CaloFuture/CaloFutureReco/options/ElectronRec.opts
new file mode 100755
index 0000000000000000000000000000000000000000..9918fa16764f778f2f479e8893450ea4cf6ace99
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/options/ElectronRec.opts
@@ -0,0 +1,7 @@
+
+
+ElectronRec.HypoTools          = { "CaloFutureExtraDigits/SpdPrsExtraE"     } ;
+ElectronRec.CorrectionTools2   = { "CaloFutureECorrection/ECorrection"      } ;
+ElectronRec.CorrectionTools2  += { "CaloFutureSCorrection/SCorrection"      } ;
+ElectronRec.CorrectionTools2  += { "CaloFutureLCorrection/LCorrection"      } ;
+
diff --git a/CaloFuture/CaloFutureReco/options/MergedPi0Rec.opts b/CaloFuture/CaloFutureReco/options/MergedPi0Rec.opts
new file mode 100755
index 0000000000000000000000000000000000000000..08ed7f453ebe79ba825e343319eb89b993e7cd35
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/options/MergedPi0Rec.opts
@@ -0,0 +1,54 @@
+// ============================================================================
+/** @file
+ *  Options file to run CaloFutureMergedPi0Alg "MergedPi0Rec" 
+ *  @author Olivier Deschamps
+ */
+// ============================================================================
+
+MergedPi0Rec.Pi0Tools = {"CaloFutureExtraDigits/SpdPrsExtraM"};
+
+
+MergedPi0Rec.ShowerProfile.Parameters = {
+  //                    function   #param     params :    outer | middle | inner
+  "profile" : {   6 , 10 ,  
+                  -0.0060,  0.0464  ,0.0981,
+                  2.4956,  2.0384,  2.2529,
+                  115.0827, 36.5885, 33.8837,
+                  9.8842,  8.0260,  8.0532,
+                  0.0320,  0.0460,  0.0654,
+                  2.0982,  2.3936,  2.2046,
+                  1.0302,  1.0703,  1.1092,
+                  0.0409,  0.1611,  0.1645,
+                  0.0030,  0.0238,  0.0248,
+                  -9.6135, -5.8899, -5.7248},
+
+  // converted photons
+  "profileC" :{   6 , 10 ,     
+                  0.0486,  0.0882,  0.1111,
+                  2.7847,  1.7910,  1.7909,
+                  68.4815, 24.4324, 18.0852,
+                  9.0870,  7.4802,  7.1122,
+                  0.0116,  0.0258,  0.0261,
+                  1.2591,  2.7719,  1.3889,
+                  1.0464,  1.1294,  1.1846,
+                  -0.0900, -0.0802, -0.0934,
+                  0.0005,  0.0024,  0.0029,
+                  -12.9098, -9.7273, -8.9966}
+};
+
+
+MergedPi0Rec.Pi0SCorrection.Parameters ={
+  "shapeX"    : { 5        ,   1     ,              0.102      , 0.129       , 0.144 },
+  "shapeY"    : { 5        ,   1     ,              0.102      , 0.129       , 0.144 }
+};
+
+MergedPi0Rec.Pi0LCorrection.Parameters ={
+  "gamma0"     : { 1      ,     1    ,              22.305  , 19.053    , 17.936     },
+  "gammaP"     : { 2      ,     2    ,               2.04   ,  1.53     ,  1.15 ,
+                                                    -0.0281  , -0.455   , -0.0392    },
+  "delta0"     : { 1      ,     1    ,              49.04   ,  51.87    , 45.54      },
+  "deltaP"     : { 2      ,     2    ,               4.38   ,   4.15    ,  4.02 ,     
+                                                    -0.0247 , -0.0597   , -0.0308    }
+};
+//
+MergedPi0Rec.EtCut = 2.*GeV;
diff --git a/CaloFuture/CaloFutureReco/options/PhotonFromMergedRec.opts b/CaloFuture/CaloFutureReco/options/PhotonFromMergedRec.opts
new file mode 100755
index 0000000000000000000000000000000000000000..dbd94b1a4311d03106ccb598c9637dbd300cc29c
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/options/PhotonFromMergedRec.opts
@@ -0,0 +1,6 @@
+PhotonFromMergedRec.HypoType = "SplitPhotons";
+PhotonFromMergedRec.Tools    += { "CaloFutureECorrection/ECorrection" };   // Ecorrection
+PhotonFromMergedRec.Tools    += { "CaloFutureSCorrection/SCorrection" };   // Scorrection
+PhotonFromMergedRec.Tools    += { "CaloFutureLCorrection/LCorrection" };   // Lcorrection
+PhotonFromMergedRec.Tools    += { "CaloFutureExtraDigits/SpdPrsExtraS" };   // ExtraDigits
+
diff --git a/CaloFuture/CaloFutureReco/options/SinglePhotonRec.opts b/CaloFuture/CaloFutureReco/options/SinglePhotonRec.opts
new file mode 100755
index 0000000000000000000000000000000000000000..e9926c3784bae8c6bf09c049082988a0ac00937d
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/options/SinglePhotonRec.opts
@@ -0,0 +1,6 @@
+
+
+SinglePhotonRec.HypoTools          = { "CaloFutureExtraDigits/SpdPrsExtraG"     } ;
+SinglePhotonRec.CorrectionTools2   = { "CaloFutureECorrection/ECorrection"      } ;
+SinglePhotonRec.CorrectionTools2  += { "CaloFutureSCorrection/SCorrection"      } ;
+SinglePhotonRec.CorrectionTools2  += { "CaloFutureLCorrection/LCorrection"      } ;
diff --git a/CaloFuture/CaloFutureReco/options/UnpackCaloFutureHypoOnDemand.opts b/CaloFuture/CaloFutureReco/options/UnpackCaloFutureHypoOnDemand.opts
new file mode 100644
index 0000000000000000000000000000000000000000..0ec8a117fe2033f9116cc0e57fb038d7e076e77d
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/options/UnpackCaloFutureHypoOnDemand.opts
@@ -0,0 +1,19 @@
+ApplicationMgr.ExtSvc += { "DataOnDemandSvc" };
+DataOnDemandSvc.AlgMap += { "/Event/Rec/Calo/Photons"     : "UnpackCaloFutureHypo/UnpackPhotons" , 
+                            "/Event/Rec/Calo/MergedPi0s"  : "UnpackCaloFutureHypo/UnpackMergedPi0s",
+                            "/Event/Rec/Calo/Electrons"   : "UnpackCaloFutureHypo/UnpackElectrons",
+                            "/Event/Rec/Calo/SplitPhotons": "UnpackCaloFutureHypo/UnpackSplitPhotons"
+                          }; 
+
+
+
+UnpackPhotons.InputName      = "/Event/pRec/Calo/Photons" ;
+UnpackMergedPi0s.InputName   = "/Event/pRec/Calo/MergedPi0s";
+UnpackElectrons.InputName    = "/Event/pRec/Calo/Electrons";
+UnpackSplitPhotons.InputName = "/Event/pRec/Calo/SplitPhotons";
+
+UnpackPhotons.OutputName      = "/Event/Rec/Calo/Photons" ;
+UnpackMergedPi0s.OutputName   = "/Event/Rec/Calo/MergedPi0s";
+UnpackElectrons.OutputName    = "/Event/Rec/Calo/Electrons";
+UnpackSplitPhotons.OutputName = "/Event/Rec/Calo/SplitPhotons";
+
diff --git a/CaloFuture/CaloFutureReco/options/UseForwardTracksOnly.opts b/CaloFuture/CaloFutureReco/options/UseForwardTracksOnly.opts
new file mode 100755
index 0000000000000000000000000000000000000000..dab864e6f041abf297f6e99a4eaffd9ca200b84f
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/options/UseForwardTracksOnly.opts
@@ -0,0 +1,19 @@
+
+InSPD.Inputs = {"Rec/Track/Forward"}; 
+InPRS.Inputs = {"Rec/Track/Forward"}; 
+InECAL.Inputs = {"Rec/Track/Forward"}; 
+InHCAL.Inputs = {"Rec/Track/Forward"};  
+InBREM.Inputs = {"Rec/Track/Forward"};
+
+ClusterMatch.Tracks = {"Rec/Track/Forward"};
+ElectronMatch.Tracks = {"Rec/Track/Forward"};
+BremMatch.Tracks = {"Rec/Track/Forward"};  
+
+EcalE.Inputs = {"Rec/Track/Forward"};
+HcalE.Inputs = {"Rec/Track/Forward"};
+PrsE.Inputs = {"Rec/Track/Forward"};
+SpdE.Inputs = {"Rec/Track/Forward"};
+
+FutureEcalChi22ID.Tracks = {"Rec/Track/Forward"};
+BremChi22ID.Tracks = {"Rec/Track/Forward"};
+FutureClusChi22ID.Tracks = {"Rec/Track/Forward"};
diff --git a/CaloFuture/CaloFutureReco/python/CaloFutureReco/Configuration.py b/CaloFuture/CaloFutureReco/python/CaloFutureReco/Configuration.py
new file mode 100644
index 0000000000000000000000000000000000000000..88db7789ef54ab6224aa42727b7fffd1d656caf3
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/python/CaloFutureReco/Configuration.py
@@ -0,0 +1,1061 @@
+#!/usr/bin/env gaudirun.py
+# =============================================================================
+## Confurable for CaloFuturerimeter Reconstruction
+#  @author Vanya BELYAEV Ivan.Belyaev@nikhe.nl
+#  @date 2008-07-17
+# =============================================================================
+"""
+Configurable for CaloFuturerimeter Reconstruction
+"""
+
+# =============================================================================
+__author__  = "Vanya BELYAEV Ivan.Belyaev@nikhef.nl"
+__version__ = "CVS tag $Name: not supported by cvs2svn $, version $Revision: 1.16 $"
+# =============================================================================
+__all__ = (
+    'HltCaloFutureRecoConf'     ,
+    'OffLineCaloFutureRecoConf' ,
+    'CaloFutureRecoConf',
+    'CaloFutureProcessor',
+    'CaloFutureLines'
+    )
+# =============================================================================
+
+from LHCbKernel.Configuration import *
+
+
+from GaudiKernel.SystemOfUnits import MeV, GeV
+from CaloKernel.ConfUtils     import ( addAlgs        ,
+                                       printOnDemand  ,
+                                       prntCmp        ,
+                                       hltContext     , 
+                                       setTheProperty ,
+                                       getAlgo
+                                       )
+from Reconstruction           import ( clusterFutureReco    , 
+                                       photonFutureReco     ,
+                                       electronFutureReco   ,
+                                       mergedPi0FutureReco  ) 
+
+from Configurables            import CaloFutureDigitConf
+from Configurables            import CaloFuturePIDsConf
+##from Configurables            import GlobalRecoConf
+from Configurables            import GaudiSequencer
+
+
+import logging
+_log = logging.getLogger ('CaloFutureReco')
+
+import os
+# =============================================================================
+## @class CaloFutureRecoConf
+#  Configurable for CaloFuturerimeter Reconstruction
+#  @author Vanya BELYAEV Ivan.Belyaev@nikhef.nl
+#  @date 2008-07-17
+class CaloFutureRecoConf(LHCbConfigurableUser):
+    """
+    Class/Configurable to define the calorimeter reconstruction
+
+    """
+   ## define the slots
+    __slots__ = {
+        ##
+        "Context"              : ''   # The context to run (default = offline)
+        , "MeasureTime"        : False       # Measure the time for sequencers
+        , "OutputLevel"        : INFO        # The global output level
+        ##
+        , 'Sequence'           : None        # The sequencer to add the CALOFUTURE reconstruction algorithms to
+        , 'RecList'            : [ 'Digits'       ,
+                                   'Clusters'     ,
+                                   'Photons'      ,
+                                   'MergedPi0s'   ,
+                                   'SplitPhotons' , # the same action as 'MergedPi0s'
+                                   'Electrons'    ] #
+        , 'ForceDigits'         : True       # Force digits recontruction to be run with Clusters
+        , 'CreateADCs'          : False      # Create CaloFuture-ADCs
+        , 'UseTracks'           : True       # Use Tracks as Neutrality Criteria 
+        , 'UseSpd'              : False      # Use Spd as Neutrality Criteria
+        , 'UsePrs'              : False      # Use Prs to select Neutral clusters
+        , 'UseTracksE'          : True       # Use Tracks as Charge  Criteria 
+        , 'UseSpdE'             : True       # Use Spd as Charged Criteria
+        , 'UsePrsE'             : True       # Use Prs to select Charged clusters
+        , 'UseTracksM'          : True       # Use Tracks for MergedPi0s-ID
+        , 'CaloFutureStandalone'      : False      # useTrackX = false + usePrs/Spd = true
+        , 'NeutralID'           : False      # Apply neutralID (CaloFuturePIDs is in charge + problems with onDemand to be fixed)
+        , 'EnableRecoOnDemand'  : False      # Enable Reco-On-Demand (only for components on RecList)
+        , 'TrackLocation'       : ''         # Track location (Neutral/Charged cluster selection with UseTrack(E) )
+        , 'ClMatchTrTypes'      : []         # Accepted track types for cluster matching (default Long, Downstream , TTracks)
+        , 'ExternalClusters'    : ''         # Start the reconstruction sequence from an external cluster container (HLT)
+        , 'FastReco'            : False      # faster reconstruction (HLT)
+        , 'SkipNeutrals'        : False
+        , 'SkipCharged'         : False
+        , 'ForceOnDemand'       : False      # force DoD for ALL components (incl. those not in RecList)
+        , 'PhotonPt'            : 50.*MeV    # Min Cluster Et
+        , 'ElectronPt'          : 50.*MeV    # Min Cluster Et 
+        , 'MergedPi0Pt'         : 1.5*GeV
+        , 'ClusterPt'           : 0.
+        , 'MakeExternalClustersWithTag': ''
+        , 'NoSpdPrs'            : False
+        , 'ClusterEnergyMasks'   : []
+        , 'ClusterPositionMasks' : []
+        , 'Verbose'              : False
+        , 'SetCounters'         : 1         # Quiet is the default
+        ##
+        }
+    ## documentation lines 
+    _propertyDocDct = {
+        ##
+        "Context"              : """ The context to run """
+        , "MeasureTime"        : """ Measure the time for sequencers """ 
+        , "OutputLevel"        : """ The global output level """ 
+        ##
+        , 'Sequence'           : """ The sequencer to add the CALOFUTURE reconstruction algorithms to """
+        , 'RecList'            : """ The recontruction sketch """
+        , 'ForceDigits'        : """ Force digits recontruction to be run with Clusters """ 
+        , 'CreateADCs'         : """ Create CaloFuture-ADCs """ 
+        , 'UseTracks'          : """ Use Tracks as Neutrality criterion """ 
+        , 'UseSpd'             : """ Use Spd as Neutrality criterion """ 
+        , 'UsePrs'             : """ Use Prs as  EM criterion for neutrals """ 
+        , 'UseTracksE'         : """ Use Tracks as Charge criterion """ 
+        , 'UseSpdE'            : """ Use Spd as Charge criterion """ 
+        , 'UsePrsE'            : """ Use Prs as  EM criterion for charged """ 
+        , 'UseTracksM'         : """ Use Tracks for MergedPi0s-ID """
+        , 'CaloFutureStandalone'     : """ UseTrack = false + usePrs/Spd = true """ 
+        , 'NeutralID'          : """ Apply neutralID """ 
+        , 'EnableRecoOnDemand' : """ Enable Reco-On-Demand (for components in RecList) """ 
+        , 'TrackLocation'      : """ TrackLocation (Photon/Electron selection)""" 
+        , 'ClMatchTrTypes'     : """ Accepted track types for cluster matching (default Long, Downstream , TTracks) """
+        , 'SkipNeutrals'       : """ Skip Neutral reco components in RecList""" 
+        , 'SkipCharged'        : """ Skip Charged reco components in RecList"""
+        , 'ForceOnDemand'      : """ force DoD for ALL components"""
+        , 'FastReco'           : """ Speed-up reconstruction (empty so far)"""
+        , 'ExternalClusters'   : """ Start the reconstruction sequence from an external cluster container (HLT)"""
+        , 'PhotonPt'           : """ Photon Hypo Pt cut """ 
+        , 'ElectronPt'         : """ Electron Hypo Pt cut """
+        , 'MergedPi0Pt'        : """ MergedPi0 Pt cut """
+        , 'ClusterPt'          : """ Cluster Pt """
+        , 'MakeExternalClustersWithTag'   :""" Build tagged external clusters in the sequence (only if ExternalClusters != '')"""
+        , 'NoSpdPrs'           : """ Upgrade configuration without Prs/Spd - implies UsePrs/Spd = False """
+        , 'ClusterEnergyMasks'  : """ Set the cluster mask for energy   evaluation (default : set from DB) """
+        , 'ClusterPositionMasks': """ Set the cluster mask for position evaluation (default : set from DB) """
+        , 'Verbose'             : """ Verbose printout"""
+        , 'SetCounters'        : """ Counters verbosity"""
+        ##
+    }
+    
+    ## used configurables 
+    __used_configurables__ = (
+        (CaloFutureDigitConf,None) ,
+        )
+    
+    ## configure processing of Digits
+    def digits   ( self ) :
+        """
+        Configure processing of Digits
+        """
+        digitConf=CaloFutureDigitConf()
+        digitConf.Context="Offline"
+        digitConf.OutputLevel 		= self.getProp ('OutputLevel'       )
+        digitConf.EnableDigitsOnDemand 	= self.getProp ('EnableRecoOnDemand')
+        digitConf.CreateADCs		= self.getProp ('CreateADCs'        )
+        digitConf.Verbose               = self.getProp ('Verbose'           )
+        if self.getProp('NoSpdPrs') :
+            digitConf.Detectors = ['Ecal','Hcal']            
+            # deactivate Spd/Prs in DecoderDB
+            from DAQSys.Decoders import DecoderDB
+            from DAQSys.DecoderClass import Decoder
+            Decoder("CaloFutureDigitsFromRaw/FutureSpdFromRaw",active=False,conf=DecoderDB)
+            Decoder("CaloFutureDigitsFromRaw/FuturePrsFromRaw",active=False,conf=DecoderDB)
+            
+        return digitConf.digits()
+    
+    ## Configure reconstruction of Ecal Clusters
+    def clusters ( self ) :
+        """
+        Configure reconstruction of Ecal Clusters
+        """
+        cmp = clusterFutureReco   ( self.getProp('Context')             ,
+                                    self.getProp('EnableRecoOnDemand' ) ,
+                                    self.getProp('ClusterPt')           ,
+                                    self.getProp('FastReco')            ,
+                                    self.getProp('ExternalClusters')    ,
+                                    self.getProp('MakeExternalClustersWithTag'),
+                                    self.getProp('NoSpdPrs'),
+                                    self.getProp('ClusterEnergyMasks'),
+                                    self.getProp('ClusterPositionMasks'),
+                                    self.getProp('MergedPi0Pt')
+                                    )
+        _log.info ('Configured Ecal Clusters Reco : %s ' % cmp.name()  )
+        
+        if self.getProp ( 'ForceDigits' ) :
+            ## insert digits into Cluster Sequence
+            cmp.Members = [ self.digits() ] + cmp.Members 
+            
+        ##
+        return cmp
+    
+    ## reconstruct the photons
+    def photons  ( self ) :
+        """
+        Define the reconstruction of Photons
+        """
+        uTracks = self.getProp ( 'UseTracks'      ) 
+        uSpd    = self.getProp ( 'UseSpd'            ) 
+        uPrs    = self.getProp ( 'UsePrs'            ) 
+        if self.getProp('CaloFutureStandalone') :
+            uTracks = False
+            uSpd    = True
+            uPrs    = True
+            
+        cmp = photonFutureReco   ( self.getProp ( 'Context'           ) ,
+                                   self.getProp ( 'EnableRecoOnDemand') ,
+                                   uTracks,
+                                   uSpd,
+                                   uPrs,
+                                   self.getProp( 'TrackLocation' ),
+                                   self.getProp( 'NeutralID' ) ,
+                                   self.getProp('PhotonPt')            ,
+                                   self.getProp('FastReco')            ,
+                                   self.getProp('ExternalClusters')    ,
+                                   self.getProp('NoSpdPrs')            ,
+                                   self.getProp('ClMatchTrTypes')
+                                   )
+        ##
+        _log.info ('Configured Single Photons Reco : %s ' % cmp.name()  )
+        return cmp
+
+    ## Configure recontruction of Electrons
+    def electrons ( self ) :
+        """
+        Configure recontruction of Electrons
+        """
+        uTracks = self.getProp ( 'UseTracksE'      ) 
+        uSpd    = self.getProp ( 'UseSpdE'            ) 
+        uPrs    = self.getProp ( 'UsePrsE'            ) 
+        if self.getProp('CaloFutureStandalone') and not self.getProp( 'NoSpdPrs') :
+            uTracks = False
+            uSpd    = True
+            uPrs    = True
+
+        cmp = electronFutureReco ( self.getProp( 'Context'            ) ,
+                                   self.getProp( 'EnableRecoOnDemand' ) ,
+                                   uTracks,
+                                   uSpd,
+                                   uPrs,
+                                   self.getProp('TrackLocation') ,
+                                   self.getProp('ElectronPt')          ,
+                                   self.getProp('FastReco')            ,
+                                   self.getProp('ExternalClusters'),
+                                   self.getProp('NoSpdPrs')  ,
+                                   self.getProp('ClMatchTrTypes')  
+                                   )
+
+
+        ##
+        _log.info ('Configured Electron Hypos Reco : %s ' % cmp.name()  )
+        return cmp
+
+    ## Configure recontruction of Merged Pi0
+    def mergedPi0s ( self ) :
+        """
+        Configure recontruction of Merged Pi0
+        """
+        uTracks = self.getProp ( 'UseTracksM'        )
+        if self.getProp('CaloFutureStandalone') :
+            uTracks = False
+
+        cmp = mergedPi0FutureReco ( self.getProp ( 'Context'            ) ,
+                                    self.getProp ( 'EnableRecoOnDemand' ) ,
+                                    False ,
+                                    self.getProp ( 'NeutralID'         )  ,
+                                    uTracks,
+                                    self.getProp('MergedPi0Pt')         ,
+                                    self.getProp('FastReco')            ,
+                                    self.getProp('ExternalClusters'),
+                                    self.getProp('NoSpdPrs'),
+                                    self.getProp('ClusterEnergyMasks'),
+                                    self.getProp('ClusterPositionMasks')
+                                    )
+        
+
+        ##
+        _log.info ('Configured Merged Pi0 Reco : %s ' % cmp.name()  )
+        return cmp
+    
+    ## Check the configuration
+    def checkConfiguration ( self ) :
+        """
+        Check the configuration
+        """
+        _log.debug('Configuration is not checked !')
+
+
+    def setCounterLevel( self) :
+        # == Counter level
+        from Configurables import ToolSvc,CounterLevel,CaloFutureDigitFilterTool
+        tsvc=ToolSvc()
+        tsvc.addTool(CounterLevel,name="CounterLevel")
+        tsvc.addTool(CaloFutureDigitFilterTool,'FutureFilterTool')
+        level= self.getProp('SetCounters')
+        _log.info( 'Configurabe : Counter level is %s ', level);
+        tsvc.CounterLevel.SetLevel=level
+        tsvc.FutureFilterTool.SetCounterLevel=level
+
+
+        
+    def printConf(self,verbose=False) :
+        if self.getProp('NoSpdPrs') :
+            _log.info("CaloFutureRecoConf : upgrade configuration without Spd/Prs")
+        if self.getProp('Verbose') or verbose:
+            _log.info ( self )
+
+
+    ## Calorimeter Reconstruction Configuration
+    def applyConf ( self ) :
+        """
+        Calorimeter Reconstruction Configuration
+        """
+        
+        self.printConf()
+        
+        _log.info ('Apply CaloFutureRecoConf configuration for %s ',  self.getProp('RecList'))
+
+        recList = self.getProp ( 'RecList') 
+        skipNeutrals  = self.getProp('SkipNeutrals')
+        skipCharged   = self.getProp('SkipCharged')
+        forceOnDemand = self.getProp('ForceOnDemand') 
+            
+        seq     = []
+
+        # configure all components for DoD
+        if forceOnDemand :
+            _log.info('Force Data-On-Demand for all components')
+            self.setProp ( 'EnableRecoOnDemand', 'True' )
+            self.digits()
+            self.clusters()
+            self.photons()
+            self.mergedPi0s()
+            self.electrons()
+
+        if self.getProp('NoSpdPrs') : 
+            self.setProp('UseSpd',False)
+            self.setProp('UsePrs',False)
+            self.setProp('UseSpdE',False)
+            self.setProp('UsePrsE',False)
+            # configure the public getter tool
+            from Configurables import ToolSvc,CaloFutureGetterTool
+            tsvc=ToolSvc()
+            tsvc.addTool(CaloFutureGetterTool,name="CaloFutureGetter")
+            tsvc.CaloFutureGetter.DetectorMask=12
+
+        self.setCounterLevel()
+
+        # add only the requested components to the sequence
+        if 'Digits'     in recList :
+            addAlgs ( seq , self.digits() ) 
+            CaloFutureDigitConf().printConf()
+        if 'Clusters'   in recList :
+            addAlgs ( seq , self.clusters() ) 
+            if 'Digits' not in recList :
+                CaloFutureDigitConf().printConf()
+        if not skipNeutrals :
+            if 'Photons'    in recList : addAlgs ( seq , self.photons() )
+            if 'MergedPi0s' in recList or 'SplitPhotons' in recList : addAlgs ( seq , self.mergedPi0s() )
+        if not skipCharged :
+            if 'Electrons'  in recList : addAlgs ( seq , self.electrons() )
+        
+        setTheProperty ( seq , 'Context'     , self.getProp ( 'Context'     ) )
+        setTheProperty ( seq , 'MeasureTime' , self.getProp ( 'MeasureTime' ) )
+        if self.isPropertySet("OutputLevel") :
+            setTheProperty ( seq , 'OutputLevel' , self.getProp ( 'OutputLevel' ) )
+        
+        if self.isPropertySet('Sequence') :
+            main = self.getProp('Sequence') 
+            addAlgs  ( main , seq ) 
+            _log.info ('Configure main CaloFuture Reco Sequence  : %s '% main.name() )
+            if self.getProp('Verbose') :
+                _log.info ( prntCmp ( main ) ) 
+        else :
+            _log.info ('Configure CaloFuturerimeter Reco blocks ' )            
+            if self.getProp('Verbose') :
+                _log.info ( prntCmp ( seq  ) )
+
+        if self.getProp( 'EnableRecoOnDemand' )  :
+            _log.info("CaloFutureReco onDemand enabled")
+            if self.getProp('Verbose') :
+                _log.info ( printOnDemand () ) 
+
+            
+# =============================================================================
+## @class HltCaloFutureRecoConf
+#  Configurable for CaloFuturerimeter Reconstruction in Hlt context 
+#  @author Vanya BELYAEV Ivan.Belyaev@nikhef.nl
+#  @date 2008-07-17
+class HltCaloFutureRecoConf(CaloFutureRecoConf):
+    """
+    Class/Configurable to define the calorimeter reconstruction for Hlt
+    
+    """
+    __slots__ = {}
+
+    ## Check the configuration
+    def checkConfiguration ( self ) :
+        """
+        Check the configuration
+        """
+        if not hltContext ( self.getProp('Context') ) :
+            raise AttributeError, 'Invalid context for HltCaloFutureRecoConf'
+        
+# =============================================================================
+## @class OffLineCaloFutureRecoConf
+#  Configurable for CaloFuturerimeter Reconstruction in OffLine context 
+#  @author Vanya BELYAEV Ivan.Belyaev@nikhef.nl
+#  @date 2008-07-17
+class OffLineCaloFutureRecoConf(CaloFutureRecoConf):
+    """
+    Class/Configurable to define the calorimeter reconstruction for Off-Line
+    
+    """
+    __slots__ = {}
+
+    ## Check the configuration
+    def checkConfiguration ( self ) :
+        """
+        Check the configuration
+        """
+        if hltContext ( self.getProp( 'Context' ) ) :
+            raise AttributeError, 'Invalid context for OffLineCaloFutureRecoConf'        
+
+# =============================================================================
+class CaloFutureProcessor( CaloFutureRecoConf,LHCbConfigurableUser ):
+    """
+    Class/Configurable to define the Full calorimeter reconstruction
+    """
+
+## -- re-use CaloFutureRecoConf and add caloPIDs and ProtoP [double-inheritance fails due to conflicts]
+
+   ## define the additional slots
+    __slots__ = {
+        'CaloFutureReco'           : True , ## process CaloFutureReco part
+        'CaloFuturePIDs'           : True , ## process CaloFuturePID part
+        'EnableOnDemand'     : False, ## overwrite EnableRecoOnDemand & EnablePIDsOnDemand
+        'ProtoOnDemand'      : False,
+        'NeutralProtoLocation':'',
+        'ChargedProtoLocation':'',
+        'CaloFutureSequencer'       : None,
+        'ProtoSequencer'      : None,
+        'NeutralProtoSequencer'  : None,
+        'ChargedProtoSequencer'  : None,
+        ## PRIVATE TrackTypes & TrackCuts property (as in GlobalRecoConf) : for ChargedProto creation OnD.
+        "TrackTypes"  : [ "Long", "Upstream", "Downstream" ],
+        "TrackCuts"   : {  "Long"       : { "Chi2Cut" : [0,10] }
+                           ,"Upstream"   : { "Chi2Cut" : [0,10] }
+                           ,"Downstream" : { "Chi2Cut" : [0,10] } },
+        ##
+        'DataType'           : 'MC09',
+        'CaloFuturePIDTrTypes'      : []   ,
+        'BremPIDTrTypes'      : []   ,
+        'PIDList'            : ['InAcceptance',
+                                  'Match',
+                                  'Energy',
+                                  'Chi2',
+                                  'DLL',
+                                  'NeutralPID'
+                                  ] # List of PID fragments to be included (alternative full sequence per technique : [ 'EcalPID', 'BremPID', 'HcalPID','PrsPID', 'SpdPID', 'NeutralPID' ] )
+        }
+    
+    
+    ## used configurables 
+    __used_configurables__ = (
+        (CaloFuturePIDsConf,None ),
+        (CaloFutureDigitConf,None )
+	)
+
+    def caloPIDs ( self ) :
+
+        pidConf=CaloFuturePIDsConf('CaloFuturePIDsFor'+self.getName())
+        pidConf.Verbose=self.getProp('Verbose')
+        pidConf.Context=self.getProp( 'Context')  
+        pidConf.EnablePIDsOnDemand=self.getProp( 'EnableOnDemand' )  
+        pidConf.PIDList=self.getProp('PIDList')
+        pidConf.TrackLocation=self.getProp('TrackLocation')
+        pidConf.ClMatchTrTypes=self.getProp('ClMatchTrTypes')
+        pidConf.CaloFuturePIDTrTypes=self.getProp('CaloFuturePIDTrTypes')
+        pidConf.BremPIDTrTypes=self.getProp('BremPIDTrTypes')        
+        pidConf.SkipNeutrals=self.getProp('SkipNeutrals')
+        pidConf.SkipCharged=self.getProp('SkipCharged')
+        pidConf.FastPID=self.getProp('FastReco')
+        pidConf.ExternalClusters=self.getProp('ExternalClusters')
+        pidConf.NoSpdPrs=self.getProp('NoSpdPrs')
+        pidConf.DataType= self.getProp('DataType')        
+        pidConf.OutputLevel=self.getProp('OutputLevel')
+        pidConf.printConf()
+        ##
+        return pidConf.caloPIDs()
+
+    def caloFutureSequence ( self,   tracks=''  ) :
+        _log.info("TEST:  caloFutureSequence")
+        seq  = GaudiSequencer ( self.getName() + 'CaloFutureSeq'   )
+        seq.Members[:] = []
+        self.setProp("CaloFutureSequencer", seq)
+        context = self.getProp('Context')
+        if context == '' :
+            self.setProp("Context", self.getName() )        
+        if tracks:
+            self.setProp("TrackLocation", tracks)
+            _log.info("CaloFutureProcessor.caloFutureSequence : update TrackLocation %s: " % tracks)
+            
+        self.applyConf()
+        return seq
+    def protoSequence ( self,   tracks='' , protoPrefix = '' ) :
+        _log.info("TEST:  photonFutureSequence")
+        seq  = GaudiSequencer (self.getName() + 'ProtoPUpdateSeq'   )
+        seq.Members[:] = []
+        self.setProp("ProtoSequencer", seq)
+        if self.getProp('Context') == '' : 
+            self.setProp("Context", self.getName() )
+        if tracks:
+            self.setProp("TrackLocation", tracks)        
+            _log.info("CaloFutureProcessor.protoSequence : update TrackLocation %s: " % tracks)
+        if protoPrefix:
+            nloc = os.path.join(protoPrefix, 'Neutrals')
+            cloc = os.path.join(protoPrefix, 'Charged')
+            self.setProp("ChargedProtoLocation",cloc)
+            self.setProp("NeutralProtoLocation",nloc)            
+            _log.info("CaloFutureProcessor.protoSequence : update protoP Location with prefix %s: " % protoPrefix)
+        self.applyConf()
+        return seq
+    def chargedProtoSequence ( self,   tracks = '', protoPrefix = '' ) :
+        _log.info("TEST:  chargedProtoFutureSequence")
+        seq  = GaudiSequencer ( self.getName() + 'ChargedProtoPUpdateSeq'  )
+        seq.Members[:] = []
+        self.setProp("ChargedProtoSequencer", seq)
+        if self.getProp('Context') == '' : 
+            self.setProp("Context", self.getName() )
+        if tracks:
+            self.setProp("TrackLocation", tracks)        
+            _log.info("CaloFutureProcessor.chargedProtoSequence : update TrackLocation %s: " % tracks)
+        if protoPrefix:
+            cloc = protoPrefix
+            if not cloc.endswith('Charged'):
+                cloc = os.path.join( protoPrefix, 'Charged')
+            self.setProp("ChargedProtoLocation",cloc)
+            _log.info("CaloFutureProcessor.chargedProtoSequence : update protoP Location with prefix %s: " % protoPrefix)
+
+        self.applyConf()
+        return seq
+    def neutralProtoSequence ( self,   tracks = '', protoPrefix = '' ) :
+        _log.info("TEST:  neutralProtoSequence")
+        seq  = GaudiSequencer (  self.getName() + 'NeutralProtoPUpdateSeq' )
+        seq.Members[:] = []
+        self.setProp("NeutralProtoSequencer", seq) 
+        if self.getProp('Context') == '' : 
+            self.setProp("Context", self.getName() )
+        if tracks:
+            self.setProp("TrackLocation", tracks ) 
+            _log.info("CaloFutureProcessor.neutralProtoSequence : update TrackLocation %s: " % tracks)
+        if protoPrefix:
+            nloc = protoPrefix
+            if not nloc.endswith('Neutrals'):
+                nloc = os.path.join( protoPrefix,'Neutrals' )
+            self.setProp("NeutralProtoLocation",nloc)            
+            _log.info("CaloFutureProcessor.neutralProtoSequence : update protoP Location with prefix %s: " % protoPrefix)
+        self.applyConf()
+        return seq
+    def sequence ( self,   tracks='', protoPrefix = ''  ) :
+        _log.info("TEST:  sequence")
+        seq  = GaudiSequencer ( self.getName() + 'FullSeq'   )
+        seq.Members[:] = []
+        self.setProp("Sequence", seq)
+        if self.getProp('Context') == '' : 
+            self.setProp("Context", self.getName() )
+        if tracks:
+            self.setProp("TrackLocation", tracks)        
+            _log.info("CaloFutureProcessor.sequence : update TrackLocation %s: " % tracks)
+        if protoPrefix:
+            nloc = os.path.join(protoPrefix, 'Neutrals')
+            cloc = os.path.join(protoPrefix, 'Charged')
+            self.setProp("ChargedProtoLocation",cloc)
+            self.setProp("NeutralProtoLocation",nloc)            
+            _log.info("CaloFutureProcessor.sequence : update protoP Location with prefix %s: " % protoPrefix)
+
+        self.applyConf()
+        return seq
+
+
+    def printConf( self,verbose=False) :
+        if self.getProp('NoSpdPrs') :
+            _log.info("CaloFutureProcessor : upgrade configuration without Spd/Prs")
+        if self.getProp('Verbose') or verbose:
+            _log.info ( self )
+
+        
+    def applyConf ( self) :        
+
+        _log.info ('Apply CaloFutureProcessor configuration for %s and %s',  self.getProp('RecList'), self.getProp('PIDList'))
+        
+        self.printConf()
+
+        knownMasks = ['3x3','2x2','SwissCross'] 
+
+        for tag in self.getProp('ClusterEnergyMasks') :
+            if tag not in knownMasks :
+                raise AttributeError,'ClusterEnergyMasks contains unknown tag'+tag+' -should be in' + knownMasks
+        for tag in self.getProp('ClusterPositionMasks') :
+            if tag not in knownMasks :
+                raise AttributeError,'PositionEnergyMasks contains unknown tag '+tag+' -should be in' + knownMasks
+            
+
+            
+        from Configurables import ( GaudiSequencer,
+                                    ChargedProtoParticleAddEcalInfo,
+                                    ChargedProtoParticleAddBremInfo,
+                                    ChargedProtoParticleAddHcalInfo,
+                                    ChargedProtoParticleAddPrsInfo,
+                                    ChargedProtoParticleAddSpdInfo,
+                                    FutureChargedProtoParticleAddEcalInfo,
+                                    FutureChargedProtoParticleAddBremInfo,
+                                    FutureChargedProtoParticleAddHcalInfo,
+                                    FutureChargedProtoParticleAddPrsInfo,
+                                    FutureChargedProtoParticleAddSpdInfo,
+                                    ChargedProtoParticleMaker,
+                                    ChargedProtoCombineDLLsAlg
+                                    )
+
+        fullSeq     = []
+
+
+        if self.getName() == 'CaloFutureProcessor' and ( self.getProp('Context') == '' or self.getProp('Context') == 'CaloFutureProcessor' ) :
+            self.setProp('Context','Offline') # default is Offline is neither context nor name is specified
+
+        # prepare the NoSpdPrs configuration
+        if self.getProp('NoSpdPrs') : 
+            self.setProp('UseSpd',False)
+            self.setProp('UsePrs',False)
+            self.setProp('UseSpdE',False)
+            self.setProp('UsePrsE',False)
+            # configure the public getter tool
+            from Configurables import ToolSvc,CaloFutureGetterTool
+            tsvc=ToolSvc()
+            tsvc.addTool(CaloFutureGetterTool,name="CaloFutureGetter")
+            tsvc.CaloFutureGetter.DetectorMask=12
+
+        self.setCounterLevel()
+        # overwrite Reco & PID onDemand
+        dod = self.getProp('EnableOnDemand')
+        pdod = self.getProp('ProtoOnDemand')
+
+        if dod :
+            pdod = dod            
+        self.setProp('EnableRecoOnDemand',dod)
+            
+        ## define the calo sequence
+        caloSeq     = []
+        
+        doReco = self.getProp('CaloFutureReco')
+        doPIDs = self.getProp('CaloFuturePIDs')
+        skipNeutrals = self.getProp('SkipNeutrals')
+        skipCharged  = self.getProp('SkipCharged')
+        context = self.getProp('Context')
+
+
+        # CaloFutureReco sequence
+        recoSeq = getAlgo( GaudiSequencer , "CaloFutureRecoFor"+self.getName() , context ) 
+        recoSeq.Members[:] = []
+        recList = self.getProp ( 'RecList')         
+
+
+        # configure all components by default (DoD)
+        forceOnDemand = self.getProp('ForceOnDemand')
+        if forceOnDemand :
+            self.setProp('EnableOnDemand','True')
+            self.setProp('EnableRecoOnDemand','True')
+            dig=self.digits()
+            clu=self.clusters()
+            pho=self.photons()
+            mer=self.mergedPi0s()
+            ele=self.electrons()
+
+
+        #  add only the requested components to the sequence
+        if 'Digits'     in recList :
+            addAlgs ( recoSeq , self.digits() ) 
+            CaloFutureDigitConf().printConf()
+        if 'Clusters'   in recList :
+            addAlgs ( recoSeq , self.clusters() ) 
+            if 'Digits' not in recList :
+                CaloFutureDigitConf().printConf()
+
+        if not skipNeutrals :
+            if 'Photons'    in recList : addAlgs ( recoSeq , self.photons() )
+            if 'MergedPi0s' in recList or 'SplitPhotons' in recList : addAlgs ( recoSeq , self.mergedPi0s() )
+        if not skipCharged :
+            if 'Electrons'  in recList : addAlgs ( recoSeq , self.electrons() )
+
+        # CaloFuturePIDs sequence
+        #        pidSeq = getAlgo( GaudiSequencer , "CaloFuturePIDsSeq" , context ) 
+        #        addAlgs ( pidSeq , self.caloPIDs  () )
+        
+        pidSeq=self.caloPIDs()
+
+                
+        # update CaloFutureSequence
+        if doReco :
+            addAlgs ( caloSeq , recoSeq  )
+        if doPIDs        :
+            addAlgs ( caloSeq , pidSeq )            
+
+
+        ## propagate the global properties
+        setTheProperty ( caloSeq , 'Context'     , self.getProp ( 'Context'     ) )
+        setTheProperty ( caloSeq , 'MeasureTime' , self.getProp ( 'MeasureTime' ) )
+        if self.isPropertySet("OutputLevel") :
+            setTheProperty ( caloSeq , 'OutputLevel' , self.getProp ( 'OutputLevel' ) )
+
+
+        ######## ProtoParticle update ##########
+        protoSeq     = []
+        cProtoSeq    = []
+        nProtoSeq    = []
+        #  ProtoParticle locations
+        nloc = self.getProp('NeutralProtoLocation')
+        cloc = self.getProp('ChargedProtoLocation')
+        # try automatic location if not explicit for HLT's sequence
+        if hltContext ( self.getProp('Context') ) :
+            if not nloc:
+                nloc = os.path.join( context, 'ProtoP/Neutrals' )
+            if not cloc:
+                cloc = os.path.join( context, 'ProtoP/Charged' )
+
+        # ChargedProtoParticle
+        if not self.getProp('SkipCharged') :
+            suffix="For"+self.getName()                
+            if self.getProp("NoSpdPrs") :
+                ecal = getAlgo( FutureChargedProtoParticleAddEcalInfo,"FutureChargedProtoPAddEcal"+suffix, context)
+                brem = getAlgo( FutureChargedProtoParticleAddBremInfo,"FutureChargedProtoPAddBrem"+suffix, context)
+                hcal = getAlgo( FutureChargedProtoParticleAddHcalInfo,"FutureChargedProtoPAddHcal"+suffix, context)
+            else:
+                ecal = getAlgo( ChargedProtoParticleAddEcalInfo,"ChargedProtoPAddEcal"+suffix, context)
+                brem = getAlgo( ChargedProtoParticleAddBremInfo,"ChargedProtoPAddBrem"+suffix, context)
+                hcal = getAlgo( ChargedProtoParticleAddHcalInfo,"ChargedProtoPAddHcal"+suffix, context)
+            if not self.getProp('NoSpdPrs') :
+                prs  = getAlgo( ChargedProtoParticleAddPrsInfo ,"ChargedProtoPAddPrs"+suffix , context)
+                spd  = getAlgo( ChargedProtoParticleAddSpdInfo ,"ChargedProtoPAddSpd"+suffix , context)            
+            comb = getAlgo( ChargedProtoCombineDLLsAlg, "ChargedProtoPCombineDLLs"+suffix, context)
+
+            # ChargedProtoP Maker on demand (not in any sequencer)  ####
+            maker = getAlgo( ChargedProtoParticleMaker, "ChargedProtoMaker" , context, cloc , pdod )
+            # protoPMaker settings (from GlobalRecoConf)
+            from Configurables import DelegatingTrackSelector,GaudiSequencer
+            ## ppConf = GlobalRecoConf('DummyConf',RecoSequencer=GaudiSequencer('DummySeq')) 
+            ##ttypes = ppConf.getProp('TrackTypes')
+            ##tcuts  = ppConf.getProp('TrackCuts')
+
+            ttypes = self.getProp('TrackTypes')
+            tcuts  = self.getProp('TrackCuts')
+            
+            maker.addTool( DelegatingTrackSelector, name="TrackSelector" )
+            maker.TrackSelector.TrackTypes = ttypes
+            from Configurables import TrackSelector
+            for type in ttypes : 
+                maker.TrackSelector.addTool(TrackSelector,name=type)
+                ts = getattr(maker.TrackSelector,type)
+                ts.TrackTypes = [type]
+                if type in tcuts :
+                    for name,cut in tcuts[type].iteritems() :
+                        ts.setProp("Min"+name,cut[0])
+                        ts.setProp("Max"+name,cut[1])
+            #########################################
+            if cloc:
+                maker.Output = cloc
+
+            if not hltContext( self.getProp( 'Context' ) ) and self.getProp('TrackLocation'): 
+                maker.Inputs = [self.getProp('TrackLocation')]
+            
+            # location
+            if cloc:
+                ecal.ProtoParticleLocation = cloc
+                brem.ProtoParticleLocation = cloc
+                hcal.ProtoParticleLocation = cloc
+                if not self.getProp('NoSpdPrs') :
+                    prs.ProtoParticleLocation = cloc
+                    spd.ProtoParticleLocation = cloc            
+                comb.ProtoParticleLocation = cloc            
+            # Fill the sequence
+            cpSeq = getAlgo( GaudiSequencer , self.getName()+"ChargedProtoPCaloFutureUpdateSeq", context )            
+            cpSeq.Members = [ ecal,brem,hcal ]
+            if not self.getProp('NoSpdPrs') :
+                cpSeq.Members += [ prs,spd ]
+            cpSeq.Members += [ comb ]
+            addAlgs(protoSeq , cpSeq )
+            addAlgs(cProtoSeq, cpSeq.Members )
+
+
+
+        # NeutralProtoParticleProtoP components        
+        if not self.getProp('SkipNeutrals') :
+            from Configurables import NeutralProtoPAlg, FutureNeutralProtoPAlg
+            suffix="For"+self.getName()                
+            if self.getProp('NoSpdPrs') :
+                neutral = getAlgo( FutureNeutralProtoPAlg,"FutureNeutralProtoPMaker"+suffix, context)
+            else:
+                neutral = getAlgo( NeutralProtoPAlg,"NeutralProtoPMaker"+suffix, context)
+            # location
+            if nloc:
+                neutral.ProtoParticleLocation = nloc
+            # fill the sequence
+            addAlgs(protoSeq, neutral )
+            addAlgs(nProtoSeq, neutral )
+
+
+        ## propagate the global properties
+        setTheProperty ( protoSeq , 'Context'     , self.getProp ( 'Context'     ) )
+        setTheProperty ( protoSeq , 'MeasureTime' , self.getProp ( 'MeasureTime' ) )
+        if self.isPropertySet("OutputLevel") :
+            setTheProperty ( protoSeq , 'OutputLevel' , self.getProp ( 'OutputLevel' ) )
+
+        setTheProperty ( nProtoSeq , 'Context'     , self.getProp ( 'Context'     ) )
+        setTheProperty ( nProtoSeq , 'MeasureTime' , self.getProp ( 'MeasureTime' ) )
+        if self.isPropertySet("OutputLevel") :
+            setTheProperty ( nProtoSeq , 'OutputLevel' , self.getProp ( 'OutputLevel' ) )
+
+        setTheProperty ( cProtoSeq , 'Context'     , self.getProp ( 'Context'     ) )
+        setTheProperty ( cProtoSeq , 'MeasureTime' , self.getProp ( 'MeasureTime' ) )
+        if self.isPropertySet("OutputLevel") :
+            setTheProperty ( cProtoSeq , 'OutputLevel' , self.getProp ( 'OutputLevel' ) )
+
+        # Full sequence
+        addAlgs( fullSeq, caloSeq )
+        addAlgs( fullSeq, protoSeq )
+                    
+        
+        ## define the sequencers
+        if self.isPropertySet('Sequence') :
+            main = self.getProp('Sequence') 
+            main.Members[:]=[]
+            addAlgs  ( main , fullSeq ) 
+            _log.info ('Configure full sequence %s with '% main.name() )
+            _log.info ('    Reco : %s '% self.getProp('RecList'))
+            _log.info ('    PIDs : %s '% self.getProp('PIDList'))
+            _log.info ('    and ProtoParticle update')
+            if self.getProp('Verbose') :
+                _log.info ( prntCmp ( main ) ) 
+
+        if self.isPropertySet('CaloFutureSequencer') :
+            calo = self.getProp('CaloFutureSequencer') 
+            calo.Members[:]=[]
+            addAlgs  ( calo , caloSeq ) 
+            _log.info ('Configure caloFutureSequencer  : %s '% calo.name() )
+            if self.getProp('Verbose') :
+                _log.info ( prntCmp ( calo ) ) 
+
+        if self.isPropertySet('ProtoSequencer') :
+            proto = self.getProp('ProtoSequencer') 
+            proto.Members[:]=[]
+            addAlgs  ( proto , protoSeq ) 
+            _log.info ('Configure protoSequencer  : %s '% proto.name() )
+            if self.getProp('Verbose') :
+                _log.info ( prntCmp ( proto ) ) 
+
+
+        if self.isPropertySet('ChargedProtoSequencer') :
+            cproto = self.getProp('ChargedProtoSequencer') 
+            cproto.Members[:]=[]
+            addAlgs  ( cproto , cProtoSeq ) 
+            _log.info ('Configure chargedProtoSequencer  : %s '% cproto.name() )
+            if self.getProp('Verbose') :
+                _log.info ( prntCmp ( cproto ) ) 
+
+        if self.isPropertySet('NeutralProtoSequencer') :
+            nproto = self.getProp('NeutralProtoSequencer') 
+            nproto.Members[:]=[]
+            addAlgs  ( nproto , nProtoSeq ) 
+            _log.info ('Configure neutralProtoSequencer  : %s '% nproto.name() )
+            if self.getProp('Verbose') :
+                _log.info ( prntCmp ( nproto ) ) 
+
+        if self.getProp( 'EnableOnDemand' )  :
+            _log.info("CaloFutureProcessor onDemand enabled")
+            if self.getProp('Verbose') :
+                _log.info ( printOnDemand () ) 
+
+
+#####################################
+class CaloFutureLines(LHCbConfigurableUser):
+    """
+    Class/Configurable to define the HLT2 fast reconstruction for high-ET photon, low-ET photon/pi0 & low-ET electrons
+    """
+
+
+#    __used_configurables__ = [ CaloFutureProcessor ]
+
+   ## define the additional slots
+    __slots__ = {
+        "Context"            : '' ,    # The context to run (default = offline)
+        'TrackLocation'      : '',    # Track location (Neutral/Charged cluster selection with UseTrack(E) )
+        'HighPhoton'         : True , ## process the highEt-threshold photon reconstruction
+        'LowPhoton'          : True , ## process the lowEt-threshold photon reconstruction
+        'LowElectron'        : True , ## process the LowEt-threshold electron reconstruction
+        'EnableOnDemand'     : False, ## overwrite EnableRecoOnDemand & EnablePIDsOnDemand
+        'HighEt'             : 2000.*MeV ,
+        'LowEt'              : 300.*MeV,
+        'ClusterEtFactor'    : 1.,     # pre-cut on cluster Et is factor * Low(High)ET (should be <=1)
+        'L0CaloFuture2CaloFuture'        : True,
+        'ClusterizationLevel': 2,      # clusterizationLevel (when L0CaloFuture2CaloFuture == True only)   
+        'ProtoOnDemand'      : False,
+        'Sequencer'          : None,
+        'OutputLevel'        : INFO,
+        'HighEtProtoPPrefix' : '',
+        'LowEtProtoPPrefix'  : '',
+        'NoSpdPrs'           : False
+        }
+
+    
+
+
+    def sequence ( self,   tracks=''  ) :
+        _log.info("TEST:  def sequence")
+        seq  = GaudiSequencer ( 'CaloFutureLines' + self.getName() )
+        seq.Members[:] = []
+        self.setProp("Sequencer", seq)
+        context = self.getProp('Context')
+        if context == '' :
+            self.setProp("Context", self.getName() )        
+        self.setProp("TrackLocation", tracks)        
+        self.applyConf()
+        return seq
+ 
+        
+    def applyConf ( self ) :
+        
+
+        from Configurables import ( GaudiSequencer,
+                                    HltL0CaloFutureCandidates
+                                    )
+
+
+        if self.getName() == 'CaloFutureLines' and ( self.getProp('Context') == '' or self.getProp('Context') == 'CaloFutureLines' ) :
+            self.setProp('Context','Offline') # default is Offline is neither context nor name is specified
+
+
+
+        # overwrite Reco & PID onDemand
+        dod = self.getProp('EnableOnDemand')
+        pdod = self.getProp('ProtoOnDemand')
+        if dod :
+            pdod = dod            
+
+        trackLocation = self.getProp('TrackLocation')
+
+        ###
+        caloLines = GaudiSequencer( 'CaloFutureLinesSeq' + self.getName() )
+        caloLines.Members[:] = []
+
+        if self.getProp('L0CaloFuture2CaloFuture') : 
+            l0calo2calo=HltL0CaloFutureCandidates('L0CaloFuture2CaloFuture')
+            if self.getProp('ClusterizationLevel') > 0 : 
+                level = self.getProp('ClusterizationLevel')
+                l0calo2calo.ClusterizationLevel=level
+            addAlgs( caloLines,  l0calo2calo )
+            tagHighP = ''
+            tagLowP = ''
+            tagLowE = ''
+        else :
+            tagHighP = 'HighPhoton'
+            tagLowP  = 'LowPhoton'
+            tagLowE  = 'LowElectron'
+            
+        name = self.getName()
+        fac  = self.getProp('ClusterEtFactor') 
+
+        if self.getProp('HighPhoton') :            
+            context = self.getProp('Context')
+            if  context != '' :
+                context = context +'HighPhoton'
+            hp = CaloFutureProcessor(name+'HighPhoton'
+                               ,TrackLocation = trackLocation
+                               ,Context = context
+                               ,RecList = ['Digits','Clusters','Photons']
+                               ,CaloFuturePIDs = False
+                               ,ExternalClusters="/Event/Rec/Calo/HighEtPhotons"
+                               ,ClusterPt = self.getProp('HighEt')*fac
+                               ,PhotonPt = self.getProp('HighEt')
+                               ,MakeExternalClustersWithTag = tagHighP
+                               ,NoSpdPrs=self.getProp('NoSpdPrs')
+                               )
+            
+            addAlgs( caloLines, hp.caloFutureSequence(tracks=trackLocation) )
+
+            if self.getProp('HighEtProtoPPrefix') == '' :
+                hploc = name+'HighPhoton/ProtoP'
+            else :
+                hploc = self.getProp('HighEtProtoPPrefix')
+            addAlgs( caloLines, hp.neutralProtoSequence(protoPrefix = hploc, tracks=trackLocation)  )
+
+        if self.getProp('LowPhoton') :
+            context = self.getProp('Context')
+            if  context != '' :
+                context = context +'LowPhoton'
+            lp = CaloFutureProcessor(name+'LowPhoton'
+                               ,TrackLocation = trackLocation
+                               ,Context = context
+                               ,RecList = ['Digits','Clusters','Photons','MergedPi0s','SplitPhotons']
+                               ,ExternalClusters="/Event/Rec/Calo/LowEtPhotons"
+                               ,CaloFuturePIDs = False
+                               ,ClusterPt = self.getProp('LowEt')*fac
+                               ,PhotonPt = self.getProp('LowEt')
+                               ,MakeExternalClustersWithTag = tagLowP
+                               ,NoSpdPrs=self.getProp('NoSpdPrs')
+                               )
+            addAlgs( caloLines , lp.caloFutureSequence(tracks=trackLocation) )
+            if self.getProp('LowEtProtoPPrefix') == '' :
+                lploc = name+'LowPhoton/ProtoP'
+            else :
+                lploc = self.getProp('LowEtProtoPPrefix')
+            addAlgs( caloLines ,  lp.neutralProtoSequence(protoPrefix=lploc, tracks=trackLocation))
+            
+
+        if self.getProp('LowElectron') :
+            context = self.getProp('Context')
+            if  context != '' :
+                context = context +'LowElectron'
+            le = CaloFutureProcessor(name+'LowElectron'
+                               ,TrackLocation = trackLocation
+                               ,Context = context
+                               ,RecList = ['Digits','Clusters','Electrons']
+                               ,ExternalClusters="/Event/Rec/Calo/LowEtElectrons"
+                               ,ClusterPt = self.getProp('LowEt')*fac
+                               ,ElectronPt = self.getProp('LowEt')
+                               ,SkipNeutrals = True
+                               ,ProtoOnDemand = pdod
+                               ,MakeExternalClustersWithTag = tagLowE
+                               ,NoSpdPrs=self.getProp('NoSpdPrs')
+                               )
+            addAlgs( caloLines , le.caloFutureSequence(tracks=trackLocation))
+            if self.getProp('LowEtProtoPPrefix') == '' :
+                leloc = name+'LowElectron/ProtoP'
+            else :
+                leloc = self.getProp('LowEtProtoPPrefix')
+            addAlgs( caloLines , le.chargedProtoSequence(protoPrefix=leloc, tracks=trackLocation))
+
+
+        caloLines.IgnoreFilterPassed = True
+        ## propagate the global properties
+        if self.isPropertySet("OutputLevel") :
+            setTheProperty ( caloLines , 'OutputLevel'     , self.getProp ( 'OutputLevel'     ) )
+
+        ## define the sequencers
+        if self.isPropertySet('Sequencer') :
+            main = self.getProp('Sequencer') 
+            addAlgs  ( main , caloLines ) 
+
+
+
+# =============================================================================
+if '__main__' == __name__ :
+    print __doc__
+    print __author__
+    print __version__
+    
+            
+    
diff --git a/CaloFuture/CaloFutureReco/python/CaloFutureReco/Corrections.py b/CaloFuture/CaloFutureReco/python/CaloFutureReco/Corrections.py
new file mode 100644
index 0000000000000000000000000000000000000000..0580acb12b0bd8bd8f0375a3f1dfcf7d1a2d8c46
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/python/CaloFutureReco/Corrections.py
@@ -0,0 +1,153 @@
+
+#!/usr/bin/env python
+# =============================================================================
+# $Id: Corrections.py,v 1.4 2010-05-20 09:47:06 odescham Exp $ 
+# =============================================================================
+## @file CaloFutureReco/Corrections.py
+#  Set of E/S/L-correction parameters
+#  @see CaloFutureECorrection
+#  @see CaloFutureSCorrection
+#  @see CaloFutureLCorrection
+#  @todo Move the correction to Conditions Data Base 
+# =============================================================================
+"""
+Set of CaloFuture E/S/L-correction parameters
+"""
+# =============================================================================
+__version__ = "CVS tag $Name: not supported by cvs2svn $, version $Revision: 1.4 $"
+# =============================================================================
+__all__  = (
+    'eCorrection'  , ## E-corretions 
+    'sCorrection'  , ## S-corretions 
+    'lCorrection'  , ## L-corretions 
+    'showerProfile'    ## Transversal shower profile
+    )
+# =============================================================================
+from Gaudi.Configuration import log 
+# =============================================================================
+## function which sets the E-correction parameters
+#  @see CaloFutureECorrection
+def eCorrection ( ecorr , version = None ) : 
+    """
+    Function which sets the E-correction parameters:
+
+    >>> tool = ...
+    >>> eCorrection ( tool )
+    """    
+    # ============================================================================
+    #                      function   #params      Outer         Middle       Inner 
+    # ============================================================================
+    ecorr.Parameters["alphaG"] = [ 0      ,     1    ,               1.0          , 1.0         ,  1.0           ]
+    ecorr.Parameters["alphaE"]  = [ 0      ,     2    ,               1.0105       , 1.0208      ,  1.0325 ,  0.11561E-06  , 0.33802E-07 , -0.28272E-07   ]
+    ecorr.Parameters["alphaB"]  = [ 0      ,     2    ,               1.0159       , 1.0210      ,  1.0256 , -0.67500E-01  ,-0.78525E-01 , -0.8901E-01    ]
+    ecorr.Parameters["alphaX"]  = [ 0      ,     2    ,        1,1,1, 0.     , 0.0171 ,  0.0315    ]
+    ecorr.Parameters["alphaY"]  = [ 0      ,     2    ,        1,1,1, 0.     , 0.0362 ,  0.0479    ]
+    ecorr.Parameters["beta"]    = [ 1      ,     1    ,               8.3    , 8.8    ,  9.5       ]
+    ecorr.Parameters["globalC"] = [ 0      ,     1    ,               0.977  , 0.977  ,  0.977     ]
+    
+    ##
+    log.debug ('Configure E-Corrections for Ecal hypotheses: %s' % ecorr.name () )
+    #    ecorr.OutputLevel = 2
+    return ecorr
+
+# =============================================================================
+## function which sets the S-correction parameters
+#  @see CaloFutureSCorrection
+def sCorrection ( scorr , version = None ) :
+    """
+    Function which sets the S-correction parameters:
+    
+    >>> tool = ...
+    >>> sCorrection ( tool )
+    """    
+    scorr.Parameters["shapeX"] = [ 5        ,   1     ,              0.102      , 0.129       , 0.144] 
+    scorr.Parameters["shapeY"] = [ 5        ,   1     ,              0.102      , 0.129       , 0.144] 
+    scorr.Parameters["residual"] = [ 1        ,   8     ,
+                                     -0.47496E-03, -0.97712E-05, -0.14401E-03,
+                                     0.44911    ,  0.33898    ,  0.29037,
+                                     -0.34187E-01,  0.14566E-01,  0.28848E-01,
+                                     -9.0335     , -5.9958     , -5.1697,
+                                     0.46190    , -0.13533    , -0.34664,
+                                     53.041      , 32.711      , 26.885,
+                                     -1.2801     ,  0.33460E-01,  0.99928,  
+                                     -97.865      ,-58.743      ,-45.032]
+    scorr.Parameters["asymP"] = [ 1       ,    3     ,
+                                  0.24742E-01, 0.28587E-01, 0.19870E-01,
+                                  0.11487E-01, 0.11557E-01, 0.38043E-02,
+                                  -0.32640    ,-0.31548    ,-0.21436]
+    scorr.Parameters["asymM"] = [ 1       ,    3     ,
+                                  -0.29386E-01,-0.28587E-01,-0.19870E-01,
+                                  0.11472E-01, 0.11557E-01, 0.38043E-02,
+                                  0.35928    , 0.31548    , 0.21436]    
+    ##
+    log.debug ('Configure S-Corrections for Ecal hypotheses: %s' % scorr.name () ) 
+    return scorr
+
+
+# =============================================================================
+## function which sets the L-correction parameters
+#  @see CaloFutureLCorrection
+def lCorrection ( lcorr , version = None ) :
+    """
+    Function which sets the L-correction parameters:
+    
+    >>> tool = ...
+    >>> lCorrection ( tool )
+    """    
+    lcorr.Parameters["gamma0"] = [ 1      ,     1    ,     22.305 ,    19.053  ,  17.936 ]
+    lcorr.Parameters["gammaP"] = [ 2      ,     2    ,      2.04  ,     1.53   ,   1.15  , -0.0281, -0.455, -0.0392]
+    lcorr.Parameters["delta0"] = [ 1      ,     1    ,     49.04  ,     51.87  ,  45.54  ]
+    lcorr.Parameters["deltaP"] = [ 2      ,     2    ,      4.38  ,      4.15  ,   4.02  , -0.0247,    -0.0597 ,  -0.0308 ]
+    
+    ##
+    log.debug ('Configure L-Corrections for Ecal hypotheses: %s' % lcorr.name () ) 
+    return lcorr
+
+
+
+# =============================================================================
+## function which provide the Transversal Shower profile (for MergedPi0 reconstruction)
+#  @see CaloFutureMergedPi0ALg
+def showerProfile ( shape , version = None ) : 
+    """
+    Function which sets the E-correction parameters:
+    """    
+
+    # ============================================================================
+    #                      function   #params      Outer         Middle       Inner 
+    # ============================================================================
+    shape.Parameters["profile"] = [6 , 10 ,  
+                                   -0.0060,  0.0464  ,0.0981,
+                                   2.4956,  2.0384,  2.2529,
+                                   115.0827, 36.5885, 33.8837,
+                                   9.8842,  8.0260,  8.0532,
+                                   0.0320,  0.0460,  0.0654,
+                                   2.0982,  2.3936,  2.2046,
+                                   1.0302,  1.0703,  1.1092,
+                                   0.0409,  0.1611,  0.1645,
+                                   0.0030,  0.0238,  0.0248,
+                                   -9.6135, -5.8899, -5.7248]
+    shape.Parameters["profileC"] = [6 , 10 ,     
+                                   0.0486,  0.0882,  0.1111,
+                                   2.7847,  1.7910,  1.7909,
+                                   68.4815, 24.4324, 18.0852,
+                                   9.0870,  7.4802,  7.1122,
+                                   0.0116,  0.0258,  0.0261,
+                                   1.2591,  2.7719,  1.3889,
+                                   1.0464,  1.1294,  1.1846,
+                                   -0.0900, -0.0802, -0.0934,
+                                   0.0005,  0.0024,  0.0029,
+                                   -12.9098, -9.7273, -8.9966]
+    
+    
+    ##
+    log.debug ('Configure showerShape for Ecal hypotheses: %s' % shape.name () )
+    #    shape.OutputLevel = 2
+    return shape
+
+
+# =============================================================================
+if '__main__' == __name__ :
+    print __doc__ 
+    print __version__ 
+
diff --git a/CaloFuture/CaloFutureReco/python/CaloFutureReco/Reconstruction.py b/CaloFuture/CaloFutureReco/python/CaloFutureReco/Reconstruction.py
new file mode 100644
index 0000000000000000000000000000000000000000..f23dfcb360aaedb80c0c3ca0a50674576099ba8d
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/python/CaloFutureReco/Reconstruction.py
@@ -0,0 +1,458 @@
+#!/usr/bin/env python
+# =============================================================================
+# $Id: Reconstruction.py,v 1.12 2010-05-20 09:47:06 odescham Exp $
+# =============================================================================
+## The major building blocks of CaloFuturerimeter Reconstruction
+#  @author Vanya BELYAEV Ivan.Belyaev@nikhe.nl
+#  @date 2008-07-17
+# =============================================================================
+"""
+The major building blocks of CaloFuturerimeter Reconstruction
+"""
+
+# =============================================================================
+__author__  = "Vanya BELYAEV Ivan.Belyaev@nikhef.nl"
+__version__ = "CVS tag $Name: not supported by cvs2svn $, version $Revision: 1.12 $"
+# =============================================================================
+__all__ = (
+    'clustersReco'   , 
+    'photonsReco'    , 
+    'mergedPi0sReco' 
+    )
+# =============================================================================
+from Gaudi.Configuration import *
+
+from Configurables import GaudiSequencer
+
+from GaudiKernel.SystemOfUnits import MeV, GeV
+
+
+from CaloKernel.ConfUtils import ( prntCmp        ,
+                                   addAlgs        ,
+                                   hltContext     ,
+                                   setTheProperty ,
+                                   onDemand       ,
+                                   caloOnDemand   ,
+                                   getAlgo        ) 
+
+import logging
+_log = logging.getLogger('CaloFutureReco')
+
+# =============================================================================
+## prepare the digits for the recontruction
+def digitsFutureReco  ( context            ,
+                  enableRecoOnDemand ,
+                  createADC          ) :
+    """
+    Prepare the digits for the recontruction
+    """
+
+    from CaloFutureDAQ.CaloFutureDigits  import caloDigits
+
+    _log.warning('CaloFutureReco.digitsFutureReco is deprecated, use CaloFutureDigitConf instead')
+
+    # warning : the caloDigits TES should be context-independent
+    return caloDigits ( context            ,
+                        enableRecoOnDemand ,
+                        createADC          )
+
+## ============================================================================
+## define the recontruction of Ecal clusters
+def clusterFutureReco ( context , enableRecoOnDemand , clusterPt = 0.  , fastReco = False , external = '', makeTag=False,
+                  noSpdPrs=False , masksE=[] , masksP=[] , mergedPi0Pt = 2* GeV) :
+    """
+    Define the recontruction of Ecal Clusters
+    """
+    
+    from Configurables import ( CaloFutureDigitFilterAlg       ,
+                                CaloFutureDigitFilterTool      ,
+                                FutureCellularAutomatonAlg     ,
+                                CaloFutureShowerOverlap        ,
+                                # CaloFutureSharedCellAlg        , # obsolete
+                                CaloFutureClusterCovarianceAlg ,
+                                CaloFutureClusterizationTool) 
+
+    # cluster TES  is 'almost' context-independent : single HLT TES whatever the HLT-type else 'offline' TES
+    ## Warning MUST be synchronous with CaloFutureAlgUtils TES settings
+    ### Exception when external clusters location is given
+
+    if external == '' :
+        _cont = context
+        if '' != context and 'OFFLINE' != _cont.upper() and _cont.upper().find( 'HLT' ) != -1 :
+            context = 'Hlt'
+        else :
+            context = ''
+    elif makeTag != '':
+        context = makeTag
+    
+
+    ## Define the context-dependent sequencer
+    seq   = getAlgo ( GaudiSequencer           , "ClusterFutureReco", context , "Rec/Calo/EcalClusters" , enableRecoOnDemand )
+
+    seq.Members[:]=[]
+    filter= getAlgo ( CaloFutureDigitFilterAlg       , "CaloFutureDigitFilter",context)
+    if noSpdPrs :
+        filter.PrsFilter=0
+        filter.SpdFilter=0
+
+    clust = getAlgo ( FutureCellularAutomatonAlg     , "FutureEcalClust"  , context )
+#   share = getAlgo ( CaloFutureSharedCellAlg        , "EcalShare"  , context )   # obsolete
+    share = getAlgo ( CaloFutureShowerOverlap        , "FutureEcalShare"  , context )  
+    covar = getAlgo ( CaloFutureClusterCovarianceAlg , "FutureEcalCovar"  , context ) 
+
+    if masksE != [] :
+        share.EnergyTags = masksE
+        covar.EnergyTags = masksE
+    if masksP != [] :
+        share.PositionTags = masksP
+        covar.PositionTags = masksP
+
+    if external != '' :                  # use non-default clusters 
+        share.InputData = external
+        covar.InputData = external
+        if makeTag != '' :               # make the non-default clusters
+            seq.Members += [ filter, clust ]
+            clust.OutputData = external
+    else :
+        seq.Members += [ filter, clust ]        # make default clusters
+
+
+    if clusterPt > 0 :
+        from Configurables import CaloFutureClusterizationTool
+        clust.addTool(CaloFutureClusterizationTool,'CaloFutureClusterizationTool')
+        clust.CaloFutureClusterizationTool.ETcut = clusterPt
+        clust.CaloFutureClusterizationTool.withET = True
+
+    seq.Members += [ share , covar ]
+    setTheProperty ( seq , 'Context' , context )
+
+
+    ## setup onDemand for SplitClusters
+    if enableRecoOnDemand : 
+        splitSeq   = mergedPi0Reco( context , enableRecoOnDemand , True, False, False,mergedPi0Pt,False,'',noSpdPrs,masksE,masksP)
+        onDemand ( 'Rec/Calo/EcalSplitClusters' , splitSeq , context ) 
+
+
+    ## printout
+    _log.debug ( 'Configure Ecal Cluster Reco Seq : %s   for %s : ' % (seq.name()  , context) )
+    if enableRecoOnDemand : 
+        _log.info    ('ClusterFutureReco onDemand')
+    
+    ##    
+    return seq
+
+# ============================================================================
+## define the recontruction of  Single Photons
+def photonFutureReco ( context , enableRecoOnDemand, useTracks = True , useSpd = False, usePrs = False , trackLocation = '', neutralID = True,
+                 photonPt=50.*MeV, fastReco = False, external = '',noSpdPrs=False,matchTrTypes=[]) :
+    """
+    Define the recontruction of Single Photon Hypo
+    """
+    
+    from Configurables import   CaloFutureSinglePhotonAlg                
+    from Configurables import   CaloFutureHypoAlg     
+    from Configurables import ( CaloFutureSelectCluster                  , 
+                                CaloFutureSelectClusterWithPrs           ,
+                                CaloFutureSelectNeutralClusterWithTracks , 
+                                CaloFutureSelectNeutralClusterWithSpd    ,
+                                CaloFutureSelectChargedClusterWithSpd    , 
+                                CaloFutureSelectorNOT                    ,
+                                CaloFutureSelectorOR                     )
+    
+    from Configurables import ( CaloFutureExtraDigits ,
+                                CaloFutureECorrection , 
+                                CaloFutureSCorrection , 
+                                CaloFutureLCorrection )
+                                 
+    
+    
+    ## build the context-dependent sequence (  TrackMatch + SinglePhotonRec )
+    seq = getAlgo ( GaudiSequencer , "PhotonFutureReco" , context , "Rec/Calo/Photons"  , enableRecoOnDemand   )
+    seq.Members=[]
+
+    # 1/ PhotonMatch from CaloFuturePIDs (if tracking is requested)
+    if useTracks : 
+        from CaloFuturePIDs.PIDs import trackMatch
+        tm =  trackMatch ( context,enableRecoOnDemand, trackLocation , matchTrTypes, fastReco, external)
+        addAlgs ( seq , tm ) 
+    
+
+    ##2/ SinglePhotonRec alg
+    alg = getAlgo ( CaloFutureSinglePhotonAlg, "SinglePhotonRecFuture" , context )
+    alg.PropertiesPrint = False
+    if external != '' :
+        alg.InputData = external
+    
+    # cluster selection tools:
+    ### a/ generic selection (energy/multiplicity)
+    alg.addTool ( CaloFutureSelectCluster  , "PhotonClusterFuture" )
+    alg.SelectionTools = [ alg.PhotonClusterFuture ]
+    alg.PhotonClusterFuture.MinEt     = photonPt
+    alg.PhotonClusterFuture.MinDigits = 2  # skip single-cell clusters
+    
+    ### b/ Neutral cluster (track-based and/or Spd/Prs-based)    
+    if   useTracks     :
+        alg.addTool ( CaloFutureSelectNeutralClusterWithTracks , "NeutralClusterFuture" )
+        alg.NeutralClusterFuture.MinChi2 = 4
+        alg.SelectionTools += [ alg.NeutralClusterFuture ]
+        _log.debug    ('CaloFutureReco/PhotonFutureReco: Configure Neutral Cluster Selector with Tracks     : %s' %  alg.NeutralClusterFuture.getFullName() )
+
+    if usePrs :
+        alg.addTool ( CaloFutureSelectClusterWithPrs           , "ClusterWithPrsFuture" )
+        alg.ClusterWithPrsFuture.MinEnergy = 10.*MeV
+        alg.SelectionTools += [ alg.ClusterWithPrsFuture ]
+        _log.debug ('CaloFutureReco/PhotonFutureReco: Configure Cluster Selector with  Prs       : %s' %  alg.ClusterWithPrs.getFullName() )
+
+    if  useSpd  :
+        alg.addTool ( CaloFutureSelectNeutralClusterWithSpd    , "NeutralClusterWithSpdFuture"    )        
+        alg.SelectionTools += [ alg.NeutralClusterWithSpdFuture ]
+        _log.debug ('CaloFutureReco/PhotonFutureReco: Configure Neutral Cluster Selector with !Spd : %s ' %   alg.NeutralClusterWithSpdFuture.getFullName()  )
+        
+        
+    ## hypo tools : add Spd/Prs digits
+
+    if not noSpdPrs :
+        alg.addTool ( CaloFutureExtraDigits , 'SpdPrsExtraG' )
+        alg.HypoTools = [ alg.SpdPrsExtraG ]
+    else :
+        alg.HypoTools = []
+        
+    ## correction tools : E/S/L
+    alg.addTool ( CaloFutureECorrection , 'ECorrection' )
+    alg.addTool ( CaloFutureSCorrection , 'SCorrection' )
+    alg.addTool ( CaloFutureLCorrection , 'LCorrection' )
+    
+    ecorr = alg.ECorrection
+    scorr = alg.SCorrection
+    lcorr = alg.LCorrection
+
+    # tool configuration via condDB only (remove default configuration)
+    alg.CorrectionTools2 = [ ecorr , scorr , lcorr ]                      
+
+    # update the sequence
+    addAlgs ( seq , alg ) 
+
+    ## 3/ PhotonID
+    from CaloFuturePIDs.PIDs import PhotonID
+    if neutralID : 
+        pID =  PhotonID ( context,enableRecoOnDemand, useTracks )
+        addAlgs ( seq , pID ) 
+
+    ## global context
+    setTheProperty ( seq , 'Context' , context )
+
+    ## printout
+    _log.debug ( 'Configure Photon Reco Seq : %s  for : %s' % (seq.name() , context ) )
+    if enableRecoOnDemand : 
+        _log.info    ('PhotonFutureReco onDemand')
+        
+    return seq
+
+# ============================================================================
+## define the recontruction of Electorn Hypos
+def electronFutureReco ( context , enableRecoOnDemand , useTracksE = True , useSpdE = True, usePrsE = True, trackLocation = '' ,
+                   electronPt=50.*MeV , fastReco = False, external = '' ,noSpdPrs=False,matchTrTypes=[]) :
+    """
+    Define the reconstruction of
+    """
+
+    from Configurables import   CaloFutureElectronAlg                
+    from Configurables import   CaloFutureHypoAlg 
+    
+    from Configurables import ( CaloFutureSelectCluster                  , 
+                                CaloFutureSelectClusterWithPrs           ,
+                                CaloFutureSelectNeutralClusterWithTracks , 
+                                CaloFutureSelectNeutralClusterWithSpd    ,
+                                CaloFutureSelectChargedClusterWithSpd    , 
+                                CaloFutureSelectorNOT                    )
+    
+    from Configurables import ( CaloFutureExtraDigits ,
+                                CaloFutureECorrection , 
+                                CaloFutureSCorrection , 
+                                CaloFutureLCorrection ) 
+    
+
+    ## build the context-dependent sequence (  TrackMatch + SingleElectronRec )
+    seq = getAlgo ( GaudiSequencer , "ElectronFutureReco" , context  , 'Rec/Calo/Electrons' , enableRecoOnDemand   ) 
+    seq.Members=[]
+
+    # 1/ ElectronMatch from CaloFuturePIDs (if useTracks)
+    if useTracksE :
+        from CaloFuturePIDs.PIDs import trackMatch
+        tm =  trackMatch ( context,enableRecoOnDemand, trackLocation , matchTrTypes, fastReco , external)
+        addAlgs ( seq , tm ) 
+
+    ## 2/ Electron Rec alg
+    alg = getAlgo ( CaloFutureElectronAlg ,  'SingleElectronRecFuture', context  ) 
+    alg.PropertiesPrint = False
+    if external != '' :
+        alg.InputData = external
+        
+    # cluster selection tools:
+
+    ## 1/ generic selection (energy/multiplicity)
+    alg.addTool ( CaloFutureSelectCluster               , "ElectronClusterFuture" )
+    alg.SelectionTools = [ alg.ElectronClusterFuture ]
+    alg.ElectronClusterFuture.MinEt = electronPt
+    alg.ElectronClusterFuture.MinDigits = 2 # skip single-cell clusters
+
+    ## 2/  hits in Spd
+    if useSpdE : 
+        alg.addTool ( CaloFutureSelectChargedClusterWithSpd , "ChargedClusterWithSpdFuture"  )
+        alg.SelectionTools += [ alg.ChargedClusterWithSpdFuture ]
+        _log.debug    ('CaloFutureReco/ElectronFutureReco: Configure Charged Cluster Selector with Spd     : %s' %  alg.ChargedClusterWithSpdFuture.getFullName() )
+
+    ## 3/ energy in Prs
+    if usePrsE :  
+        alg.addTool ( CaloFutureSelectClusterWithPrs        , "ClusterWithPrsFuture"  )
+        alg.ClusterWithPrsFuture.MinEnergy = 10 * MeV
+        alg.SelectionTools += [ alg.ClusterWithPrsFuture ]
+        _log.debug    ('CaloFutureReco/ElectronFutureReco: Configure Cluster Selector with Prs    : %s' %  alg.ClusterWithPrsFuture.getFullName() )
+
+    ## 4/  match with tracks
+    if useTracksE :
+        alg.addTool ( CaloFutureSelectorNOT   , "ChargedClusterFuture"  )
+        clnot = alg.ChargedClusterFuture
+        clnot.addTool ( CaloFutureSelectNeutralClusterWithTracks , "NotNeutralClusterFuture" )
+        clnot.NotNeutralClusterFuture.MinChi2 = 25
+        clnot.SelectorTools = [ clnot.NotNeutralClusterFuture ]
+        alg.SelectionTools += [ alg.ChargedClusterFuture ]
+        _log.debug   ('CaloFutureReco/ElectronFutureReco: Configure Charged Cluster Selector with Tracks     : %s' %  alg.ChargedClusterFuture.getFullName() )
+
+
+    ## hypo tools : add Spd/Prs digits
+    if not noSpdPrs :
+        alg.addTool ( CaloFutureExtraDigits , 'SpdPrsExtraEFuture' )
+        alg.HypoTools = [ alg.SpdPrsExtraEFuture ]
+    else :
+        alg.HypoTools = []
+
+    ## correction tools : E/S/L
+    alg.addTool ( CaloFutureECorrection , 'ECorrectionFuture' )
+    alg.addTool ( CaloFutureSCorrection , 'SCorrectionFuture' )
+    alg.addTool ( CaloFutureLCorrection , 'LCorrectionFuture' )
+
+    ecorr = alg.ECorrectionFuture
+    scorr = alg.SCorrectionFuture
+    lcorr = alg.LCorrectionFuture
+
+    # tool configuration via condDB (remove default configuration)
+    alg.CorrectionTools2 = [ ecorr , scorr , lcorr ]
+    
+    ## update the sequence
+    addAlgs ( seq , alg ) 
+
+    # global context 
+    setTheProperty ( seq , 'Context' , context )
+
+    ## printout
+    _log.debug ( 'Configure Electron Reco Seq : %s  for : %s' % (seq.name() , context ))
+    if enableRecoOnDemand : 
+        _log.info    ('ElectronFutureReco onDemand')
+
+    return seq
+
+    
+# =============================================================================
+## define the reconstruction of Merged Pi0s Hypos 
+def mergedPi0FutureReco ( context , enableRecoOnDemand , clusterOnly = False , neutralID = True , useTracks = True,
+                    mergedPi0Pt = 2* GeV ,fastReco = False, external = '',noSpdPrs=False,
+                    masksE=[] , masksP=[] ) :
+
+    """
+    Define the recontruction of Merged Pi0s
+    """
+
+    from Configurables import   CaloFutureMergedPi0 # CaloFutureMergedPi0Alg is obsolete (replaced by CaloFutureMergedPi0)
+    from Configurables import   CaloFutureHypoAlg 
+
+    from Configurables import ( CaloFutureExtraDigits ,
+                                CaloFutureECorrection , 
+                                CaloFutureSCorrection , 
+                                CaloFutureLCorrection 
+                                ) 
+
+
+    # build the sequences
+    seq = getAlgo ( GaudiSequencer , 'MergedPi0FutureReco' , context )
+    sseq = getAlgo ( GaudiSequencer , 'SplitClusterFutureReco' , context )
+        
+    ## Merged Pi0
+    if clusterOnly :
+        pi0 = getAlgo ( CaloFutureMergedPi0 , 'SplitClustersRec', context )
+        pi0.CreateSplitClustersOnly = True
+        sseq.Members=[pi0]
+    else :
+        pi0 = getAlgo ( CaloFutureMergedPi0 , 'MergedPi0RecFuture', context )        
+
+    if masksE != [] :
+        pi0.EnergyTags = masksE
+    if masksP != [] :
+        pi0.PositionTags = masksP
+
+    if external  != '' :
+        pi0.InputData = external
+
+    pi0.PropertiesPrint = False
+    
+    pi0.EtCut    = mergedPi0Pt
+
+    if clusterOnly :
+        setTheProperty ( sseq , 'Context' , context )
+        return sseq
+    
+    ## MergedPi0 sequence
+    
+    ## 2/ SplitPhotons
+    #    splitg = getAlgo ( CaloFutureHypoAlg , 'PhotonFromMergedRec' , context )    
+    #    splitg.HypoType = "SplitPhotons";
+    #    splitg.PropertiesPrint = False   
+    
+    ## Add Prs/Spd digits
+    if not noSpdPrs :
+        pi0.addTool ( CaloFutureExtraDigits , 'SpdPrsExtraSFuture' )
+        pi0.addTool ( CaloFutureExtraDigits , 'SpdPrsExtraMFuture' )
+    ## Pi0 correction tools
+    pi0.addTool ( CaloFutureECorrection , 'ECorrectionFuture' )
+    pi0.addTool ( CaloFutureSCorrection , 'SCorrectionFuture' )
+    pi0.addTool ( CaloFutureLCorrection , 'LCorrectionFuture' )
+
+    # tool configuration via condDB only (remove default configuration)
+    if not noSpdPrs :
+        pi0.PhotonTools = [ pi0.SpdPrsExtraSFuture , pi0.ECorrectionFuture,pi0.SCorrectionFuture, pi0.LCorrectionFuture ]
+        pi0.Pi0Tools    = [ pi0.SpdPrsExtraMFuture ]
+    else :       
+        pi0.PhotonTools = [ pi0.ECorrectionFuture,pi0.SCorrectionFuture, pi0.LCorrectionFuture ]
+
+    seq.Members=[pi0]
+    
+    ## 3/ (PhotonFrom)MergedID
+    if neutralID : 
+        from CaloFuturePIDs.PIDs import (MergedID , PhotonFromMergedID )
+        idSeq = getAlgo( GaudiSequencer, "MergedIDSeq",context)
+        mID =  MergedID ( context,enableRecoOnDemand, useTracks )
+        pmID =  PhotonFromMergedID( context, enableRecoOnDemand, useTracks )
+        idSeq.Members = [ mID, pmID ]  
+        addAlgs ( seq , idSeq ) 
+
+    # propagate the context
+    setTheProperty ( seq , 'Context' , context )
+
+
+    ## onDemand
+    if enableRecoOnDemand :
+            onDemand ( 'Rec/Calo/SplitPhotons'      , seq , context ) 
+            onDemand ( 'Rec/Calo/MergedPi0s'        , seq , context )
+            #onDemand ( 'Rec/Calo/EcalSplitClusters' , seq , context )  ## ??
+
+    ## printout
+    _log.debug ( 'Configure MergedPi0 Reco Seq : %s  for : %s' %( seq.name() , context ))
+    if enableRecoOnDemand : 
+        _log.info    ('MergedPi0FutureReco onDemand')
+
+    return seq
+
+
+# =============================================================================
+if '__main__' == __name__ :
+    print __doc__
diff --git a/CaloFuture/CaloFutureReco/python/CaloFutureReco/__init__.py b/CaloFuture/CaloFutureReco/python/CaloFutureReco/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..3a678ef87471205a06d9465af67c9fc71c40f1a5
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/python/CaloFutureReco/__init__.py
@@ -0,0 +1,11 @@
+# $Id: __init__.py,v 1.2 2010-03-08 01:19:39 odescham Exp $
+# =============================================================================
+## Fictive module to define python "package" for CaloFuturerimeter Reconstruction
+#  @author Vanya BELYAEV Ivan.Belyaev@nikhe.nl
+#  @date 2008-07-17
+# =============================================================================
+__author__  = "Vanya BELYAEV Ivan.Belyaev@nikhef.nl"
+__version__ = "CVS tag $Name: not supported by cvs2svn $, version $Revision: 1.2 $"
+# =============================================================================
+# The END 
+# =============================================================================
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureClusterCorrect3x3Position.cpp b/CaloFuture/CaloFutureReco/src/CaloFutureClusterCorrect3x3Position.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1ae480f922356526448853a96e2abfb373bc2cad
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureClusterCorrect3x3Position.cpp
@@ -0,0 +1,146 @@
+// ============================================================================
+// Include files
+// STD & STL
+#include <algorithm>
+// from Gaudi
+#include "GaudiKernel/SmartDataPtr.h"
+// CaloFutureInterfaces
+#include "CaloFutureInterfaces/ICaloFutureClusterTool.h"
+#include "CaloFutureInterfaces/ICaloFutureHypoTool.h"
+// CaloDet
+#include "CaloDet/DeCalorimeter.h"
+// CaloFutureEvent
+#include "Event/CaloCluster.h"
+#include "Event/CaloHypo.h"
+#include "Event/CaloPosition.h"
+// CaloFutureUtils
+#include "CaloFutureUtils/CaloFutureDataFunctor.h"
+#include "CaloFutureUtils/CaloFutureAlgUtils.h"
+// Kernel
+#include "Kernel/CaloCellID.h"
+// local
+#include "CaloFutureClusterCorrect3x3Position.h"
+
+// ============================================================================
+/** @file CaloFutureClusterCorrect3x3Position.cpp
+ *
+ *  Implementation file for class : CaloFutureClusterCorrect3x3Position
+ *
+ *  @author Olivier Deschamps
+ *  @date 10/05/2002
+ *
+ *  Revision 1.2 2004/09/02 20:46:40  odescham
+ * - Transv. Shape parameters in option file
+ *
+ */
+// ============================================================================
+
+DECLARE_COMPONENT( CaloFutureClusterCorrect3x3Position )
+
+// ============================================================================
+/** Standard constructor
+ *  @param   name   algorithm name
+ *  @param   svcloc pointer to service locator
+ */
+// ============================================================================
+CaloFutureClusterCorrect3x3Position::CaloFutureClusterCorrect3x3Position
+( const std::string& name    ,
+  ISvcLocator*       svcloc  )
+  : GaudiAlgorithm ( name , svcloc )
+{
+  // set default data as a function of detector & context
+  m_detData= LHCb::CaloFutureAlgUtils::DeCaloFutureLocation( name ) ;
+  m_inputData = LHCb::CaloFutureAlgUtils::CaloFutureClusterLocation( name , context() );
+
+}
+
+// ============================================================================
+/** helper function to calculate number of digits
+ *  in the cluster with given status
+ *  @param cluster pointet to the cluster object
+ *  @param status  digit statsu to be checked
+ *  @return number of digits with given status.
+ *       In the case of errors it returns -1
+ */
+// ============================================================================
+long CaloFutureClusterCorrect3x3Position::numberOfDigits
+( const LHCb::CaloCluster*             cluster ,
+  const LHCb::CaloDigitStatus::Status& status  ) const
+{
+  /// check arguments
+  if( !cluster )
+  { Error(" numberOfDigits! CaloCluster* points to NULL!").ignore(); return -1;}
+  ///
+  const auto& entries = cluster->entries();
+  return std::count_if( entries.begin(), entries.end(),
+                        [&](const LHCb::CaloClusterEntry& entry) -> bool {
+                            return entry.status()&status;
+                        } );
+}
+
+// ============================================================================
+/** standard algorithm execution
+ *  @return status code
+ */
+// ============================================================================
+StatusCode CaloFutureClusterCorrect3x3Position::execute()
+{
+  /// avoid long names
+  using namespace  LHCb::CaloDataFunctor;
+  typedef LHCb::CaloClusters        Clusters;
+
+  /// load data
+  SmartDataPtr<DeCalorimeter> detector( detSvc() , m_detData );
+  if( !detector )
+    { return Error("could not locate calorimeter '"+m_detData+"'");}
+
+  const DeCalorimeter* calo =  getDet<DeCalorimeter>( m_detData ) ;
+  m_cell3x3.setDet ( calo ) ;
+  m_neighbour.setDet ( calo );
+  SmartDataPtr<Clusters>  clusters( eventSvc() , m_inputData );
+  if( !clusters ) { 
+      return Error("Could not load input data ='"+m_inputData+"'");
+  }
+
+  /// loop over all clusters
+  for( LHCb::CaloCluster* cluster : *clusters ) {
+      if( !cluster ) { continue ; }
+
+      double Energy=0;
+      double PosX=0;
+      double PosY=0;
+      /// Find Cluster Seed
+      const auto iSeed =
+        clusterLocateDigit( cluster->entries().begin() ,
+                            cluster->entries().end  () ,
+                            LHCb::CaloDigitStatus::SeedCell     );
+      const LHCb::CaloDigit* seed = iSeed->digit() ;
+      if( !seed) { continue ; }
+      const LHCb::CaloCellID&  seedID = seed->cellID() ;
+      // Loop over 3x3 digits
+      for(const auto& entry : cluster->entries()) {
+        const LHCb::CaloDigit*   cell = entry.digit();
+        const LHCb::CaloCellID&  cellID = cell->cellID() ;
+        if( 0 != m_cell3x3( seedID , cellID) && m_neighbour(seedID,cellID) ){
+          Energy += cell->e() * entry.fraction();
+          PosX += detector->cellX(cellID) * cell->e() * entry.fraction();
+          PosY += detector->cellY(cellID) * cell->e() * entry.fraction();
+        }
+      }
+      PosX=PosX/Energy;
+      PosY=PosY/Energy;
+      LHCb::CaloPosition pos = cluster->position();
+      LHCb::CaloPosition::Parameters  params;
+
+      params(LHCb::CaloPosition::Index::X)=PosX;
+      params(LHCb::CaloPosition::Index::Y)=PosY;
+      params(LHCb::CaloPosition::Index::E)=Energy;
+      pos.setParameters( params );
+      cluster->setPosition( pos );
+  }
+  return StatusCode::SUCCESS;
+}
+
+// ============================================================================
+// The End
+// ============================================================================
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureClusterCorrect3x3Position.h b/CaloFuture/CaloFutureReco/src/CaloFutureClusterCorrect3x3Position.h
new file mode 100644
index 0000000000000000000000000000000000000000..ace541f3ef80c11e3a609a02c9b3b4eee7ea11c1
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureClusterCorrect3x3Position.h
@@ -0,0 +1,59 @@
+#ifndef CALOFUTURERECO_CaloFutureClusterCorrect3x3Position_H
+#define CALOFUTURERECO_CaloFutureClusterCorrect3x3Position_H 1
+// Include files
+// from STL
+#include <string>
+#include <vector>
+//
+#include "GaudiAlg/GaudiAlgorithm.h"
+//CaloFutureUtils
+#include "CaloFutureUtils/CellMatrix3x3.h"
+#include "CaloFutureUtils/CellNeighbour.h"
+// forward declarations
+class    CaloCluster   ;
+struct  ICaloFutureHypoTool  ;
+
+/** @class CaloFutureClusterCorrect3x3Position CaloFutureClusterCorrect3x3Position.h
+ *
+ *  Merged pi0 reconstruction with Iterativ Method
+ *
+ *  @author Olivier Deschamps
+ *  @date   05/10/2002
+ */
+
+class CaloFutureClusterCorrect3x3Position : public GaudiAlgorithm
+{
+public:
+  /** Standard constructor
+   *  @param   name   algorithm name
+   *  @param   svcloc pointer to service locator
+   */
+  CaloFutureClusterCorrect3x3Position( const std::string& name   ,
+                                 ISvcLocator*       svcloc );
+
+  /** standard algorithm execution
+   *  @return status code
+   */
+  StatusCode execute   () override;
+
+protected:
+
+  /** helper function to calculate number of digits
+   *  in the cluster with given status
+   *  @param cluster pointet to the cluster object
+   *  @param status  digit statsu to be checked
+   *  @return number of digits with given status.
+   *       In the case of errors it returns -1
+   */
+  long numberOfDigits ( const LHCb::CaloCluster*             cluster ,
+                        const LHCb::CaloDigitStatus::Status& status  ) const ;
+
+ private:
+  CellMatrix3x3 m_cell3x3 ;
+  CellNeighbour m_neighbour;
+  Gaudi::Property<std::string> m_inputData {this, "InputData", LHCb::CaloClusterLocation::Ecal};
+  Gaudi::Property<std::string> m_detData {this, "Detector", DeCalorimeterLocation::Ecal};
+};
+
+// ============================================================================
+#endif // CaloFutureClusterCorrect3x3Position_H
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureClusterCovarianceAlg.cpp b/CaloFuture/CaloFutureReco/src/CaloFutureClusterCovarianceAlg.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..041833808e4e6cd06045b04947bd32646a56b49a
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureClusterCovarianceAlg.cpp
@@ -0,0 +1,154 @@
+//  ===========================================================================
+#define CALOFUTURERECO_CALOFUTURECLUSTERCOVARIANCEALG_CPP 1 
+/// ===========================================================================
+// Include files
+#include  "Event/CaloCluster.h"
+#include  "CaloFutureInterfaces/ICaloFutureClusterTool.h"
+#include  "FutureSubClusterSelectorTool.h"
+#include  "CaloFutureUtils/CovarianceEstimator.h"
+#include  "CaloFutureUtils/CaloFutureAlgUtils.h"
+#include  "CaloFutureClusterCovarianceAlg.h"
+
+// ===========================================================================
+/** @file
+ * 
+ *  Implementation file for class CaloFutureClusterCovarianceAlg
+ * 
+ *  @see CaloFutureClusterCovarinanceAlg
+ *  @see ICaloFutureClusterTool
+ *  @see ICaloFutureSubClusterTag 
+ * 
+ *  @author Vanya Belyaev Ivan.Belyaev@itep.ru
+ *  @date 04/07/2001 
+s */
+// ===========================================================================
+
+DECLARE_COMPONENT( CaloFutureClusterCovarianceAlg )
+
+// ============================================================================
+/** Standard constructor
+ *  @param   name          algorithm name
+ *  @param   pSVcLocator   pointer to Service Locator
+*/
+// ============================================================================
+CaloFutureClusterCovarianceAlg::CaloFutureClusterCovarianceAlg
+( const std::string& name,
+  ISvcLocator* pSvcLocator)
+  : GaudiAlgorithm        ( name , pSvcLocator            ) 
+{
+  // following properties might be inherited by the covariance tool
+  declareProperty( "CovarianceParameters" , m_covParams    ) ; // KEEP IT UNSET ! INITIAL VALUE WOULD BYPASS DB ACCESS
+
+  // set default data as a function of detector
+  m_inputData = LHCb::CaloFutureAlgUtils::CaloFutureClusterLocation( name , context() );
+
+  std::string caloName =  LHCb::CaloFutureAlgUtils::CaloFutureNameFromAlg( name );
+  m_covName    = caloName + "CovarTool" ;
+  m_spreadName = caloName + "SpreadTool";
+  m_tagName    = caloName + "ClusterTag";
+}
+
+// ===========================================================================
+/** standard initialization method 
+ *  @see GaudiAlgorithm
+ *  @see     Algorithm 
+ *  @see    IAlgorithm
+ *  @return status code 
+ */
+// ===========================================================================
+StatusCode CaloFutureClusterCovarianceAlg::initialize(){
+  // try to initialize base class   
+  StatusCode sc = GaudiAlgorithm::initialize();
+  if( sc.isFailure() )
+    { return Error("Could not initialize the base class GaudiAlgorithm"); }  
+
+  // locate the tagger (inherit from relevant properties)
+  m_tagger = tool<FutureSubClusterSelectorTool>( "FutureSubClusterSelectorTool" , m_tagName , this );
+
+  // locate the tool for covariance matrix calculations 
+  m_cov    = m_covName.empty() ?
+    tool<ICaloFutureClusterTool>(    m_covType                   , this ) :
+    tool<ICaloFutureClusterTool>(    m_covType    , m_covName    , this ) ;
+  
+  // locate the tool for cluster spread(2nd moments) estimation 
+  m_spread = m_spreadName.empty() ? 
+    tool<ICaloFutureClusterTool>(    m_spreadType                , this ) :
+    tool<ICaloFutureClusterTool>(    m_spreadType , m_spreadName , this ) ;
+  
+  // copy flag
+  m_copy = (!m_outputData.empty()) && (m_outputData.value() != m_inputData.value());
+
+  counterStat = tool<IFutureCounterLevel>("FutureCounterLevel");
+  return StatusCode::SUCCESS;
+}
+
+
+
+// ===========================================================================
+StatusCode CaloFutureClusterCovarianceAlg::finalize(){
+  // finalize the base class 
+  return GaudiAlgorithm::finalize();
+}
+
+// ===========================================================================
+StatusCode CaloFutureClusterCovarianceAlg::execute(){
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) debug() << "==> Execute" << endmsg;
+  
+  // useful typedefs
+  typedef LHCb::CaloClusters        Clusters ;
+  
+  // locate input data
+  Clusters* clusters =    get<Clusters> ( m_inputData );
+  if( 0 == clusters ) { return StatusCode::FAILURE ; }
+  //
+  
+  // define the output data 
+  Clusters* output = 0;
+  if( m_copy ){
+    // make a copy of container 
+    output = new Clusters();
+    put( output , m_outputData );
+    // make a copy 
+    for( const LHCb::CaloCluster* i: *clusters ) {
+      if ( i ) output->insert( new LHCb::CaloCluster(*i) ) ;
+    }
+  }
+  else { output = clusters; } // update existing sequence
+  
+  // 
+  for( Clusters::iterator cluster =  output->begin() ; output->end() != cluster ; ++cluster ){
+
+    // skip nulls 
+    if( 0 == *cluster  ) { continue ; }
+
+    
+    // == APPLY TAGGER
+    StatusCode sc = m_tagger -> tag ( *cluster );
+    if( sc.isFailure() ){
+      Error("Error from tagger, skip cluster ", sc ).ignore() ; 
+      if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) debug() << *cluster << endmsg ;
+      continue ; 
+    }
+
+    // == APPLY COVARIANCE ESTIMATOR
+    sc = cov() -> process( *cluster ) ;    
+    if( sc.isFailure() ){ 
+      Error("Error from cov,    skip cluster ", sc, 0 ).ignore() ; 
+      if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) debug() << *cluster << endmsg ;
+      continue ; 
+    }
+
+    // == APPLY SPREAD ESTIMATOR
+    sc = spread() -> process( *cluster ) ;
+    if( sc.isFailure() ){ 
+      Error("Error from spread, skip cluster ", sc, 0 ).ignore() ; 
+      if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) debug() << *cluster << endmsg ;
+      continue ; 
+    }
+  }
+  
+  // == FUTURECOUNTER
+  if(counterStat->isQuiet())counter ( "#Clusters from '" + m_inputData  + "'") += clusters->size() ;
+  return StatusCode::SUCCESS ;
+}
+
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureClusterCovarianceAlg.h b/CaloFuture/CaloFutureReco/src/CaloFutureClusterCovarianceAlg.h
new file mode 100644
index 0000000000000000000000000000000000000000..321b15737848579024ec2daef4d9ed43c4c34ad3
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureClusterCovarianceAlg.h
@@ -0,0 +1,112 @@
+// ===========================================================================
+#ifndef CALOFUTURERECO_CALOFUTURECLUSTERCOVARIANCEALG_H
+#define CALOFUTURERECO_CALOFUTURECLUSTERCOVARIANCEALG_H 1
+/// ===========================================================================
+// Include files
+// from STL
+#include <string>
+#include "GaudiAlg/GaudiAlgorithm.h"
+#include "CaloFutureInterfaces/IFutureCounterLevel.h"
+
+struct ICaloFutureClusterTool   ;
+class FutureSubClusterSelectorTool ;
+
+/** @class CaloFutureClusterCovarianceAlg CaloFutureClusterCovarianceAlg.h
+ *
+ *   Simple algorithm for evaluation of covariance matrix
+ *   for CaloFutureCluster object
+ *
+ *  @author Vanya BElyaev Ivan Belyaev
+ *  @date   04/07/2001
+ */
+
+class CaloFutureClusterCovarianceAlg : public GaudiAlgorithm
+{
+public:
+
+  /** Standard constructor
+   *  @param   name          algorith name
+   *  @param   pSvcLocator   pointer to Service Locator
+   */
+  CaloFutureClusterCovarianceAlg
+  ( const std::string& name  ,
+    ISvcLocator*       pSvcLocator );
+  
+  /** standard initialization method
+   *  @see GaudiAlgorithm
+   *  @see     Algorithm
+   *  @see    IAlgorithm
+   *  @return status code
+   */
+  StatusCode initialize() override;
+
+  /** standard execution method
+   *  @see GaudiAlgorithm
+   *  @see     Algorithm
+   *  @see    IAlgorithm
+   *  @return status code
+   */
+  StatusCode execute() override;
+
+  /** standard finalization method
+   *  @see GaudiAlgorithm
+   *  @see     Algorithm
+   *  @see    IAlgorithm
+   *  @return status code
+   */
+  StatusCode finalize() override;
+
+protected:
+
+  inline ICaloFutureClusterTool*       cov    () const { return m_cov    ; }
+  inline ICaloFutureClusterTool*       spread () const { return m_spread ; }
+  inline FutureSubClusterSelectorTool* tagger () const { return m_tagger ; }
+
+
+private:
+
+  /// default constructor is private
+  CaloFutureClusterCovarianceAlg();
+
+  /** copy constructor is private
+   *  @param copy object to be copied
+   */
+  CaloFutureClusterCovarianceAlg
+  ( const  CaloFutureClusterCovarianceAlg& copy );
+
+  /** assignement operator is private
+   *  @param copy object to be copied
+   */
+  CaloFutureClusterCovarianceAlg& operator=
+  ( const  CaloFutureClusterCovarianceAlg& copy );
+
+private:
+
+  bool                    m_copy = false ;  /// copy flag
+
+  // tool used for covariance matrix calculation
+  Gaudi::Property<std::string> m_covType {this, "CovarianceType", "FutureClusterCovarianceMatrixTool"};
+  Gaudi::Property<std::string> m_covName {this, "CovarianceName"};
+  ICaloFutureClusterTool*       m_cov    = nullptr ; ///< tool
+  FutureSubClusterSelectorTool* m_tagger = nullptr ;
+
+  // tool used for cluster spread estimation
+  Gaudi::Property<std::string> m_spreadType {this, "SpreadType", "FutureClusterSpreadTool"};
+  Gaudi::Property<std::string> m_spreadName {this, "SpreadName"};
+  ICaloFutureClusterTool*       m_spread = nullptr ; ///< tool
+
+  Gaudi::Property<std::string> m_outputData {this, "OutputData"};
+  Gaudi::Property<std::string> m_inputData  {this, "InputData"};
+  Gaudi::Property<std::string> m_tagName    {this, "TaggerName"};
+
+  // following properties are inherited by the selector tool when defined:
+  Gaudi::Property<std::vector<std::string>> m_taggerE {this, "EnergyTags"};
+  Gaudi::Property<std::vector<std::string>> m_taggerP {this, "PositionTags"};
+
+  // collection of known cluster shapes
+  std::map<std::string , std::string> m_clusterShapes;
+  std::map<std::string,std::vector<double> > m_covParams;
+  IFutureCounterLevel* counterStat = nullptr;
+  };
+
+#endif // CALOFUTURERECO_CALOFUTURECLUSTERCOVARIANCEALG_H
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureClusterizationTool.cpp b/CaloFuture/CaloFutureReco/src/CaloFutureClusterizationTool.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ce32f5a33595933f0f9ff8fdac294dacb875fa7d
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureClusterizationTool.cpp
@@ -0,0 +1,388 @@
+// Include files
+
+// from Gaudi
+#include "GaudiKernel/SystemOfUnits.h"
+// ============================================================================
+#include "DetDesc/IGeometryInfo.h"
+// ============================================================================
+#include "Event/CaloDigit.h"
+#include "Event/CaloCluster.h"
+#include "CaloFutureUtils/CaloFutureDataFunctor.h"
+#include "Event/CellID.h"
+// ============================================================================
+#include "CaloFutureUtils/ClusterFunctors.h"
+#include "CaloFutureUtils/CaloFutureNeighbours.h"
+// local
+#include "CaloFutureClusterizationTool.h"
+#include "TaggedCellFunctor.h"
+
+//-----------------------------------------------------------------------------
+// Implementation file for class : CaloFutureClusterizationTool
+//
+// 2008-04-04 : Victor Egorychev
+//-----------------------------------------------------------------------------
+
+// Declaration of the Tool Factory
+DECLARE_COMPONENT( CaloFutureClusterizationTool )
+
+// ============================================================================
+inline bool CaloFutureClusterizationTool::isLocMax
+( const LHCb::CaloDigit*                     digit ,
+  const CaloFutureClusterizationTool::DirVector&   hits  ,
+  const DeCalorimeter*                       det   ) const
+{
+
+  const CaloNeighbors& ns = det->neighborCells( digit -> cellID() ) ;
+  double e = digit -> e() ;
+
+  LHCb::CaloDataFunctor::EnergyTransverse<const DeCalorimeter*> et ( det ) ;
+
+  double eT = ( m_withET ? et(digit) : 0. );
+
+  for ( const auto& iN : ns ) {
+    const CelAutoTaggedCell* cell = hits[iN];
+    if ( !cell   ) { continue     ; }
+    const LHCb::CaloDigit* nd = cell->digit() ;
+    if ( !nd     ) { continue     ; }
+
+    if ( nd->e() > e ) { return false ; }
+
+    if ( m_withET ) { eT += et ( nd ) ; }
+  }
+
+  if ( m_withET && eT < m_ETcut ) { return false ; }
+
+  return true ;
+}
+// ============================================================================
+/* Application of rules of tagging on one cell
+ *   - No action if no clustered neighbor
+ *   - Clustered if only one clustered neighbor
+ *   - Edge if more then one clustered neighbor
+ */
+// ============================================================================
+inline void
+CaloFutureClusterizationTool::appliRulesTagger
+( CelAutoTaggedCell*             cell ,
+  CaloFutureClusterizationTool::DirVector&  hits ,
+  const DeCalorimeter*           det  ,
+  const bool  releaseBool) const
+{
+
+  // Find in the neighbors cells tagged before, the clustered neighbors cells
+  const LHCb::CaloCellID&    cellID = cell->cellID() ;
+  const CaloNeighbors& ns     = det->neighborCells ( cellID ) ;
+  bool hasEdgeNeighbor = false;
+  bool hasClusteredNeighbor = false;
+  for ( CaloNeighbors::const_iterator iN = ns.begin() ; ns.end() != iN ; ++iN ){
+    const CelAutoTaggedCell* nei = hits[ *iN ] ;
+    if ( 0 == nei                 ) { continue ; }
+    //
+    if( nei->isEdge() && releaseBool ){
+      hasEdgeNeighbor = true;
+      for( std::vector<LHCb::CaloCellID>::const_iterator id = nei->seeds().begin();id != nei->seeds().end();id++){
+        if( !cell->isWithSeed( *id ) )cell->addSeed( *id );
+      }
+    }
+    //
+    if ( !nei->isClustered()      ) { continue ; }
+    hasClusteredNeighbor = true;
+    const LHCb::CaloCellID& seed = nei->seedForClustered() ;
+    if ( cell->isWithSeed( seed ) ) { continue ; }
+    cell->addSeed ( seed ) ;
+  }
+
+
+  // Tag or or not the cell
+
+  switch ( cell -> numberSeeds() ) {
+  case 0:
+    if( !releaseBool)break;
+    if( hasEdgeNeighbor && !hasClusteredNeighbor)cell->setEdge(); //
+    break;
+  case 1:
+    cell->setClustered();
+    break;
+  default:
+    cell->setEdge();
+    break;
+  }
+}
+
+// ============================================================================
+inline StatusCode CaloFutureClusterizationTool::setEXYCluster( LHCb::CaloCluster& cluster, const DeCalorimeter* detector ) const
+{
+  ///
+  double E, X, Y;
+  ///
+  StatusCode sc = LHCb::ClusterFunctors::calculateEXY
+    ( cluster.entries().begin() ,
+      cluster.entries().end  () ,
+      detector , E , X , Y      );
+  ///
+  m_clusterEnergy += E;
+  if( sc.isSuccess() ){
+    cluster.position().parameters()( LHCb::CaloPosition::Index::E ) = E ;
+    cluster.position().parameters()( LHCb::CaloPosition::Index::X ) = X ;
+    cluster.position().parameters()( LHCb::CaloPosition::Index::Y ) = Y ;
+  }
+  else
+  { Error( " E,X and Y of cluster could not be evaluated!",sc).ignore(); }
+  ///
+  return sc;
+}
+
+unsigned int CaloFutureClusterizationTool::clusterize( std::vector<LHCb::CaloCluster*>&       clusters     ,
+                                                const LHCb::CaloDigits& hits,
+                                                const DeCalorimeter* m_detector   ,
+                                                const std::vector<LHCb::CaloCellID>&   _cell_list   ,
+                                                const unsigned int                     m_neig_level ) const
+{
+
+  //
+
+  // cmb: this needs to be done every time in order
+  // to allow different detectors in the same algorithm
+  // --> to be revisited in a future round
+  CellSelector cellSelectorE;
+  CellSelector cellSelectorP;
+  cellSelectorE.setSelector(m_usedE);
+  cellSelectorP.setSelector(m_usedP);
+  cellSelectorE.setDet(m_detector);
+  cellSelectorP.setDet(m_detector);
+  bool releaseBool = false;
+  bool useData = false;
+  //
+  LHCb::CaloCellID::Set out_cells;
+
+
+  /*
+
+  _cell_list.empty()  && level > 0   ->  All local maxima + neighborhood(level)
+  _cell_list.empty()  && level = 0   ->  All data (default)
+  !_cell_list.empty() && level > 0   ->  seed lis + neighborhood(level)
+  !_cell_list.empty() && level = 0   ->  seed list
+  */
+
+
+  // fill with data if level >0 and no predefined seed list
+  std::vector<LHCb::CaloCellID> cell_list;
+  if( _cell_list.empty() && m_neig_level>0){
+    useData = true;
+
+    cell_list.reserve(hits.size());
+    for(const auto& i : hits ) {
+      const CaloNeighbors& neighbors = m_detector->neighborCells( i -> cellID() ) ;
+      if ( std::none_of( neighbors.begin(), neighbors.end(),
+                                  [&,e = i->e()](const auto& n) {
+                                      if ( !m_detector->valid( n )) return false;
+                                      const LHCb::CaloDigit* dig = hits( n );
+                                      return dig && dig->e() > e;
+                                   } ) )  {
+          cell_list.push_back( i->cellID() );
+      }
+    }
+  }
+  else{
+    cell_list.assign( _cell_list.begin(), _cell_list.end() );
+  }
+
+
+  //  info() << "Cell list " << _cell_list << " level = " << m_neig_level  << endmsg;
+
+  // if list of "seed" is not empty
+  if( !cell_list.empty() ){
+    out_cells.insert( cell_list.begin(), cell_list.end() );
+
+    /** find all neighbours for the given set of cells for the givel level
+     *  @param cells    (UPDATE) list of cells
+     *  @param level    (INPUT)  level
+     *  @param detector (INPUT) the detector
+     *  @return true if neighbours are added
+     */
+    LHCb::CaloFutureFunctors::neighbours(out_cells, m_neig_level, m_detector);
+  }
+
+  // z-position of cluster
+  LHCb::ClusterFunctors::ZPosition zPosition( m_detector );
+
+  // Create access direct and sequential on the tagged cells
+  DirVector taggedCellsDirect( (CelAutoTaggedCell*) 0 ) ;
+  /// container to tagged  cells with sequential access
+  std::vector<CelAutoTaggedCell*> taggedCellsSeq;
+
+  size_t local_size = cell_list.empty() ? hits.size() : out_cells.size();
+  const CelAutoTaggedCell cell0_ = CelAutoTaggedCell () ;
+  std::vector<CelAutoTaggedCell> local_cells ( local_size  , cell0_ ) ;
+
+  if( cell_list.empty() ){
+    taggedCellsDirect.reserve ( hits.size() ) ;
+    taggedCellsDirect.setSize ( 14000        ) ;
+    taggedCellsSeq.reserve    ( hits.size() ) ;
+  }
+  else{
+    taggedCellsDirect.reserve ( out_cells.size() ) ;
+    taggedCellsDirect.setSize ( 14000            ) ;
+    taggedCellsSeq.reserve    ( out_cells.size() ) ;
+  }
+
+  if( cell_list.empty() ){
+    // fill with the data
+    size_t index = 0 ;
+
+    for( auto ihit =hits.begin() ; hits.end() != ihit ; ++ihit , ++index ){
+      const LHCb::CaloDigit* digit   = *ihit ;
+      if ( !digit ) { continue ; }  // CONTINUE !!!
+      CelAutoTaggedCell& taggedCell = *(local_cells.begin() + index ) ;
+      taggedCell = digit ;
+
+      taggedCellsDirect.addEntry ( &taggedCell , digit->cellID() ) ;
+      taggedCellsSeq.push_back   ( &taggedCell                   ) ;
+
+    }
+  }else{//fill for HLT
+    size_t index = 0 ;
+
+    for(std::set<LHCb::CaloCellID>::const_iterator icell = out_cells.begin();
+        out_cells.end() != icell; ++icell , ++index){
+
+      const LHCb::CaloDigit* digit   = hits(*icell);
+      if ( 0 == digit ) { continue ; }  // CONTINUE !!!
+
+      CelAutoTaggedCell& taggedCell = *(local_cells.begin() + index ) ;
+      taggedCell = digit ;
+
+      taggedCellsDirect.addEntry ( &taggedCell , digit->cellID() ) ;
+      taggedCellsSeq.push_back   ( &taggedCell                   ) ;
+    }
+
+  }
+
+
+   // Find and mark the seeds (local maxima)
+  if(useData){
+    for(std::vector<LHCb::CaloCellID>::iterator seed = cell_list.begin();seed!=cell_list.end();seed++){
+      taggedCellsDirect[*seed]->setIsSeed();
+    }
+  }
+  else{
+    for( auto itTag = taggedCellsSeq.begin(); taggedCellsSeq.end() != itTag ; ++itTag ){
+      if ( isLocMax ( (*itTag)->digit() ,taggedCellsDirect ,m_detector)       ) {
+        (*itTag)->setIsSeed();
+      }
+    }
+  }
+
+  /// Tag the cells which are not seeds
+  auto itTagLastSeed = std::stable_partition( taggedCellsSeq.begin () ,
+                                              taggedCellsSeq.end   () ,
+                                              TaggedCellFunctor::isClustered() );
+
+  auto itTagLastClustered = itTagLastSeed      ;
+  auto itTagFirst         = itTagLastClustered ;
+  unsigned int nPass = 0;
+  while ( itTagLastClustered != taggedCellsSeq.end() ) {
+
+    // Apply rules tagger for all not tagged cells
+    for ( auto itTag = itTagLastClustered ; taggedCellsSeq.end() != itTag ; ++itTag ){
+      appliRulesTagger( (*itTag),  taggedCellsDirect , m_detector, releaseBool );
+    }
+
+    // Valid result
+    std::for_each ( itTagFirst, taggedCellsSeq.end(), TaggedCellFunctor::setStatus() );
+
+    itTagLastClustered = std::stable_partition( itTagFirst,
+                                                taggedCellsSeq.end(),
+                                                TaggedCellFunctor::isClusteredOrEdge() );
+
+    // Test if cells are tagged in this pass
+    if ( itTagLastClustered == itTagFirst && releaseBool ){
+      const long number = taggedCellsSeq.end() - itTagLastClustered ;
+      if( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+        debug() << " TAGGING NOT FULL - Remain "
+                << std::to_string ( number  )
+                << " not clustered cells" << endmsg ;
+      itTagLastClustered = taggedCellsSeq.end();
+    }
+    if( itTagLastClustered == itTagFirst )releaseBool = true; // try additional passes releasing appliRulesTagger criteria
+    nPass++;
+    itTagFirst = itTagLastClustered;
+    if( m_passMax > 0 && nPass >= m_passMax)break;
+  }
+
+
+
+  LHCb::CaloDigitStatus::Status usedForE = LHCb::CaloDigitStatus::UseForEnergy   | LHCb::CaloDigitStatus::UseForCovariance  ;
+  LHCb::CaloDigitStatus::Status usedForP = LHCb::CaloDigitStatus::UseForPosition | LHCb::CaloDigitStatus::UseForCovariance  ;
+  LHCb::CaloDigitStatus::Status seed = LHCb::CaloDigitStatus::SeedCell |LHCb::CaloDigitStatus::LocalMaximum | usedForP | usedForE;
+
+
+  itTagLastClustered = std::stable_partition( itTagLastSeed                    ,
+                                              taggedCellsSeq.end()             ,
+                                              TaggedCellFunctor::isClustered() ) ;
+  auto itTagSeed = taggedCellsSeq.begin();
+  auto itTagClustered1 = itTagLastSeed;
+  while ( itTagSeed != itTagLastSeed ){
+    const LHCb::CaloDigit* digit = (*itTagSeed)->digit() ;
+
+    if( digit->e() <= 0 ) {
+      itTagSeed++;
+      m_negativeSeed += digit->e();
+      continue; // does not keep cluster with seed.energy <= 0
+    }
+
+    LHCb::CaloCellID seedID = (*itTagSeed)->cellID();
+    // Do partitions first
+    auto itTagClustered2 = std::stable_partition( itTagClustered1 ,
+                                                  itTagLastClustered ,
+                                                  TaggedCellFunctor::isWithSeed(seedID) ) ;
+    auto itTagFirstEdge = itTagLastClustered ;
+    auto itTagLastEdge  = std::stable_partition( itTagLastClustered ,
+                                                 taggedCellsSeq.end() ,
+                                                 TaggedCellFunctor::isWithSeed (seedID) ) ;
+
+    // Create cluster, reserve, fill
+    auto cluster = std::make_unique<LHCb::CaloCluster>();
+    cluster->entries().reserve(1 + (itTagClustered2 - itTagClustered1) + (itTagLastEdge - itTagFirstEdge) );
+
+    // set seed
+    cluster->entries().emplace_back( digit , seed );
+    cluster->setSeed( digit->cellID() );
+
+    // Owned cells
+    for (  ; itTagClustered1 != itTagClustered2 ; ++itTagClustered1 ){
+      LHCb::CaloCellID  cellID = (*itTagClustered1)->cellID();
+      const LHCb::CaloDigit* digit = (*itTagClustered1)->digit() ;
+      LHCb::CaloDigitStatus::Status owned  = LHCb::CaloDigitStatus::OwnedCell ;
+      if( cellSelectorE( seedID, cellID) > 0.)owned |= usedForE;
+      if( cellSelectorP( seedID, cellID) > 0.)owned |= usedForP;
+      cluster->entries().emplace_back( digit , owned );
+    }
+    // Shared cells
+    for(  ; itTagFirstEdge != itTagLastEdge ; ++itTagFirstEdge  ){
+      const LHCb::CaloDigit* digit = (*itTagFirstEdge)->digit() ;
+      LHCb::CaloCellID  cellID = (*itTagFirstEdge)->cellID();
+      LHCb::CaloDigitStatus::Status shared = LHCb::CaloDigitStatus::SharedCell;
+      if( cellSelectorE( seedID, cellID) > 0.)shared |= usedForE;
+      if( cellSelectorP( seedID, cellID) > 0.)shared |= usedForP;
+      cluster->entries().emplace_back( digit , shared );
+    };
+
+    if( setEXYCluster ( *cluster, m_detector ).isSuccess() ){
+      cluster->setType( LHCb::CaloCluster::Type::CellularAutomaton ) ;
+      cluster->position().setZ( zPosition( cluster.get() )  );
+      //  put cluster to the output
+      clusters.push_back( cluster.release() );
+      m_clusterEnergy += clusters.back()->entries().size();
+    }
+    itTagClustered1 = itTagClustered2;
+    itTagSeed++;
+  }
+
+  // clear local storages
+  taggedCellsSeq    .clear () ;
+  taggedCellsDirect .clear () ;
+  local_cells       .clear () ;
+
+  return nPass;
+}
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureClusterizationTool.h b/CaloFuture/CaloFutureReco/src/CaloFutureClusterizationTool.h
new file mode 100644
index 0000000000000000000000000000000000000000..3ea629544a225e64080f9273e930f83f8f7ee4b0
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureClusterizationTool.h
@@ -0,0 +1,60 @@
+#ifndef CALOFUTURECLUSTERIZATIONTOOL_H
+#define CALOFUTURECLUSRERIZATIONTOOL_H 1
+// ============================================================================
+#include <string>
+#include "GaudiAlg/GaudiTool.h"
+#include "CaloKernel/CaloVector.h"
+#include "CaloFutureInterfaces/ICaloFutureClusterization.h"
+#include "GaudiKernel/Counters.h"
+#include "CaloDet/DeCalorimeter.h"
+#include "CelAutoTaggedCell.h"
+#include "CaloFutureUtils/CellSelector.h"
+
+/** @class CaloFutureClusterizationTool CaloFutureClusterizationTool.h
+ *
+ *
+ *  @author Victor Egorychev
+ *  @date   2008-04-03
+ */
+class CaloFutureClusterizationTool : public extends<GaudiTool,ICaloFutureClusterization> {
+
+public:
+  /// container to tagged  cells with direct (by CaloCellID key)  access
+  typedef CaloVector<CelAutoTaggedCell*>  DirVector ;
+
+  /// Extend ICaloFutureClusterization
+  using extends<GaudiTool,ICaloFutureClusterization>::extends;
+
+  unsigned int clusterize
+  ( std::vector<LHCb::CaloCluster*>&      clusters   ,
+    const LHCb::CaloDigits&               hits       ,
+    const DeCalorimeter*                  detector   ,
+    const std::vector<LHCb::CaloCellID>&  seeds      ,
+    const unsigned int                    level      ) const override;
+
+private:
+
+  inline bool isLocMax
+  ( const LHCb::CaloDigit*     digit ,
+    const DirVector&     hits  ,
+    const DeCalorimeter* det ) const ;
+
+  inline void appliRulesTagger
+  ( CelAutoTaggedCell*   taggedCell,
+    DirVector&           taggedCellsDirect,
+    const DeCalorimeter* detector,
+    const bool           releaseBool) const ;
+
+  inline StatusCode setEXYCluster( LHCb::CaloCluster&         cluster,const DeCalorimeter* detector ) const ;
+
+  Gaudi::Property<bool> m_withET{this, "withET", false};
+  Gaudi::Property<double> m_ETcut{this, "ETcut", -10. * Gaudi::Units::GeV};
+  Gaudi::Property<std::string> m_usedE{this, "CellSelectorForEnergy", "3x3"};
+  Gaudi::Property<std::string> m_usedP{this, "CellSelectorForPosition", "3x3"};
+  Gaudi::Property<unsigned int> m_passMax{this, "MaxIteration", 10};
+
+  mutable Gaudi::Accumulators::StatCounter<> m_clusterEnergy{this, "Cluster energy"};
+  mutable Gaudi::Accumulators::StatCounter<> m_negativeSeed{this, "Negative seed energy"};
+  mutable Gaudi::Accumulators::StatCounter<> m_clusterSize{this, "Cluster size"};
+  };
+#endif // CALOFUTURECLUSTERIZATIONTOOL_H
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureCorrectionBase.cpp b/CaloFuture/CaloFutureReco/src/CaloFutureCorrectionBase.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..32862abb41665726b83baf4cb7d88754c8b79656
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureCorrectionBase.cpp
@@ -0,0 +1,557 @@
+// Include files 
+
+#include "Event/ProtoParticle.h"
+#include "CaloFutureCorrectionBase.h"
+
+//-----------------------------------------------------------------------------
+// Implementation file for class : CaloFutureCorrectionBase
+//
+// 2010-05-07 : Olivier Deschamps
+//-----------------------------------------------------------------------------
+
+// Declaration of the Tool Factory
+DECLARE_COMPONENT( CaloFutureCorrectionBase )
+
+
+//=============================================================================
+// Standard constructor, initializes variables
+//=============================================================================
+CaloFutureCorrectionBase::CaloFutureCorrectionBase( const std::string& type   , 
+                                        const std::string& name   ,
+                                        const IInterface*  parent ) 
+  : GaudiTool ( type, name , parent )
+{
+  declareInterface<CaloFutureCorrectionBase>(this);
+  m_cmLoc = LHCb::CaloFutureAlgUtils::CaloFutureIdLocation("ClusterMatch", context());
+}
+
+//=============================================================================
+// Initialization
+//=============================================================================
+StatusCode CaloFutureCorrectionBase::initialize() {
+  StatusCode sc = GaudiTool::initialize(); // must be executed first
+  if ( sc.isFailure() ) return sc;  // error printed already by GaudiTool
+
+  if ( UNLIKELY (msgLevel(MSG::DEBUG) ) ) debug() << "==> Initialize" << endmsg;
+
+  // register to incident service
+  IIncidentSvc* inc = incSvc() ;
+  if ( inc ) inc -> addListener( this , IncidentType::EndEvent ) ;
+
+  // check the setting
+
+  // transform vector of accepted hypos
+  m_hypos.clear () ;
+  for( const auto& hypo : m_hypos_ ) {
+    if( hypo <= (int) LHCb::CaloHypo::Hypothesis::Undefined ||
+        hypo >= (int) LHCb::CaloHypo::Hypothesis::Other      )
+    { return Error("Invalid/Unknown  Calorimeter hypothesis object!" ) ; }
+    m_hypos.push_back( LHCb::CaloHypo::Hypothesis( hypo ));
+  }
+  
+  // locate and set and configure the Detector 
+  m_det = getDet<DeCalorimeter>( m_detData ) ;
+  if( !m_det ) { return StatusCode::FAILURE ; }
+  m_calo.setCaloFuture( m_detData);
+  //
+  if( m_hypos.empty() )return Error("Empty vector of allowed Calorimeter Hypotheses!" ) ; 
+  
+  // debug printout of all allowed hypos 
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) {
+    debug() << " List of allowed hypotheses : " << endmsg;
+    for( const auto& h : m_hypos ) {
+      debug ()  <<  " -->" << h  << endmsg ; 
+    }
+    for( const auto& c : m_corrections ) {
+      debug() << "Accepted corrections :  '" << c <<"'" << endmsg;
+    }
+  }
+
+  // get external tools
+  m_caloElectron = tool<ICaloFutureElectron>("CaloFutureElectron", this);
+  m_pileup = tool<ICaloFutureDigitFilterTool>("CaloFutureDigitFilterTool","FilterTool");
+  m_tables = tool<ICaloFutureRelationsGetter>("CaloFutureRelationsGetter","CaloFutureRelationsGetter",this);
+  counterStat = tool<IFutureCounterLevel>("FutureCounterLevel");
+  return setConditionParams(m_conditionName);
+}
+
+
+//=============================================================================
+//  Finalize
+//=============================================================================
+StatusCode CaloFutureCorrectionBase::finalize()
+{
+  if ( UNLIKELY(msgLevel(MSG::DEBUG)) ) debug() << "==> Finalize" << endmsg;
+
+  if( m_corrections.size() > 1 || *(m_corrections.begin()) != "All" ){
+    for( const auto& c :  m_corrections ) {
+      info() << "Accepted corrections :  '" << c <<"'" << endmsg;
+    }
+  }
+  if( m_corrections.empty())warning() << "All corrections have been disabled for " <<  name() << endmsg;
+  
+    if( m_cond == nullptr )
+      warning() << " Applied corrections configured via options for  " << name() <<endmsg;
+    else if( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+      debug() << " Applied corrections configured via condDB  ('" << m_conditionName << "') for " 
+              << name() << endmsg;
+    
+  for ( const auto& param : m_params ) 
+  {
+    if ( !param.active ) continue;
+    const auto & type = param.type;
+    const auto & vec  = param.data;
+    if ( !vec.empty() )
+    {
+      int func = vec[0];
+      int dim  = vec[1];
+      if( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+        debug() << " o  '" << type <<"'  correction as a '" << CaloFutureCorrection::funcName[ func ] 
+                << "' function of " << dim << " parameters" << endmsg;
+    }
+    else
+    {
+      warning() << " o '" << type << "' correction HAS NOT BEEN APPLIED  (badly configured)" << endmsg;
+    }
+  }
+
+  return GaudiTool::finalize();  // must be called after all other actions
+}
+
+//=============================================================================©©fi
+StatusCode CaloFutureCorrectionBase::setDBParams(){
+  if(m_update)return StatusCode::SUCCESS; // don't update twice before next incident
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+    debug() << "Get params from CondDB condition = " << m_conditionName << endmsg;
+  m_params = Params::Vector(CaloFutureCorrection::nT);
+  registerCondition(m_conditionName, m_cond, &CaloFutureCorrectionBase::updParams);
+  return runUpdate();  
+}
+// ============================================================================
+StatusCode CaloFutureCorrectionBase::setOptParams(){
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) )debug() << "Get params from options " << endmsg;
+  if( m_optParams.empty() && m_conditionName != "none"  ){
+    info()<< "No default options parameters defined"<<endmsg;
+    return StatusCode::SUCCESS;
+  }
+  m_params = Params::Vector(CaloFutureCorrection::nT);
+  for ( const auto&  p : m_optParams ) 
+  {
+    const std::string& name = p.first;
+    if ( accept( name ) ) 
+    {
+      m_params[stringToCorrectionType(name)] = Params( name, p.second );
+    }  
+  }
+  checkParams();
+  return StatusCode::SUCCESS;
+}
+// ============================================================================
+StatusCode CaloFutureCorrectionBase::updParams(){
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+    debug() << "updParams() called" << endmsg;
+  if ( !m_cond ) return Error("Condition points to NULL", StatusCode::FAILURE);
+
+  // toDo
+  for( const auto& paramName : m_cond->paramNames() ) {
+    if( m_cond -> exists( paramName ) ){
+      const auto & params = m_cond->paramAsDoubleVect( paramName ); 
+      if ( accept( paramName ) ) 
+      {
+        m_params[ stringToCorrectionType(paramName) ] = Params( paramName, params );
+      }
+    }
+  }
+  m_update = true;
+  checkParams(); 
+
+  return StatusCode::SUCCESS;
+}
+
+
+CaloFutureCorrection::Parameters 
+CaloFutureCorrectionBase::getParams(const CaloFutureCorrection::Type type, const LHCb::CaloCellID id) const
+{
+  const auto & params = m_params[type];
+  if ( !params.active ) return { CaloFutureCorrection::Unknown, CaloFutureCorrection::ParamVector{} };
+
+  // get parameters
+  const auto & pars = params.data;
+  if ( pars.size() < 2 ) return { CaloFutureCorrection::Unknown, CaloFutureCorrection::ParamVector{} };
+  
+  // consistency of pars checked elsewhere - straight parsing here
+  const auto&  func = pars[0];
+  const auto&  dim  = pars[1];
+  const int narea   = ( func != CaloFutureCorrection::GlobalParamList ) ? 3         : 1;
+  const int shift   = ( func != CaloFutureCorrection::GlobalParamList ) ? id.area() : 0;
+  int         pos   = 2 + shift;
+
+  CaloFutureCorrection::ParamVector v; v.reserve(dim);
+  for ( int i = 0 ; i < dim ; ++i )
+  {
+    v.push_back( pars[pos] );
+    pos += narea;
+  }
+  return { (CaloFutureCorrection::Function) func , std::move(v) }; 
+}
+
+
+double CaloFutureCorrectionBase::getCorrection(const CaloFutureCorrection::Type type,  
+                                         const LHCb::CaloCellID id,
+                                         double var, double def) const
+{
+
+  const auto pars = getParams(type,id);
+
+  if ( UNLIKELY(msgLevel( MSG::DEBUG) ) )
+  {
+    const auto& name =  CaloFutureCorrection::typeName[ type ];
+    debug() << "Correction type " << name << " to be applied on cluster (seed = " << id << ") is a '" 
+            << CaloFutureCorrection::funcName[ pars.first ] << "' function with params = " << pars.second
+            << endmsg;
+  }
+
+  // compute correction 
+  if( pars.first == CaloFutureCorrection::Unknown ||  pars.second.empty() ) return def; 
+
+  // list accessor - not correction :
+  if( pars.first == CaloFutureCorrection::ParamList || pars.first == CaloFutureCorrection::GlobalParamList)
+  {
+    warning() << " Param accessor is a fake function - no correction to be applied - return default value" << endmsg;
+    return def;
+  }
+
+  double cor = def; 
+  // polynomial correction 
+  const auto & temp = pars.second;
+
+  // polynomial functions
+  if (pars.first == CaloFutureCorrection::Polynomial || 
+      pars.first == CaloFutureCorrection::InversPolynomial || 
+      pars.first == CaloFutureCorrection::ExpPolynomial ||
+      pars.first == CaloFutureCorrection::ReciprocalPolynomial ){
+    double v = 1.;
+    cor = 0.;
+    for( auto  i = temp.begin() ; i != temp.end() ; ++ i){
+      cor += (*i) * v;
+      if( pars.first == CaloFutureCorrection::ReciprocalPolynomial )
+        v = (var == 0) ? 0. : v/var ;
+      else
+        v *= var;
+#if defined(__clang__)
+#warning "Activating workaround for FPE with clang"
+      // Without this, clang optimiser does something with this loop that causes FPE...
+      if ( UNLIKELY(msgLevel(MSG::VERBOSE)) ) verbose() << "cor = " << cor << endmsg;
+#endif
+    }
+    if( pars.first == CaloFutureCorrection::InversPolynomial) cor = ( cor == 0 ) ? def : 1./cor;
+    if( pars.first == CaloFutureCorrection::ExpPolynomial) cor = ( cor == 0 ) ? def : myexp(cor);
+  }
+
+  // sigmoid function
+  else if( pars.first == CaloFutureCorrection::Sigmoid ){
+    if( temp.size() == 4){
+      const auto&  a = temp[0];
+      const auto&  b = temp[1];
+      const auto&  c = temp[2];
+      const auto&  d = temp[3];
+      cor = a + b*mytanh(c*(var+d));
+    }
+    else{
+      Warning("The power sigmoid function must have 4 parameters").ignore();
+    }
+  }
+
+  // Sshape function
+  else if( pars.first == CaloFutureCorrection::Sshape || pars.first == CaloFutureCorrection::SshapeMod ){
+    if( temp.size() == 1){
+      const auto& b = temp[0];
+      constexpr double delta = 0.5;
+      if( b > 0 ) {
+        double arg = var/delta ;
+        if      ( pars.first == CaloFutureCorrection::SshapeMod ) { arg *= mysinh(delta/b); }
+        else if ( pars.first == CaloFutureCorrection::Sshape    ) { arg *= mycosh(delta/b); }        
+        cor = b * mylog( arg + std::sqrt( arg*arg + 1.0 ) );
+      }
+    }
+    else{
+      Warning("The Sshape function must have 1 parameter").ignore();
+    }  
+  }
+
+  // Shower profile function
+  else if( pars.first == CaloFutureCorrection::ShowerProfile ){
+    if( temp.size() == 10){
+      if( var > 0.5 ) {
+        cor = temp[0]  * myexp( -temp[1]*var);
+        cor += temp[2] * myexp( -temp[3]*var);
+        cor += temp[4] * myexp( -temp[5]*var);
+      }else{
+        cor  = 2.;
+        cor -= temp[6] * myexp( -temp[7]*var);
+        cor -= temp[8] * myexp( -temp[9]*var);
+      }
+    }else{
+      Warning("The ShowerProfile function must have 10 parameters").ignore();
+    }  
+  }
+
+  // Sinusoidal function
+  else if( pars.first == CaloFutureCorrection::Sinusoidal ){
+    if( temp.size() == 1){
+      const double& A = temp[0];
+      cor = A*mysin(2*M_PI*var);
+    }
+    else{
+      Warning("The Sinusoidal function must have 1 parameter").ignore();
+    }
+  }
+
+  if(counterStat->isVerbose())kounter(type,id.areaName()) += cor; 
+
+  return cor;
+}
+
+
+void CaloFutureCorrectionBase::checkParams(){
+  if ( m_params.size() != CaloFutureCorrection::nT ){
+    warning() << "Corrections vector size != " << CaloFutureCorrection::nT << endmsg;
+  }
+  for( auto& param : m_params ){
+    if ( !param.active ) continue;
+    const auto & type = param.type;
+    // is the type registered
+    bool ok = false;
+    for( unsigned int i = 0 ; i != CaloFutureCorrection::lastType ; ++i ){
+      if( type == CaloFutureCorrection::typeName[i]){
+        ok = true;
+        break;
+      }      
+    }
+    if( !ok ){
+      warning() << " o Type " << type << " is not registered" << endmsg;
+      param.clear();
+      continue;
+    }
+    
+    const auto & vec = param.data;
+    int func = CaloFutureCorrection::Unknown;
+    int dim  = 0;
+    if( vec.size() < 3 ) ok = false;
+    else{
+      func = vec[0];
+      dim  = vec[1];
+      if( func >= CaloFutureCorrection::Unknown )ok = false;
+      int narea = ( func != CaloFutureCorrection::GlobalParamList ) ? 3 : 1;
+      if( narea*dim+2 != (int) vec.size())ok=false;    
+      if( dim <= 0 ) ok = false;
+    }
+    if( !ok ){
+      warning() << " o Parameters for correction '"<< type << "' are badly defined : [ " << vec << " ]"<< endmsg;
+      param.clear();
+    }else{
+      if( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+        debug() << " o Will apply correction '" << type <<"' as a '" << CaloFutureCorrection::funcName[ func ] 
+                << "' function of " << dim << " parameters" << endmsg;
+    }
+  }
+}
+
+
+
+double CaloFutureCorrectionBase::incidence(const LHCb::CaloHypo* hypo, bool straight)const 
+{
+  const LHCb::CaloCluster* cluster = LHCb::CaloFutureAlgUtils::ClusterFromHypo(hypo,true) ;
+  double incidence = 0;
+  if ( LHCb::CaloHypo::Hypothesis::EmCharged == hypo->hypothesis() && !straight )
+  {
+    // for electron hypothesis : get the matching track
+    if ( exist<LHCb::CaloFuture2Track::IClusTrTable>(m_cmLoc) ) 
+    {
+      auto * ctable = m_tables->getClusTrTable( m_cmLoc );
+      const auto range = ctable -> relations(cluster);
+      if ( !range.empty() )
+      {
+        const LHCb::Track * ctrack = range.front();
+        // temporary protoParticle
+        auto * proto = new LHCb::ProtoParticle();
+        proto->setTrack( ctrack );
+        proto->addToCalo( hypo );
+        if ( m_caloElectron->set(proto) ) { incidence = m_caloElectron->caloState().momentum().Theta() ; }
+        delete proto;
+      }
+    } 
+  }
+  else
+  {
+    // for neutrals :
+    auto cMomentum = LHCb::CaloMomentum( hypo );
+    incidence = cMomentum.momentum().Theta();    
+  }
+  return incidence;
+}      
+
+double CaloFutureCorrectionBase::getCorrectionDerivative(const CaloFutureCorrection::Type type,  
+                                                   const LHCb::CaloCellID id ,
+                                                   double var, double def) const
+{
+  const auto pars = getParams( type , id );
+
+  if ( msgLevel( MSG::DEBUG) ) 
+  { 
+    const auto name =  CaloFutureCorrection::typeName[ type ];
+    debug() << "Derivative for Correction type " << name 
+            << " to be calculated for cluster (seed = " << id
+            << ") is a '" 
+            << CaloFutureCorrection::funcName[ pars.first ] 
+            << "' function with params = " << pars.second << endmsg;
+  }
+
+  // compute correction 
+  double cor = def; 
+  if( pars.first == CaloFutureCorrection::Unknown ||  pars.second.empty() ) return cor; 
+
+  // polynomial correction 
+  const auto & temp = pars.second;
+
+  // polynomial functions
+  double ds = 0.;
+  if ( pars.first == CaloFutureCorrection::Polynomial  )
+  {
+    ds  = 0.;
+    double v = 1.;
+    int cnt = 0;
+    auto i = temp.begin();
+    for( ++ i, cnt ++ ; i != temp.end() ; ++ i, cnt ++){
+      ds += (*i) * cnt * v;
+      v  *= var;
+    }
+  }
+
+  else if (pars.first == CaloFutureCorrection::InversPolynomial )
+  {
+    double v = 1.;
+    cor = 0.;
+    for( auto i = temp.begin() ; i != temp.end() ; ++ i){
+      cor += (*i) * v;
+      v *= var;
+    }
+    cor = ( cor == 0 ) ? def : 1./cor;
+
+    v       = 1.;
+    ds      = 0.;
+    int cnt = 0;
+    auto i = temp.begin();
+    for( ++ i, cnt ++ ; i != temp.end() ; ++ i, cnt ++){
+      ds  += (*i) * cnt * v;
+      v *= var;
+    }
+    ds *= -cor*cor;
+  }
+
+  else if (pars.first == CaloFutureCorrection::ExpPolynomial )
+  {
+    double v = 1.;
+    cor = 0.;
+    for( auto i = temp.begin() ; i != temp.end() ; ++ i){
+      cor += (*i) * v;
+      v *= var;
+    }
+    cor = ( cor == 0 ) ? def : myexp(cor);
+ 
+    ds = 0.;
+    v  = 1.;
+    int cnt = 0;
+    auto i = temp.begin();
+    for( ++ i, cnt ++ ; i != temp.end() ; ++ i, cnt ++){
+      ds  += (*i) * cnt * v;
+      v *= var;
+    }
+ 
+    ds *= cor;
+  }
+
+  else if (pars.first == CaloFutureCorrection::ReciprocalPolynomial )
+  {
+    ds = 0.;
+    if ( var != 0 ){ 
+      auto v = 1./(var*var);
+      int cnt = 0;
+      auto i = temp.begin();
+      for( ++ i, cnt ++ ; i != temp.end() ; ++ i, cnt ++){
+        ds  -= (*i) * cnt * v;
+        v /= var;
+      }
+    }
+  }
+
+  // sigmoid function
+  else if( pars.first == CaloFutureCorrection::Sigmoid )
+  {
+    ds = 0.;
+    if( temp.size() == 4){
+      // double a = temp[0];
+      const auto & b = temp[1];
+      const auto & c = temp[2];
+      const auto & d = temp[3];
+      ds  = b*c*(1.- std::pow( mytanh(c*(var+d)),2) );
+    }
+    else{
+      Warning("The power sigmoid function must have 4 parameters").ignore();
+    }
+  }
+
+
+  // Sshape function
+  else if( pars.first == CaloFutureCorrection::Sshape || pars.first == CaloFutureCorrection::SshapeMod ){
+    ds = 0.;
+    if( temp.size() == 1){
+      const auto& b = temp[0];
+      double delta = 0.5;
+      if( b > 0 ) {
+        double csh = 1.;
+        if      ( pars.first == CaloFutureCorrection::SshapeMod ) { csh = mysinh(delta/b); }
+        else if ( pars.first == CaloFutureCorrection::Sshape    ) { csh = mycosh(delta/b); }       
+        const auto arg = var/delta * csh;
+        ds = b / delta * csh / std::sqrt( arg*arg + 1. );
+      }
+    }
+    else{
+      Warning("The Sshape function must have 1 parameter").ignore();
+    }
+  }
+
+  // Shower profile function
+  else if( pars.first == CaloFutureCorrection::ShowerProfile ){
+    ds = 0.;
+    if( temp.size() == 10){
+      if( var > 0.5 ) {
+        ds = -temp[0]*temp[1]*myexp( -temp[1]*var);
+        ds+= -temp[2]*temp[3]*myexp( -temp[3]*var);
+        ds+= -temp[4]*temp[5]*myexp( -temp[5]*var);
+      }else{
+        ds =  temp[6]*temp[7]*myexp( -temp[7]*var);
+        ds+=  temp[8]*temp[9]*myexp( -temp[9]*var);
+      }
+    }else{
+      Warning("The ShowerProfile function must have 10 parameters").ignore();
+    }  
+  }
+
+  // Sinusoidal function
+  else if( pars.first == CaloFutureCorrection::Sinusoidal ){
+    ds = 0.;
+    if( temp.size() == 1){
+      const auto& A = temp[0];
+      constexpr double twopi=2.*M_PI;
+      ds = A*twopi*mycos(twopi*var);
+    }
+    else{
+      Warning("The Sinusoidal function must have 1 parameter").ignore();
+    }
+
+  }  
+
+  return ds;
+}
+ 
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureCorrectionBase.h b/CaloFuture/CaloFutureReco/src/CaloFutureCorrectionBase.h
new file mode 100644
index 0000000000000000000000000000000000000000..486d7dde151d80df04e1b66f7e6b141b1ea8e685
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureCorrectionBase.h
@@ -0,0 +1,400 @@
+#ifndef CALOFUTURECORRECTIONBASE_H
+#define CALOFUTURECORRECTIONBASE_H 1
+
+// Include files
+#include "GaudiAlg/GaudiTool.h"
+#include "DetDesc/Condition.h"
+#include "CaloFutureUtils/CaloFutureAlgUtils.h"
+#include "Kernel/CaloCellID.h"
+#include "CaloFutureUtils/ClusterFunctors.h"
+#include "CaloDet/DeCalorimeter.h"
+#include "CaloFutureDAQ/ICaloFutureDigitFilterTool.h"
+#include "Event/CaloHypo.h"
+#include "Event/CaloDigit.h"
+#include "GaudiKernel/Point3DTypes.h"
+#include "CaloFutureUtils/CaloFutureAlgUtils.h"
+#include "CaloFutureUtils/CaloMomentum.h"
+#include "CaloFutureUtils/ICaloFutureElectron.h"
+#include "CaloFutureUtils/CaloFuture2Track.h"
+#include "Relations/IRelationWeighted2D.h"
+#include "Event/Track.h"
+#include "CaloFutureInterfaces/ICaloFutureRelationsGetter.h"
+#include "CaloFutureInterfaces/IFutureCounterLevel.h"
+#include "GaudiKernel/IIncidentListener.h"
+#include "GaudiKernel/IIncidentSvc.h"
+
+// VDT
+#include "vdt/vdtMath.h"
+
+static const InterfaceID IID_CaloFutureCorrectionBase ( "CaloFutureCorrectionBase", 1, 0 );
+
+/** @class CaloFutureCorrectionBase CaloFutureCorrectionBase.h
+ *
+ *
+ *  @author Olivier Deschamps
+ *  @date   2010-05-07
+ */
+
+
+namespace CaloFutureCorrectionUtils{
+  class DigitFromCaloFuture {
+  public:
+    explicit DigitFromCaloFuture( const int  calo ): m_calo(                                calo   ) {} ;
+    explicit DigitFromCaloFuture( const std::string& calo ): DigitFromCaloFuture( CaloCellCode::CaloNumFromName( calo ) ) {} ;
+    inline bool operator() ( const LHCb::CaloDigit* digit ) const{
+      return digit && ( ( (int) digit->cellID().calo() ) == m_calo ) ;
+    };
+    DigitFromCaloFuture() = delete;
+  private:
+    int m_calo{0} ;
+  };
+}
+// DO NOT CHANGE THE FUNCTION ORDER FOR BACKWARD COMPATIBILITY WITH EXISTING CONDITIONS DB
+namespace CaloFutureCorrection
+{
+  enum  Function
+    {
+      InversPolynomial    =0,
+      Polynomial          =1,
+      ExpPolynomial       =2,
+      ReciprocalPolynomial=3,
+      Sigmoid             =4,
+      Sshape              =5,
+      ShowerProfile       =6,
+      SshapeMod           =7,
+      Sinusoidal          =8,
+      ParamList           =9, // simple parameter access (by area)
+      GlobalParamList     =10, // simple parameter access (ind. of area)
+      Unknown // MUST be the last item
+    };
+  using ParamVector = std::vector<double>;
+  using Parameters  = std::pair< CaloFutureCorrection::Function , ParamVector >;
+  enum Type
+    {
+      // E-Correction parameters
+      alphaG, // global alpha factor
+      alphaE, // alpha(E)
+      alphaB, // alpha(Bary)
+      alphaX, // alpha(Dx)
+      alphaY, // alpha(Dy)
+      alphaP, // alpha(ePrs)
+      beta,   // Prs correction (with possible eEcal dependency)
+      betaP,  // Prs correction  (with possible ePrs dependency)
+      betaPR, //  Prs correction (with possible ePrs/eEcal dependency)
+      betaC,   // Prs correction for converted photons (use beta if not defined)
+      betaCP,  // ""
+      betaCPR, // ""
+      globalC,   // global factor for converted photons
+      globalT,   // global(DeltaTheta) function of incidence angle
+      offsetT,   // offset(DeltaTheta) function of incidence angle
+      offset,   // offset( sinTheta ) energy (or ET ) offset
+      offsetC,   // offset( sinTheta ) energy (or ET ) offset for converted photons
+      //
+      ClusterCovariance, // parameters for cluster covariance estimation
+      // L-Correction parameters
+      gamma0,
+      delta0,
+      gammaP,
+      deltaP,
+      // S-correction parameters
+      shapeX,
+      shapeY,
+      residual,
+      residualX,
+      residualY,
+      asymP,
+      asymM,
+      angularX,
+      angularY,
+      // ShowerShape profile
+      profile,
+      profileC, // for converted photons
+      // Cluster masking
+      EnergyMask,
+      PositionMask,
+      lastType  // MUST BE THE LAST LINE
+    };
+  static const int nT = lastType+1;
+  static const int nF = Unknown+1;
+  static const std::string typeName[nT] =
+    { "alphaG", "alphaE","alphaB","alphaX","alphaY","alphaP","beta","betaP","betaPR","betaC","betaCP","betaCPR"          // E-corrections
+      ,"globalC","globalT" ,"offsetT","offset","offsetC","ClusterCovariance"
+      ,"gamma0","delta0","gammaP","deltaP"                                                                      // L-Corrections
+      ,"shapeX","shapeY","residual","residualX","residualY","asymP","asymM","angularX","angularY"               // S-Corrections
+      ,"profile","profileC"                                                                                     // Profile shape
+      ,"EnergyMask","PositionMask"
+      ,"Unknown"};
+
+  static const std::string funcName[nF] =
+    { "InversPolynomial", "Polynomial","ExpPolynomial","ReciprocalPolynomial","Sigmoid"
+      ,"Sshape","ShowerProfile","SshapeMod","Sinusoidal","ParamList","GlobalParamList","Unknown" };
+}
+
+class CaloFutureCorrectionBase : public GaudiTool, virtual public IIncidentListener
+{
+
+public:
+
+  // Return the interface ID
+  static const InterfaceID& interfaceID() { return IID_CaloFutureCorrectionBase; }
+
+  /// Standard constructor
+  CaloFutureCorrectionBase( const std::string& type,
+                      const std::string& name,
+                      const IInterface* parent);
+
+  StatusCode initialize() override;    ///< Algorithm initialization
+  StatusCode finalize() override;    ///< Algorithm finalization
+
+  void setOrigin(Gaudi::XYZPoint origin){m_origin = origin;}
+  StatusCode updParams();
+
+  StatusCode setConditionParams(const std::string & cond,bool force=false)
+  { // force = true : forcing access via condDB only
+    if(cond != m_conditionName)m_conditionName = cond;
+
+    // get parameters from options  :
+    if( !m_useCondDB && !force )return setOptParams();
+
+    // get from DB if exists :
+    if( !existDet<DataObject>( m_conditionName)  ){
+      if(force){
+        if ( m_conditionName != "none" ) info() << "Condition '"<< m_conditionName.value() << "' has not been found " << endmsg;
+        return StatusCode::SUCCESS;
+      }else{
+        if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) debug() << " Condition '" << m_conditionName.value() << "' has not found -- try options parameters !" << endmsg;
+        return setOptParams();
+      }
+    }
+    return setDBParams();
+  }
+
+
+  // accessors
+  CaloFutureCorrection::Parameters getParams(const CaloFutureCorrection::Type type,
+                                       const LHCb::CaloCellID id=LHCb::CaloCellID()) const;
+  inline CaloFutureCorrection::ParamVector getParamVector(const CaloFutureCorrection::Type type,
+                                                    const LHCb::CaloCellID id=LHCb::CaloCellID()) const
+  {
+    return getParams(type,id).second;
+  }
+  double getParameter(CaloFutureCorrection::Type type, unsigned int i,
+                      const LHCb::CaloCellID id=LHCb::CaloCellID(),double def=0.) const
+  {
+    const auto  params = getParams(type,id);
+    const auto& data   = params.second;
+    return (i < data.size()) ? data[i] : def;
+  }
+  /// return value of analytic derivative for a given function type in cell id at a given point var with default value def
+  double getCorrectionDerivative(const CaloFutureCorrection::Type type, const LHCb::CaloCellID id , double var = 0.,double def = 0.) const;
+  //// propagate cov.m. cov0 according to Jacobian jac: cov1 = (jac * cov * jac^T), see comments in CaloFutureECorrection.cpp and CaloFutureSCorrection.cpp
+  // void recalculate_cov(const TMatrixD &jac, const TMatrixDSym &cov0, TMatrixDSym &cov1) const;
+
+
+  double getCorrection(const CaloFutureCorrection::Type type, const LHCb::CaloCellID id , double var = 0.,double def = 1.) const;
+  double incidence(const LHCb::CaloHypo* hypo,bool straight=false) const;
+
+  void getPrsSpd(const LHCb::CaloHypo* hypo,double& ePrs,double& eSpd) const
+  {
+    typedef const LHCb::CaloHypo::Digits Digits;
+    const auto & digits = hypo->digits();
+    for( Digits::const_iterator d = digits.begin() ; digits.end() != d ; ++d )
+    {
+      if     ( *d == 0     ) { continue           ; }
+      else if( m_prs( *d ) ) { ePrs  += (*d)->e() ; }
+      else if( m_spd( *d ) ) { eSpd  += (*d)->e() ; }
+    }
+  }
+
+  ICaloFutureDigitFilterTool* pileup() const noexcept { return m_pileup;}
+
+  bool hasConditionChanged() const noexcept {return m_update;}
+  void handle(const Incident&  ) override { m_update = false; }// reset update flag
+
+protected:
+
+  Gaudi::Property<std::string> m_conditionName {this, "ConditionName", "none"};
+  Gaudi::Property<std::vector<std::string>> m_corrections {this, "Corrections", {"All"}};
+  //
+  typedef std::vector<LHCb::CaloHypo::Hypothesis>   Hypotheses  ;
+  typedef std::vector<int>                          Hypotheses_ ;
+  Hypotheses  m_hypos;
+  Gaudi::Property<Hypotheses_> m_hypos_ {this, "Hypotheses", {
+    (int) LHCb::CaloHypo::Hypothesis::Photon,
+    (int) LHCb::CaloHypo::Hypothesis::PhotonFromMergedPi0,
+    (int) LHCb::CaloHypo::Hypothesis::EmCharged,
+  }, "acceptable hypotheses"};
+
+  LHCb::ClusterFunctors::ClusterArea      m_area;
+  LHCb::ClusterFunctors::ClusterFromCaloFuture  m_calo{DeCalorimeterLocation::Ecal};
+  CaloFutureCorrectionUtils::DigitFromCaloFuture    m_spd{DeCalorimeterLocation::Spd};
+  CaloFutureCorrectionUtils::DigitFromCaloFuture    m_prs{DeCalorimeterLocation::Prs};
+  std::string m_detData{DeCalorimeterLocation::Ecal};
+  const DeCalorimeter* m_det = nullptr;
+  Gaudi::XYZPoint  m_origin;
+  ICaloFutureDigitFilterTool* m_pileup = nullptr;
+  Gaudi::Property<bool> m_correctCovariance {this, "CorrectCovariance", true};
+
+  template< typename TYPE >
+  inline TYPE myexp( const TYPE x ) const
+  {
+    //info() << "In myexp " << x << endmsg;
+    //return std::exp(x);
+    return vdt::fast_exp(x);
+  }
+
+  template< typename TYPE >
+  inline TYPE mylog( const TYPE x ) const
+  {
+    //info() << "In mylog " << x << endmsg;
+    //return std::log(x);
+    return vdt::fast_log(x);
+  }
+
+  template< typename TYPE >
+  inline TYPE myatan( const TYPE x ) const
+  {
+    //info() << "In myatan " << x << endmsg;
+    //return std::atan(x);
+    return vdt::fast_atan(x);
+  }
+
+  template< typename TYPE >
+  inline TYPE myatan2( const TYPE x, const TYPE y ) const
+  {
+    //info() << "In myatan2 " << x << " " << y << endmsg;
+    //return std::atan2(x,y);
+    return vdt::fast_atan2(x,y);
+  }
+
+  template< typename TYPE >
+  inline TYPE mycos( const TYPE x ) const
+  {
+    //info() << "In mycos " << x << endmsg;
+    //return std::cos(x);
+    return vdt::fast_cos(x);
+  }
+
+  template< typename TYPE >
+  inline TYPE mysin( const TYPE x ) const
+  {
+    //info() << "In mysin " << x << endmsg;
+    //return std::sin(x);
+    return vdt::fast_sin(x);
+  }
+
+  template< typename TYPE >
+  inline TYPE mytanh( const TYPE x ) const
+  {
+    //info() << "In mytanh " << x << endmsg;
+    //return std::tanh(x);
+    const auto y = myexp(-2.0*x);
+    return ( 1.0 - y ) / ( 1.0 + y );
+  }
+
+  template< typename TYPE >
+  inline TYPE mysinh( const TYPE x ) const
+  {
+    //info() << "In mysinh " << x << endmsg;
+    //return std::sinh(x);
+    const auto y = myexp(-x);
+    return 0.5 * ( (1.0/y) - y );
+  }
+
+  template< typename TYPE >
+  inline TYPE mycosh( const TYPE x ) const
+  {
+    //info() << "In mycosh " << x << endmsg;
+    //return std::cosh(x);
+    const auto y = myexp(-x);
+    return 0.5 * ( (1.0/y) + y );
+  }
+
+private:
+
+  inline CaloFutureCorrection::Type stringToCorrectionType ( const std::string & type )
+  {
+    for ( int i = 0; i < CaloFutureCorrection::nT; ++i )
+    {
+      if ( CaloFutureCorrection::typeName[i] == type ) return static_cast<CaloFutureCorrection::Type>(i);
+    }
+    return static_cast<CaloFutureCorrection::Type>(CaloFutureCorrection::lastType);
+  }
+
+  ICaloFutureElectron * m_caloElectron = nullptr;
+
+  bool accept(const std::string& name){
+    for( auto it = m_corrections.begin() ; m_corrections.end() != it ; ++it){
+      if( name == *it || *it == "All")return true;
+    }
+    return false;
+  }
+
+  StatusCode setOptParams();
+  StatusCode setDBParams();
+  void checkParams();
+
+  class Params
+  {
+  public:
+    Params() = default;
+    Params( const std::string & t,
+            const CaloFutureCorrection::ParamVector & v )
+      : active(true), type(t), data(v) { }
+  public:
+    void clear() { active = false; data.clear(); }
+  public:
+    bool active{false};
+    std::string type;
+    CaloFutureCorrection::ParamVector data;
+  public:
+    typedef std::vector<Params> Vector;
+  };
+
+  /// Cache counters, as looking them up as
+  ///    counter( CaloFutureCorrection::typeName[ type ] + " correction processing (" + areaName + ")" )
+  /// requires the creation of a temporary string every time, which in turn
+  /// involves (eventually) a call to 'new' and 'delete'  -- and the above was the source of 10% (!)
+  /// of the # of calls to 'new' and 'delete' in the HLT!!!! (FYI: there are, on average, 1K calls
+  /// per event to this method!!!)
+  ///
+  /// On top of that, this also speeds up the actual search for the correct counter,
+  /// by making it a two-step process, and the first step is a direct lookup
+  /// instead of a 'find'.
+  ///
+  /// in the end, this change alone speeds up the total HLT by about 1%...
+  inline StatEntity& kounter(const CaloFutureCorrection::Type type, const std::string& areaName) const
+  {
+    assert( type < CaloFutureCorrection::lastType+1 );
+    auto a = m_counters[type].find(areaName);
+    if ( UNLIKELY( a == std::end(m_counters[type]) ) )
+    {
+      const auto name = CaloFutureCorrection::typeName[type] + " correction processing (" + areaName + ")";
+      auto r = m_counters[type].insert( areaName, &counter(name) );
+      assert(r.second);
+      a = r.first;
+    }
+    assert(a->second);
+    return *(a->second);
+  }
+
+private:
+
+  Params::Vector m_params{ CaloFutureCorrection::nT };
+
+  Gaudi::Property<std::map< std::string, std::vector<double> >> m_optParams 
+    {this, "Parameters"};
+
+  mutable std::array< GaudiUtils::VectorMap<std::string, StatEntity* >, CaloFutureCorrection::lastType+1 > m_counters;
+  Condition* m_cond = nullptr;
+  Gaudi::Property<std::string> m_cmLoc {this, "ClusterMatchLocation"};
+  ICaloFutureRelationsGetter* m_tables = nullptr;
+  Gaudi::Property<bool> m_useCondDB {this, "UseCondDB", true};
+  bool m_update{false};
+
+protected:
+
+  IFutureCounterLevel* counterStat = nullptr;
+
+};
+#endif // CALOFUTURECORRECTIONBASE_H
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureDigitsFilterAlg.cpp b/CaloFuture/CaloFutureReco/src/CaloFutureDigitsFilterAlg.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d320c83c5f3f0f551124328931ed3a0c5f50fabe
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureDigitsFilterAlg.cpp
@@ -0,0 +1,157 @@
+// ============================================================================
+// Include files
+// Event 
+#include "Event/CaloDigit.h"
+#include "Event/CaloCluster.h"
+#include "Event/CaloHypo.h"
+// local
+#include "CaloFutureDigitsFilterAlg.h"
+
+// ============================================================================
+/** @file CaloFutureDigitsFilterAlg.cpp
+ * 
+ *  Template implementation file for class : CaloFutureDigitsFilterAlg
+ *  @see CaloFutureDigitsFilterAlg
+ * 
+ *  @author Vanya Belyaev Ivan.Belyaev@itep.ru
+ *  @date 02/11/2001
+ */
+// ============================================================================
+
+DECLARE_COMPONENT( CaloFutureDigitsFilterAlg )
+
+// ============================================================================
+/** standard algorithm finalization 
+ *  @see GaudiAlgorithm
+ *  @see     Algorithm
+ *  @see    IAlgorithm
+ *  @return status code 
+ */
+// ============================================================================
+StatusCode CaloFutureDigitsFilterAlg::finalize() 
+{  
+  /// clear container 
+  m_hypos.clear();
+  /// finalize the base class 
+  return GaudiAlgorithm::finalize();
+}
+// ============================================================================
+
+// ============================================================================
+/** standard algorithm execution 
+ *  @see GaudiAlgorithm
+ *  @see     Algorithm
+ *  @see    IAlgorithm
+ *  @return status code 
+ */
+// ============================================================================
+StatusCode CaloFutureDigitsFilterAlg::execute() 
+{  
+  /// avoid long names and types 
+  typedef  LHCb::CaloHypos                     Hypos    ;
+  typedef  LHCb::CaloHypo::Digits              Digs     ;
+  typedef  LHCb::CaloDigits                    Digits   ;
+  typedef  LHCb::CaloClusters                  Clusters ;
+  typedef  LHCb::CaloCluster::Entries          Entries  ;
+  typedef  LHCb::CaloDigitStatus::Status       Status   ;
+  
+  // get digits
+  Digits*  digits = get<Digits>( m_inputData );
+  if( 0 == digits ) { return StatusCode::FAILURE ; }
+  
+  // create new digits 
+  Digits  filter;
+  
+  // auxillary container of "used" IDs 
+  typedef std::vector<LHCb::CaloDigit*> Tmp;
+  Tmp used;
+  
+  // loop over containers of hypos 
+  for( Addresses::const_iterator address = m_hypos.begin() ; 
+       m_hypos.end() != address ; ++address )
+  {
+    Hypos* hypos = get<Hypos> ( *address ) ;
+    if( 0 == hypos ) { return StatusCode::FAILURE ; }
+    // loop over all hypos 
+    for( Hypos::iterator hypo = hypos->begin() ; 
+         hypos->end() != hypo ; ++hypo) 
+    {
+      if( 0 == *hypo ) { continue ; }
+      // loop over all "extra" digits 
+      Digs& digs = (*hypo)->digits();
+      for( Digs::iterator digit = digs.begin() ; 
+           digs.end() != digit ; ++digit )
+      {
+        LHCb::CaloDigit* dig = *digit ;
+        if( 0 == dig ) { continue ; }
+        if( dig->parent() == digits ) { used.push_back( dig ); }
+      } // end of loop over all "extra" digits
+    } // end loop over all hypos 
+  } // end of loop over all containers of hypos
+  
+  
+  if( !m_statuses.empty() ) 
+  {
+    // loop over containers clusters 
+    for( Addresses::const_iterator address = m_clusters.begin() ;
+         m_clusters.end() != address ; ++address )
+    {
+      Clusters* clusters = get<Clusters>( *address );
+      if( 0 == clusters ) { return StatusCode::FAILURE ; }
+      // loop over  clusters
+      for( Clusters::iterator cluster = clusters->begin() ;
+           clusters->end() != cluster ; ++cluster ) 
+      {
+        LHCb::CaloCluster* cl = *cluster ;
+        if( 0 == cl ) { continue ; }
+        Entries& entries = cl->entries() ;
+        for( Entries::iterator entry = entries.begin() ;
+             entries.end() != entry ; ++entry ) 
+        {
+          LHCb::CaloDigit* digit = entry->digit();
+          if( 0 == digit                ) { continue ; }
+          // correct parent ?
+          if( digits != digit->parent() ) { continue ; }
+          bool keep = false ;
+          for( Statuses::const_iterator st = m_statuses.begin() ; 
+               m_statuses.end() != st ; ++st )
+          {
+            if( entry->status() & (Status) *st ) 
+            { keep = true ; break; }
+          }
+          if( keep ) { used.push_back  ( digit          ) ; }
+          else       { entry->setDigit ( (LHCb::CaloDigit*) 0 ) ; }
+        }
+      }
+    }
+  }
+  
+  { // eliminate duplicates 
+    std::stable_sort( used.begin() , used.end() );  
+    Tmp::iterator it = std::unique( used.begin() , used.end() );
+    used.erase( it , used.end() );
+    while( !used.empty() ) { filter.insert( used.back() ) ; used.pop_back();} 
+  }
+  
+  const unsigned int all  = digits -> size() ;
+  
+  {  // clear digits 
+    digits -> clear();
+    // copy filter to digits 
+    for( Digits::iterator dig = filter.begin() ; filter.end() != dig ; ++dig ) 
+    { digits->insert( *dig ); }
+    // clear filter 
+    filter.clear();
+  }
+  
+  const unsigned int kept = digits->size() ;
+  
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+    debug () << "'"        << m_inputData << "' : "
+             << " Kept  "  << kept        << " digits from " 
+             << all        << endmsg ;
+  
+  return StatusCode::SUCCESS ;
+}
+// ============================================================================
+
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureDigitsFilterAlg.h b/CaloFuture/CaloFutureReco/src/CaloFutureDigitsFilterAlg.h
new file mode 100644
index 0000000000000000000000000000000000000000..4606afbdaeb5c358fb6be64504fdbf6c7b638f19
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureDigitsFilterAlg.h
@@ -0,0 +1,59 @@
+#ifndef CALOFUTURERECO_CALOFUTUREDIGITSFILTERALG_H
+#define CALOFUTURERECO_CALOFUTUREDIGITSFILTERALG_H 1
+// Include files
+// from STL
+#include <string>
+#include <vector>
+
+// from GaudiAlg
+#include "GaudiAlg/GaudiAlgorithm.h"
+
+
+/** @class CaloFutureDigitsFilterAlg CaloFutureDigitsFilterAlg.h
+ *
+ *  Simple algorithm to perform filtering of CaloDigits
+ *
+ *  @author Vanya Belyaev Ivan.Belyaev@itep.ru
+ *  @date   2002-06-11
+ */
+class CaloFutureDigitsFilterAlg :
+  public GaudiAlgorithm
+{
+public:
+
+  /** standard algorithm execution
+   *  @see GaudiAlgorithm
+   *  @see     Algorithm
+   *  @see    IAlgorithm
+   *  @return status code
+   */
+  StatusCode execute() override;
+
+  /** standard algorithm finalization
+   *  @see GaudiAlgorithm
+   *  @see     Algorithm
+   *  @see    IAlgorithm
+   *  @return status code
+   */
+  StatusCode finalize() override;
+
+  /// Standard constructor
+  using GaudiAlgorithm::GaudiAlgorithm;
+
+private:
+
+  typedef std::vector<std::string> Addresses  ;
+  typedef std::vector<int>         Statuses   ;
+
+  Gaudi::Property<std::string> m_inputData {this, "InputData"};
+  Gaudi::Property<Addresses>   m_hypos     {this, "Hypotheses"};
+  Gaudi::Property<Addresses>   m_clusters  {this, "Clusters"};
+  Gaudi::Property<Statuses>    m_statuses  {this, "Statuses", {
+    LHCb::CaloDigitStatus::SeedCell,
+    LHCb::CaloDigitStatus::LocalMaximum,
+    LHCb::CaloDigitStatus::CentralCell,
+  }};
+
+};
+// ============================================================================
+#endif // CALOFUTURERECO_CALOFUTUREDIGITSFILTERALG_H
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureECorrection.cpp b/CaloFuture/CaloFutureReco/src/CaloFutureECorrection.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..928b4aee0c4518806405f75a7405f0c790f330c2
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureECorrection.cpp
@@ -0,0 +1,638 @@
+// ============================================================================
+// Include files
+#include "GaudiKernel/SystemOfUnits.h"
+#include "Event/CaloHypo.h"
+#include "CaloFutureECorrection.h"
+
+/** @file
+ *  Implementation file for class : CaloFutureECorrection
+ *
+ *  @date 2003-03-10
+ *  @author Deschamps Olivier
+ */
+
+DECLARE_COMPONENT( CaloFutureECorrection )
+
+// ============================================================================
+/*  Standard constructor
+ *  @see GaudiTool
+ *  @see  AlgTool
+ *  @param type tool type (?)
+ *  @param name tool name
+ *  @param parent  tool parent
+ */
+// ============================================================================
+CaloFutureECorrection::CaloFutureECorrection( const std::string& type   ,
+                                  const std::string& name   ,
+                                  const IInterface*  parent )
+  : CaloFutureCorrectionBase( type , name , parent )
+{
+
+  // define conditionName
+  const std::string uName ( LHCb::CaloFutureAlgUtils::toUpper( name ) ) ;
+  if ( uName.find( "ELECTRON" ) != std::string::npos  ) {
+    m_conditionName = "Conditions/Reco/Calo/ElectronECorrection";
+  } else if ( uName.find( "MERGED" )  != std::string::npos   ||  uName.find( "SPLITPHOTON" )  != std::string::npos ) {
+    m_conditionName = "Conditions/Reco/Calo/SplitPhotonECorrection";
+  } else if (  uName.find( "PHOTON" ) ) {
+    m_conditionName = "Conditions/Reco/Calo/PhotonECorrection";
+  }
+
+  declareInterface<ICaloFutureHypoTool> ( this ) ;
+
+  std::vector<std::string> caloAreas = {"Outer" , "Middle" , "Inner" , "PinArea"};
+  m_countersAlpha.reserve(k_numOfCaloFutureAreas);
+  m_countersBetaTimesEprs.reserve(k_numOfCaloFutureAreas);
+  for (auto i = 0; i < k_numOfCaloFutureAreas; i++) {
+    m_countersAlpha.emplace_back(this, "<alpha> " + caloAreas[i]);
+    m_countersBetaTimesEprs.emplace_back(this, "<beta*ePrs> " + caloAreas[i]);
+  }
+}
+// ============================================================================
+// destructor
+// ============================================================================
+StatusCode CaloFutureECorrection::finalize   ()
+{
+  m_hypos.clear();
+  return CaloFutureCorrectionBase::finalize () ;
+}
+// ============================================================================
+StatusCode CaloFutureECorrection::initialize ()
+{
+  // first initialize the base class
+  StatusCode sc = CaloFutureCorrectionBase::initialize();
+  if ( sc.isFailure() )return Error ( "Unable initialize the base class CaloFutureCorrectionBase!" , sc ) ;
+
+  if ( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+    debug() << "Condition name : " << m_conditionName << endmsg;
+
+  //info() << "  =========== Condition name : " << m_conditionName << endmsg;
+
+
+
+
+  return StatusCode::SUCCESS ;
+}
+
+// ============================================================================
+StatusCode CaloFutureECorrection::operator() ( LHCb::CaloHypo* hypo  ) const
+{
+  return process( hypo );
+}
+
+// ============================================================================
+StatusCode CaloFutureECorrection::process    ( LHCb::CaloHypo* hypo  ) const
+{
+
+  // check arguments
+  if ( 0 == hypo )return Warning( " CaloHypo* points to NULL!", StatusCode::SUCCESS ) ;
+
+  // check the Hypo
+  Hypotheses::const_iterator h = std::find( m_hypos.begin() , m_hypos.end() , hypo->hypothesis() ) ;
+  if ( m_hypos.end() == h )return Error ( "Invalid hypothesis -> no correction applied" , StatusCode::SUCCESS) ;
+
+  // No correction for negative energy :
+  if ( hypo->e() < 0.) {
+    ++m_counterSkippedNegativeEnergyCorrection;
+    return StatusCode::SUCCESS;
+  }
+
+  // Somewhat inelegant way of data sharing between this const method process() and calcECorrection(). Use of private fields
+  // of this CaloFutureECorrection class for the same purpose would break the constness of the process() interface.
+  struct ECorrInputParams  _params; // input parameters calculated once in process() and used in all the calcECorrection() calls
+  ECorrOutputParams       _results; // Jacobian elements plus many various intermediate parameters, used e.g. for debug printout
+
+  // input variables passed from process() to calcECorrection()
+  LHCb::CaloCellID& cellID  = _params.cellID;
+  Gaudi::XYZPoint&  seedPos = _params.seedPos;
+  double&           eSpd    = _params.eSpd;
+  double&           dtheta  = _params.dtheta;
+  unsigned int&     area    = _params.area;
+
+
+  // get Prs/Spd
+  double ePrs = 0 ;
+  eSpd = 0 ;
+  getPrsSpd(hypo, ePrs, eSpd);
+
+  if ( eSpd == 0 && (m_sFilt & 0x1) == 0)return StatusCode::SUCCESS;
+  if ( eSpd >  0 && (m_sFilt & 0x2) == 0)return StatusCode::SUCCESS;
+  if ( ePrs == 0 && (m_pFilt & 0x1) == 0)return StatusCode::SUCCESS;
+  if ( ePrs >  0 && (m_pFilt & 0x2) == 0)return StatusCode::SUCCESS;
+  if ( UNLIKELY(msgLevel( MSG::DEBUG) ))
+    debug() << " Accepted  spd/prs : " << (int) (eSpd > 0 ) << " / " << (int) (ePrs > 0) << endmsg;
+
+  // get cluster  (special case for SplitPhotons)
+  const LHCb::CaloCluster* GlobalCluster = LHCb::CaloFutureAlgUtils::ClusterFromHypo(hypo, false);
+  const LHCb::CaloCluster* MainCluster = LHCb::CaloFutureAlgUtils::ClusterFromHypo(hypo, true) ;
+
+
+  /*
+    Position information (e/x/y )
+  */
+  if ( 0 == MainCluster )return Warning ( "CaloCluster* points to NULL -> no correction applied" , StatusCode::SUCCESS) ;
+
+  // For Split Photon - share the Prs energy
+  if (  LHCb::CaloHypo::Hypothesis::PhotonFromMergedPi0 == hypo->hypothesis() ) {
+    ePrs *= MainCluster->position().e() / GlobalCluster->position().e() ;
+  }
+
+  // Get position
+  const LHCb::CaloPosition& position = MainCluster->position();
+  double eEcal = position. e () ;
+  const double xBar  = position. x () ;
+  const double yBar  = position. y () ;
+
+  // seed ID & position
+  const LHCb::CaloCluster::Entries& entries = MainCluster->entries();
+  LHCb::CaloCluster::Entries::const_iterator iseed =
+    LHCb::ClusterFunctors::locateDigit ( entries.begin () , entries.end() , LHCb::CaloDigitStatus::SeedCell );
+  if ( entries.end() == iseed )return Warning( "The seed cell is not found -> no correction applied", StatusCode::SUCCESS ) ;
+
+  // get the "area" of the cluster (where seed is)
+  area = m_area( MainCluster );
+  const LHCb::CaloDigit*  seed    = iseed->digit();
+  if ( 0 == seed )return Warning ( "Seed digit points to NULL -> no correction applied", StatusCode::SUCCESS ) ;
+  // Cell ID for seed digit
+  cellID = seed->cellID() ;
+  seedPos = m_det->cellCenter( cellID  );
+
+  //  incidence angle
+  dtheta = incidence( hypo ) - incidence(hypo, true);
+  //  info() << "------> " << incidence( hypo ) << " " <<  incidence(hypo, true) << "  " << dtheta << endmsg;
+
+  // Pileup subtraction at the cluster level
+  if ( m_pileup->method("Ecal") >= 10 ) {
+    bool spd = (eSpd > 0) ? true : false;
+    double offset = m_pileup->offset( cellID, spd );
+    if (offset < eEcal) {
+      const double eee = eEcal;
+      eEcal -= offset;
+      m_counterPileupOffset += offset;
+      m_counterPileupSubstractedRatio += eEcal / eee;
+      m_counterPileupScale += m_pileup->getScale();
+    }
+  }
+
+
+  /** here all information is available
+   *
+   *  (1) Ecal energy in 3x3     :    eEcal
+   *  (2) Prs and Spd energies   :    ePrs, eSpd
+   *  (3) weighted barycenter    :    xBar, yBar
+   *  (4) Zone/Area in Ecal      :    area
+   *  (5) SEED digit             :    seed    (NO for split!)
+   *  (6) CellID of seed digit   :    cellID  (OK for split!)
+   *  (7) Position of seed cell  :    seedPos (OK for split!)
+   *
+   */
+
+
+  /////////////////////////////////////////////////////////
+
+
+  /* Calculate corrected energy in a separate function call. Necessary for debugging the Jacobian by calculating
+   * numeric derivatives w.r.t. (X, Y, E, [and possibly ePrs]) in case of any changes in the correction code.
+   *
+   * Input positions and energies are passed as parameters for ease of numeric derivative calculation,
+   * all the other paramers and results of intermediate calculations are shared between the two methods
+   * using local struct ECorrInputParams _params, and [zero-initialized] ECorrOutputParams _results.
+   */
+  double eCor = calcECorrection(xBar, yBar, eEcal, ePrs, _params, &_results);
+
+  // results of semi-analytic derivative calculation
+  const double& dEcor_dXcl = _results.dEcor_dXcl;
+  const double& dEcor_dYcl = _results.dEcor_dYcl;
+  const double& dEcor_dEcl = _results.dEcor_dEcl;
+
+  // protection against unphysical d(Ehypo)/d(Ecluster) == 0
+  if ( fabs( dEcor_dEcl ) < 1e-10 ) {
+    if ( UNLIKELY(msgLevel( MSG::DEBUG) ))debug() << "unphysical d(Ehypo)/d(Ecluster) = " << dEcor_dEcl << " reset to 1 as if Ehypo = Ecluster" << endmsg;
+    ++m_counterUnphysical;
+    const_cast<double&>(dEcor_dEcl) = 1.;
+  }
+
+  // debugging necessary in case if any new corrections are added or their sequence is changed!
+  if ( UNLIKELY( msgLevel(MSG::DEBUG) && m_correctCovariance ) ) {
+    const double dx_rel(1e-5), dy_rel(1e-5), de_rel(1e-3); // dx,dy ~ few*0.1*mm, de ~ few MeV
+
+    // calculate numeric derivatives to be compared with analytic ones
+    debug() << "\n ------------------------ ECorrection(x+dx, y, e) calculation follows ------------------- " << endmsg;
+    double eCor_x    = calcECorrection(xBar * (1 + dx_rel), yBar,            eEcal,            ePrs, _params, NULL);
+
+    debug() << "\n ------------------------ ECorrection(x, y+dy, e) calculation follows ------------------- " << endmsg;
+    double eCor_y    = calcECorrection(xBar,            yBar * (1 + dy_rel), eEcal,            ePrs, _params, NULL);
+
+    debug() << "\n ------------------------ ECorrection(e, y, e+de) calculation follows ------------------- " << endmsg;
+    double eCor_e    = calcECorrection(xBar,            yBar,            eEcal * (1 + de_rel), ePrs, _params, NULL);
+
+
+    double dn_eCor_dx = (eCor_x - eCor) / xBar / dx_rel;
+    double dn_eCor_dy = (eCor_y - eCor) / yBar / dy_rel;
+    double dn_eCor_de = (eCor_e - eCor) / eEcal / de_rel;
+
+    // avoid division in comparison for possible dE/dX == 0 or dE/dY == 0
+    if (   fabs(dEcor_dXcl - dn_eCor_dx) > fabs(dEcor_dXcl) * 0.1
+           || fabs(dEcor_dYcl - dn_eCor_dy) > fabs(dEcor_dYcl) * 0.1
+           || fabs(dEcor_dEcl - dn_eCor_de) > fabs(dEcor_dEcl) * 0.1 ) {
+      debug() << " some CaloFutureECorrection analytically-calculated Jacobian elements differ (by > 10%) from numerically-calculated ones! " << endmsg;
+    }
+
+    debug() << "**********" << " betaC_flag = " << _results.betaC_flag << " ******* Jacobian elements J(2,*) =" << endmsg;
+    debug() << "   semi-analytic dEcor_dXcl = " << dEcor_dXcl << " numeric dn_eCor_dx = " << dn_eCor_dx << endmsg;
+    debug() << "   semi-analytic dEcor_dYcl = " << dEcor_dYcl << " numeric dn_eCor_dy = " << dn_eCor_dy << endmsg;
+    debug() << "   semi-analytic dEcor_dEcl = " << dEcor_dEcl << " numeric dn_eCor_de = " << dn_eCor_de << endmsg;
+  }
+
+
+
+  // revoir le debug
+  if ( UNLIKELY(msgLevel( MSG::DEBUG) )) {
+    debug() << "CaloFuture hypothesis : " << hypo->hypothesis() << endmsg;
+    debug() << "cellID          : " << cellID << endmsg;
+    debug() << "eSpd : "  << eSpd <<  " "    << "ePrs : "  << ePrs  <<  endmsg;
+    debug() << "asx : "  << _results.Asx <<  " " << "asy : "  << _results.Asy  << endmsg;
+    debug() << "alpha " << _results.alpha << " = " << _results.aG << " x " << _results.aE << " x " << _results.aB << " x " << _results.aX << " x " << _results.aY <<  endmsg;
+    debug() << "beta "  << _results.beta << endmsg;
+    debug() << "Global Factor " << _results.gC << endmsg;
+    debug() << "Global theta correction " << _results.gT << endmsg;
+    debug() << "eEcal " << eEcal <<  " --> "    << "eCor "  <<  eCor    << endmsg;
+  }
+
+  /// assert(cellID.area()>=0 &&cellID.area()<4);
+  m_countersAlpha.at(cellID.area()) += _results.alpha;
+  m_countersBetaTimesEprs.at(cellID.area()) += _results.beta * ePrs;
+
+  // update position
+  LHCb::CaloPosition::Parameters& parameters = hypo ->position() ->parameters () ;
+  parameters ( LHCb::CaloPosition::Index::E ) = eCor ;
+  m_counterCorrectedEnergy += eCor;
+  m_counterDeltaEnergy += eCor - eEcal;
+
+
+  // ----------------------------------------- apply semi-analytic cov.m. propagation due to the (X,Y,E) corrections
+  if ( m_correctCovariance ) {
+    LHCb::CaloPosition::Covariance& covariance = hypo ->position() ->covariance () ;
+
+    if ( UNLIKELY(msgLevel( MSG::DEBUG)) ) {
+      debug() << "before E-corr. cov.m. = \n" << covariance << endmsg;
+    }
+
+    // index numbering just follows ROOT::Math::SMatrix<double,3,3>::Array() for row/column indices (X:0, Y:1, E:2)
+    double c0[6], c1[6];
+    /*
+     * Indexing following ROOT::Math::SMatrix<double,3,3,ROOT::Math::MatRepSym<double,3> >::Array() :
+     *
+     * The iterators access the matrix element in the order how they are
+     * stored in memory. The C (row-major) convention is used, and in the
+     * case of symmetric matrices the iterator spans only the lower diagonal
+     * block. For example for a symmetric 3x3 matrices the order of the 6
+     * elements \f${a_0,...a_5}\f$ is:
+     * \f[
+     * M = \left( \begin{array}{ccc}
+     *     a_0 & a_1 & a_3  \\
+     *     a_1 & a_2  & a_4  \\
+     *     a_3 & a_4 & a_5   \end{array} \right)
+     * \f]
+     */
+    c0[0] = covariance(LHCb::CaloPosition::Index::X, LHCb::CaloPosition::Index::X); // arr[0] not relying on LHCb::CaloFuturePosition::Index::X == 0
+    c0[2] = covariance(LHCb::CaloPosition::Index::Y, LHCb::CaloPosition::Index::Y); // arr[2] not relying on LHCb::CaloFuturePosition::Index::Y == 1
+    c0[5] = covariance(LHCb::CaloPosition::Index::E, LHCb::CaloPosition::Index::E); // arr[5] not relying on LHCb::CaloFuturePosition::Index::E == 2
+    c0[1] = covariance(LHCb::CaloPosition::Index::X, LHCb::CaloPosition::Index::Y); // arr[1]
+    c0[3] = covariance(LHCb::CaloPosition::Index::X, LHCb::CaloPosition::Index::E); // arr[3]
+    c0[4] = covariance(LHCb::CaloPosition::Index::Y, LHCb::CaloPosition::Index::E); // arr[4]
+
+    // cov1 = (J * cov0 * J^T) for the special case of Jacobian for (X,Y,E) -> (X1=X, Y1=Y, E1=E(X,Y,E))
+    c1[0] = c0[0];
+    c1[1] = c0[1];
+    c1[2] = c0[2];
+    c1[3] = c0[0] * dEcor_dXcl + c0[1] * dEcor_dYcl + c0[3] * dEcor_dEcl;
+    c1[4] = c0[1] * dEcor_dXcl + c0[2] * dEcor_dYcl + c0[4] * dEcor_dEcl;
+    double tmp = c0[3] * dEcor_dXcl + c0[4] * dEcor_dYcl + c0[5] * dEcor_dEcl;
+    c1[5] = c1[3] * dEcor_dXcl + c1[4] * dEcor_dYcl + tmp * dEcor_dEcl;
+
+    // additional protection against cov.m.(E,E) <= 0 due to numerical effects
+    if (  c1[5] < 1.e-10 ) {
+      if ( UNLIKELY(msgLevel( MSG::DEBUG) ))debug() << "unphysical variance(Ehypo) = " << c1[5] << " reset cov.m.(Ehypo,*) = cov.m.(Ecluster,*) as if Ehypo = Ecluster" << endmsg;
+      ++m_counterUnphysicalVariance;
+      c1[5] = c0[5];
+      c1[3] = c0[3];
+      c1[4] = c0[4];
+    }
+
+    // --------------------------------------------------------------------------- alternative calculation for a general-form Jacobian
+    // /* typedef ROOT::Math::SMatrix<double, 3, 3, ROOT::Math::MatRepSym<double,3> >	Gaudi::SymMatrix3x3;
+    //  * typedef Gaudi::SymMatrix3x3                                              	LHCb::CaloPosition::Covariance;
+    //  *
+    //  * calculations done with TMatrixDSym (for which TMatrixD.Mult() is defined) for simplicity instead of ROOT::Math::SMatrix<...>
+    //  * cov1 = J * cov0 * J^T
+    //  */
+    //
+    // // Jacobian for (X,Y,E) -> (X1=X, Y1=Y, E1=E(X,Y,E))
+    // TMatrixD jac(3, 3);
+    // jac(0,0) = 1.;
+    // jac(1,1) = 1.;
+    // jac(2,0) = dEcor_dXcl;
+    // jac(2,1) = dEcor_dYcl;
+    // jac(2,2) = dEcor_dEcl;
+    // // std::cout << "jacobian = " << std::endl; jac.Print();
+    //
+    // TMatrixDSym cov0( 3 ); // cov.m. is 3x3
+    //
+    // // use of SMatrix<>::Array() would have required less to type but assumes a particular storage sequence of the (X,Y,E) elements
+    // cov0(0,0) =             covariance(LHCb::CaloPosition::Index::X, LHCb::CaloPosition::Index::X); // c0[0] nomatter if LHCb::CaloPosition::Index::X == 0
+    // cov0(1,1) =             covariance(LHCb::CaloPosition::Index::Y, LHCb::CaloPosition::Index::Y); // c0[2] nomatter if LHCb::CaloPosition::Index::Y == 1
+    // cov0(2,2) =             covariance(LHCb::CaloPosition::Index::E, LHCb::CaloPosition::Index::E); // c0[5] nomatter if LHCb::CaloPosition::Index::E == 2
+    // cov0(1,0) = cov0(0,1) = covariance(LHCb::CaloPosition::Index::X, LHCb::CaloPosition::Index::Y); // c0[1]
+    // cov0(2,0) = cov0(0,2) = covariance(LHCb::CaloPosition::Index::X, LHCb::CaloPosition::Index::E); // c0[3]
+    // cov0(2,1) = cov0(1,2) = covariance(LHCb::CaloPosition::Index::Y, LHCb::CaloPosition::Index::E); // c0[4]
+    //
+    // // cov1 = J * cov *J^T  using  TMatrixD.Mult()  and  TMatrixDSym  for a general-form Jacobian J
+    // TMatrixDSym cov1( cov0 );
+    // recalculate_cov(jac, cov0, cov1);
+    //
+    // // std::cout << "cov0 = " << std::endl; cov0.Print();
+    // // std::cout << "cov1 = " << std::endl; cov1.Print();
+    // -------------------------------------------------------------------------------------------------------------------------------
+
+    // finally update CaloHypo::position()->covariance()
+    covariance(LHCb::CaloPosition::Index::X, LHCb::CaloPosition::Index::X) = c1[0]; // cov1(0,0);
+    covariance(LHCb::CaloPosition::Index::Y, LHCb::CaloPosition::Index::Y) = c1[2]; // cov1(1,1);
+    covariance(LHCb::CaloPosition::Index::E, LHCb::CaloPosition::Index::E) = c1[5]; // cov1(2,2);
+    covariance(LHCb::CaloPosition::Index::X, LHCb::CaloPosition::Index::Y) = c1[1]; // cov1(0,1);
+    covariance(LHCb::CaloPosition::Index::X, LHCb::CaloPosition::Index::E) = c1[3]; // cov1(0,2);
+    covariance(LHCb::CaloPosition::Index::Y, LHCb::CaloPosition::Index::E) = c1[4]; // cov1(1,2);
+
+    // // paranoic test (should be always ok since Covariance is SMatrix<3,3,double> with internal representation as double array[5])
+    // assert( covariance(LHCb::CaloPosition::Index::X, LHCb::CaloPosition::Index::Y) == covariance(LHCb::CaloPosition::Index::Y, LHCb::CaloPosition::Index::X));
+    // assert( covariance(LHCb::CaloPosition::Index::X, LHCb::CaloPosition::Index::E) == covariance(LHCb::CaloPosition::Index::E, LHCb::CaloPosition::Index::X));
+    // assert( covariance(LHCb::CaloPosition::Index::Y, LHCb::CaloPosition::Index::E) == covariance(LHCb::CaloPosition::Index::E, LHCb::CaloPosition::Index::Y));
+
+    if ( UNLIKELY(msgLevel( MSG::DEBUG)) ) {
+      debug() << "after E-corr. cov.m. = \n" << covariance << endmsg;
+    }
+  }
+
+  return StatusCode::SUCCESS ;
+}
+
+
+double CaloFutureECorrection::calcECorrection( double xBar, double yBar, double eEcal, double ePrs,
+    const struct CaloFutureECorrection::ECorrInputParams& _params,
+    CaloFutureECorrection::ECorrOutputParams*             _results ) const
+{
+  // local aliases for the input variables passed from process() to calcECorrection()
+  const LHCb::CaloCellID& cellID  = _params.cellID;
+  const Gaudi::XYZPoint&  seedPos = _params.seedPos;
+  const double&           eSpd    = _params.eSpd;
+  const double&           dtheta  = _params.dtheta;
+  const unsigned int&     area    = _params.area;
+
+  const int ShiftCol[3] = {  0 ,  0 ,  8 };
+  const int ShiftRow[3] = {  6 , 12 , 14 };
+
+  double CellSize =  m_det->cellSize( cellID  );
+  double Asx   = ( xBar - seedPos.x() ) / CellSize ; // Asx0
+  double Asy   = ( yBar - seedPos.y() ) / CellSize ; // Asy0
+
+  const double Asx0 = Asx;
+  const double Asy0 = Asy;
+
+  unsigned int    Col   = cellID.col()  - ShiftCol[area] + 1;
+  unsigned int    Row   = cellID.row()  - ShiftRow[area] + 1;
+
+
+  double bDist = sqrt( Asx * Asx + Asy * Asy) * sqrt ( 2. ) ;
+
+  // leakage induced by Ecal module frame
+  double signX = 0;
+  if ( 1 == Col % (area + 1) )  {
+    signX  = +1.;
+  }
+  if ( 0 == Col % (area + 1) )  {
+    signX  = -1.;
+  }
+  double signY = 0;
+  if ( 1 == Row % (area + 1) )  {
+    signY  = +1.;
+  }
+  if ( 0 == Row % (area + 1) )  {
+    signY  = -1.;
+  }
+  Asx *=  signX; // Asx1
+  Asy *=  signY; // Asy1
+
+
+  // analytic derivatives of the correction functions
+  double DaE(0), DaB(0), DaX(0), DaY(0), Dbeta(0), DbetaPR(0), DbetaC(0), DbetaCPR(0);
+
+  //
+  // apply corrections
+  // NB: numeric derivative calculation calls and printouts which are commented-out below
+  // are useful for debugging in case of changes in the correction function code
+  //
+  //// aG = const(X,Y,E), no need to calculate derivatives
+  double aG  = getCorrection(CaloFutureCorrection::alphaG    , cellID         );  // global Ecal factor
+
+  //// aE = alphaE(eEcal)
+  double aE  = getCorrection(CaloFutureCorrection::alphaE    , cellID , eEcal );  // longitudinal leakage
+  if ( m_correctCovariance ) {
+    if ( _results ) DaE      = getCorrectionDerivative(CaloFutureCorrection::alphaE    , cellID , eEcal );
+    // double dn_aE  = (getCorrection(CaloFutureCorrection::alphaE    , cellID , eEcal*1.02 )-aE)/eEcal/2.e-2;
+    // std::cout << " alphaE: eEcal = " << eEcal << " aE = " << aE << " DaE = " << DaE
+    //           << " numeric d(aE)/d(eEcal) = dn_aE = " << dn_aE  << std::endl;
+  }
+
+  //// aB = alphaB(bDist)
+  double aB  = getCorrection(CaloFutureCorrection::alphaB    , cellID , bDist );  // lateral leakage
+  if ( m_correctCovariance ) {
+    if ( _results ) DaB      = getCorrectionDerivative(CaloFutureCorrection::alphaB    , cellID , bDist );
+    // double tmpd = ( bDist > 1e-5 ) ? bDist*2.e-2 : 2.e-7;
+    // double dn_aB = (getCorrection(CaloFutureCorrection::alphaB    , cellID , bDist + tmpd )-aB)/tmpd;
+    // std::cout << "\t alphaB: bDist = " << bDist << " aB = " << aB << " DaB = " << DaB
+    //           << " numeric  d(aB)/d(bDist) = dn_aB = " << dn_aB << std::endl;
+  }
+
+  //// aX = alphaX(Asx1)
+  double aX  = getCorrection(CaloFutureCorrection::alphaX    , cellID , Asx   );  // module frame dead material X-direction
+  if ( m_correctCovariance ) {
+    if ( _results ) DaX  = getCorrectionDerivative(CaloFutureCorrection::alphaX    , cellID , Asx   );
+    // double tmpd = ( fabs(Asx) > 1e-5 ) ? Asx*2.e-2 : 2.e-7;
+    // double dn_aX  = (getCorrection(CaloFutureCorrection::alphaX    , cellID , Asx + tmpd  ) -aX)/ tmpd;
+    // std::cout << "\t alphaX Asx = " << Asx << " aX = " << aX << " DaX = " << DaX
+    //           << " numeric d(aX)/d(Asx1) = dn_aX = " << dn_aX << std::endl;
+  }
+
+  //// aY = alphaY(Asy1)
+  double aY  = getCorrection(CaloFutureCorrection::alphaY    , cellID , Asy   );  // module frame dead material Y-direction
+  if ( m_correctCovariance ) {
+    if ( _results ) DaY  = getCorrectionDerivative(CaloFutureCorrection::alphaY    , cellID , Asy   );
+    // double tmpd = ( fabs(Asy) > 1e-5 ) ? Asy*2.e-2 : 2.e-7;
+    // double dn_aY  = (getCorrection(CaloFutureCorrection::alphaY    , cellID , Asy + tmpd  ) -aY)/ tmpd;
+    // std::cout << "\t alphaY: Asy = " << Asy << " aY = " << aY << " DaY = " << DaY
+    //           << " numeric d(aY)/d(Asy1) = dn_aY = " << dn_aY  << std::endl;
+  }
+
+  //// alphaP(ePrs) = const(X,Y,E), no need to calculate derivatives
+  //// unless a full 4D cov.m.(X,Y,E,ePrs) is used including sigma(ePrs) and ePrs correlations with X,Y,E
+  double aP  = getCorrection(CaloFutureCorrection::alphaP    , cellID , ePrs  );  // Prs deposit dependency
+
+
+  // Prs correction
+  double ratio = (eEcal > 0 ) ? ePrs / eEcal : 0. ;
+  //// beta0 = beta(eEcal)
+  double beta = getCorrection(CaloFutureCorrection::beta , cellID , eEcal  , 0. );    // eEcal dependency if any
+  if ( m_correctCovariance ) {
+    if ( _results ) Dbeta = getCorrectionDerivative(CaloFutureCorrection::beta , cellID , eEcal , 0 );
+    // double dn_beta = (getCorrection(CaloFutureCorrection::beta       , cellID , eEcal*1.02 , 0. )-beta)/eEcal/2.e-2;
+    // std::cout << "\t beta: eEcal = " << eEcal << " beta = " << beta << " Dbeta = " << Dbeta
+    //           << " numeric d(beta)/d(eEcal) = dn_beta = " << dn_beta  << std::endl;
+  }
+
+  double betaP = getCorrection(CaloFutureCorrection::betaP      , cellID , ePrs   , 0. );    // add Eprs dependency if any
+  beta += betaP; // beta1
+  //// betaPR(ratio = ePrs/eEcal)
+  double betaPR = getCorrection(CaloFutureCorrection::betaPR     , cellID , ratio  , 0. );    // add ePrs/eEcal dependency if any
+  if ( m_correctCovariance ) {
+    if ( _results ) DbetaPR = getCorrectionDerivative(CaloFutureCorrection::betaPR     , cellID , ratio  , 0. );
+  }
+  beta += betaPR; // beta2
+
+
+  // angular correction
+  // assume dtheta to be independent of X,Y,E, although it may still be implicitly a bit dependent on X,Y
+  double gT  = getCorrection(CaloFutureCorrection::globalT   , cellID , dtheta );  // incidence angle (delta)
+  double dT  = getCorrection(CaloFutureCorrection::offsetT   , cellID , dtheta , 0. );  // incidence angle (delta)
+
+
+  // Energy offset
+  double sinT  =  m_det->cellSine( cellID );
+  double offset = ( eSpd == 0) ?
+                  getCorrection(CaloFutureCorrection::offset, cellID , sinT , 0.) :
+                  getCorrection(CaloFutureCorrection::offsetC, cellID , sinT , 0.) ;
+
+  // - dedicate correction for 'converted photon'
+  double gC = 1.;
+  bool betaC_flag = false;
+  if ( eSpd > 0) {
+    gC = getCorrection(CaloFutureCorrection::globalC , cellID ); // global correction factor for converted photons
+    //// betaC0 = betaC(eEcal)
+    double betaC = getCorrection(CaloFutureCorrection::betaC      , cellID , eEcal , 0.  );
+    if ( m_correctCovariance ) {
+      if ( _results ) DbetaC = getCorrectionDerivative(CaloFutureCorrection::betaC      , cellID , eEcal , 0.  );
+    }
+
+    //// betaCP = betaCP(ePrs) = const(X,Y,E) => no need to calculate derivaties unless 4D cov.m.(X,Y,E,ePrs) is used
+    double betaCP = getCorrection(CaloFutureCorrection::betaCP          , cellID , ePrs  , 0.  );
+    betaC += betaCP; // betaC1
+
+    //// betaCPR(ratio = ePrs/eEcal)
+    double betaCPR = getCorrection(CaloFutureCorrection::betaCPR         , cellID , ratio , 0.  );
+    if ( m_correctCovariance ) {
+      if ( _results ) DbetaCPR = getCorrectionDerivative(CaloFutureCorrection::betaCPR         , cellID , ratio , 0.  );
+    }
+    betaC += betaCPR; // betaC2
+
+    if ( betaC != 0.) {
+      beta = betaC;
+      betaC_flag = true;
+    }
+  }
+
+
+
+  // Apply Ecal leakage corrections
+  double alpha = aG * aE * aB * aX * aY  * aP;
+  double eCor  = ( alpha * eEcal + beta * ePrs ) * gC * gT + dT + offset;
+
+
+
+  /* DG,20140714: derivative calculation
+   *
+   * Asx0  = (Xcluster-seedPos.x)/CellSize
+   * bDist = sqrt(2)*sqrt(Asx0**2+Asy0**2)
+   * signX = signX(cellID); // const(X,Y,Ecluster)
+   * Asx1  = signX*Asx0
+   * eEcal = Ecluster - pileup_offset(cellID, eSpd); // => d(eEcal)/d(Ecluster) = 1
+   * aG    = alphaG(cellID); // const(X,Y, Ecluster)
+   * aE    = alphaE(eEcal)
+   * aB    = alphaB(bDist)
+   * aX    = alphaX(Asx1)
+   * aY    = alphaY(Asy1)
+   * aP    = alphaP(ePrs); // const(X,Y, Ecluster)
+   * ratio = ePrs/eEcal; //  if eEcal > 0, otherwise = 0
+   * beta0 = beta(eEcal)
+   * beta1 = beta0 + betaP(ePrs)
+   * beta2 = beta1 + betaPR(ratio)
+   * gT    = globalT(dtheta); // const(X,Y,Ecluster) although dtheta may indirectly depend on (X,Y)
+   * dT    = offsetT(dtheta); // const(X,Y,Ecluster)
+   * sinT  = cellSince(cellID); // const(X,Y,Ecluster)
+   * offset= eSpd > 0 ? offsetC(cellID, sinT) : offset(cellID, sinT)
+   * gC    = eSpd > 0 ? globalC(cellID) : 1; // const(X,Y,Ecluster)
+   * betaC0= betaC(eEcal)
+   * betaC1= betaC0_betaCP(ePrs)
+   * betaC2= betaC1+betaCPR(ratio)
+   *
+   * betaQ2= betaC_flag ? betaC2 : beta2
+   *
+   * d(Asx0)/dX       = +1/CellSize
+   * d(Asx1)/d(Asx0)  = signX
+   * d(bDist)/d(Asx0) = sqrt(2)*2*Asx0/2/sqrt(Asx0**2+Asy0**2) = 2*Asx0/bDist; // if bDist != 0, otherwise 0
+   *   if bDist=0 <=> (Asx=0,Asy=0), but for any Asy!=0 (if Asx=0 => d(bDist)/d(Asx) = 0)
+   *   => for continuity similarly define the same for Asy=0, i.e. if bDist=0 => d(bDist)/d(Asx) = 0
+   *
+   * d(aB)/dX             = d(aB)/d(bDist)*d(bDist)/d(Asx0)*d(Asx0)/dX = DalphpaB*(2*Asx0/bDist)*(1/CellSize)
+   * d(aX)/dX             = d(aX)/d(Asx1)*d(Asx1)/d(Asx0)*d(Asx0)/dX = DalphaX*signX*(1/CellSize)
+   * d(eEcal)/d(Ecluster) = 1
+   * d(ratio)/d(eEcal)    = - ePrs/eEcal**2 = - ratio / eEcal; // if eEcal > 0, otherwise = 0
+   *
+   * betaQ        = betaC_flag ? betaC : beta
+   * d(betaQ2)/dE = d( betaQ(eEcal) + betaQP(ePrs) + betaQPR(ratio) )/d(eEcal) = DbetaQ + 0 + DbetaQ*d(ratio)/dE =
+   *              = DbetaQ - DbetaQPR*ePrs/eEcal**2 = DbetaQ - DbetaQPR*ratio/eEcal
+   *
+   * alpha = aG * aE(eEcal) * aB(bDist) * aX(Asx1) * aY(Asy1)  * aP(ePrs);
+   * Ehypo = eCor = ( alpha(eEcal, bDist, Asx1, Asy1) * eEcal + beta2(eEcal, ratio, ePrs) * ePrs ) * gC * gT + dT + offset;
+   *
+   * d(alpha)/d(eEcal) = (aG*aB*aX*aY*aP) * d(aE)/d(eEcal) = (alpha/aE) * DalphaE; // if aE!=0, otherwise aG*aB*aX*aY*aP*DalphaE
+   *
+   *
+   * d(Ehypo)/d(Ecluster) = gC*gT*(eEcal*d(alpha)/d(eEcal) + alpha + ePrs*d(beta2)/d(eEcal))
+   *                      = gC * gT * ( ePrs *  DbetaQ2 + alpha * (1. + DaE / aE * eEcal) )
+   * d(Ehypo)/d(Xcluster) = gC*gT*eEcal*d(alpha)/dX = gC*gT*eEcal*aG*aE*aY*aP*(d(aB)/dX*aX+d(aX)/dX*aB)
+   *                      = gC * gT * eEcal * aG * aE * aY * aP * (DaB*2.*Asx0/bDist*aX + signX*aB*DaX)/CellSize
+   * d(Ehypo)/d(Ycluster) = [ same as for d(Ehypo)/d(Xcluster) with ( X <-> Y ) ]
+   * 			= gC * gT * eEcal * aG * aE * aX * aP * (DaB*2.*Asy0/bDist*aY + signY*aB*DaY)/CellSize
+   */
+
+  if ( _results != NULL ) {
+    if ( m_correctCovariance ) {
+      double DbetaQ2 = betaC_flag ? ( DbetaC - (eEcal > 0 ? DbetaCPR * ratio / eEcal : 0) )
+                       : ( Dbeta  - (eEcal > 0 ? DbetaPR * ratio / eEcal : 0) );
+      double d_alpha_dE = (aE != 0) ? DaE * alpha / aE : DaE * aG * aB * aX * aY * aP; // though in principle, aE should never be 0
+
+      _results->dEcor_dEcl  = gC * gT * ( ePrs *  DbetaQ2 + alpha + d_alpha_dE * eEcal );
+      _results->dEcor_dXcl  = gC * gT * eEcal * aG * aE * aY * aP * ((bDist == 0 ? 0. : DaB * 2.*Asx0 / bDist * aX) + signX * aB * DaX) / CellSize;
+      _results->dEcor_dYcl  = gC * gT * eEcal * aG * aE * aX * aP * ((bDist == 0 ? 0. : DaB * 2.*Asy0 / bDist * aY) + signY * aB * DaY) / CellSize;
+
+      _results->betaC_flag  = betaC_flag;
+    }
+
+    _results->beta  = beta; // betaQ2
+    _results->alpha = alpha;
+
+    // intermediate variables calculated by calcECorrection() needed for debug printout inside process()
+    if ( UNLIKELY(msgLevel( MSG::DEBUG)) ) {
+      _results->Asx   = Asx; // Asx1
+      _results->Asy   = Asy; // Asy1
+      _results->aG    = aG;
+      _results->aE    = aE;
+      _results->aB    = aB;
+      _results->aX    = aX;
+      _results->aY    = aY;
+      _results->gC    = gC;
+      _results->gT    = gT;
+    }
+  }
+
+  return eCor;
+}
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureECorrection.h b/CaloFuture/CaloFutureReco/src/CaloFutureECorrection.h
new file mode 100644
index 0000000000000000000000000000000000000000..e2cd400744e30e10beed27747468b4c95c036e38
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureECorrection.h
@@ -0,0 +1,106 @@
+#ifndef CALOFUTURERECO_CALOFUTUREECORRECTION_H
+#define CALOFUTURERECO_CALOFUTUREECORRECTION_H 1
+// Include files
+#include <string>
+#include <map>
+#include "CaloFutureInterfaces/ICaloFutureHypoTool.h"
+#include "CaloFutureCorrectionBase.h"
+#include "GaudiKernel/Counters.h"
+
+/** @namespace CaloFutureECorrection_Local
+ */
+
+
+/** @class CaloFutureECorrection CaloFutureECorrection.h
+ *
+ *
+ *  @author Deschamps Olivier
+
+ *  @date   2003-03-10
+ */
+class CaloFutureECorrection :
+  public virtual ICaloFutureHypoTool,
+  public CaloFutureCorrectionBase
+{
+
+public:
+
+  StatusCode process    ( LHCb::CaloHypo* hypo  ) const override;
+  StatusCode operator() ( LHCb::CaloHypo* hypo  ) const override;
+
+public:
+
+  StatusCode initialize() override;
+  StatusCode finalize() override;
+
+  CaloFutureECorrection ( const std::string& type   ,
+                    const std::string& name   ,
+                    const IInterface*  parent ) ;
+
+private:
+  Gaudi::Property<int> m_pFilt {this, "PrsFilter", 0x3, "1 : noPrs ; 2 : Prs ; 3: both"};
+  Gaudi::Property<int> m_sFilt {this, "SpdFilter", 0x3, "1 : noSpd ; 2 : Spd ; 3: both"};
+
+  /// input variables calculated once in process() and passed to all calcECorrection() calls
+  struct ECorrInputParams {
+    LHCb::CaloCellID cellID;
+    Gaudi::XYZPoint  seedPos;
+    double           eSpd;
+    double           dtheta;
+    unsigned int     area;
+  };
+
+  /// Jacobian elements and intermediate variables sometimes returned from calcECorrection() to process()
+  class ECorrOutputParams
+  {
+  public:
+    ECorrOutputParams() : dEcor_dXcl(0), dEcor_dYcl(0), dEcor_dEcl(0),
+      alpha(0), beta(0), Asx(0), Asy(0), aG(0), aE(0), aB(0), aX(0), aY(0), gC(0), gT(0), betaC_flag(false) {}
+
+    // output Jacobian elements returned from calcECorrection() to process()
+    double dEcor_dXcl;
+    double dEcor_dYcl;
+    double dEcor_dEcl;
+
+    // intermediate variables calculated by calcECorrection() needed for debug printout inside process()
+    double alpha;
+    double beta;
+    double Asx;
+    double Asy;
+    double aG;
+    double aE;
+    double aB;
+    double aX;
+    double aY;
+    double gC;
+    double gT;
+
+    bool   betaC_flag;
+  };
+
+  /// calculate corrected CaloHypo energy depending on CaloCluster position, energy, and Prs energy
+  double calcECorrection( double xBar, double yBar, double eEcal, double ePrs,
+                          const struct CaloFutureECorrection::ECorrInputParams& _params,
+                          CaloFutureECorrection::ECorrOutputParams*             _results ) const;
+
+  using IncCounter =  Gaudi::Accumulators::Counter<>;
+  using SCounter =  Gaudi::Accumulators::StatCounter<float>;
+
+  mutable IncCounter m_counterSkippedNegativeEnergyCorrection{this, "Skip negative energy correction"};
+
+  mutable SCounter m_counterPileupOffset{this, "Pileup offset"};
+  mutable SCounter m_counterPileupSubstractedRatio{this, "Pileup subtracted ratio"};
+  mutable SCounter m_counterPileupScale{this, "Pileup scale"};
+
+  mutable IncCounter m_counterUnphysical{this, "Unphysical d(Ehypo)/d(Ecluster)"};
+
+  mutable SCounter m_counterCorrectedEnergy{this, "Corrected energy"};
+  mutable SCounter m_counterDeltaEnergy{this, "Delta(E)"};
+
+  mutable IncCounter m_counterUnphysicalVariance{this, "Unphysical variance(Ehypo)"};
+
+  static constexpr int k_numOfCaloFutureAreas{4};
+  mutable std::vector<SCounter> m_countersAlpha;
+  mutable std::vector<SCounter> m_countersBetaTimesEprs;
+};
+#endif // CALOFUTURERECO_CALOFUTUREECORRECTION_H
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureElectronAlg.cpp b/CaloFuture/CaloFutureReco/src/CaloFutureElectronAlg.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..02ac04f8f8467d9e42a3c29523f44ec50fd0ca9e
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureElectronAlg.cpp
@@ -0,0 +1,174 @@
+// ============================================================================
+// Include files
+// ============================================================================
+// STD & STL
+// ============================================================================
+#include <algorithm>
+// ============================================================================
+#include "CaloFutureUtils/CaloFutureDataFunctor.h"
+#include "Event/CellID.h"
+#include "Event/CaloCluster.h"
+#include "Event/CaloHypo.h"
+#include "CaloFutureInterfaces/ICaloFutureClusterSelector.h"
+#include "CaloFutureInterfaces/ICaloFutureHypoTool.h"
+#include "CaloFutureUtils/CaloFutureAlgUtils.h"
+#include "CaloFutureUtils/CaloMomentum.h"
+#include "CaloFutureElectronAlg.h"
+// ============================================================================
+/** @file
+ *
+ *  Implementation file for class : CaloFutureElectronAlg
+ *  The implementation is based on F.Machefert's codes.
+ *  @see CaloFutureElectronAlg
+ *
+ *  @author Vanya Belyaev Ivan.Belyaev@itep.ru
+ *  @date 31/03/2002
+ */
+// ============================================================================
+namespace {
+    template <typename Container, typename Arg, typename Parent>
+    bool apply(const Container& c, Arg& arg, const char* errmsg, const Parent& parent) {
+        bool r = std::all_of( std::begin(c), std::end(c),
+                            [&](typename Container::const_reference elem)
+                            { return (*elem)(&arg).isSuccess(); } );
+        if (UNLIKELY(!r)) parent.Error( errmsg, StatusCode::FAILURE ).ignore();
+        return r;
+    }
+}
+DECLARE_COMPONENT( CaloFutureElectronAlg )
+// ============================================================================
+/*  Standard constructor
+ *  @param name algorithm name
+ *  @param pSvc service locator
+ */
+// ============================================================================
+CaloFutureElectronAlg::CaloFutureElectronAlg
+( const std::string& name ,
+  ISvcLocator*       pSvcLocator )
+  : ScalarTransformer( name, pSvcLocator,
+                       KeyValue("InputData",{}), // note: context can not be used here -- only _after_ the baseclass is initialized!
+                       KeyValue("OutputData",{}) )
+
+{
+  updateHandleLocation( *this, "InputData", LHCb::CaloFutureAlgUtils::CaloFutureClusterLocation("Ecal", context() ));
+  updateHandleLocation( *this, "OutputData", LHCb::CaloFutureAlgUtils::CaloFutureHypoLocation("Electrons", context() ));
+
+
+  setProperty ( "PropertiesPrint" , true ) ;
+}
+// ============================================================================
+/*   standard Algorithm initialization
+ *   @return status code
+ */
+// ============================================================================
+StatusCode CaloFutureElectronAlg::initialize()
+{
+  // initialize  the base class
+  StatusCode sc = ScalarTransformer::initialize();
+  if( sc.isFailure() ){ return Error("Could not initialize the base class GaudiAlgorithm!",sc);}
+
+  // check the geometry information
+  m_det = getDet<DeCalorimeter>( m_detData ) ;
+  if( !m_det ) { return Error("Detector information is not available!");}
+
+  m_eT = LHCb::CaloDataFunctor::EnergyTransverse<const DeCalorimeter*>{ m_det } ; // TODO: can we combine this into Over_Et_Threshold and make it a property??
+
+  // locate selector tools
+  std::transform(m_selectorsTypeNames.begin(), m_selectorsTypeNames.end(),
+                 std::back_inserter( m_selectors ),
+                 [&](const std::string& name)
+                 { return this->tool<ICaloFutureClusterSelector>( name , this ); } );
+  if ( m_selectors.empty() )info()<<  "No Cluster Selection tools are specified!" <<endmsg ;
+  // locate correction tools
+  std::transform( m_correctionsTypeNames.begin(), m_correctionsTypeNames.end(),
+                  std::back_inserter(m_corrections),
+                  [&](const std::string& name)
+                  { return this->tool<ICaloFutureHypoTool>( name , this ); } );
+  if ( m_corrections.empty() )info() << "No Hypo Correction(1) tools are specified!" << endmsg ;
+  // locate other hypo  tools
+  std::transform( m_hypotoolsTypeNames.begin(), m_hypotoolsTypeNames.end(),
+                  std::back_inserter(m_hypotools),
+                  [&](const std::string& name)
+                  { return this->tool<ICaloFutureHypoTool>( name , this ); } );
+  if ( m_hypotools.empty() )info() << "No Hypo Processing(1) tools are specified!"  << endmsg ;
+  // locate correction tools
+  std::transform( m_correctionsTypeNames2.begin(), m_correctionsTypeNames2.end() ,
+                  std::back_inserter(m_corrections2),
+                  [&](const std::string& name)
+                  { return this->tool<ICaloFutureHypoTool>( name , this ); } );
+  if ( m_corrections2.empty() ) info() << "No Hypo Correction(2) tools are specified!"  << endmsg ;
+  // locate other hypo  tools
+  std::transform( m_hypotoolsTypeNames2.begin(), m_hypotoolsTypeNames2.end(),
+                  std::back_inserter(m_hypotools2),
+                  [&](const std::string& name)
+                  { return this->tool<ICaloFutureHypoTool>( name , this ); } );
+  if ( m_hypotools2.empty() )info() << "No Hypo    Processing(2) tools are specified!" << endmsg  ;
+  ///
+  counterStat = tool<IFutureCounterLevel>("FutureCounterLevel");
+  return StatusCode::SUCCESS;
+}
+// ============================================================================
+/*   standard Algorithm finalization
+ *   @return status code
+ */
+// ============================================================================
+StatusCode CaloFutureElectronAlg::finalize()
+{
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) debug()<<"Finalize"<<endmsg;
+
+  // clear containers
+  m_selectors             .clear () ;
+  m_corrections           .clear () ;
+  m_hypotools             .clear () ;
+  m_corrections2          .clear () ;
+  m_hypotools2            .clear () ;
+  m_selectorsTypeNames    .clear () ;
+  m_correctionsTypeNames  .clear () ;
+  m_hypotoolsTypeNames    .clear () ;
+  m_correctionsTypeNames2 .clear () ;
+  m_hypotoolsTypeNames2   .clear () ;
+  // finalize the base class
+  return ScalarTransformer::finalize() ;
+}
+// ============================================================================
+/*   standard Algorithm execution
+ *   @return status code
+ */
+// ============================================================================
+boost::optional<LHCb::CaloHypo>
+CaloFutureElectronAlg::operator()(const LHCb::CaloCluster& cluster) const{
+
+  // loop over all selectors
+  bool select = ( m_eT(&cluster) >= m_eTcut &&
+                  std::all_of( m_selectors.begin(), m_selectors.end(),
+                               [&](Selectors::const_reference sel)
+                               { return (*sel)(&cluster); } ) );
+  if ( !select ) return boost::none;
+
+  // create "Hypo"/"Electron" object
+  LHCb::CaloHypo hypo;
+  hypo.setHypothesis( LHCb::CaloHypo::Hypothesis::EmCharged );
+  hypo.addToClusters( &cluster );
+  hypo.setPosition( std::make_unique<LHCb::CaloPosition>(cluster.position()) );
+
+  //    return boost::none;
+  return boost::make_optional(
+			      apply( m_corrections, hypo,"Error from Correction Tool, skip the cluster " , *this ) // loop over all corrections and apply corrections
+			      && apply( m_hypotools, hypo, "Error from Other Hypo Tool, skip the cluster " , *this) // loop over other hypo tools (e.g. add extra digits)
+			      && apply( m_corrections2, hypo, "Error from Correction Tool 2 , skip the cluster " , *this) // loop over all corrections and apply corrections
+			      && apply( m_hypotools2, hypo, "Error from Other Hypo Tool 2 , skip the cluster ", *this) // loop over other hypo tools (e.g. add extra digits)
+			      && LHCb::CaloMomentum(&hypo).pt() >= m_eTcut,
+			      hypo);
+
+}
+
+void
+CaloFutureElectronAlg::postprocess(const LHCb::CaloHypos& hypos) const
+{
+  if(msgLevel(MSG::DEBUG))debug() << " # of created Electron  Hypos is  " << hypos.size()  << endmsg; // << "/" << clusters->size()<< endmsg ;
+  if(counterStat->isQuiet()){
+      std::string inputData; getProperty("InputData",inputData).ignore();
+      counter ( inputData + "=>" + outputLocation()  ) += hypos.size() ;
+  }
+}
+
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureElectronAlg.h b/CaloFuture/CaloFutureReco/src/CaloFutureElectronAlg.h
new file mode 100644
index 0000000000000000000000000000000000000000..82f0a172e96be579ed0b43c8f6690ac7468b8d17
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureElectronAlg.h
@@ -0,0 +1,96 @@
+#ifndef CALOFUTURERECO_CALOFUTUREElectronALG_H
+#define CALOFUTURERECO_CALOFUTUREElectronALG_H 1
+// Include files
+// from STL
+#include <string>
+// from GaudiAlg
+#include "GaudiAlg/ScalarTransformer.h"
+#include "CaloDet/DeCalorimeter.h"
+#include "Event/CaloHypo.h" 
+#include "Event/CaloCluster.h" 
+#include "CaloFutureInterfaces/IFutureCounterLevel.h" 
+
+// forward delcarations
+struct ICaloFutureClusterSelector ;
+struct ICaloFutureHypoTool        ;
+
+/** @class CaloFutureElectronAlg CaloFutureElectronAlg.h
+ *
+ *  The simplest algorithm of reconstruction of
+ *  electrons in electromagnetic calorimeter.
+ *
+ *  @author Vanya Belyaev      Ivan.Belyaev@itep.ru
+ *  @date   31/03/2002
+ */
+class CaloFutureElectronAlg 
+: public Gaudi::Functional::ScalarTransformer<CaloFutureElectronAlg,LHCb::CaloHypos(const LHCb::CaloClusters&)>
+{
+ public:
+  
+  CaloFutureElectronAlg(const std::string& name, ISvcLocator* pSvcLocator );
+  
+
+
+  StatusCode initialize() override;
+  StatusCode finalize() override;
+
+  using ScalarTransformer::operator();
+  boost::optional<LHCb::CaloHypo> operator()(const LHCb::CaloCluster& ) const;
+  void postprocess(const LHCb::CaloHypos&) const;  
+private:
+
+  /// container of names
+  typedef std::vector<std::string>           Names       ;
+  /// container of selector tools
+  typedef std::vector<ICaloFutureClusterSelector*> Selectors   ;
+  /// containers of hypo tools
+  typedef std::vector<ICaloFutureHypoTool*>        HypoTools   ;
+  /// container of correction tools (S-,L-,...)
+  typedef HypoTools                          Corrections ;
+
+
+  // cluster selectors
+  Selectors              m_selectors;
+  Gaudi::Property<Names> m_selectorsTypeNames {this, "SelectionTools", {
+    "CaloFutureSelectCluster/ElectronCluster",
+    "CaloFutureSelectChargedClusterWithSpd/ChargedWithSpd",
+    "CaloFutureSelectClusterWithPrs/ClusterWithPrs",
+    "CaloFutureSelectorNOT/ChargedWithTracks"
+  }, "List of Cluster selector tools"};
+
+  // corrections
+  Corrections            m_corrections;
+  Gaudi::Property<Names> m_correctionsTypeNames
+    {this, "CorrectionTools", {}, "List of primary correction tools"};
+
+  // other hypo tools
+  HypoTools              m_hypotools;
+  Gaudi::Property<Names> m_hypotoolsTypeNames
+    {this, "HypoTools", {"CaloFutureExraDigits/SpdPrsExtraE"},
+    "List of generic Hypo-tools to apply for newly created hypos"};
+
+  // corrections
+  Corrections            m_corrections2;
+  Gaudi::Property<Names> m_correctionsTypeNames2 {this, "CorrectionTools2", {
+    "CaloECorrection/ECorrection" ,
+    "CaloSCorrection/SCorrection" ,
+    "CaloLCorrection/LCorrection"
+  }, "List of tools for 'fine-corrections"};
+
+  // other hypo tools
+  HypoTools    m_hypotools2;
+  Gaudi::Property<Names> m_hypotoolsTypeNames2
+    {this, "HypoTools2", {},
+    "List of generi Hypo-tools to apply for corrected hypos"};
+
+  Gaudi::Property<std::string> m_detData    {this, "Detector", LHCb::CaloFutureAlgUtils::DeCaloFutureLocation("Ecal")  };
+  const DeCalorimeter*  m_det = nullptr;
+  Gaudi::Property<float> m_eTcut {this, "EtCut", 0, "Threshold on cluster & hypo ET"};
+  IFutureCounterLevel* counterStat = nullptr;
+  
+  LHCb::CaloDataFunctor::EnergyTransverse<const DeCalorimeter*> m_eT { nullptr } ; // TODO: can we combine this into Over_Et_Threshold and make it a property??
+
+};
+
+// ============================================================================
+#endif // CALOFUTUREElectronALG_H
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureExtraDigits.cpp b/CaloFuture/CaloFutureReco/src/CaloFutureExtraDigits.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4df502fc8d8d70ea0f244031bcb39c849b2fda6e
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureExtraDigits.cpp
@@ -0,0 +1,94 @@
+// ============================================================================
+// Include files
+// ============================================================================
+// STL
+// ============================================================================
+#include <cmath>
+#include <algorithm>
+// ============================================================================
+// from Gaudi
+// ============================================================================
+#include "GaudiKernel/SmartRef.h"
+// ============================================================================
+// local
+// ============================================================================
+#include "CaloFutureExtraDigits.h"
+// ============================================================================
+/** @file CaloFutureExtraDigits.cpp
+ *
+ *  Implementation file for class : CaloFutureExtraDigits
+ *  @see CaloFutureExtraDigits
+ *
+ *  @author Vanya Belyaev Ivan.Belyaev@itep.ru
+ *  @date 01/04/2002
+ */
+// ============================================================================
+DECLARE_COMPONENT( CaloFutureExtraDigits )
+// ============================================================================
+CaloFutureExtraDigits::CaloFutureExtraDigits
+( const std::string&  type   ,
+  const std::string&  name   ,
+  const IInterface*   parent )
+  : GaudiTool            ( type, name , parent )
+{
+  //
+  declareInterface<ICaloFutureHypoTool>     (this);
+  //
+  if ( std::string::npos != name.find ( "Prs"  ) )
+  { m_toDet.value().push_back ( "Prs"  ) ; }
+  if ( std::string::npos != name.find ( "Spd"  ) )
+  { m_toDet.value().push_back ( "Spd"  ) ; }
+  if ( std::string::npos != name.find ( "Hcal" ) )
+  { m_toDet.value().push_back ( "Hcal" ) ; }
+  if ( std::string::npos != name.find ( "Ecal" ) )
+  { m_toDet.value().push_back ( "Ecal" ) ; }
+}
+// ============================================================================
+StatusCode CaloFutureExtraDigits::initialize ()
+{
+  // initilaize the base class
+  StatusCode sc = GaudiTool::initialize ();
+  if( sc.isFailure() )
+  { return Error ( "Could not initialize the base class GaudiTool!", sc ) ; }
+  //
+  if ( m_toDet.empty() )
+  { return Error ( "List of 'ExtraDigitsFrom' is empty!" ) ; }
+  //
+  for ( std::vector<std::string>::iterator idet = m_toDet.begin();
+        idet!=m_toDet.end();idet++)
+  {
+    m_toCaloFuture[*idet]=tool<ICaloFutureHypo2CaloFuture>("CaloFutureHypo2CaloFuture", "CaloFutureHypo2" + *idet , this );
+    m_toCaloFuture[*idet]->setCalos(m_det,*idet);
+  }
+  //
+  counterStat = tool<IFutureCounterLevel>("FutureCounterLevel");
+  return StatusCode::SUCCESS ;
+}
+// ============================================================================
+StatusCode CaloFutureExtraDigits::process    ( LHCb::CaloHypo* hypo  ) const
+{ return (*this) ( hypo ); }
+// ============================================================================
+StatusCode CaloFutureExtraDigits::operator() ( LHCb::CaloHypo* hypo  ) const
+{
+  if ( 0 == hypo        ) { return Error("CaloHypo* points to NULL!" , StatusCode{200} ) ; }
+  //
+  for ( std::map<std::string,ICaloFutureHypo2CaloFuture*>::const_iterator
+          idet = m_toCaloFuture.begin(); idet!=m_toCaloFuture.end();idet++)
+  {
+    ICaloFutureHypo2CaloFuture*    tool   = idet->second ;
+    const std::string& toCaloFuture = idet->first  ;
+    unsigned int count = 0 ;
+    const std::vector<LHCb::CaloDigit*>& digits = tool->digits ( *hypo, toCaloFuture );
+    for ( std::vector<LHCb::CaloDigit*>::const_iterator id = digits.begin() ;
+          id != digits.end(); id++)
+    {
+      hypo->addToDigits( *id );
+      ++count;
+    }
+    //
+    if (UNLIKELY( msgLevel(MSG::DEBUG) ) )debug() << "Adding " << count << " digits from "<< *idet << endmsg;
+    //
+    if(counterStat->isVerbose() )counter ( toCaloFuture ) += count ;
+  }
+  return StatusCode::SUCCESS ;
+}
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureExtraDigits.h b/CaloFuture/CaloFutureReco/src/CaloFutureExtraDigits.h
new file mode 100644
index 0000000000000000000000000000000000000000..1f125b169a354e667a3270680e4ed093e82e28cf
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureExtraDigits.h
@@ -0,0 +1,39 @@
+#ifndef CALOFUTURERECO_CALOFUTUREEXTRADIGITS_H
+#define CALOFUTURERECO_CALOFUTUREEXTRADIGITS_H 1
+// Include files
+// from STL
+#include <string>
+// Kernel
+#include "GaudiAlg/GaudiTool.h"
+#include "CaloFutureInterfaces/ICaloFutureHypoTool.h"
+#include "CaloFutureInterfaces/ICaloFutureHypo2CaloFuture.h"
+#include "CaloFutureInterfaces/IFutureCounterLevel.h"
+
+/** @class CaloFutureExtraDigits CaloFutureExtraDigits.h
+ *
+ *
+ *  @author Vanya Belyaev Ivan Belyaev
+ *  @date   31/03/2002
+ */
+class CaloFutureExtraDigits :
+  public virtual     ICaloFutureHypoTool ,
+  public                  GaudiTool
+{
+public:
+
+  StatusCode initialize() override;
+  StatusCode process    ( LHCb::CaloHypo* hypo  ) const override;
+  StatusCode operator() ( LHCb::CaloHypo* hypo  ) const override;
+
+  CaloFutureExtraDigits( const std::string& type,
+                   const std::string& name,
+                   const IInterface* parent);
+
+private:
+
+  Gaudi::Property<std::vector<std::string>> m_toDet {this, "ExtraDigitFrom"};
+  std::map<std::string,ICaloFutureHypo2CaloFuture*> m_toCaloFuture;
+  Gaudi::Property<std::string> m_det {this, "Detector", "Ecal"};
+  IFutureCounterLevel* counterStat = nullptr;
+};
+#endif // CALOFUTUREEXTRADIGITS_H
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureGetterInit.cpp b/CaloFuture/CaloFutureReco/src/CaloFutureGetterInit.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b90bc72fe43d663f6579697b557115505e559578
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureGetterInit.cpp
@@ -0,0 +1,52 @@
+// Include files 
+
+// local
+#include "CaloFutureGetterInit.h"
+
+//-----------------------------------------------------------------------------
+// Implementation file for class : CaloFutureGetterInit
+//
+// 2009-04-17 : Olivier Deschamps
+//-----------------------------------------------------------------------------
+
+// Declaration of the Algorithm Factory
+DECLARE_COMPONENT( CaloFutureGetterInit )
+
+//=============================================================================
+// Initialization
+//=============================================================================
+StatusCode CaloFutureGetterInit::initialize() {
+  StatusCode sc = GaudiAlgorithm::initialize(); // must be executed first
+  if ( sc.isFailure() ) return sc;  // error printed already by GaudiAlgorithm
+
+  if ( UNLIKELY(msgLevel(MSG::DEBUG) ) ) debug() << "==> Initialize" << endmsg;
+
+
+  m_getter = tool<ICaloFutureGetterTool>("CaloFutureGetterTool", m_name );
+
+  return StatusCode::SUCCESS;
+}
+
+//=============================================================================
+// Main execution
+//=============================================================================
+StatusCode CaloFutureGetterInit::execute() {
+
+  if ( UNLIKELY(msgLevel(MSG::DEBUG) ) ) debug() << "==> Execute" << endmsg;
+
+  m_getter->update();
+
+  return StatusCode::SUCCESS;
+}
+
+//=============================================================================
+//  Finalize
+//=============================================================================
+StatusCode CaloFutureGetterInit::finalize() {
+
+  if ( UNLIKELY(msgLevel(MSG::DEBUG) ) ) debug() << "==> Finalize" << endmsg;
+
+  return GaudiAlgorithm::finalize();  // must be called after all other actions
+}
+
+//=============================================================================
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureGetterInit.h b/CaloFuture/CaloFutureReco/src/CaloFutureGetterInit.h
new file mode 100644
index 0000000000000000000000000000000000000000..17ab66493e1abd08f2790e1be72645b0a0f35c57
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureGetterInit.h
@@ -0,0 +1,30 @@
+// $Id: CaloFutureGetterInit.h,v 1.1 2009-04-17 11:44:53 odescham Exp $
+#ifndef CALOFUTUREGETTERINIT_H 
+#define CALOFUTUREGETTERINIT_H 1
+
+// Include files
+// from Gaudi
+#include "GaudiAlg/GaudiAlgorithm.h"
+//from LHCb
+#include "CaloFutureInterfaces/ICaloFutureGetterTool.h"
+
+/** @class CaloFutureGetterInit CaloFutureGetterInit.h
+ *  
+ *
+ *  @author Olivier Deschamps
+ *  @date   2009-04-17
+ */
+class CaloFutureGetterInit : public GaudiAlgorithm {
+public: 
+  /// Standard constructor
+  using GaudiAlgorithm::GaudiAlgorithm;
+
+  StatusCode initialize() override;    ///< Algorithm initialization
+  StatusCode execute() override;    ///< Algorithm execution
+  StatusCode finalize() override;    ///< Algorithm finalization
+
+private:
+  ICaloFutureGetterTool* m_getter = nullptr;
+  Gaudi::Property<std::string> m_name {this, "ToolName", "CaloFutureGetter"};
+};
+#endif // CALOFUTUREGETTERINIT_H
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureHypoAlg.cpp b/CaloFuture/CaloFutureReco/src/CaloFutureHypoAlg.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d38328cd979de45aaf8947ad5d531a9d9e15a134
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureHypoAlg.cpp
@@ -0,0 +1,126 @@
+// ============================================================================
+// Include files
+// ============================================================================
+// STD & STL 
+// ============================================================================
+#include <algorithm>
+// ============================================================================
+// CaloFutureInterfaces 
+// ============================================================================
+#include "CaloFutureInterfaces/ICaloFutureHypoTool.h" 
+// ============================================================================
+// CaloFutureEvent/Event
+// ============================================================================
+#include "Event/CaloHypo.h"
+#include "CaloFutureUtils/CaloFutureAlgUtils.h"
+// ============================================================================
+// local
+// ============================================================================
+#include "CaloFutureHypoAlg.h"
+// ============================================================================
+/** @file CaloFutureHypoAlg.cpp
+ * 
+ *  Template implementation file for class : CaloFutureHypoAlg
+ *  @see CaloFutureHypoAlg
+ * 
+ *  @author Vanya Belyaev Ivan.Belyaev@itep.ru
+ *  @date 02/09/2002
+ */
+// ============================================================================
+DECLARE_COMPONENT( CaloFutureHypoAlg )
+// ============================================================================
+/*  Standard constructor
+ *  @param   name   algorithm name 
+ *  @param   svcloc pointer to service locator 
+ */
+// ============================================================================
+CaloFutureHypoAlg::CaloFutureHypoAlg
+( const std::string& name   ,
+  ISvcLocator*       svcloc )
+  : GaudiAlgorithm ( name , svcloc ) 
+{
+  setProperty ( "PropertiesPrint" , true ) ;
+}
+// ============================================================================
+/*  standard algorithm initialization 
+ *  @see CaloFutureAlgorithm
+ *  @see     Algorithm
+ *  @see    IAlgorithm
+ *  @return status code 
+ */
+// ============================================================================
+StatusCode CaloFutureHypoAlg::initialize() 
+{  
+  StatusCode sc = GaudiAlgorithm::initialize();
+  if( sc.isFailure() ) 
+  { return Error("Could not initialize the base class CaloFutureAlgorithm",sc);}
+
+  // apply default context-dependent TES location (if not defined)
+  if(  m_inputData.empty() && !m_type.empty() )m_inputData =  LHCb::CaloFutureAlgUtils::CaloFutureHypoLocation( m_type , context() );
+
+  
+  if ( m_inputData.empty() ) 
+  { return Error ( "Empty 'InptuData'"  ) ; }
+  //
+  for( Names::const_iterator it = m_names.begin() ; 
+       m_names.end() != it ; ++it ) 
+  {
+    ICaloFutureHypoTool* t = tool<ICaloFutureHypoTool>( *it , this ) ;
+    if( 0 == t ) { return Error("Could not locate the tool!"); }
+    m_tools.push_back( t );
+  }
+  //
+  if ( m_tools.empty()     ) { Warning ( "Empty list of tools").ignore() ; }
+  //   
+  counterStat = tool<IFutureCounterLevel>("FutureCounterLevel");
+  return StatusCode::SUCCESS;
+}
+// ============================================================================
+/*  standard algorithm finalization 
+ *  @see CaloFutureAlgorithm
+ *  @see     Algorithm
+ *  @see    IAlgorithm
+ *  @return status code 
+ */
+// ============================================================================
+StatusCode CaloFutureHypoAlg::finalize() 
+{  
+  // clear the container 
+  m_tools.clear();  
+  /// finalize the base class 
+  return GaudiAlgorithm::finalize();
+}
+// ============================================================================
+/*  standard algorithm execution 
+ *  @see CaloFutureAlgorithm
+ *  @see     Algorithm
+ *  @see    IAlgorithm
+ *  @return status code 
+ */
+// ============================================================================
+StatusCode CaloFutureHypoAlg::execute() 
+{
+  // avoid long name and types 
+  typedef LHCb::CaloHypos  Hypos;
+  
+  Hypos* hypos = get<Hypos>( m_inputData ) ;
+  if( 0 == hypos ) { return StatusCode::FAILURE ; }
+  
+  for( Hypos::const_iterator hypo = hypos->begin() ; 
+       hypos->end() != hypo ; ++hypo ) 
+  {
+    // skip NUULS 
+    if( 0 == *hypo ) { continue ; }
+    // loop over all tools
+    StatusCode sc = StatusCode::SUCCESS ;
+    for( Tools::const_iterator itool = m_tools.begin() ; 
+         m_tools.end() != itool && sc.isSuccess() ; ++itool )
+    { sc = (**itool)( *hypo ); }
+    if( sc.isFailure() ) 
+    { Error("Error from the Tool! skip hypo!",sc).ignore() ; continue ; }  
+  }
+
+  if(counterStat->isQuiet())counter ( "#Hypos from '" + m_inputData +"'") += hypos->size() ;
+  //
+  return StatusCode::SUCCESS ;
+}
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureHypoAlg.h b/CaloFuture/CaloFutureReco/src/CaloFutureHypoAlg.h
new file mode 100644
index 0000000000000000000000000000000000000000..961af08c759fdba46a5092ba97b309ccf4998f2a
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureHypoAlg.h
@@ -0,0 +1,79 @@
+#ifndef CaloFutureReco_CaloFutureHypoAlg_H
+#define CaloFutureReco_CaloFutureHypoAlg_H 1
+// Include files
+// from STL
+#include <string>
+#include <vector>
+
+#include "CaloFutureInterfaces/IFutureCounterLevel.h"
+#include "GaudiAlg/GaudiAlgorithm.h"
+// forward declaration
+struct ICaloFutureHypoTool ;
+
+/** @class CaloFutureHypoAlg CaloFutureHypoAlg.h
+ *
+ *  Generic CaloFutureHypo Algorithm.
+ *  It is just applies a set of ICaloFutureHypoTools
+ *  to a container of CaloFutureHypo objects
+ *  @see ICaloFutureHypoTool
+ *  @see  CaloFutureHypo
+ *  @see  CaloFutureAlgorithm
+ *  @see      Algorithm
+ *  @see     IAlgorithm
+ *
+ *  @author Vanya Belyaev Ivan.Belyaev@itep.ru
+ *  @date   02/09/2002
+ */
+
+class CaloFutureHypoAlg : public GaudiAlgorithm
+{
+public:
+
+  /** standard algorithm initialization
+   *  @see CaloFutureAlgorithm
+   *  @see     Algorithm
+   *  @see    IAlgorithm
+   *  @return status code
+   */
+  StatusCode initialize() override;
+
+  /** standard algorithm execution
+   *  @see CaloFutureAlgorithm
+   *  @see     Algorithm
+   *  @see    IAlgorithm
+   *  @return status code
+   */
+  StatusCode execute() override;
+
+  /** standard algorithm finalization
+   *  @see CaloFutureAlgorithm
+   *  @see     Algorithm
+   *  @see    IAlgorithm
+   *  @return status code
+   */
+  StatusCode finalize() override;
+
+  /** Standard constructor
+   *  @param   name   algorithm name
+   *  @param   svcloc pointer to service locator
+   */
+  CaloFutureHypoAlg( const std::string& name   ,
+              ISvcLocator*       svcloc );
+
+private:
+
+  typedef std::vector<std::string>    Names ;
+  typedef std::vector<ICaloFutureHypoTool*> Tools ;
+
+  /// list of tool type/names
+  Gaudi::Property<Names> m_names
+    {this, "Tools", {}, "The list of generic Hypo-tools to be applied"};
+
+  /// list of tools
+  Tools   m_tools ;
+  Gaudi::Property<std::string> m_inputData {this, "InputData"};
+  Gaudi::Property<std::string> m_type      {this, "HypoType"};
+  IFutureCounterLevel* counterStat = nullptr;
+};
+// ============================================================================
+#endif // CaloFutureHypoAlg_H
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureLCorrection.cpp b/CaloFuture/CaloFutureReco/src/CaloFutureLCorrection.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d8086176dc0aca5da5571778506e4975291abc1a
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureLCorrection.cpp
@@ -0,0 +1,232 @@
+// ============================================================================
+// Include files
+#include "CaloFutureLCorrection.h"
+
+/** @file
+ *  Implementation file for class : CaloFutureLCorrection
+ *
+ *  @date 2003-03-10
+ *  @author Xxxx XXXXX xxx@xxx.com
+ */
+
+DECLARE_COMPONENT( CaloFutureLCorrection )
+
+// ============================================================================
+/** Standard constructor
+ *  @see GaudiTool
+ *  @see  AlgTool
+ *  @param type tool type (?)
+ *  @param name tool name
+ *  @param parent  tool parent
+ */
+// ============================================================================
+CaloFutureLCorrection::CaloFutureLCorrection
+( const std::string& type   ,
+  const std::string& name   ,
+  const IInterface*  parent )
+  : CaloFutureCorrectionBase( type , name , parent )
+{
+
+  // define conditionName
+  const std::string uName ( LHCb::CaloFutureAlgUtils::toUpper( name ) ) ;
+  if ( uName.find( "ELECTRON" ) != std::string::npos  ) {
+    m_conditionName = "Conditions/Reco/Calo/ElectronLCorrection";
+  } else if ( uName.find( "MERGED" )  != std::string::npos   ||  uName.find( "SPLITPHOTON" )  != std::string::npos ) {
+    m_conditionName = "Conditions/Reco/Calo/SplitPhotonLCorrection";
+  } else if (  uName.find( "PHOTON" ) ) {
+    m_conditionName = "Conditions/Reco/Calo/PhotonLCorrection";
+  }
+
+  /// interafces
+  declareInterface<ICaloFutureHypoTool> ( this ) ;
+
+  m_counterPerCaloFutureAreaDeltaZ.reserve(k_numOfCaloFutureAreas);
+  m_counterPerCaloFutureAreaGamma.reserve(k_numOfCaloFutureAreas);
+  m_counterPerCaloFutureAreaDelta.reserve(k_numOfCaloFutureAreas);
+  std::vector<std::string> caloAreas = {"Outer" , "Middle" , "Inner" , "PinArea"};
+  for (auto i = 0; i < k_numOfCaloFutureAreas; i++) {
+    m_counterPerCaloFutureAreaDeltaZ.emplace_back(this, "Delta(Z) " + caloAreas[i]);
+    m_counterPerCaloFutureAreaGamma.emplace_back(this, "<gamma> " + caloAreas[i]);
+    m_counterPerCaloFutureAreaDelta.emplace_back(this, "<delta> " + caloAreas[i]);
+  }
+}
+
+// ============================================================================
+StatusCode CaloFutureLCorrection::finalize   ()
+{
+  m_hypos.clear();
+  return CaloFutureCorrectionBase::finalize () ;
+}
+// ============================================================================
+StatusCode CaloFutureLCorrection::initialize ()
+{
+  /// first initialize the base class
+  StatusCode sc = CaloFutureCorrectionBase::initialize();
+  if ( sc.isFailure() ) {
+    return Error ( "Unable initialize the base class CaloFutureCorrectionBase !" , sc ) ;
+  }
+
+  if ( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+    debug() << "Condition name : " << m_conditionName << endmsg;
+
+  return StatusCode::SUCCESS ;
+}
+
+// ============================================================================
+StatusCode CaloFutureLCorrection::operator() ( LHCb::CaloHypo* hypo  ) const
+{
+  return process( hypo );
+}
+
+// ============================================================================
+StatusCode CaloFutureLCorrection::process    ( LHCb::CaloHypo* hypo  ) const
+{
+
+  // check arguments
+  if ( !hypo ) {
+    return Warning ( " CaloHypo* points to NULL!" , StatusCode::SUCCESS) ;
+  }
+
+  // check the Hypo
+  const auto h = std::find( m_hypos.begin() , m_hypos.end() , hypo->hypothesis() ) ;
+  if ( m_hypos.end() == h )return Error ( "Invalid hypothesis -> no correction applied", StatusCode::SUCCESS ) ;
+
+  // No correction for negative energy :
+  if ( hypo->e() < 0.) {
+    ++m_counterSkipNegativeEnergyCorrection;
+    return StatusCode::SUCCESS;
+  }
+
+
+  // get Prs/Spd
+  double ePrs = 0 ;
+  double eSpd = 0 ;
+  getPrsSpd(hypo, ePrs, eSpd);
+
+
+  // get cluster energy (special case for SplitPhotons)
+  const LHCb::CaloCluster* GlobalCluster = LHCb::CaloFutureAlgUtils::ClusterFromHypo(hypo, false);
+  const LHCb::CaloCluster* MainCluster = LHCb::CaloFutureAlgUtils::ClusterFromHypo(hypo, true) ;
+
+  /*
+    Cluster information (e/x/y  and Prs/Spd digit)
+  */
+  if ( !MainCluster ) {
+    return Error ( "CaloCLuster* points to NULL!" ) ;
+  }
+
+  // For Split Photon - share the Prs energy
+  if (  LHCb::CaloHypo::Hypothesis::PhotonFromMergedPi0 == hypo->hypothesis() ) {
+    ePrs *= MainCluster->position().e() / GlobalCluster->position().e() ;
+  }
+
+
+  const double energy = hypo->e () ;
+
+  const auto& entries = MainCluster->entries();
+  const auto iseed =
+    LHCb::ClusterFunctors::locateDigit ( entries.begin () , entries.end   () , LHCb::CaloDigitStatus::SeedCell );
+  if ( entries.end() == iseed ) {
+    return Error ( "The seed cell is not found !" ) ;
+  }
+
+  // get the "area" of the cluster (where seed is)
+  const LHCb::CaloDigit*   seed    = iseed->digit();
+  if ( !seed ) {
+    return Error ( "Seed digit points to NULL!" ) ;
+  }
+
+  // Cell ID for seed digit
+  const auto cellID = seed->cellID() ;
+
+
+  /** here all information is available
+   *
+   *  (1) Ecal energy in 3x3     :    energy
+   *  (2) Prs and Spd energies   :    ePrs, eSpd
+   *  (3) weighted barycenter    :    xBar, yBar
+   *  (4) Zone/Area in Ecal      :    area
+   *  (5) SEED digit             :    seed
+   *  (6) CellID of seed digit   :    cellID
+   *  (7) Position of seed cell  :    seedPos
+   */
+
+
+  // Account for the tilt
+  const auto plane = m_det->plane(CaloPlane::Front); // Ecal Front-Plane
+  const LHCb::CaloPosition* pos = hypo->position() ;
+
+  const auto xg = pos->x() - m_origin.X();
+  const auto yg = pos->y() - m_origin.Y();
+  const auto normal = plane.Normal();
+  const auto Hesse = plane.HesseDistance();
+  const auto z0 = (-Hesse - normal.X() * pos->x() - normal.Y() * pos->y()) / normal.Z();
+  auto zg = z0 - m_origin.Z();
+
+  // hardcoded inner offset (+7.5 mm)
+  if ( cellID.area() == 2 ) {
+    zg += 7.5;
+  }
+
+  // Uncorrected angle
+  const auto aaa = std::pow(xg, 2) + std::pow(yg, 2);
+  const auto tth = std::sqrt(aaa) / zg ;
+  //double cth = mycos ( myatan2( std::sqrt(aaa) , zg ) ) ;
+  auto cth = zg / std::sqrt( aaa + std::pow(zg, 2) );
+
+  // Corrected angle
+
+  const auto gamma0 = getCorrection(CaloFutureCorrection::gamma0, cellID);
+  const auto delta0 = getCorrection(CaloFutureCorrection::delta0, cellID);
+  const auto gammaP = getCorrection(CaloFutureCorrection::gammaP, cellID, ePrs);
+  const auto deltaP = getCorrection(CaloFutureCorrection::deltaP, cellID, ePrs);
+  const auto g = gamma0 - gammaP;
+  const auto d = delta0 + deltaP;
+
+  //double alpha = Par_Al1[zon] - myexp( Par_Al2[zon] - Par_Al3[zon] * ePrs/Gaudi::Units::MeV );
+  //double beta  = Par_Be1[zon] + myexp( Par_Be2[zon] - Par_Be3[zon] * ePrs/Gaudi::Units::MeV  );
+
+  /// assert(cellID.area()>=0 &&cellID.area()<4);
+  m_counterPerCaloFutureAreaGamma.at(cellID.area()) += g;
+  m_counterPerCaloFutureAreaDelta.at(cellID.area()) += d;
+
+  const auto tgfps = ( energy > 0.0 ? g * mylog(energy / Gaudi::Units::GeV) + d : 0.0 );
+
+  const auto bbb = ( 1. + tgfps * cth / zg );
+  //cth = mycos( myatan2( tth , bbb ) ) ;
+  cth = bbb / std::sqrt( std::pow(tth, 2) + std::pow(bbb, 2) );
+
+  const auto dzfps = cth * tgfps ;
+  /// assert(cellID.area()>=0 &&cellID.area()<4);
+  m_counterPerCaloFutureAreaDeltaZ.at(cellID.area()) += dzfps;
+  m_counterDeltaZ += dzfps;
+
+  /*
+    info() << " ======= Z0  FRONT-PLANE = " << z0 << " " << zg << endmsg;
+    ROOT::Math::Plane3D planeSM = m_det->plane(CaloPlane::ShowerMax); // Ecal Front-Plane
+    info() << " ======= Z0  SHOWERMAX = " << -planeSM.HesseDistance() <<endmsg;
+    ROOT::Math::Plane3D planeM = m_det->plane(CaloPlane::Middle); // Ecal Middle
+    info() << " ======= Z0  MIDDLE = " << -planeM.HesseDistance() <<endmsg;
+  */
+
+
+  // Recompute Z position and fill CaloFuturePosition
+  const auto zCor = z0 + dzfps;
+
+  if ( UNLIKELY( msgLevel(MSG::DEBUG) ) ) {
+    debug() << "Hypothesis :" << hypo->hypothesis() << endmsg;
+    debug() << " ENE  " << hypo->position ()->e() <<  " "
+            << "xg "   << xg <<  " " << "yg "   << yg <<  endmsg;
+    debug() << "zg "   << pos->z() << " "
+            << "z0 "   << z0 <<  " "
+            << "DeltaZ "   << dzfps <<  " "
+            << "zCor "   << zCor
+            << endmsg ;
+  }
+
+  hypo -> position() -> setZ( zCor ) ;
+
+  return StatusCode::SUCCESS ;
+}
+
+// ============================================================================
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureLCorrection.h b/CaloFuture/CaloFutureReco/src/CaloFutureLCorrection.h
new file mode 100644
index 0000000000000000000000000000000000000000..942a2f1b5245fdf8fb70e6ecf9788321c1c35eba
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureLCorrection.h
@@ -0,0 +1,64 @@
+#ifndef CALOFUTURERECO_CALOFUTURELCORRECTION_H
+#define CALOFUTURERECO_CALOFUTURELCORRECTION_H 1
+
+// from STL
+#include <string>
+#include <cmath>
+
+// CaloFuture
+#include "CaloFutureInterfaces/ICaloFutureHypoTool.h"
+#include "CaloFutureCorrectionBase.h"
+#include "CaloDet/DeCalorimeter.h"
+#include "GaudiKernel/Counters.h"
+
+// Gaudi
+#include "GaudiKernel/SystemOfUnits.h"
+
+// Event
+#include "Event/CaloHypo.h"
+
+/** @class CaloFutureLCorrection CaloFutureLCorrection.h
+ *
+ *
+ *  @author Deschamps Olivier
+ *  @date   2003-03-10
+ *  revised 2010
+ */
+
+class CaloFutureLCorrection :
+  public virtual ICaloFutureHypoTool,
+  public CaloFutureCorrectionBase
+{
+public:
+
+
+  StatusCode process    ( LHCb::CaloHypo* hypo  ) const override;
+  StatusCode operator() ( LHCb::CaloHypo* hypo  ) const override;
+
+  StatusCode initialize() override;
+  StatusCode finalize() override;
+
+  /** Standard constructor
+   *  @see GaudiTool
+   *  @see  AlgTool
+   *  @param type tool type (?)
+   *  @param name tool name
+   *  @param parent  tool parent
+   */
+  CaloFutureLCorrection ( const std::string& type,
+                    const std::string& name,
+                    const IInterface*  parent);
+private:
+  using IncCounter =  Gaudi::Accumulators::Counter<>;
+  using SCounter =  Gaudi::Accumulators::StatCounter<float>;
+
+  mutable IncCounter m_counterSkipNegativeEnergyCorrection{this, "Skip negative energy correction"};
+  mutable SCounter m_counterDeltaZ{this, "Delta(Z)"};
+
+  static constexpr int k_numOfCaloFutureAreas{4};
+  mutable std::vector<SCounter> m_counterPerCaloFutureAreaDeltaZ;
+  mutable std::vector<SCounter> m_counterPerCaloFutureAreaGamma;
+  mutable std::vector<SCounter> m_counterPerCaloFutureAreaDelta;
+};
+// ============================================================================
+#endif // CALOFUTURERECO_CALOFUTURELCORRECTION_H
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureMergedPi0.cpp b/CaloFuture/CaloFutureReco/src/CaloFutureMergedPi0.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..add1bd586b798f96f35319619f0ea0cc6eea6adb
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureMergedPi0.cpp
@@ -0,0 +1,338 @@
+// ============================================================================
+// ============================================================================
+#include <numeric>
+#include <algorithm>
+#include <cmath>
+#include "Event/CaloDataFunctor.h"
+#include "CaloDet/DeCalorimeter.h"
+#include "Event/CellID.h"
+#include "Event/CaloHypo.h"
+#include "CaloFutureUtils/CaloFutureAlgUtils.h"
+#include "Kernel/CaloCellID.h"
+#include "GaudiKernel/SystemOfUnits.h"
+#include "CaloFutureMergedPi0.h"
+#include "CaloFutureUtils/CaloMomentum.h"
+// ============================================================================
+/** @file CaloFutureMergedPi0.cpp
+ *
+ *  Implementation file for class : CaloFutureMergedPi0
+ *
+ *  @author Olivier Deschamps
+ *  @date 05/05/2014
+ *
+ *  New implementation of CaloFutureMergedPi0 algorithm
+ *
+ */
+// ============================================================================
+
+DECLARE_COMPONENT( CaloFutureMergedPi0 )
+
+  CaloFutureMergedPi0::CaloFutureMergedPi0( const std::string& name    ,
+                                      ISvcLocator*       svcloc  ): GaudiAlgorithm ( name , svcloc )
+{
+  // following properties are be inherited by the covariance tool
+  declareProperty( "CovarianceParameters" , m_covParams    ) ; // KEEP IT UNSET ! INITIAL VALUE WOULD BYPASS DB ACCESS
+
+  // default context-dependent locations
+  m_clusters  = LHCb::CaloFutureAlgUtils::CaloFutureClusterLocation ( "Ecal"     , context()    );  // input : neutral CaloFutureCluster's
+  m_mergedPi0s = LHCb::CaloFutureAlgUtils::CaloFutureHypoLocation   ("MergedPi0s" , context()   );  // output : mergedPi0 CaloFutureHypo's
+  m_splitPhotons  = LHCb::CaloFutureAlgUtils::CaloFutureHypoLocation("SplitPhotons", context() );  // output : splitPhoton CaloFutureHypo's
+  m_splitClusters = LHCb::CaloFutureAlgUtils::CaloFutureSplitClusterLocation(context()         );  // output : splitCluster CaloFutureClusters
+}
+
+bool CaloFutureMergedPi0::isNeighbor(LHCb::CaloCellID id0 , LHCb::CaloCellID id1){
+  if( id0 == LHCb::CaloCellID() || id1 == LHCb::CaloCellID() )return false;
+  if( abs(int(id0.row()) - int(id1.row()) ) > 1 )return false;
+  if( abs(int(id0.col()) - int(id1.col()) ) > 1 )return false;
+  return true;
+}
+
+// ============================================================================
+
+StatusCode CaloFutureMergedPi0::initialize(){
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) debug()<< "==> Initialise" << endmsg;
+  StatusCode sc = GaudiAlgorithm::initialize();
+  if( sc.isFailure() )return Error("Could not initialize the base class!",sc);
+
+  // Always skip negative-energy clusters :
+  if(m_minET<0.)m_minET=0.;
+
+  if(m_createClusterOnly)info() << "Producing SplitClusters only" << endmsg;
+
+  // get detectorElement
+  m_detector = getDet<DeCalorimeter>( m_det ) ;
+  if( !m_detector ){ return Error("could not locate calorimeter '"+m_det+"'");}
+
+  //==== get tools
+
+  // - main tool :
+  m_oTool=tool<ICaloFutureShowerOverlapTool>("CaloFutureShowerOverlapTool","SplitPhotonShowerOverlap",this);
+
+  // - cluster  tools
+  m_cov     = tool<ICaloFutureClusterTool>      ( "FutureClusterCovarianceMatrixTool" , "EcalCovariance"     , this ) ;
+  m_spread  = tool<ICaloFutureClusterTool>      ( "FutureClusterSpreadTool"           , "EcalSpread"         , this ) ;
+  m_tagger  = tool<FutureSubClusterSelectorTool>( "FutureSubClusterSelectorTool"      , "EcalClusterTag"     , this );
+
+  // - hypo tools
+  for ( std::vector<std::string>::const_iterator it = m_photonTools.begin() ;m_photonTools.end() != it ; ++it ){
+    ICaloFutureHypoTool* t = tool<ICaloFutureHypoTool>( *it , this );
+    if( 0 == t ) { return StatusCode::FAILURE ; }
+    m_gTools.push_back( t ) ;
+  }
+
+  for ( std::vector<std::string>::const_iterator it = m_pi0Tools.begin() ;m_pi0Tools.end() != it ; ++it ){
+    ICaloFutureHypoTool* t = tool<ICaloFutureHypoTool>( *it , this );
+    if( 0 == t ) { return StatusCode::FAILURE ; }
+    m_pTools.push_back( t ) ;
+  }
+  counterStat = tool<IFutureCounterLevel>("FutureCounterLevel");
+  return sc;
+}
+
+StatusCode CaloFutureMergedPi0::finalize(){
+  m_pTools.clear() ;
+  m_gTools.clear() ;
+  return GaudiAlgorithm::finalize();
+}
+
+StatusCode CaloFutureMergedPi0::execute(){
+
+  using namespace  LHCb::CaloDataFunctor;
+  typedef LHCb::CaloClusters Clusters;
+  typedef Clusters::iterator Iterator;
+
+  //======== load input :
+  Clusters* clusters = getIfExists<Clusters>( m_clusters );
+  if( NULL == clusters )return Warning("No cluster input container : no merged Pi0 !", StatusCode::SUCCESS);
+
+
+  //======== create cluster output :
+  //- split clusters (check it does not exist first)
+
+
+  LHCb::CaloClusters* splitclusters = new LHCb::CaloClusters();
+  int level = msgLevel();     // store outputLevel
+  try{
+    setProperty("OutputLevel", MSG::ALWAYS ).ignore();// suppress FATAL message
+    put(splitclusters, m_splitClusters );
+  } catch(GaudiException &exc ) {
+    setProperty("OutputLevel", level ).ignore();      // reset outputLevel before issuing a warning...
+    Warning("Existing SplitCluster container at "+ m_splitClusters + " found -> will replace",StatusCode::SUCCESS,1).ignore();
+    delete splitclusters;
+    splitclusters=get<LHCb::CaloClusters>( m_splitClusters );
+    splitclusters->clear();
+  }
+  setProperty("OutputLevel", level ).ignore();
+
+
+  //- pi0s & SPlitPhotons
+  LHCb::CaloHypos* pi0s = new LHCb::CaloHypos();
+  LHCb::CaloHypos* phots = new LHCb::CaloHypos();
+
+  // put on TES when requested
+  if(!m_createClusterOnly){
+    put( pi0s , m_mergedPi0s );
+    put( phots , m_splitPhotons);
+  }
+
+
+  //- load SPD container :
+  LHCb::CaloDigits* spds = getIfExists<LHCb::CaloDigits>( LHCb::CaloDigitLocation::Spd );
+
+  // - setup the estimator of cluster transverse energy
+  LHCb::CaloDataFunctor::EnergyTransverse<const DeCalorimeter*> eT ( m_detector ) ;
+
+    // define entry status'
+
+  LHCb::CaloDigitStatus::Status used   =
+    LHCb::CaloDigitStatus::UseForEnergy  |
+    LHCb::CaloDigitStatus::UseForPosition |
+    LHCb::CaloDigitStatus::UseForCovariance  ;
+  LHCb::CaloDigitStatus::Status seed   = LHCb::CaloDigitStatus::SeedCell |
+    LHCb::CaloDigitStatus::LocalMaximum | used ;
+
+  // ============ loop over all clusters ==============
+  for( Iterator icluster = clusters->begin() ; clusters->end() != icluster ; ++icluster ){
+    LHCb::CaloCluster* cluster = *icluster ;
+    if( 0 == cluster )                { continue ; }
+    if ( 0 < m_etCut &&  m_etCut > eT( cluster ) ) { continue ; }
+
+    // -- remove small clusters :
+    if( 1 >=  cluster->entries().size() )continue;
+
+    // -- locate cluster Seed
+    const LHCb::CaloCluster::Digits::iterator iSeed =
+      clusterLocateDigit( cluster->entries().begin() , cluster->entries().end  () , LHCb::CaloDigitStatus::SeedCell     );
+    LHCb::CaloDigit* dig1 = iSeed->digit() ;
+    if( 0 == dig1) continue ;
+    LHCb::CaloCellID  seed1 = dig1->cellID() ;
+
+    double seede  = dig1->e();
+
+    // -- get spd hit in front of seed1
+    int spd1 = 0 ;
+    const LHCb::CaloDigit* spddigit1 = (spds == NULL) ? NULL : spds->object( dig1->key() );
+    if( NULL != spddigit1 )spd1 = (spddigit1->e() > 0.) ? 1 : 0 ;
+
+    // -- locate seed2
+    double sube   = 0. ; // 2nd seed should must have a positive energy !
+    LHCb::CaloDigit*  dig2  = nullptr;
+    for( LHCb::CaloCluster::Digits::iterator it =cluster->entries().begin() ; cluster->entries().end() != it ; ++it ){
+      LHCb::CaloDigit* dig = it->digit() ;
+      if( !dig ) { continue ; }
+      LHCb::CaloCellID seed  = dig->cellID() ;
+      double ecel = dig->e()*it->fraction();
+      if (ecel > sube && ecel < seede && isNeighbor( seed1, seed) && !(seed==seed1)){
+        //if (ecel > sube && ecel < seede && isNeighbor( seed1, seed) ){
+        sube=ecel;
+        dig2=dig;
+      }
+    }
+
+    if ( !dig2 ){
+      if(counterStat->isQuiet())counter("Cluster without 2nd seed found") += 1;
+      continue ;
+    }
+
+    LHCb::CaloCellID  seed2 = dig2->cellID() ;
+    // -- get spd hit in front of seed2
+    const LHCb::CaloDigit* spddigit2 = ( spds  ? spds->object( dig2->key() ) : nullptr );
+    int spd2 = 0 ;
+    if( spddigit2 ) { spd2 = (spddigit2->e() > 0.) ? 1 : 0 ; }
+
+
+    // -- create and fill sub-cluster
+    auto cl1 = std::make_unique<LHCb::CaloCluster>();
+    cl1->setSeed( seed1 );
+    cl1->setType( LHCb::CaloCluster::Type::Area3x3 );
+    auto cl2 = std::make_unique<LHCb::CaloCluster>();
+    cl2->setSeed( seed2 );
+    cl2->setType( LHCb::CaloCluster::Type::Area3x3 );
+
+    for( const auto& it2 : cluster->entries() ) {
+      const LHCb::CaloDigit* dig = it2.digit() ;
+      if( !dig ) continue ;
+      const LHCb::CaloCellID  id = dig->cellID() ;
+      double fraction = it2.fraction();
+
+      // -- tag 3x3 area for energy and position
+      if ( isNeighbor( seed1, id ) ){
+        LHCb::CaloDigitStatus::Status status = ( seed1 == id ) ? seed : used;
+        // set initial weights
+        double weight1 = fraction;
+        if( seed2 == id )weight1=0.;
+        else if( seed1 == id )weight1=fraction;
+        else if (isNeighbor(seed2,id)) weight1=dig1->e() / (dig1->e() + dig2->e())*fraction;
+        cl1->entries().emplace_back( dig , status, weight1 );
+      }
+      if ( isNeighbor( seed2, id ) ){
+        LHCb::CaloDigitStatus::Status status = ( seed2 == id ) ? seed : used;
+        //set initial weights
+        double weight2 = fraction;
+        if( seed1 == id )weight2=0.;
+        else if(seed2 == id)weight2=fraction;
+        else if (isNeighbor(seed1,id))weight2=dig2->e() / (dig1->e() + dig2->e())*fraction;
+        cl2->entries().emplace_back( dig , status,weight2 );
+      }
+    }
+
+
+    // --  apply position tagger (possibly replacing the 3x3 already set)
+    // --  needed to apply hypo S/L-corrections with correct parameters internally
+    // --  keep the 3x3 energy tag for the time being (to be applied after the overlap subtraction)
+    StatusCode sc;
+    sc = m_tagger->tagPosition(  cl1.get()  ) ;
+    sc = m_tagger->tagPosition(  cl2.get()  ) ;
+    if( sc.isFailure() )Warning("SplitCluster tagging failed - keep the initial 3x3 tagging").ignore();
+
+    // == apply the mergedPi0 tool : subtract shower overlap
+    m_oTool->process(cl1.get(),cl2.get(), spd1*10+spd2, m_iter,true); // 'true' means the initial entries weight is propagated
+    if( LHCb::CaloMomentum(cl1.get()).pt() <= m_minET || LHCb::CaloMomentum(cl2.get()).pt() <= m_minET ){ // skip negative energy "clusters"
+      continue;
+    }
+
+    // == prepare outputs :
+
+    // apply loose mass window : (TODO ??)
+
+    // == APPLY CLUSTER TOOLS : Energy tagger,  covariance & spread (position tagger already applied):
+      if  (m_tagger  -> tagEnergy    ( cl1.get() ).isFailure()  )if (counterStat->isQuiet() )counter("Fails to tag(E) cluster (1)")+=1;
+      if  (m_tagger  -> tagEnergy    ( cl2.get() ).isFailure()  )if (counterStat->isQuiet() )counter("Fails to tag(E) cluster (2)")+=1;
+      if  (m_cov   -> process( cl1.get() ).isFailure()  )if (counterStat->isQuiet() )counter("Fails to set covariance (1)")+=1;
+      if  (m_cov   -> process( cl2.get() ).isFailure()  )if (counterStat->isQuiet() )counter("Fails to set covariance (2)")+=1;
+      if  (m_spread-> process( cl1.get() ).isFailure()  )if (counterStat->isQuiet() )counter("Fails to set spread (1)")    +=1;
+      if  (m_spread-> process( cl2 .get()).isFailure()  )if (counterStat->isQuiet() )counter("Fails to set spread (2)")    +=1;
+
+    // == insert splitClusters into their container
+    auto clu1 = cl1.get(); splitclusters->insert( cl1.release() ) ;
+    auto clu2 = cl2.get(); splitclusters->insert( cl2.release() ) ;
+    // == create CaloHypos if needed
+    if (!m_createClusterOnly) {
+      // new CaloHypos for splitPhotons
+      auto g1   = std::make_unique<LHCb::CaloHypo>() ;
+      g1 -> setHypothesis( LHCb::CaloHypo::Hypothesis::PhotonFromMergedPi0 ) ;
+      g1 -> addToClusters( cluster )                ;
+      g1 -> addToClusters( clu1    )                ;
+      g1 -> setPosition( std::make_unique< LHCb::CaloPosition>( clu1->position()) );
+
+      auto g2   = std::make_unique<LHCb::CaloHypo>() ;
+      g2 -> setHypothesis( LHCb::CaloHypo::Hypothesis::PhotonFromMergedPi0 ) ;
+      g2 -> addToClusters( cluster )                ;
+      g2 -> addToClusters( clu2    )                ;
+      g2 -> setPosition( std::make_unique<LHCb::CaloPosition>( clu2->position() ) );
+
+      // new CaloHypo for mergedPi0
+      auto pi0 = std::make_unique<LHCb::CaloHypo>();
+      pi0 -> setHypothesis( LHCb::CaloHypo::Hypothesis::Pi0Merged ) ;
+      pi0 -> addToClusters( cluster );
+      pi0 -> addToHypos ( g2.get() );
+      pi0 -> addToHypos ( g1.get() );
+
+      //--  Apply hypo tools : E/S/L-corrections
+      int i = 0;
+      for( ICaloFutureHypoTool* t : m_gTools ) {
+        i++;
+        if( UNLIKELY( msgLevel(MSG::DEBUG) ) )debug() << " apply SplitPhoton tool " << i << "/" << m_gTools.size() << endmsg;
+        if( !t )  continue;
+        auto sc = (*t) ( g1.get() ) ;
+        if( sc.isFailure() ) Error("Error from 'Tool' for g1 " , sc ).ignore() ;
+        sc      = (*t) ( g2.get() ) ;
+        if( sc.isFailure() )Error("Error from 'Tool' for g2 " , sc ).ignore() ;
+      }
+
+      i = 0;
+      for( ICaloFutureHypoTool* t : m_pTools ) {
+        i++;
+        if( UNLIKELY( msgLevel(MSG::DEBUG) ) )debug() << " apply MergedPi0 tool " << i << "/" << m_pTools.size() << endmsg;
+        if( !t ) { continue; }
+        auto sc = (*t) ( pi0.get() ) ;
+        if( sc.isFailure() )Error("Error from 'Tool' for pi0 " , sc ).ignore() ;
+      }
+
+
+      // skip negative energy CaloHypos
+      if( LHCb::CaloMomentum(g1.get()).pt() >= m_minET && LHCb::CaloMomentum(g2.get()).pt() >= m_minET ){
+        if ( m_verbose ) info() << " >> MergedPi0 hypo Mass : "  << LHCb::CaloMomentum(pi0.get()).mass() << endmsg;
+        phots ->insert( g1.release()  ) ;
+        phots ->insert( g2.release()  ) ;
+        pi0s -> insert( pi0.release() ) ;
+      }
+    }
+  }
+
+  // ====================== //
+  if(counterStat->isQuiet()&&!m_createClusterOnly)counter ( m_clusters + "=>" + m_mergedPi0s )   += pi0s   -> size() ;
+  if(counterStat->isQuiet()&&!m_createClusterOnly)counter ( m_clusters + "=>" + m_splitPhotons)  += phots  -> size() ;
+  if(counterStat->isQuiet())counter ( m_clusters + "=>" + m_splitClusters) += splitclusters -> size() ;
+
+  // delete (empty) container* if not on TES
+  StatusCode sc = StatusCode::SUCCESS;
+  if(m_createClusterOnly){
+    if( 0 != pi0s->size() || 0 != phots->size() ){
+      sc = Error( "Container* to be deleted are not empty", StatusCode::FAILURE);
+    }
+    delete pi0s;
+    delete phots;
+  }
+  return sc;
+}
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureMergedPi0.h b/CaloFuture/CaloFutureReco/src/CaloFutureMergedPi0.h
new file mode 100644
index 0000000000000000000000000000000000000000..6a1c95c391e62d527d1548e80df2963a8972cede
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureMergedPi0.h
@@ -0,0 +1,74 @@
+// ============================================================================
+#ifndef CALOFUTURERECO_CALOFUTUREMERGEDPI0_H
+#define CALOFUTURERECO_CALOFUTUREMERGEDPI0_H 1
+// ============================================================================
+// Include files
+// ============================================================================
+// from STL
+// ============================================================================
+#include <string>
+#include <vector>
+// ============================================================================
+#include "GaudiAlg/GaudiAlgorithm.h"
+#include "CaloFutureInterfaces/ICaloFutureClusterTool.h"
+#include "FutureSubClusterSelectorTool.h"
+#include "CaloFutureInterfaces/ICaloFutureHypoTool.h"
+#include "CaloFutureInterfaces/ICaloFutureShowerOverlapTool.h"
+#include "CaloFutureInterfaces/IFutureCounterLevel.h"
+#include "CaloDet/DeCalorimeter.h"
+#include "Event/CaloCluster.h"
+// ============================================================================
+
+/** @class CaloFutureMergedPi0 CaloFutureMergedPi0.h
+ *
+ *  Merged pi0 reconstruction with iterativ Method
+ *
+ * NEW IMPLEMENTATION
+ *
+ *  @author Olivier Deschamps
+ *  @date   05/05/2014
+ */
+
+class CaloFutureMergedPi0 : public GaudiAlgorithm{
+public:
+
+  CaloFutureMergedPi0( const std::string& name   , ISvcLocator*       svcloc );
+
+  StatusCode initialize() override;
+  StatusCode execute() override;
+  StatusCode finalize() override;
+
+private:
+  bool isNeighbor(LHCb::CaloCellID id0, LHCb::CaloCellID id1);
+
+  Gaudi::Property<std::string> m_clusters      {this, "InputData"    , LHCb::CaloClusterLocation::Ecal};
+  Gaudi::Property<std::string> m_splitClusters {this, "SplitClusters", LHCb::CaloClusterLocation::EcalSplit};
+  Gaudi::Property<std::string> m_mergedPi0s    {this, "MergedPi0s"   , LHCb::CaloHypoLocation::MergedPi0s};
+  Gaudi::Property<std::string> m_splitPhotons  {this, "SplitPhotons" , LHCb::CaloHypoLocation::SplitPhotons};
+
+  Gaudi::Property<float>  m_etCut {this, "EtCut", 1500 * Gaudi::Units::MeV};
+  Gaudi::Property<int>    m_iter {this, "MaxIterations", 25};
+  Gaudi::Property<bool>   m_createClusterOnly {this, "CreateSplitClustersOnly", false};
+
+  // tools name
+  Gaudi::Property<std::vector<std::string>> m_photonTools {this, "PhotonTools"};
+  Gaudi::Property<std::vector<std::string>> m_pi0Tools    {this, "Pi0Tools"};
+
+  // tools interfaces
+  std::vector<ICaloFutureHypoTool*>  m_gTools ;
+  std::vector<ICaloFutureHypoTool*>  m_pTools ;
+  ICaloFutureShowerOverlapTool* m_oTool  = nullptr ;
+  ICaloFutureClusterTool*       m_cov    = nullptr ;
+  ICaloFutureClusterTool*       m_spread = nullptr ;
+  FutureSubClusterSelectorTool* m_tagger = nullptr ;
+  Gaudi::Property<std::vector<std::string>> m_taggerE {this, "EnergyTags"};
+  Gaudi::Property<std::vector<std::string>> m_taggerP {this, "PositionTags"};
+  Gaudi::Property<std::string> m_det {this, "Detector", DeCalorimeterLocation::Ecal};
+  DeCalorimeter* m_detector = nullptr ;
+  Gaudi::Property<bool> m_verbose {this, "Verbose", false};
+  Gaudi::Property<float> m_minET {this, "SplitPhotonMinET", 0.};
+  std::map<std::string,std::vector<double> > m_covParams;
+  IFutureCounterLevel* counterStat = nullptr;
+};
+// ============================================================================
+#endif // CALOFUTUREMERGEDPI0_H
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureSCorrection.cpp b/CaloFuture/CaloFutureReco/src/CaloFutureSCorrection.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..948cd5efe0cdc801bcecde3acad945e3499e6e7b
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureSCorrection.cpp
@@ -0,0 +1,448 @@
+// ============================================================================
+// Include files
+#include "GaudiKernel/SystemOfUnits.h"
+#include "Event/CaloHypo.h"
+#include "CaloFutureSCorrection.h"
+
+/** @file 
+ *  Implementation file for class : CaloFutureSCorrection
+ *  
+ *  @date 2003-03-10 
+ *  @author Xxxx XXXXX xxx@xxx.com 
+ */
+
+DECLARE_COMPONENT( CaloFutureSCorrection )
+
+// ============================================================================
+/** Standard constructor
+ *  @see GaudiTool 
+ *  @see  AlgTool 
+ *  @param type tool type (?)
+ *  @param name tool name 
+ *  @param parent  tool parent 
+ */
+// ============================================================================
+CaloFutureSCorrection::CaloFutureSCorrection( const std::string& type   , 
+                                  const std::string& name   ,
+                                  const IInterface*  parent ) 
+  : CaloFutureCorrectionBase( type , name , parent ){
+
+
+  // define conditionName
+  const std::string uName ( LHCb::CaloFutureAlgUtils::toUpper( name ) ) ;
+  if( uName.find( "ELECTRON" ) != std::string::npos  ){
+    m_conditionName = "Conditions/Reco/Calo/ElectronSCorrection";
+  }else if ( uName.find( "MERGED" )  != std::string::npos   ||  uName.find( "SPLITPHOTON" )  != std::string::npos ){
+    m_conditionName = "Conditions/Reco/Calo/SplitPhotonSCorrection";
+  }  
+  else if (  uName.find( "PHOTON" ) ){
+    m_conditionName = "Conditions/Reco/Calo/PhotonSCorrection"; 
+  }  
+  declareInterface<ICaloFutureHypoTool> ( this ) ;
+}
+// ============================================================================
+
+StatusCode CaloFutureSCorrection::finalize() 
+{
+  m_hypos.clear();
+  // finalize the base class 
+  return CaloFutureCorrectionBase::finalize () ;
+}
+// ============================================================================
+
+StatusCode CaloFutureSCorrection::initialize (){
+  // first initialize the base class 
+  StatusCode sc = CaloFutureCorrectionBase::initialize();
+  if( sc.isFailure() ) 
+    { return Error ( "Unable initialize the base class CaloFutureCorrectionBase!" , sc ) ; }  
+  if (UNLIKELY( msgLevel( MSG::DEBUG)) )
+    debug() << "Condition name : " << m_conditionName << endmsg;
+
+  return StatusCode::SUCCESS ;
+}
+// ============================================================================
+
+StatusCode CaloFutureSCorrection::operator() ( LHCb::CaloHypo* hypo  ) const{ 
+return process( hypo ); 
+}
+// ============================================================================
+
+// ============================================================================
+StatusCode CaloFutureSCorrection::process    ( LHCb::CaloHypo* hypo  ) const{
+
+  // check arguments 
+  if( 0 == hypo )return Warning( " CaloHypo* points to NULL!",StatusCode::SUCCESS ) ; 
+
+
+  // check the Hypo
+  Hypotheses::const_iterator h = 
+    std::find( m_hypos.begin() , m_hypos.end() , hypo->hypothesis() ) ;
+  if( m_hypos.end() == h )return Error ( "Invalid hypothesis!",StatusCode::SUCCESS ) ;  
+
+  // No correction for negative energy :
+  if( hypo->e() < 0.){
+    ++m_counterSkipNegativeEnergyCorrection;
+    return StatusCode::SUCCESS;
+  }
+
+  // get cluster  (special case for SplitPhotons)
+  // const LHCb::CaloCluster* GlobalCluster = LHCb::CaloFutureAlgUtils::ClusterFromHypo(hypo, false); // not used
+  const LHCb::CaloCluster* MainCluster = LHCb::CaloFutureAlgUtils::ClusterFromHypo(hypo,true) ;
+
+
+  /*
+    Cluster information (e/x/y  and Prs/Spd digit)
+  */
+  if( 0 == MainCluster )return Warning ( "CaloCLuster* points to NULL -> no correction applied" , StatusCode::SUCCESS) ;
+
+  // ePrs, eSpd currently not used here
+  //
+  // // get Prs/Spd
+  // double ePrs = 0 ;
+  // double eSpd = 0 ;
+  // getPrsSpd(hypo,ePrs,eSpd);
+  // // For Split Photon - share the Prs energy
+  // if(  LHCb::CaloHypo::Hypothesis::PhotonFromMergedPi0 == hypo->hypothesis() ){
+  //   ePrs *= MainCluster->position().e()/GlobalCluster->position().e() ;
+  // }
+
+  // Get position
+  const LHCb::CaloPosition& position = MainCluster->position();
+  const double xBar  = position. x () ;
+  const double yBar  = position. y () ;
+
+
+  //  Informations from seed Digit Seed ID & position
+  const LHCb::CaloCluster::Entries& entries = MainCluster->entries();
+  LHCb::CaloCluster::Entries::const_iterator iseed =
+    LHCb::ClusterFunctors::locateDigit ( entries.begin () ,entries.end   () ,LHCb::CaloDigitStatus::SeedCell );
+  if( entries.end() == iseed )return Warning( "The seed cell is not found -> no correction applied",StatusCode::SUCCESS ) ; 
+
+  // get the "area" of the cluster (where seed is) 
+  const LHCb::CaloDigit*  seed    = iseed->digit();
+  if( 0 == seed )return Warning ( "Seed digit points to NULL -> no correction applied",StatusCode::SUCCESS ) ;
+
+  // int area = cellID.area(); // currently not used
+ 
+ 
+
+  // Somewhat inelegant way of data sharing between this const method process() and calcSCorrection(). Use of private fields
+  // of this CaloFutureSCorrection class for the same purpose would break the constness of the process() interface.
+  struct SCorrInputParams  params;           // input parameters: currently only cellID, seedPos and MainCluster->position.z
+  struct SCorrOutputParams results = {0, 0}; // output parameters: just d(Xhypo)/d(Xcluster) and d(Yhypo)/d(Ycluster)
+
+  // Cell ID for seed digit 
+  params.cellID  = seed->cellID() ;
+  params.seedPos = m_det->cellCenter( params.cellID  );
+  params.z       = position. z () ;
+  
+  /** here all information is available 
+   *     
+   *  (1) Ecal energy in 3x3     :    eEcal       ( not used )
+   *  (2) Prs and Spd energies   :    ePrs, eSpd  ( not used )
+   *  (3) weighted barycenter    :    xBar, yBar 
+   *  (4) Zone/Area in Ecal      :    area        ( not used )  
+   *  (5) SEED digit             :    seed   (NOT FOR SPLITPHOTONS !!)
+   *  (6) CellID of seed digit   :    cellID
+   *  (7) Position of seed cell  :    seedPos 
+   */
+
+
+  double xCor, yCor; // corrected hypo position
+  double xCor_x, xCor_y, yCor_x, yCor_y;
+
+
+  calcSCorrection(xBar, yBar, xCor, yCor, params, &results);
+
+  const double &dXhy_dXcl = results.dXhy_dXcl;
+  const double &dYhy_dYcl = results.dYhy_dYcl;
+
+  // protection against unphysical d(Xhypo)/d(Xcluster) == 0 or d(Yhypo)/d(Ycluster) == 0
+  if ( fabs( dXhy_dXcl ) < 1e-10 ){
+    warning() << "unphysical d(Xhypo)/d(Xcluster) = " << dXhy_dXcl << " reset to 1 as if Xhypo = Xcluster" << endmsg;
+    const_cast<double &>( dXhy_dXcl ) = 1.;
+  }
+  if ( fabs( dYhy_dYcl ) < 1e-10 ){
+    warning() << "unphysical d(Yhypo)/d(Ycluster) = " << dYhy_dYcl << " reset to 1 as if Yhypo = Ycluster" << endmsg;
+    const_cast<double &>( dYhy_dYcl ) = 1.;
+  }
+
+
+  // numeric partial derivatives w.r.t. X and Y, necessary to check after any change to the S-corrections
+  if ( UNLIKELY(msgLevel(MSG::DEBUG)) && m_correctCovariance ){  
+    const double dx_rel(1.e-5); // dx ~ 0.1 mm for numeric derivative calculation
+
+    debug() << " ---------- calculation of numeric derivative dXhypo/dXcluster follows -----------" << endmsg;
+    calcSCorrection(xBar*(1+dx_rel), yBar,            xCor_x, yCor_x, params, NULL);
+
+    debug() << " ---------- calculation of numeric derivative dYhypo/dYcluster follows -----------" << endmsg;
+    calcSCorrection(xBar,            yBar*(1+dx_rel), xCor_y, yCor_y, params, NULL);
+
+    const double dn_xCor_dx = (xCor_x-xCor)/xBar/dx_rel;
+    const double dn_yCor_dx = (yCor_x-yCor)/xBar/dx_rel; // sanity test, should be 0
+    const double dn_xCor_dy = (xCor_y-xCor)/yBar/dx_rel; // sanity test, should be 0
+    const double dn_yCor_dy = (yCor_y-yCor)/yBar/dx_rel;
+
+
+    if ( fabs((dXhy_dXcl-dn_xCor_dx)/dXhy_dXcl) > 0.02 || fabs((dYhy_dYcl-dn_yCor_dy)/dYhy_dYcl) > 0.02 
+         || fabs( dn_yCor_dx ) > 1e-8 || fabs( dn_xCor_dy ) > 1e-7 )
+      debug() << " SCorrection numerically-caluclated Jacobian differs (by > 2%) from analytically-calculated one" << endmsg;
+
+    debug() << "================== Jacobian elements ============= " << endmsg;
+    debug() << "  semi-analytic dXhy_dXcl = " << dXhy_dXcl << " numeric dn_xCor_dx = " << dn_xCor_dx << " dn_xCor_dy = " << dn_xCor_dy << endmsg;
+    debug() << "  semi-analytic dYhy_dYcl = " << dYhy_dYcl << " numeric dn_yCor_dy = " << dn_yCor_dy << " dn_yCor_dx = " << dn_yCor_dx << endmsg;
+  }
+
+  const LHCb::CaloPosition* pos = hypo->position() ;
+
+  if (UNLIKELY( msgLevel( MSG::DEBUG)) ){  
+    debug() << "Calo Hypothesis :" << hypo->hypothesis() << endmsg;
+    debug() << "cellID          : " << params.cellID << endmsg;
+    debug() << "Hypo E :  " << hypo->position ()->e()   <<  " "  << params.cellID << endmsg;
+    debug() << "xBar/yBar " << xBar  <<  "/" << yBar   <<  endmsg;
+    debug() << "xg/yg  "      << pos->x() << "/" << pos->y() <<  endmsg;
+    debug() << "xNew/yNew "   << xCor <<  "/" << yCor    <<  endmsg;
+    debug() << "xcel/ycel "   << params.seedPos.x() <<  "/" << params.seedPos.y() << endmsg ;
+  }
+  
+  // update position
+  LHCb::CaloPosition::Parameters& parameters = hypo ->position() ->parameters () ;
+  parameters ( LHCb::CaloPosition::Index::X ) = xCor ;
+  parameters ( LHCb::CaloPosition::Index::Y ) = yCor ;
+  m_counterDeltaX += xCor-xBar;
+  m_counterDeltaY += yCor-yBar;
+
+  // update cov.m.: error propagation due to the S-correction
+  if ( m_correctCovariance ){
+    LHCb::CaloPosition::Covariance& covariance = hypo ->position() ->covariance () ;
+
+    if ( UNLIKELY(msgLevel( MSG::DEBUG)) ){
+      debug() << "before s-cor cov.m. = \n" << covariance << endmsg;
+    }
+
+    // cov.m packing in double array[5] following ROOT::Math::SMatrix<double,3,3>::Array()
+    // for row/column indices (X:0, Y:1, E:2), see comments in CaloFutureECorrection::process()
+    double c1[6];
+
+    c1[0] = covariance(LHCb::CaloPosition::Index::X, LHCb::CaloPosition::Index::X); // arr[0] not relying on LHCb::CaloPosition::Index::X == 0
+    c1[2] = covariance(LHCb::CaloPosition::Index::Y, LHCb::CaloPosition::Index::Y); // arr[2] not relying on LHCb::CaloPosition::Index::Y == 1
+    c1[5] = covariance(LHCb::CaloPosition::Index::E, LHCb::CaloPosition::Index::E); // arr[5] not relying on LHCb::CaloPosition::Index::E == 2
+    c1[1] = covariance(LHCb::CaloPosition::Index::X, LHCb::CaloPosition::Index::Y); // arr[1]
+    c1[3] = covariance(LHCb::CaloPosition::Index::X, LHCb::CaloPosition::Index::E); // arr[3]
+    c1[4] = covariance(LHCb::CaloPosition::Index::Y, LHCb::CaloPosition::Index::E); // arr[4]
+
+    // cov1 = (J * cov0 * J^T) for the special case of diagonal Jacobian for (X,Y,E) -> (X1=X1(X), Y1=Y1(Y), E1=E)
+    c1[0] *= dXhy_dXcl * dXhy_dXcl;
+    c1[1] *= dXhy_dXcl * dYhy_dYcl;
+    c1[2] *= dYhy_dYcl * dYhy_dYcl;
+    c1[3] *= dXhy_dXcl;
+    c1[4] *= dYhy_dYcl;
+    // c1[5] remains unchanged (energy is not chaged by S-correction)
+
+
+    // alternatively, a code fragment for a general-form Jacobian (cf. a similar comment in CaloFutureECorrection::process())
+    // TMatrixD jac(3, 3); // just a diagonal Jacobian in case of (X,Y,E) -> (X1(X), Y1(Y), E) transformation
+    // jac(0,0) = dXhy_dXcl;
+    // jac(1,1) = dYhy_dYcl;
+    // jac(2,2) = 1.;
+    // if ( msgLevel( MSG::DEBUG) ){ debug() << "s-cor jacobian = " << endmsg; jac.Print(); }
+    // TMarixDSym cov0(3) = ...          // to be initilized from hypo->position()->covariance()
+    // TMarixDSym cov1(3);               // resulting extrapolated cov.m.
+    // recalculate_cov(jac, cov0, cov1); // calculate:  cov1 = (J * cov0 * J^T)
+
+
+    // finally update CaloHypo::position()->covariance()
+    covariance(LHCb::CaloPosition::Index::X, LHCb::CaloPosition::Index::X) = c1[0]; // cov1(0,0);
+    covariance(LHCb::CaloPosition::Index::Y, LHCb::CaloPosition::Index::Y) = c1[2]; // cov1(1,1);
+    covariance(LHCb::CaloPosition::Index::E, LHCb::CaloPosition::Index::E) = c1[5]; // cov1(2,2);
+    covariance(LHCb::CaloPosition::Index::X, LHCb::CaloPosition::Index::Y) = c1[1]; // cov1(0,1);
+    covariance(LHCb::CaloPosition::Index::X, LHCb::CaloPosition::Index::E) = c1[3]; // cov1(0,2);
+    covariance(LHCb::CaloPosition::Index::Y, LHCb::CaloPosition::Index::E) = c1[4]; // cov1(1,2);
+
+    // // DG: my little paranoia, should be always ok since Covariance is SMatrix<3,3,double> internally represented as double array[5]
+    // assert( covariance(LHCb::CaloFuturePosition::Index::X, LHCb::CaloFuturePosition::Index::Y) == covariance(LHCb::CaloFuturePosition::Index::Y, LHCb::CaloFuturePosition::Index::X));
+    // assert( covariance(LHCb::CaloFuturePosition::Index::X, LHCb::CaloFuturePosition::Index::E) == covariance(LHCb::CaloFuturePosition::Index::E, LHCb::CaloFuturePosition::Index::X));
+    // assert( covariance(LHCb::CaloFuturePosition::Index::Y, LHCb::CaloFuturePosition::Index::E) == covariance(LHCb::CaloFuturePosition::Index::E, LHCb::CaloFuturePosition::Index::Y));
+
+    if ( UNLIKELY(msgLevel( MSG::DEBUG)) ){
+      debug() << "after s-cor cov.m. = \n" << covariance << endmsg;
+    }
+  }
+
+
+  return StatusCode::SUCCESS ;
+
+}
+// ============================================================================
+
+void CaloFutureSCorrection::calcSCorrection( double  xBar, double  yBar, double &xCor, double &yCor,
+                                       const struct SCorrInputParams                  &params,
+                                       struct SCorrOutputParams                      *results ) const
+{
+  // declare local short aliases for the input variables passed from process() to calcSCorrection()
+  const LHCb::CaloCellID &cellID  = params.cellID;
+  const Gaudi::XYZPoint  &seedPos = params.seedPos;
+  const double           &z       = params.z;
+
+
+  double CellSize =  m_det->cellSize( cellID  );
+  double Asx   = - ( xBar - seedPos.x() ) / CellSize ;
+  double Asy   = - ( yBar - seedPos.y() ) / CellSize ;
+
+  // cash intermediate values
+  const double Asx0 = Asx;
+  const double Asy0 = Asy;
+
+
+  // Sshape correction :
+  Asx = getCorrection(CaloFutureCorrection::shapeX , cellID , Asx , Asx ); // Asx1 
+  Asy = getCorrection(CaloFutureCorrection::shapeY , cellID , Asy , Asy ); // Asy1
+
+  // // cash intermediate values: necessary for debugging by calculating numeric derivatives dn_shapeX, dn_shapeY below
+  // const double Asx1 = Asx;
+  // const double Asy1 = Asy;
+
+
+  // Angular correction (if any) [ NEW  - inserted between Sshape and residual correction ]
+  const double xs = seedPos.x() - Asx * CellSize; // xscor
+  const double ys = seedPos.y() - Asy * CellSize; // yscor
+  const double thx = myatan2( xs , z );
+  const double thy = myatan2( ys , z );
+  const double daX = getCorrection(CaloFutureCorrection::angularX   , cellID , thx , 0.);
+  const double daY = getCorrection(CaloFutureCorrection::angularY   , cellID , thy , 0.);
+  Asx -= daX;
+  Asy -= daY;
+
+  // cash intermediate values
+  const double Asx2 = Asx;
+  const double Asy2 = Asy;
+
+
+  // residual correction (if any):
+  bool residualX_flag = false;
+  double dcX = getCorrection(CaloFutureCorrection::residual  , cellID , Asx , 0.);
+  if( dcX == 0.){
+    dcX = getCorrection(CaloFutureCorrection::residualX  , cellID , Asx , 0.); // check X-specific correction
+    residualX_flag = true;
+  }
+  bool residualY_flag = false;
+  double dcY = getCorrection(CaloFutureCorrection::residual  , cellID , Asy , 0.);
+  if( dcY == 0.){
+    dcY = getCorrection(CaloFutureCorrection::residualY  , cellID , Asy , 0.); // check Y-specific correction
+    residualY_flag = true;
+  }
+  Asx -= dcX;
+  Asy -= dcY;
+
+  // cash intermediate values
+  const double Asx3 = Asx;
+  const double Asy3 = Asy;
+
+
+  // left/right - up/down asymmetries correction (if any) :
+  double ddcX = (xBar < 0 ) ? 
+    getCorrection(CaloFutureCorrection::asymM , cellID , Asx , 0.): 
+    getCorrection(CaloFutureCorrection::asymP , cellID , Asx , 0.);
+  double ddcY = (yBar < 0 ) ?
+    getCorrection(CaloFutureCorrection::asymM , cellID , Asy , 0.):
+    getCorrection(CaloFutureCorrection::asymP , cellID , Asy , 0.);
+  Asx += ddcX;  // Asx4
+  Asy += ddcY;  // Asy4
+
+
+  // Recompute position and fill CaloFuturePosition
+  xCor = seedPos.x() - Asx * CellSize;
+  yCor = seedPos.y() - Asy * CellSize;
+
+
+
+/* DG,20140714: derivative calculation for  d(Xhypo)/d(Xcluster)
+ *
+ * Asx0 =-(xBar - seedPos.x)/CellSize; // xBar = Xcluster
+ * Asx1 = shapeX(Asx0)
+ * xs   = seedPos.x - Asx1*CellSize
+ * thx  = atan(xs/z); // in principle, this brings in an implicit dependence on cluster E, but it's logarithmic so let's neglect it
+ * daX  = angular(thx)
+ * Asx2 = Asx1 - daX
+ * dcX  = residual(Asx2) != 0 ? residual(Asx2) : residualX(Asx2); // add an auxiliary bool residualX_flag
+ * Asx3 = Asx2 - dcX
+ * ddcX = asym(Asx3)
+ * Asx4 = Asx3 + ddcX = Asx
+ * Xhypo= xCor(Asx4)  = seedPos.x - Asx4*CellSize
+ *
+ * d(Xhypo)/d(Xcluster) = d(xCor)/d(Asx4) * product[ d(Asx%i)/d(Asx%{i-1}), for i=1..4 ] * d(Asx0)/d(Xcluster)
+ *
+ * d(xCor)/d(Asx4)      =-CellSize
+ * d(Asx0)/d(Xcluster)  = d(Asx0)/d(xBar)     = -1/CellSize
+ * d(Asx1)/d(Asx0)      = DshapeX(Asx0)
+ * d(thx)/d(Asx1)       = d(thx)/d(xs) * d(xs)/d(Asx1) =-CellSize/(1+(xc/z)**2)*(1/z)
+ * d(xs)/d(Asx1)        =-CellSize
+ * d(Asx2)/d(Asx1)      = 1 - d(daX)/d(Asx1)  = 1 - Dangular(thx)*d(thx)/d(Asx1) = 1 + Dangular(thx)*CellSize/z/(1+(xs/z)**2)
+ * d(Asx3)/d(Asx2)      = 1 - d(dcX)/d(Asx2)  = 1 - ( residual(Asx2) != 0 ? Dresidual(Asx2) : DresidualX(Asx2) ) 
+ * residualX_flag       = residual(Asx2) != 0 ? false : true
+ * d(Asx4)/d(Asx3)      = 1 + d(ddcX)/d(Asx3) = 1 + Dasym(Asx3)
+ *
+ *
+ * d(Xhypo)/d(Xcluster) = (1 + Dasym(Asx3)) * (1 - (resudualX_flag ? DresidualX(Asx2) : Dresidual(Asx2)))
+ *                       *(1 + Dangular(thx)*CellSize/z/(1+(xs/z)**2)) * DshapeX(Asx0)
+ */
+
+  if ( m_correctCovariance && results ){
+    // // ---- calculation of numeric derivatives of individual correction functions, important for debugging in case of code changes ---
+    // debug() << "---------- numeric derivatives of individual S-correction functions ---------------" << endmsg;
+    // double tmpd = ( fabs(Asx0) > 1.e-5 ) ? Asx0*2.e-2 : 2.e-7;
+    // double dn_shapeX    = ( getCorrection(CaloFutureCorrection::shapeX, cellID, Asx0 + tmpd, Asx0 + tmpd) - Asx1 )/tmpd;
+    // tmpd = ( fabs(Asy0) > 1.e-5 ) ? Asy0*2.e-2 : 2.e-7;
+    // double dn_shapeY    = ( getCorrection(CaloFutureCorrection::shapeY, cellID, Asy0 + tmpd, Asy0 + tmpd) - Asy1 )/tmpd;
+    // 
+    // double dn_angularX  = ( getCorrection(CaloFutureCorrection::angularX, cellID, thx*1.002, 0.) - daX )/thx/2e-3;
+    // double dn_angularY  = ( getCorrection(CaloFutureCorrection::angularY, cellID, thy*1.002, 0.) - daY )/thy/2e-3;
+    // 
+    // tmpd = ( fabs(Asx2) > 1.e-5 ) ? Asx2*2.e-3 : 2.e-8;
+    // double dn_residualX = ( getCorrection((residualX_flag ? CaloFutureCorrection::residualX : CaloFutureCorrection::residual),
+    //                                                                                          cellID, Asx2 + tmpd, 0.) - dcX )/tmpd;
+    // tmpd = ( fabs(Asy2) > 1.e-5 ) ? Asy2*2.e-3 : 2.e-8;
+    // double dn_residualY = ( getCorrection((residualY_flag ? CaloFutureCorrection::residualY : CaloFutureCorrection::residual),
+    //                                                                                         cellID, Asy2 + tmpd, 0.) - dcY )/tmpd;
+    // tmpd = ( fabs(Asx3) > 1.e-5 ) ? Asx3*2.e-3 : 2.e-8;
+    // double dn_asymX     = (xBar < 0 ) ? 
+    //   ( getCorrection(CaloFutureCorrection::asymM , cellID , Asx2 + tmpd , 0.) - ddcX )/tmpd : 
+    //   ( getCorrection(CaloFutureCorrection::asymP , cellID , Asx2 + tmpd , 0.) - ddcX )/tmpd  ;
+    // 
+    // tmpd = ( fabs(Asy3) > 1.e-5 ) ? Asy3*2.e-3 : 2.e-8;
+    // double dn_asymY     = (yBar < 0 ) ?
+    //   ( getCorrection(CaloFutureCorrection::asymM , cellID , Asy2 + tmpd , 0.) - ddcY )/tmpd :
+    //   ( getCorrection(CaloFutureCorrection::asymP , cellID , Asy2 + tmpd , 0.) - ddcY )/tmpd  ;
+    // // -------------------------------------------------------------------------------------------------------------------------------
+
+
+    // calculation of the analytic derivatives:
+    // NB: printouts comparing analytic calculations with numeric derivatives which are commented-out below
+    // are useful for debugging in case of changes in the correction function code
+    if ( UNLIKELY(msgLevel( MSG::DEBUG)) )
+      debug() << "---------- analytic derivatives of individual S-correction functions ---------------" << endmsg;
+
+    double DshapeX = getCorrectionDerivative(CaloFutureCorrection::shapeX , cellID , Asx0 , 1. );
+    double DshapeY = getCorrectionDerivative(CaloFutureCorrection::shapeY , cellID , Asy0 , 1. );
+
+
+    double DangularX  = getCorrectionDerivative(CaloFutureCorrection::angularX   , cellID , thx , 0.);
+    double DangularY  = getCorrectionDerivative(CaloFutureCorrection::angularY   , cellID , thy , 0.);
+
+    double DresidualX = getCorrectionDerivative((residualX_flag ? CaloFutureCorrection::residualX : CaloFutureCorrection::residual), cellID , Asx2 , 0.);
+    double DresidualY = getCorrectionDerivative((residualY_flag ? CaloFutureCorrection::residualY : CaloFutureCorrection::residual), cellID , Asy2 , 0.);
+
+    double DasymX = (xBar < 0 ) ? 
+      getCorrectionDerivative(CaloFutureCorrection::asymM , cellID , Asx3 , 0.): 
+      getCorrectionDerivative(CaloFutureCorrection::asymP , cellID , Asx3 , 0.);
+    double DasymY = (yBar < 0 ) ?
+      getCorrectionDerivative(CaloFutureCorrection::asymM , cellID , Asy3 , 0.):
+      getCorrectionDerivative(CaloFutureCorrection::asymP , cellID , Asy3 , 0.);
+
+    double tx = xs / z;
+    double ty = ys / z;
+
+    results->dXhy_dXcl = (1. + DasymX) * (1. - DresidualX) *(1. + DangularX*CellSize/z/(1.+tx*tx)) * DshapeX;
+    results->dYhy_dYcl = (1. + DasymY) * (1. - DresidualY) *(1. + DangularY*CellSize/z/(1.+ty*ty)) * DshapeY;
+  }
+}
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureSCorrection.h b/CaloFuture/CaloFutureReco/src/CaloFutureSCorrection.h
new file mode 100644
index 0000000000000000000000000000000000000000..5b95f303ede0c59b0929db879b34d38baa337bae
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureSCorrection.h
@@ -0,0 +1,65 @@
+#ifndef CALOFUTURERECO_CALOFUTURESCORRECTION_H
+#define CALOFUTURERECO_CALOFUTURESCORRECTION_H 1
+// Include files
+// Include files
+#include <string>
+#include "CaloFutureInterfaces/ICaloFutureHypoTool.h"
+#include "CaloFutureCorrectionBase.h"
+#include "GaudiKernel/Counters.h"
+
+/** @class CaloFutureSCorrection CaloFutureSCorrection.h
+ *
+ *
+ *   @author Deschamps Olivier
+ *  @date   2003-03-10
+ */
+
+class CaloFutureSCorrection :
+  public virtual ICaloFutureHypoTool ,
+  public              CaloFutureCorrectionBase{
+public:
+
+  StatusCode process    ( LHCb::CaloHypo* hypo  ) const override;
+  StatusCode operator() ( LHCb::CaloHypo* hypo  ) const override;
+
+public:
+
+  StatusCode initialize() override;
+  StatusCode finalize() override;
+
+  CaloFutureSCorrection ( const std::string& type   ,
+                    const std::string& name   ,
+                    const IInterface*  parent ) ;
+
+private:
+
+  /// input variables calculated once in process() and passed to all calcSCorrection() calls
+  struct SCorrInputParams {
+    LHCb::CaloCellID  cellID;
+    Gaudi::XYZPoint  seedPos;
+    double                 z;
+  };
+
+  /// Jacobian elements returned from calcSCorrection() to process()
+  struct SCorrOutputParams {
+    double dXhy_dXcl;
+    double dYhy_dYcl;
+  };
+
+
+  /// calculate corrected CaloHypo position depending on CaloCluster position
+  void calcSCorrection( double  xBar, double  yBar, double &xCor, double &yCor,
+                        const struct SCorrInputParams                  &params,
+                        struct SCorrOutputParams                       *results ) const;
+
+private:
+  using IncCounter =  Gaudi::Accumulators::Counter<>;
+  using SCounter =  Gaudi::Accumulators::StatCounter<float>;
+  using MapOfCounters = std::map<std::string, SCounter >;
+
+  mutable IncCounter m_counterSkipNegativeEnergyCorrection{this, "Skip negative energy correction"};
+  mutable SCounter m_counterDeltaX{this, "Delta(X)"};
+  mutable SCounter m_counterDeltaY{this, "Delta(Y)"};
+};
+// ============================================================================
+#endif // CALOFUTURERECO_CALOFUTURESCORRECTION_H
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureSelectChargedClusterWithSpd.cpp b/CaloFuture/CaloFutureReco/src/CaloFutureSelectChargedClusterWithSpd.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..84eddea30292fe871ba4862358581d52b026f3fb
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureSelectChargedClusterWithSpd.cpp
@@ -0,0 +1,37 @@
+// ============================================================================
+#include "CaloFutureSelectClusterWithSpd.h"
+// ============================================================================
+/** @class CaloFutureSelectChargedClusterWithSpd
+ *  Simple seleclton of newural clusters based on Spd information
+ *  @author Olivier Deschamps
+ *  @author Vanya BELYAEV
+ */
+// ============================================================================
+
+class CaloFutureSelectChargedClusterWithSpd : public CaloFutureSelectClusterWithSpd
+{
+public:
+  // ==========================================================================
+  bool select ( const LHCb::CaloCluster* cluster ) const override
+  { return (*this) ( cluster ) ; }
+  // ==========================================================================
+  bool operator()( const LHCb::CaloCluster* cluster ) const override
+  {
+    if ( 0 == cluster )
+    {
+      Warning ( "CaloCluster* points to NULL, return false" );
+      return false ;                                                  // RETURN
+    }
+    //
+    bool sel = cut() < n_hit ( *cluster ) ;
+    if(counterStat->isVerbose())counter("selected clusters") += (int) sel;
+    return sel;
+  }
+  // ==========================================================================
+  /// constructor
+  using CaloFutureSelectClusterWithSpd::CaloFutureSelectClusterWithSpd;
+  // ==========================================================================
+};
+// ============================================================================
+DECLARE_COMPONENT( CaloFutureSelectChargedClusterWithSpd )
+// ============================================================================
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureSelectCluster.cpp b/CaloFuture/CaloFutureReco/src/CaloFutureSelectCluster.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..fe2b37a30bb0121628978d5f0f2a9e21ca47537c
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureSelectCluster.cpp
@@ -0,0 +1,46 @@
+#include "GaudiKernel/SystemOfUnits.h"
+#include "CaloFutureUtils/CaloMomentum.h"
+#include "Event/CaloCluster.h"
+#include "CaloFutureSelectCluster.h"
+
+DECLARE_COMPONENT( CaloFutureSelectCluster )
+
+// ============================================================================
+CaloFutureSelectCluster::CaloFutureSelectCluster
+( const std::string& type, 
+  const std::string& name,
+  const IInterface*  parent)
+  : GaudiTool (type ,name ,parent) 
+{
+  declareInterface<ICaloFutureClusterSelector> (this);
+}
+// ============================================================================
+
+StatusCode CaloFutureSelectCluster::initialize (){  
+  StatusCode sc = GaudiTool::initialize () ;
+  return sc;
+}
+
+bool CaloFutureSelectCluster::select( const LHCb::CaloCluster* cluster ) const
+{ 
+  return (*this) (cluster); 
+}
+
+bool CaloFutureSelectCluster::operator()( const LHCb::CaloCluster* cluster) const 
+{
+  if ( 0 == cluster ) { Warning ( "CaloCluster* points to NULL!" ).ignore() ; return false ; }
+
+  double e = cluster->e();
+  LHCb::CaloMomentum moment = LHCb::CaloMomentum(cluster);
+  double et = moment.momentum().Pt();
+  int m = cluster->entries().size();
+
+  if( UNLIKELY(msgLevel( MSG::DEBUG) ))debug() << "Cluster has " << m << " entries " 
+                                      << " for a total energy of " << e <<  "(Et = " << et << ")" << endmsg;
+
+  bool isSelected =  (e>m_cut) && (m < m_mult) && (et > m_etCut) && (m > m_multMin);
+  if (isSelected ) { 
+    ++m_counter;
+  }
+  return isSelected;
+}
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureSelectCluster.h b/CaloFuture/CaloFutureReco/src/CaloFutureSelectCluster.h
new file mode 100644
index 0000000000000000000000000000000000000000..237ed64f9d1649954e6dbfb2fa65a7f285474579
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureSelectCluster.h
@@ -0,0 +1,33 @@
+//
+// ============================================================================
+#ifndef CALOFUTURERECO_CALOFUTURESELECTCLUSTER_H
+#define CALOFUTURERECO_CALOFUTURESELECTCLUSTER_H 1
+// ============================================================================
+#include <string>
+#include "GaudiAlg/GaudiTool.h"
+#include "CaloFutureInterfaces/ICaloFutureClusterSelector.h"
+#include "GaudiKernel/Counters.h"
+// ============================================================================
+
+class CaloFutureSelectCluster :
+  public virtual ICaloFutureClusterSelector,
+  public GaudiTool
+{
+public:
+
+  bool select( const LHCb::CaloCluster* cluster ) const override;
+  virtual bool operator()( const LHCb::CaloCluster* cluster ) const override;
+  StatusCode initialize () override;
+
+  CaloFutureSelectCluster( const std::string& type,
+                     const std::string& name,
+                     const IInterface* parent);
+
+private:
+  Gaudi::Property<float> m_cut {this, "MinEnergy", 0.};
+  Gaudi::Property<float> m_etCut {this, "MinEt", 0.};
+  Gaudi::Property<int> m_mult {this, "MaxDigits", 9999};
+  Gaudi::Property<int> m_multMin {this, "MinDigits", -9999};
+  mutable Gaudi::Accumulators::Counter<> m_counter{this, "selected clusters"};
+};
+#endif // CALOFUTURERECO_CALOFUTURESELECTCLUSTER_H
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureSelectClusterWithPrs.cpp b/CaloFuture/CaloFutureReco/src/CaloFutureSelectClusterWithPrs.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9b77cfa36a8f33783af5749c604e3204b08eb7e0
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureSelectClusterWithPrs.cpp
@@ -0,0 +1,49 @@
+#include "GaudiKernel/SystemOfUnits.h"
+#include "CaloFutureSelectClusterWithPrs.h"
+
+DECLARE_COMPONENT( CaloFutureSelectClusterWithPrs )
+
+// ============================================================================
+CaloFutureSelectClusterWithPrs::CaloFutureSelectClusterWithPrs
+( const std::string& type   , 
+  const std::string& name   ,
+  const IInterface*  parent )
+  : GaudiTool ( type , name , parent )
+{
+  declareInterface<ICaloFutureClusterSelector> ( this ) ;
+}
+// ============================================================================
+
+StatusCode CaloFutureSelectClusterWithPrs::initialize (){  
+  // initialize the base class 
+  StatusCode sc = GaudiTool::initialize () ;
+  //
+  m_toPrs = tool<ICaloFutureHypo2CaloFuture>("CaloFutureHypo2CaloFuture", "CaloFutureHypo2Prs");
+  m_toPrs->setCalos(m_det,"Prs");
+  counterStat = tool<IFutureCounterLevel>("FutureCounterLevel");
+  return sc;
+}
+
+// ============================================================================
+/** @brief "select"  method 
+ *
+ *  Cluster is considered to be "selected" if there are Spd/Prs hit in front 
+ *
+ */
+// ============================================================================
+bool CaloFutureSelectClusterWithPrs::select( const LHCb::CaloCluster* cluster ) const{ 
+return (*this) ( cluster ); 
+}
+// ============================================================================
+bool CaloFutureSelectClusterWithPrs::operator()( const LHCb::CaloCluster* cluster   ) const{
+  // check the cluster 
+  if ( 0 == cluster ) { Warning ( "CaloCluster* points to NULL!" ).ignore() ; return false ; }
+  double ePrs = m_toPrs->energy( *cluster, "Prs");
+  int mPrs = m_toPrs->multiplicity();
+  if ( UNLIKELY(msgLevel( MSG::DEBUG) ))debug() << "Found " << mPrs << "Prs hits " 
+                                      << " for a total energy of " << ePrs <<  endmsg;
+
+  bool sel = (ePrs>m_cut) && (mPrs>m_mult) ;
+  if(counterStat->isVerbose())counter("selected clusters") += (int) sel;
+  return sel;
+}
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureSelectClusterWithPrs.h b/CaloFuture/CaloFutureReco/src/CaloFutureSelectClusterWithPrs.h
new file mode 100644
index 0000000000000000000000000000000000000000..44b824da266e24c0f47e95c522dfb40b3323d644
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureSelectClusterWithPrs.h
@@ -0,0 +1,33 @@
+// ============================================================================
+#ifndef CALOFUTURERECO_CALOFUTURESELECTCLUSTERWITHPRS_H
+#define CALOFUTURERECO_CALOFUTURESELECTCLUSTERWITHPRS_H 1
+// ============================================================================
+#include <string>
+#include "GaudiAlg/GaudiTool.h"
+#include "CaloFutureInterfaces/ICaloFutureClusterSelector.h"
+#include "CaloFutureInterfaces/ICaloFutureHypo2CaloFuture.h"
+#include "CaloFutureInterfaces/IFutureCounterLevel.h"
+// ============================================================================
+
+class CaloFutureSelectClusterWithPrs :
+  public virtual ICaloFutureClusterSelector ,
+  public          GaudiTool
+{
+public:
+
+  bool select( const LHCb::CaloCluster* cluster ) const override;
+  bool operator()( const LHCb::CaloCluster* cluster ) const override;
+  StatusCode initialize() override;
+
+  CaloFutureSelectClusterWithPrs( const std::string& type   ,
+                            const std::string& name   ,
+                            const IInterface*  parent );
+
+private:
+  Gaudi::Property<float> m_cut  {this, "MinEnergy", -10. *Gaudi::Units::MeV};
+  Gaudi::Property<float> m_mult {this, "MinMultiplicity", 0.};
+  ICaloFutureHypo2CaloFuture* m_toPrs = nullptr;
+  Gaudi::Property<std::string> m_det {this, "Detector", "Ecal"};
+  IFutureCounterLevel* counterStat = nullptr;
+};
+#endif // CALOFUTURERECO_CALOFUTURESELECTCLUSTERWITHPRS_H
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureSelectClusterWithSpd.cpp b/CaloFuture/CaloFutureReco/src/CaloFutureSelectClusterWithSpd.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7e7ebe0b90863585cb7d2454c593ea803d450890
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureSelectClusterWithSpd.cpp
@@ -0,0 +1,41 @@
+// ============================================================================
+// Include files 
+// ============================================================================
+// Local
+// ============================================================================
+#include "CaloFutureSelectClusterWithSpd.h"
+// ============================================================================
+/** @file
+ *  Implementation file for class CaloFutureSelectClusterWithSpd
+ *  @date 2009-07-18 
+ *  @author Vanya BELYAEV Ivan.Belyaev@nikhef.nl
+ */
+// ============================================================================
+// standard constructor 
+// ============================================================================
+CaloFutureSelectClusterWithSpd::CaloFutureSelectClusterWithSpd
+( const std::string& type   , 
+  const std::string& name   ,
+  const IInterface*  parent )
+  : GaudiTool ( type , name , parent )
+{
+  declareInterface<ICaloFutureClusterSelector> ( this ) ;
+}
+// ============================================================================
+// initialization 
+// ============================================================================
+StatusCode CaloFutureSelectClusterWithSpd::initialize ()
+{
+  // initialize the base class 
+  StatusCode sc = GaudiTool::initialize () ;  
+  m_toSpd = tool<ICaloFutureHypo2CaloFuture> ( "CaloFutureHypo2CaloFuture", "CaloFutureHypo2Spd" , this );
+  m_toSpd->setCalos( m_det,"Spd");
+  counterStat = tool<IFutureCounterLevel>("FutureCounterLevel");
+  return sc ;
+}
+// ============================================================================
+// the main method 
+// ============================================================================
+int CaloFutureSelectClusterWithSpd::n_hits( const LHCb::CaloCluster& cluster ) const
+{ return m_toSpd->multiplicity ( cluster, "Spd" ) ; }
+
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureSelectClusterWithSpd.h b/CaloFuture/CaloFutureReco/src/CaloFutureSelectClusterWithSpd.h
new file mode 100644
index 0000000000000000000000000000000000000000..b30eec41e9e58e37a50c2261ae6729b808a46341
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureSelectClusterWithSpd.h
@@ -0,0 +1,68 @@
+// ============================================================================
+#ifndef CALOFUTURESELECTCLUSTERWITHSPD_H
+#define CALOFUTURESELECTCLUSTERWITHSPD_H 1
+// ============================================================================
+// Include files
+// ============================================================================
+// GaudiAlg
+// ============================================================================
+#include "GaudiAlg/GaudiTool.h"
+// ============================================================================
+// CaloFutureInterfaces
+// ============================================================================
+#include "CaloFutureInterfaces/ICaloFutureClusterSelector.h"
+#include "CaloFutureInterfaces/ICaloFutureHypo2CaloFuture.h"
+#include "CaloFutureInterfaces/IFutureCounterLevel.h"
+// ============================================================================
+/** @class CaloFutureSelectClusterWithSpd
+ *  Helper base class for "cluster selectioin with Spd" tools
+ *
+ *  @author Vanya BELYAEV Ivan.Belyaev@nikhef.nl
+ *  @date 2009-07-18
+ */
+// ============================================================================
+class CaloFutureSelectClusterWithSpd :
+  public virtual ICaloFutureClusterSelector ,
+  public          GaudiTool
+{
+public:
+  // ==========================================================================
+  /// initialize the tool
+  StatusCode initialize() override;
+  // ==========================================================================
+public:
+  // ==========================================================================
+  /// number of hits in SPD
+  int n_hits ( const LHCb::CaloCluster& cluster ) const ;
+  /// number of hits in SPD
+  int n_hit  ( const LHCb::CaloCluster& cluster ) const
+  { return n_hits ( cluster ) ; }
+  // ==========================================================================
+  /// standard constructor
+  CaloFutureSelectClusterWithSpd
+  ( const std::string& type   ,
+    const std::string& name   ,
+    const IInterface*  parent ) ;
+  // ==========================================================================
+protected:
+  // ==========================================================================
+  /// get number of hits
+  int cut () const { return m_cut ; }
+  /// get the tool
+  ICaloFutureHypo2CaloFuture* calo2calo () const { return m_toSpd ; }
+  /// get the calorimeter
+  const std::string& det() const { return m_det   ; }
+  IFutureCounterLevel* counterStat = nullptr;
+  // ==========================================================================
+private:
+  // ==========================================================================
+  /// number of hits in spd
+  Gaudi::Property<int> m_cut {this, "MinMultiplicity", 0, "number of hits in spd "};
+  /// Calo -> Calo tool
+  ICaloFutureHypo2CaloFuture* m_toSpd = nullptr;
+  /// Calorimeter
+  Gaudi::Property<std::string> m_det {this, "Detector", "Ecal"};
+  // ==========================================================================
+};
+#endif // CALOFUTURESELECTCLUSTERWITHSPD_H
+// ============================================================================
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureSelectNeutralClusterWithSpd.cpp b/CaloFuture/CaloFutureReco/src/CaloFutureSelectNeutralClusterWithSpd.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9b1b6aa0cf5a30a220e764fa0fecb9bbcfc6df35
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureSelectNeutralClusterWithSpd.cpp
@@ -0,0 +1,39 @@
+// ============================================================================
+// Local
+// ============================================================================
+#include "CaloFutureSelectClusterWithSpd.h"
+// ============================================================================
+/** @class CaloFutureSelectNsutralClusterWithSpd
+ *  Simple seleclton of newural clusters based on Spd information
+ *  @author Olivier Deschamps
+ *  @author Vanya BELYAEV
+ */
+// ============================================================================
+class CaloFutureSelectNeutralClusterWithSpd : public CaloFutureSelectClusterWithSpd
+{
+public:
+  // ==========================================================================
+  bool select ( const LHCb::CaloCluster* cluster ) const override
+  { return (*this) ( cluster ) ; }
+  // ==========================================================================
+  bool operator()( const LHCb::CaloCluster* cluster ) const override
+  {
+    if ( 0 == cluster )
+    {
+      Warning ( "CaloCluster* points to NULL, return false" );
+      return false ;                                                  // RETURN
+    }
+    //
+
+  bool sel = cut() >= n_hit ( *cluster ) ;
+  if(counterStat->isVerbose())counter("selected clusters") += (int) sel;
+  return sel;
+  }
+  // ==========================================================================
+  /// constructor
+  using CaloFutureSelectClusterWithSpd::CaloFutureSelectClusterWithSpd;
+  // ==========================================================================
+};
+// ============================================================================
+DECLARE_COMPONENT( CaloFutureSelectNeutralClusterWithSpd )
+// ============================================================================
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureSelectNeutralClusterWithTracks.cpp b/CaloFuture/CaloFutureReco/src/CaloFutureSelectNeutralClusterWithTracks.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..eb32794ac61a5c5b29de4e6dc783af4e9c39c5aa
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureSelectNeutralClusterWithTracks.cpp
@@ -0,0 +1,106 @@
+// ============================================================================
+//CaloFutureUtils
+#include "CaloFutureUtils/CaloFuture2Track.h"
+#include "CaloFutureUtils/CaloFutureAlgUtils.h"
+// local 
+#include "CaloFutureSelectNeutralClusterWithTracks.h"
+
+// ============================================================================
+/** @file 
+ *
+ *  implementation file for class CaloFutureSelectNeutralClusterWithTracks
+ *
+ *  @author Vanya Belyaev Ivan.Belyaev@itep.ru
+ *  @date 26 Apr 2002 
+ */
+// ============================================================================
+
+DECLARE_COMPONENT( CaloFutureSelectNeutralClusterWithTracks )
+
+// ============================================================================
+/** Standard constructor
+ *  @see  GaudiTool
+ *  @see   AlgTool
+ *  @see  IAlgTool 
+ *  @param type tool type (?)
+ *  @param name name of the concrete instance 
+ *  @param parent pointer to the parent 
+ */
+// ============================================================================
+CaloFutureSelectNeutralClusterWithTracks::CaloFutureSelectNeutralClusterWithTracks
+( const std::string& type   , 
+  const std::string& name   ,
+  const IInterface*  parent )
+  : GaudiTool ( type , name , parent )
+{
+  declareInterface<ICaloFutureClusterSelector> (this) ;
+  m_tableLocation = LHCb::CaloFutureAlgUtils::CaloFutureIdLocation( "ClusterMatch", context() );
+}
+
+// ============================================================================
+/** standard initialization method 
+ *  @see GaudiTool
+ *  @see  AlgTool
+ *  @see IAlgTool
+ *  @return status code
+ */
+// ============================================================================
+StatusCode 
+CaloFutureSelectNeutralClusterWithTracks::initialize ()
+{  
+  // initialize the base class 
+  StatusCode sc = GaudiTool::initialize () ;
+  if( sc.isFailure() )
+  {return Error("Could not initialize the base class GaudiTool!",sc); }
+  m_tables = tool<ICaloFutureRelationsGetter>("CaloFutureRelationsGetter","CaloFutureRelationsGetter",this);  
+  return StatusCode::SUCCESS ;
+}
+
+// ============================================================================
+/** @brief "select"  method 
+ *
+ *  Cluster is considered to be "selected" 
+ *  if there are no reconstructed tracks with 
+ *  chi2 value for 2D-matching under the threshold value 
+ *
+ *  @see ICaloFutureClusterSelector
+ *  @param  cluster pointer to calo cluster object to be selected 
+ *  @return true if cluster is selected
+ */
+// ============================================================================
+bool CaloFutureSelectNeutralClusterWithTracks::select     
+( const LHCb::CaloCluster* cluster ) const 
+{ return (*this) ( cluster ); }
+// ============================================================================
+
+// ============================================================================
+/** @brief "select"  method (functor interface)
+ *
+ *  Cluster is considered to be "selected" 
+ *  if there are no reconstructed tracks with 
+ *  chi2 value for 2D-matching under the threshold value 
+ *
+ *  @see ICaloFutureClusterSelector
+ *  @param  cluster pointer to calo cluster object to be selected 
+ *  @return true if cluster is selected
+ */
+// ============================================================================
+bool CaloFutureSelectNeutralClusterWithTracks::operator() 
+  ( const LHCb::CaloCluster* cluster   ) const 
+{
+  // check the cluster 
+  if ( 0 == cluster ) { Warning ( "CaloCluster* points to NULL!" ).ignore() ; return false ; }
+  
+  // locate the table 
+  LHCb::CaloFuture2Track::IClusTrTable* table = m_tables->getClusTrTable( m_tableLocation );
+  if( NULL == table )return true;
+
+  // get all relations with WEIGHT = 'chi2' under the threshold value 
+  const LHCb::CaloFuture2Track::IClusTrTable::Range range = table -> relations ( cluster , m_chi2cut , false ) ;
+
+  bool isSelected = range.empty();
+  if (isSelected ) { 
+    ++m_counter;
+  }
+  return isSelected;
+}
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureSelectNeutralClusterWithTracks.h b/CaloFuture/CaloFutureReco/src/CaloFutureSelectNeutralClusterWithTracks.h
new file mode 100644
index 0000000000000000000000000000000000000000..14d64c0b18e1674fc05abb347d872c7a83744c32
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureSelectNeutralClusterWithTracks.h
@@ -0,0 +1,93 @@
+// ===================================================q=========================
+#ifndef CALOFUTURERECO_CALOFUTURESELECTNEUTRALCLUSTERWITHTRACKS_H
+#define CALOFUTURERECO_CALOFUTURESELECTNEUTRALCLUSTERWITHTRACKS_H 1
+// ============================================================================
+// Include files
+#include "Relations/IRelationWeighted.h"
+// from STL
+#include <string>
+// CaloFutureInterfaces
+#include "CaloFutureInterfaces/ICaloFutureClusterSelector.h"
+#include "CaloFutureInterfaces/ICaloFutureRelationsGetter.h"
+// GaudiAlg
+#include "GaudiAlg/GaudiTool.h"
+//Event
+#include "Event/CaloCluster.h"
+#include "Event/Track.h"
+#include "GaudiKernel/Counters.h"
+// ============================================================================
+
+/** @class CaloFutureSelectNeutralClusterWithTracks CaloFutureSelectNeutralClusterWithTracks.h
+ *
+ *  Concrete tool, which select the Neutral clusters
+ *  (photon candidates) looking through the relation table
+ *  of 2D-matched CaloClusters and Tracks
+ *
+ *  Cluster is considered to be "selected"
+ *  if there are no reconstructed tracks with
+ *  chi2 value for 2D-matching under the threshold value
+ *
+ *  @author Vanya Belyaev Ivan.Belyaev@itep.ru
+ *  @date   26/04/2002
+ */
+class CaloFutureSelectNeutralClusterWithTracks :
+  public virtual ICaloFutureClusterSelector ,
+  public          GaudiTool
+{
+public:
+
+  /** @brief "select"  method
+   *
+   *  Cluster is considered to be "selected"
+   *  if there are no reconstructed tracks with
+   *  chi2 value for 2D-matching under the threshold value
+   *
+   *  @see ICaloFutureClusterSelector
+   *  @param  cluster pointer to calo cluster object to be selected
+   *  @return true if cluster is selected
+   */
+  bool select
+  ( const LHCb::CaloCluster* cluster ) const override;
+
+  /** @brief "select"  method (functor interface)
+   *
+   *  Cluster is considered to be "selected"
+   *  if there are no reconstructed tracks with
+   *  chi2 value for 2D-matching under the threshold value
+   *
+   *  @see ICaloFutureClusterSelector
+   *  @param  cluster pointer to calo cluster object to be selected
+   *  @return true if cluster is selected
+   */
+  bool operator()
+    ( const LHCb::CaloCluster* cluster ) const override;
+
+  /** standard initialization method
+   *  @see GaudiTool
+   *  @see  AlgTool
+   *  @see IAlgTool
+   *  @return status code
+   */
+  StatusCode initialize() override;
+
+  /** Standard constructor
+   *  @see  GaudiTool
+   *  @see   AlgTool
+   *  @see  IAlgTool
+   *  @param type tool type (?)
+   *  @param name name of the concrete instance
+   *  @param parent pointer to the parent
+   */
+  CaloFutureSelectNeutralClusterWithTracks
+  ( const std::string& type   ,
+    const std::string& name   ,
+    const IInterface*  parent );
+
+private:
+
+  Gaudi::Property<std::string> m_tableLocation {this, "Table", LHCb::CaloFutureIdLocation::ClusterMatch};
+  Gaudi::Property<float> m_chi2cut {this, "MinChi2", -100};
+  ICaloFutureRelationsGetter*  m_tables = nullptr;
+  mutable Gaudi::Accumulators::Counter<> m_counter{this, "selected clusters"};
+};
+#endif // CALOFUTURERECO_CALOFUTURESELECTNEUTRALCLUSTERWITHTRACKS_H
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureSelector.cpp b/CaloFuture/CaloFutureReco/src/CaloFutureSelector.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e2ba4e8c688a449c9e60749707d01a8180de8ad3
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureSelector.cpp
@@ -0,0 +1,98 @@
+// ============================================================================
+// Include files
+// CaloFutureInterfaces 
+#include "CaloFutureInterfaces/ICaloFutureLikelihood.h"
+// local
+#include "CaloFutureSelector.h"
+
+// ============================================================================
+/** @file CaloFutureSelector.cpp 
+ *
+ *  Implementation file for class : CaloFutureSelector
+ * 
+ *  @author Vanya Belyaev Ivan.Belyaev@itep.ru 
+ *  @date 31/03/2002 
+ */
+// ============================================================================
+
+DECLARE_COMPONENT( CaloFutureSelector )
+
+// ============================================================================
+/** Standard constructor
+ *  @param    type   tool type (?)
+ *  @param    name   tool name 
+ *  @param    parent tool parent 
+ */
+// ============================================================================
+CaloFutureSelector::CaloFutureSelector( const std::string&  type   ,
+                            const std::string&  name   ,
+                            const IInterface*   parent )
+  : GaudiTool ( type, name , parent ) 
+{  
+  // interfaces  
+  declareInterface<ICaloFutureClusterSelector> (this);
+}
+
+// ============================================================================
+/** standard initialization of the tool 
+ *  @see IAlgTool 
+ *  @see AlgTool 
+ *  @see GaudiTool 
+ *  @return status code 
+ */
+// ============================================================================
+StatusCode CaloFutureSelector::initialize() 
+{
+  // initialialize the base class 
+  StatusCode sc = GaudiTool::initialize() ;
+  if( sc.isFailure() ) 
+  { return Error("Could not initialize the base class GaudiTool!",sc);}
+  /// locate the tool 
+  m_likelihood = m_lhName.empty() ?
+    tool<ICaloFutureLikelihood>( m_lhType            , this ) :
+    tool<ICaloFutureLikelihood>( m_lhType , m_lhName , this ) ;
+  if( 0 == m_likelihood ) { return StatusCode::FAILURE ; }
+  //
+  return StatusCode::SUCCESS ;
+}
+
+// ============================================================================
+/** standard finalization  of the tool 
+ *  @see IAlgTool 
+ *  @see AlgTool 
+ *  @see GaudiTool 
+ *  @return status code 
+ */
+// ============================================================================
+StatusCode CaloFutureSelector::finalize() 
+{
+  ///finalize the base class 
+  return GaudiTool::finalize() ;
+}
+
+// ============================================================================
+/** "select"/"preselect" method (functor interface)
+ *  @see ICaloFutureClusterSelector 
+ *  @param  cluster pointer to calo cluster object to be selected 
+ *  @return true if cluster is selected
+ */
+// ============================================================================
+bool CaloFutureSelector::operator() ( const LHCb::CaloCluster* cluster ) const
+{
+  if( 0 == cluster ) {  return false ; }
+  return  m_cut <= (*m_likelihood) (cluster) ;
+}
+
+// ============================================================================
+/** "select"/"preselect" method 
+ *  @see ICaloFutureClusterSelector 
+ *  @param  cluster pointer to calo cluster object to be selected 
+ *  @return true if cluster is selected
+ */
+// ============================================================================
+bool CaloFutureSelector::select     ( const LHCb::CaloCluster* cluster ) const 
+{ return (*this) ( cluster ); }
+
+// ============================================================================
+// The End 
+// ============================================================================
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureSelector.h b/CaloFuture/CaloFutureReco/src/CaloFutureSelector.h
new file mode 100644
index 0000000000000000000000000000000000000000..a8c1e51d5eb039ec2ac4fd0ccc2a857628bba30e
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureSelector.h
@@ -0,0 +1,92 @@
+#ifndef CALOFUTURERECO_CALOFUTURESELECTOR_H
+#define CALOFUTURERECO_CALOFUTURESELECTOR_H 1
+// Include files
+// from STL
+#include <string>
+// from GaudiAlg
+#include "GaudiAlg/GaudiTool.h"
+// from CaloFutureInterfaces
+#include "CaloFutureInterfaces/ICaloFutureClusterSelector.h"
+// forward declaratiosn
+struct ICaloFutureLikelihood ; // from CaloFutureInterfaces ;
+
+/** @class CaloFutureSelector CaloFutureSelector.h
+ *
+ *  Concrete cluster-selector tool, to select CaloFutureClusters
+ *  which satisfy the given calorimeter hypothesis
+ *  Tool in turn uses the tool with ICaloFutureLikelihood
+ *  interaface to calculate the likelihood.
+ *  @see ICaloFutureClusterSelector
+ *  @see ICaloFutureLikelyhood
+ *  @see CaloCluster
+ *
+ *  @author Vanya Belyaev Ivan.Belyaev@itep.ru
+ *  @date   31/03/2002
+ */
+class CaloFutureSelector :
+  public virtual   ICaloFutureClusterSelector ,
+  public                       GaudiTool
+{
+public:
+
+  /** "select"/"preselect" method
+   *  @see ICaloFutureClusterSelector
+   *  @param  cluster pointer to calo cluster object to be selected
+   *  @return true if cluster is selected
+   */
+  bool select     ( const LHCb::CaloCluster* cluster ) const override;
+
+  /** "select"/"preselect" method (functor interface)
+   *  @see ICaloFutureClusterSelector
+   *  @param  cluster pointer to calo cluster object to be selected
+   *  @return true if cluster is selected
+   */
+  bool operator() ( const LHCb::CaloCluster* cluster ) const override;
+
+  /** standard initialization of the tool
+   *  @see IAlgTool
+   *  @see AlgTool
+   *  @see GaudiTool
+   *  @return status code
+   */
+  StatusCode initialize() override;
+
+  /** standard finalization  of the tool
+   *  @see IAlgTool
+   *  @see AlgTool
+   *  @see GaudiTool
+   *  @return status code
+   */
+  StatusCode finalize() override;
+
+  /** Standard constructor
+   *  @param    type   tool type (?)
+   *  @param    name   tool name
+   *  @param    parent tool parent
+   */
+  CaloFutureSelector
+  ( const std::string&  type   ,
+    const std::string&  name   ,
+    const IInterface*   parent );
+
+private:
+
+  // type of Likelyhood tool to be used
+  Gaudi::Property<std::string> m_lhType
+    {this, "LikelihoodType", "", "type of Likelyhood tool to be used"};
+
+  // name of Likelyhood tool to be used
+  Gaudi::Property<std::string> m_lhName
+    {this, "LikelihoodName", "", "name of Likelyhood tool to be used"};
+
+  // Likelyhood tool to be used
+  ICaloFutureLikelihood* m_likelihood = nullptr;
+
+  // cut on likelyhood
+  Gaudi::Property<double> m_cut {this, "LikelihoodCut", 1.e+50, "cut on likelyhood"};
+
+};
+
+// ============================================================================
+#endif // CALOFUTURERECO_CALOFUTURESELECTOR_H
+// ============================================================================
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureSelectorAND.cpp b/CaloFuture/CaloFutureReco/src/CaloFutureSelectorAND.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..830a61ae015f9b29b112895cd1689a024a4d6ec3
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureSelectorAND.cpp
@@ -0,0 +1,103 @@
+// ============================================================================
+// Include files
+// ============================================================================
+// Local
+// ============================================================================
+#include "CaloFutureSelectorAND.h"
+// ============================================================================
+/** @file 
+ * 
+ *  Implementation file for class : CaloFutureSelectorAND
+ * 
+ *  @author Vanya Belyaev Ivan.Belyaev@itep.ru
+ *  @date 27 Apr 2002 
+ */
+// ============================================================================
+DECLARE_COMPONENT( CaloFutureSelectorAND )
+// ============================================================================
+/*  Standard constructor
+ *  @see GaudiTool
+ *  @see  AlgTool 
+ *  @see IAlgTool 
+ *  @param type   tool type (?)
+ *  @param name   tool name 
+ *  @param parent tool parent   
+ */
+// ============================================================================
+CaloFutureSelectorAND::CaloFutureSelectorAND
+( const std::string& type,
+  const std::string& name,
+  const IInterface* parent )
+  : GaudiTool ( type, name , parent ) 
+{
+  declareInterface<ICaloFutureClusterSelector> (this);
+}
+// ============================================================================
+/*  standard initialization of the tool 
+ *  @see IAlgTool 
+ *  @see AlgTool 
+ *  @see GaudiTool 
+ *  @return status code 
+ */
+// ============================================================================
+StatusCode CaloFutureSelectorAND::initialize () 
+{
+  // initialize the base class
+  StatusCode sc = GaudiTool::initialize() ;
+  if( sc.isFailure() ) 
+    { return Error("Could not initialize the base class GaudiTool",sc);}
+  // locate selectors 
+  std::transform( m_selectorsTypeNames.begin(), m_selectorsTypeNames.end(),
+                  std::back_inserter(m_selectors),
+                  [&](const std::string& name)
+                  { return  tool<ICaloFutureClusterSelector>( name, this ); } );
+  ///
+  return StatusCode::SUCCESS ;
+}
+// ============================================================================
+/*  standard finalization  of the tool 
+ *  @see IAlgTool 
+ *  @see AlgTool 
+ *  @see GaudiTool 
+ *  @return status code 
+ */
+// ============================================================================
+StatusCode CaloFutureSelectorAND::finalize   () 
+{
+  // clear containers 
+  m_selectors          .clear() ;
+  m_selectorsTypeNames .clear() ;
+  // finalize the base class 
+  return GaudiTool::finalize () ;
+}
+// ============================================================================
+
+// ============================================================================
+/** "select"/"preselect" method 
+ *  @see ICaloFutureClusterSelector
+ *  @param  cluster pointer to calo cluster object to be selected 
+ *  @return true if cluster is selected
+ */
+// ============================================================================
+bool CaloFutureSelectorAND::select     
+( const LHCb::CaloCluster* cluster ) const { return (*this) ( cluster ) ; }
+// ============================================================================
+
+// ============================================================================
+/** "select"/"preselect" method (functor interface)
+ *  @see ICaloFutureClusterSelector
+ *  @param  cluster pointer to calo cluster object to be selected 
+ *  @return true if cluster is selected
+ */
+// ============================================================================
+bool CaloFutureSelectorAND::operator() ( const LHCb::CaloCluster* cluster ) const
+{
+  // no selectors!
+  if( m_selectors.empty() ) { return false ; } // note: this is not what std::all_of does for an empty range!
+  return std::all_of( m_selectors.begin(), m_selectors.end(),
+                      [&](Selectors::const_reference s)
+                      { return (*s)(cluster); } );
+}
+// ============================================================================
+// The END 
+// ============================================================================
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureSelectorAND.h b/CaloFuture/CaloFutureReco/src/CaloFutureSelectorAND.h
new file mode 100644
index 0000000000000000000000000000000000000000..32eb5de49483d9f65746c49e2d76c7c27293b6b7
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureSelectorAND.h
@@ -0,0 +1,99 @@
+#ifndef CALOFUTURERECO_CALOFUTURESELECTORAND_H
+#define CALOFUTURERECO_CALOFUTURESELECTORAND_H
+// Include files
+// from STL
+#include <string>
+// from GaudiAlg
+#include "GaudiAlg/GaudiTool.h"
+// From CaloFutureInterfaces
+#include "CaloFutureInterfaces/ICaloFutureClusterSelector.h"
+
+/** @class CaloFutureSelectorAND CaloFutureSelectorAND.h
+ *
+ *  Helper concrete tool for selection of calocluster objects
+ *  This selector selects the cluster if
+ *  all of its daughter selector select it!
+ *
+ *  @author Vanya Belyaev Ivan.Belyaev@itep.ru
+ *  @date   27/04/2002
+ */
+class CaloFutureSelectorAND :
+  public virtual ICaloFutureClusterSelector ,
+  public          GaudiTool
+{
+public:
+  /// container of types&names
+  typedef std::vector<std::string>           Names     ;
+  /// container of selectors
+  typedef std::vector<ICaloFutureClusterSelector*> Selectors ;
+
+public:
+
+  /** "select"/"preselect" method
+   *  @see ICaloFutureClusterSelector
+   *  @param  cluster pointer to calo cluster object to be selected
+   *  @return true if cluster is selected
+   */
+  bool select
+  ( const LHCb::CaloCluster* cluster ) const  override;
+
+  /** "select"/"preselect" method (functor interface)
+   *  @see ICaloFutureClusterSelector
+   *  @param  cluster pointer to calo cluster object to be selected
+   *  @return true if cluster is selected
+   */
+  bool operator ()
+    ( const LHCb::CaloCluster* cluster ) const  override;
+
+  /** standard initialization of the tool
+   *  @see IAlgTool
+   *  @see AlgTool
+   *  @see GaudiTool
+   *  @return status code
+   */
+  StatusCode initialize() override;
+
+  /** standard finalization  of the tool
+   *  @see IAlgTool
+   *  @see AlgTool
+   *  @see GaudiTool
+   *  @return status code
+   */
+  StatusCode finalize() override;
+
+  /** Standard constructor
+   *  @see GaudiTool
+   *  @see  AlgTool
+   *  @see IAlgTool
+   *  @param type   tool type (?)
+   *  @param name   tool name
+   *  @param parent tool parent
+   */
+  CaloFutureSelectorAND
+  ( const std::string& type,
+    const std::string& name,
+    const IInterface* parent);
+
+private:
+
+  ///   default  constructor  is  private
+  CaloFutureSelectorAND();
+  ///   copy     constructor  is  private
+  CaloFutureSelectorAND
+  (const CaloFutureSelectorAND& );
+  ///   assignement operator  is  private
+  CaloFutureSelectorAND& operator=
+  (const CaloFutureSelectorAND& );
+
+private:
+
+  Gaudi::Property<Names> m_selectorsTypeNames {this, "SelectorTools"};
+  Selectors m_selectors;
+
+};
+
+// ============================================================================
+// The END
+// ============================================================================
+#endif // CALOFUTURERECO_CALOFUTURESELECTORAND_H
+// ============================================================================
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureSelectorNOT.cpp b/CaloFuture/CaloFutureReco/src/CaloFutureSelectorNOT.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..cbe3530784811ce033bb2d7e1c67d5c460dcce01
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureSelectorNOT.cpp
@@ -0,0 +1,107 @@
+// ============================================================================
+// Include files
+// ============================================================================
+// local
+#include "CaloFutureSelectorNOT.h"
+// ============================================================================
+/** @file
+ *
+ *  Implementation file for class : CaloFutureSelectorNOT
+ *
+ *  @author Vanya Belyaev Ivan.Belyaev@itep.ru
+ *  @date 27 Apr 2002
+ */
+// ============================================================================
+DECLARE_COMPONENT( CaloFutureSelectorNOT )
+// ============================================================================
+/*  StNOTard constructor
+ *  @see GaudiTool
+ *  @see  AlgTool
+ *  @see IAlgTool
+ *  @param type   tool type (?)
+ *  @param name   tool name
+ *  @param parent tool parent
+ */
+// ============================================================================
+CaloFutureSelectorNOT::CaloFutureSelectorNOT
+( const std::string& type,
+  const std::string& name,
+  const IInterface* parent )
+  : GaudiTool ( type, name, parent )
+{
+  declareInterface<ICaloFutureClusterSelector> (this);
+}
+// ============================================================================
+/*  stNOTard initialization of the tool
+ *  @see IAlgTool
+ *  @see AlgTool
+ *  @see GaudiTool
+ *  @return status code
+ */
+// ============================================================================
+StatusCode CaloFutureSelectorNOT::initialize ()
+{
+  // initialize the base class
+  StatusCode sc = GaudiTool::initialize() ;
+  if ( sc.isFailure() ) {
+    return Error("Could not initialize the base class GaudiTool", sc);
+  }
+  // locate selectors
+  for ( Names::const_iterator it = m_selectorsTypeNames.begin() ;
+        m_selectorsTypeNames.end() != it ; ++it ) {
+    ICaloFutureClusterSelector* selector = tool<ICaloFutureClusterSelector>( *it, this );
+    m_selectors.push_back( selector );
+  };
+  ///
+  return StatusCode::SUCCESS ;
+}
+// ============================================================================
+/*  stNOTard finalization  of the tool
+ *  @see IAlgTool
+ *  @see AlgTool
+ *  @see GaudiTool
+ *  @return status code
+ */
+// ============================================================================
+StatusCode CaloFutureSelectorNOT::finalize   ()
+{
+  // clear containers
+  m_selectors          .clear() ;
+  m_selectorsTypeNames .clear() ;
+  // finalize the base class
+  return GaudiTool::finalize () ;
+}
+// ============================================================================
+/*  "select"/"preselect" method
+ *  @see ICaloFutureClusterSelector
+ *  @param  cluster pointer to calo cluster object to be selected
+ *  @return true if cluster is selected
+ */
+// ============================================================================
+bool CaloFutureSelectorNOT::select( const LHCb::CaloCluster* cluster ) const
+{
+  return (*this) (cluster);
+}
+// ============================================================================
+/* "select"/"preselect" method (functor interface)
+ *  @see ICaloFutureClusterSelector
+ *  @param  cluster pointer to calo cluster object to be selected
+ *  @return true if cluster is selected
+ */
+// ============================================================================
+bool CaloFutureSelectorNOT::operator() ( const LHCb::CaloCluster* cluster ) const
+{
+  bool notSelected = false ;
+  for ( Selectors::const_iterator selector = m_selectors.begin() ;
+        !notSelected && m_selectors.end() != selector ; ++selector ) {
+    notSelected = (**selector)( cluster );
+  }
+  if (!notSelected) { 
+    ++m_counter;
+  }
+  return !notSelected;
+}
+
+
+
+
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureSelectorNOT.h b/CaloFuture/CaloFutureReco/src/CaloFutureSelectorNOT.h
new file mode 100644
index 0000000000000000000000000000000000000000..44b85c625fa08ce814e9b34b13dc8c53b2b5a6a4
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureSelectorNOT.h
@@ -0,0 +1,64 @@
+#ifndef CALOFUTURERECO_CALOFUTURESELECTORNOT_H
+#define CALOFUTURERECO_CALOFUTURESELECTORNOT_H 1
+// Include files
+// from STL
+#include <string>
+// from GaudiAlg
+#include "GaudiAlg/GaudiTool.h"
+#include "GaudiKernel/Counters.h"
+// From CaloFutureInterfaces
+#include "CaloFutureInterfaces/ICaloFutureClusterSelector.h"
+/** @class CaloFutureSelectorNOT CaloFutureSelectorNOT.h
+ *
+ *  Helper concrete tool for selection of calocluster objects
+ *  This selector selects the cluster if
+ *  none  of its daughter selector select it!
+ *
+ *  @author Vanya Belyaev Ivan.Belyaev@itep.ru
+ *  @date   27/04/2002
+ */
+class CaloFutureSelectorNOT :
+  public virtual ICaloFutureClusterSelector,
+  public GaudiTool
+{
+public:
+  using Names = std::vector<std::string>;
+  using Selectors= std::vector<ICaloFutureClusterSelector*>;
+  using IncCounter =  Gaudi::Accumulators::Counter<>;
+
+  /** "select"/"preselect" method
+   *  @see ICaloFutureClusterSelector
+   *  @param  cluster pointer to calo cluster object to be selected
+   *  @return true if cluster is selected
+   */
+  bool select
+  (const LHCb::CaloCluster* cluster) const override;
+
+  /** "select"/"preselect" method (functor interface)
+   *  @see ICaloFutureClusterSelector
+   *  @param  cluster pointer to calo cluster object to be selected
+   *  @return true if cluster is selected
+   */
+  bool operator ()
+  ( const LHCb::CaloCluster* cluster ) const  override;
+
+  StatusCode initialize() override;
+  StatusCode finalize() override;
+
+  /** StNOTard constructor
+   *  @param type   tool type
+   *  @param name   tool name
+   *  @param parent tool parent
+   */
+  CaloFutureSelectorNOT
+  (const std::string& type,
+   const std::string& name,
+   const IInterface* parent);
+
+private:
+  Gaudi::Property<Names> m_selectorsTypeNames {this, "SelectorTools"};
+  Selectors m_selectors;
+  mutable IncCounter m_counter{this, "selected clusters"};
+};
+// ============================================================================
+#endif // CALOFUTURERECO_CALOFUTURESELECTORNOT_H
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureSelectorOR.cpp b/CaloFuture/CaloFutureReco/src/CaloFutureSelectorOR.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d3baea35ebc157ef02c14ddee01999374c429a44
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureSelectorOR.cpp
@@ -0,0 +1,97 @@
+// ============================================================================
+// Include files 
+// ============================================================================
+// local
+// ============================================================================
+#include "CaloFutureSelectorOR.h"
+// ============================================================================
+/** @file 
+ * 
+ *  Implementation file for class : CaloFutureSelectorOR
+ * 
+ *  @author Vanya Belyaev Ivan.Belyaev@itep.ru
+ *  @date 27 Apr 2002 
+ */
+// ============================================================================
+DECLARE_COMPONENT( CaloFutureSelectorOR )
+// ============================================================================
+/*  Standard constructor
+ *  @see GaudiTool
+ *  @see  AlgTool 
+ *  @see IAlgTool 
+ *  @param type   tool type (?)
+ *  @param name   tool name 
+ *  @param parent tool parent   
+ */
+// ============================================================================
+CaloFutureSelectorOR::CaloFutureSelectorOR
+( const std::string& type,
+  const std::string& name,
+  const IInterface* parent )
+  : GaudiTool ( type, name , parent ) 
+{
+  declareInterface<ICaloFutureClusterSelector> (this);
+}
+// ============================================================================
+/*  standard initialization of the tool
+ *  @see IAlgTool 
+ *  @see AlgTool 
+ *  @see GaudiTool 
+ *  @return status code 
+ */
+// ============================================================================
+StatusCode CaloFutureSelectorOR::initialize () 
+{
+  // initialize the base class
+  StatusCode sc = GaudiTool::initialize() ;
+  if( sc.isFailure() ) 
+    { return Error("Could not initialize the base class GaudiTool",sc);}
+  // locate selectors 
+  std::transform( m_selectorsTypeNames.begin(), m_selectorsTypeNames.end(),
+                  std::back_inserter(m_selectors),
+                  [&](const std::string& name)
+                  { return  tool<ICaloFutureClusterSelector>( name, this ); } );
+  ///
+  return StatusCode::SUCCESS ;
+}
+// ============================================================================
+/*  standard finalization  of the tool
+ *  @see IAlgTool 
+ *  @see AlgTool 
+ *  @see GaudiTool 
+ *  @return status code 
+ */
+// ============================================================================
+StatusCode CaloFutureSelectorOR::finalize   () 
+{
+  // clear containers 
+  m_selectors          .clear() ;
+  m_selectorsTypeNames .clear() ;
+  // finalize the base class 
+  return GaudiTool::finalize () ;
+}
+// ============================================================================
+/*  "select"/"preselect" method 
+ *  @see ICaloFutureClusterSelector
+ *  @param  cluster pointer to calo cluster object to be selected 
+ *  @return true if cluster is selected
+ */
+// ============================================================================
+bool CaloFutureSelectorOR::select     
+( const LHCb::CaloCluster* cluster ) const { return (*this) ( cluster ) ; }
+// ============================================================================
+/** "select"/"preselect" method (functor interface)
+ *  @see ICaloFutureClusterSelector
+ *  @param  cluster pointer to calo cluster object to be selected 
+ *  @return true if cluster is selected
+ */
+// ============================================================================
+bool CaloFutureSelectorOR::operator() ( const LHCb::CaloCluster* cluster ) const
+{
+  return std::any_of( m_selectors.begin(), m_selectors.end(),
+                      [&](typename Selectors::const_reference s)
+                      { return (*s)(cluster); } );
+}
+// ============================================================================
+// The END 
+// ============================================================================
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureSelectorOR.h b/CaloFuture/CaloFutureReco/src/CaloFutureSelectorOR.h
new file mode 100644
index 0000000000000000000000000000000000000000..3d4888fbeecc02201ef0268717e1f7bfa30a32f9
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureSelectorOR.h
@@ -0,0 +1,99 @@
+#ifndef CALOFUTURERECO_CALOFUTURESELECTOROR_H
+#define CALOFUTURERECO_CALOFUTURESELECTOROR_H 1
+// Include files
+// from STL
+#include <string>
+// from GaudiAlg
+#include "GaudiAlg/GaudiTool.h"
+// From CaloFutureInterfaces
+#include "CaloFutureInterfaces/ICaloFutureClusterSelector.h"
+
+/** @class CaloFutureSelectorOR CaloFutureSelectorOR.h
+ *
+ *  Helper concrete tool for selection of calocluster objects
+ *  This selector selects the cluster if
+ *  at least one  of its daughter selector select it!
+ *
+ *  @author Vanya Belyaev Ivan.Belyaev@itep.ru
+ *  @date   27/04/2002
+ */
+class CaloFutureSelectorOR :
+  public virtual ICaloFutureClusterSelector ,
+  public          GaudiTool
+{
+public:
+  /// container of types&names
+  typedef std::vector<std::string>           Names     ;
+  /// container of selectors
+  typedef std::vector<ICaloFutureClusterSelector*> Selectors ;
+
+public:
+
+  /** "select"/"preselect" method
+   *  @see ICaloFutureClusterSelector
+   *  @param  cluster pointer to calo cluster object to be selected
+   *  @return true if cluster is selected
+   */
+  bool select
+  ( const LHCb::CaloCluster* cluster ) const  override;
+
+  /** "select"/"preselect" method (functor interface)
+   *  @see ICaloFutureClusterSelector
+   *  @param  cluster pointer to calo cluster object to be selected
+   *  @return true if cluster is selected
+   */
+  bool operator ()
+    ( const LHCb::CaloCluster* cluster ) const  override;
+
+  /** standard initialization of the tool
+   *  @see IAlgTool
+   *  @see AlgTool
+   *  @see GaudiTool
+   *  @return status code
+   */
+  StatusCode initialize() override;
+
+  /** standard finalization  of the tool
+   *  @see IAlgTool
+   *  @see AlgTool
+   *  @see GaudiTool
+   *  @return status code
+   */
+  StatusCode finalize() override;
+
+  /** Standard constructor
+   *  @see GaudiTool
+   *  @see  AlgTool
+   *  @see IAlgTool
+   *  @param type   tool type (?)
+   *  @param name   tool name
+   *  @param parent tool parent
+   */
+  CaloFutureSelectorOR
+  ( const std::string& type,
+    const std::string& name,
+    const IInterface* parent);
+
+private:
+
+  ///   default  constructor  is  private
+  CaloFutureSelectorOR();
+  ///   copy     constructor  is  private
+  CaloFutureSelectorOR
+  (const CaloFutureSelectorOR& );
+  ///   assignement operator  is  private
+  CaloFutureSelectorOR& operator=
+  (const CaloFutureSelectorOR& );
+
+private:
+
+  Gaudi::Property<Names> m_selectorsTypeNames {this, "SelectorTools"};
+  Selectors m_selectors;
+
+};
+
+// ============================================================================
+// The END
+// ============================================================================
+#endif // CALOFUTURERECO_CALOFUTURESELECTOROR_H
+// ============================================================================
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureSharedCellAlg.cpp b/CaloFuture/CaloFutureReco/src/CaloFutureSharedCellAlg.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e55adfe5e9d6167e2cb5875e83b024fe0632cb9c
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureSharedCellAlg.cpp
@@ -0,0 +1,174 @@
+// ===========================================================================
+// Include files
+// from GaudiKernel
+#include "GaudiKernel/MsgStream.h" 
+// CaloFutureGen 
+#include "CaloKernel/CaloException.h"
+//LHCb Kernel
+#include "GaudiKernel/SystemOfUnits.h"
+// CaloFutureEvent 
+#include "Event/CaloCluster.h"
+#include "Event/CaloDigit.h"
+// CaloFutureUtils
+#include "CaloFutureUtils/Digit2ClustersConnector.h"
+#include "CaloFutureUtils/ClusterFunctors.h"
+#include "CaloFutureUtils/SharedCells.h"
+#include "CaloFutureUtils/CaloFutureAlgUtils.h"
+// local
+#include "CaloFutureSharedCellAlg.h"
+
+// ============================================================================
+/** @file CaloFutureSharedCellAlg.cpp
+ * 
+ *  Implementation file for class : CaloFutureSharedCellAlg
+ *
+ *  @see CaloFutureSharedCellAlg
+ *  @see Digit2ClustersConnector 
+ *  @see SharedCells 
+ * 
+ *  @author Vanya Belyaev Ivan.Belyaev@itep.ru
+ *  @date 30/06/2001 
+ */
+// ============================================================================
+
+DECLARE_COMPONENT( CaloFutureSharedCellAlg )
+
+// ============================================================================
+// Standard creator, initializes variables
+// ============================================================================
+CaloFutureSharedCellAlg::CaloFutureSharedCellAlg( const std::string& name,
+                                      ISvcLocator* pSvcLocator)
+  : GaudiAlgorithm ( name , pSvcLocator )
+{
+  // set default data as a function of detector
+  m_detData= LHCb::CaloFutureAlgUtils::DeCaloFutureLocation( name ) ;
+  m_inputData = LHCb::CaloFutureAlgUtils::CaloFutureClusterLocation( name , context() );
+}
+
+// ============================================================================
+// Initialisation. Check parameters
+// ============================================================================
+StatusCode CaloFutureSharedCellAlg::initialize() 
+{
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) debug() << "==> Initialise" << endmsg;
+  ///
+  StatusCode sc = GaudiAlgorithm::initialize();
+  ///
+  if( sc.isFailure() ) 
+    { return Error("could not initialize base class GaudiAlgorithm!");}
+  
+  /// copy mode ? 
+  m_copy = (!m_outputData.empty()) && (m_outputData.value() != m_inputData.value());
+
+  counterStat = tool<IFutureCounterLevel>("FutureCounterLevel");
+  return StatusCode::SUCCESS;
+}
+
+// ============================================================================
+// Main execution
+// ============================================================================
+StatusCode CaloFutureSharedCellAlg::execute() 
+{
+  // avoid long names
+  using namespace SharedCells     ;
+  using namespace LHCb::CaloDigitStatus ;
+  
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) debug() << "==> Execute" << endmsg;
+  //
+
+  // useful typedefs
+  typedef LHCb::CaloClusters        Clusters ;
+  typedef const DeCalorimeter Detector ;
+  
+  // locate input data
+  Clusters* clusters = get<Clusters>( m_inputData );
+  if( 0 == clusters ) { return StatusCode::FAILURE ; }
+  
+  // locate geometry (if needed) 
+  Detector* detector = 0;
+  if( m_useDistance )
+  {    
+    detector = getDet<DeCalorimeter> ( m_detData );
+    if( 0 == detector ){ return StatusCode::FAILURE ;}
+  }
+  
+  Clusters* output = 0;
+  if( m_copy ) ///< make a new container 
+  {
+    output = new Clusters();
+    put( output , m_outputData );
+    // make a copy 
+    for ( const LHCb::CaloCluster* i : *clusters )
+    { if( i ) { output->insert( new LHCb::CaloCluster{ *i }); } }
+  }
+  else { output = clusters; } ///< update existing sequence
+  
+  /** build inverse connection table/object 
+   *  keep only digits which have connections 
+   *   with 2 clusters and more!
+   */
+  const unsigned int cutOff = 2 ;
+  typedef Digit2ClustersConnector   Table;
+  Table  table;
+  StatusCode scc = table.load( output->begin() , output->end  () , cutOff ) ;
+  if(scc.isFailure())warning()<<"Unable to load the table"<<endmsg;
+  
+  // sort digit by energy in order the subsequent processing is pointer address independent !
+  std::vector<const LHCb::CaloDigit*> reOrder;
+  for( Table::Map::iterator entry = table.map().begin() ; table.map().end() != entry ; ++entry ){
+    const LHCb::CaloDigit* dig = entry->first ;
+    reOrder.push_back( dig );
+  }
+  std::stable_sort( reOrder.begin(), reOrder.end  () ,LHCb::CaloDataFunctor::inverse( LHCb::CaloDataFunctor::Less_by_Energy ) ) ;
+  
+
+  /// loop over all digits in the table  
+  for( std::vector<const LHCb::CaloDigit*>::const_iterator idig = reOrder.begin() ; reOrder.end() != idig ; ++idig ){    
+    Table::Map::iterator entry = table.map().find( *idig );
+    if( entry == table.map().end() ) continue;
+    const LHCb::CaloDigit* dig = entry->first ;
+    /// ignore  artificial zeros  
+    if( 0 == dig ) { continue; }
+    
+    StatusCode sc = StatusCode::SUCCESS; 
+    if      ( m_useSumEnergy &&  !m_useDistance ){    
+      sc = summedEnergyAlgorithm ( entry->second   , m_numIterations  ) ; // do not apply weights at this stage 
+    }
+    else if ( !m_useSumEnergy && !m_useDistance ){ 
+      sc = seedEnergyAlgorithm( entry->second   , SeedCell ) ; 
+    }
+    else if ( m_useSumEnergy &&   m_useDistance ){ 
+      sc = summedDistanceAlgorithm( entry->second   , 
+                                    detector        ,
+                                    dig->cellID()   , 
+                                    m_showerSizes   ,
+                                    m_numIterations  ) ; 
+    }
+    else if ( !m_useSumEnergy &&  m_useDistance ){ 
+      sc = seedDistanceAlgorithm( entry->second   ,
+                                  detector        ,
+                                  SeedCell        ,
+                                  dig->cellID()   ,
+                                  m_showerSizes                    ) ;
+    }
+    else { return Error("Funny condition :-)) "); }
+    ///
+    if( sc.isFailure() ){ return Error("Could not redistribute the energy!"); }
+  }
+  
+
+  if(counterStat->isQuiet())counter ( "#Clusters from '" + m_inputData +"'") += clusters->size() ;
+  
+  ///
+  return StatusCode::SUCCESS;
+  ///  
+}
+
+StatusCode CaloFutureSharedCellAlg::finalize() {
+
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) debug() << "==> Finalize" << endmsg;
+
+  return GaudiAlgorithm::finalize();  // must be called after all other actions
+}
+
+
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureSharedCellAlg.h b/CaloFuture/CaloFutureReco/src/CaloFutureSharedCellAlg.h
new file mode 100644
index 0000000000000000000000000000000000000000..604a6797b4fecf4e4a6eb7d1af9a89a3b5f77129
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureSharedCellAlg.h
@@ -0,0 +1,87 @@
+#ifndef CALOFUTURERECO_CALOFUTURESHAREDCELLALG_H
+#define CALOFUTURERECO_CALOFUTURESHAREDCELLALG_H 1
+// ============================================================================
+// Include files
+// CaloDet
+#include "CaloDet/DeCalorimeter.h"
+// CaloFutureEvent/Event
+#include "Event/CaloCluster.h"
+// from GaudiAlg
+#include "GaudiAlg/GaudiAlgorithm.h"
+#include "CaloFutureInterfaces/IFutureCounterLevel.h"
+
+/** @class  CaloFutureSharedCellAlg CaloFutureSharedCellAlg.h
+ *
+ *  A very simple algorithm, which performs the
+ *  energy redistribution
+ *  between shared cells
+ *
+ *  @author Ivan Belyaev
+ *  @date   30/06/2001
+ */
+
+class CaloFutureSharedCellAlg : public GaudiAlgorithm
+{
+public:
+
+  /** standard initialization method
+   *  @see CaloFutureAlgorithm
+   *  @see     Algorithm
+   *  @see    IAlgorithm
+   *  @return status code
+   */
+  StatusCode initialize() override;
+  StatusCode finalize() override;
+
+  /** standard execution method
+   *  @see CaloFutureAlgorithm
+   *  @see     Algorithm
+   *  @see    IAlgorithm
+   *  @return status code
+   */
+  StatusCode execute() override;
+
+  /**  Standard constructor
+   *   @param name           name of the algorithm
+   *   @param pSvcLocator    poinetr to Service Locator
+   */
+  CaloFutureSharedCellAlg
+  ( const std::string& name        ,
+    ISvcLocator*       pSvcLocator );
+
+private:
+
+  bool m_copy = true; ///< copy flag
+
+  Gaudi::Property<bool> m_useSumEnergy
+    {this, "ShareSumEnergy", true,
+    "should one use the summed cluster energy or central cell energy?"};
+
+  Gaudi::Property<int> m_numIterations
+    {this, "Iterations", 5,
+    "number of iterations iif one use summed cluster energy"};
+
+  Gaudi::Property<bool> m_useDistance
+    {this, "ShareDistance", false,
+    "should one take into account the the distance?"};
+
+  Gaudi::Property<std::vector<double>> m_showerSizes
+    {this, "ShowerSizes", {
+      0.1090 * 121.50 * Gaudi::Units::mm,
+      0.1326 *  60.75 * Gaudi::Units::mm,
+      0.1462 *  40.50 * Gaudi::Units::mm,
+    }, "shower size parameters (for different areas)"};
+
+  Gaudi::Property<std::string> m_inputData
+    {this, "InputData", LHCb::CaloClusterLocation::Ecal};
+
+  Gaudi::Property<std::string> m_outputData
+    {this, "OutputData"};
+
+  Gaudi::Property<std::string> m_detData
+    {this, "Detector", DeCalorimeterLocation::Ecal};
+
+  IFutureCounterLevel* counterStat = nullptr;
+};
+// ============================================================================
+#endif // CALOFUTURESHAREDCELLALG_H
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureShowerOverlap.cpp b/CaloFuture/CaloFutureReco/src/CaloFutureShowerOverlap.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..54c20f464c6610e50c9e42a6989ee363342f73fc
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureShowerOverlap.cpp
@@ -0,0 +1,99 @@
+// Include files
+
+ // from Gaudi
+#include "CaloFutureUtils/CaloFutureAlgUtils.h"
+// local
+#include "CaloFutureShowerOverlap.h"
+
+//-----------------------------------------------------------------------------
+// Implementation file for class : CaloFutureShowerOverlap
+//
+// 2014-06-02 : Olivier Deschamps
+//-----------------------------------------------------------------------------
+
+// Declaration of the Algorithm Factory
+DECLARE_COMPONENT( CaloFutureShowerOverlap )
+
+
+//=============================================================================
+// Standard constructor, initializes variables
+//=============================================================================
+CaloFutureShowerOverlap::CaloFutureShowerOverlap( const std::string& name,
+                                      ISvcLocator* pSvcLocator)
+: GaudiAlgorithm ( name , pSvcLocator )
+{
+  m_input = LHCb::CaloFutureAlgUtils::CaloFutureClusterLocation( name , context() );
+  m_det   = LHCb::CaloFutureAlgUtils::DeCaloFutureLocation( name ) ;
+}
+
+//=============================================================================
+// Initialization
+//=============================================================================
+StatusCode CaloFutureShowerOverlap::initialize() {
+  StatusCode sc = GaudiAlgorithm::initialize(); // must be executed first
+  if ( sc.isFailure() ) return sc;  // error printed already by GaudiAlgorithm
+
+  if ( msgLevel(MSG::DEBUG) ) debug() << "==> Initialize" << endmsg;
+
+  m_oTool   = tool<ICaloFutureShowerOverlapTool>("CaloFutureShowerOverlapTool","PhotonShowerOverlap",this);
+  m_tagger  = tool<FutureSubClusterSelectorTool>( "FutureSubClusterSelectorTool" , "EcalClusterTag" , this );
+
+  m_detector  = getDet<DeCalorimeter> ( m_det );
+  return StatusCode::SUCCESS;
+}
+
+//=============================================================================
+// Main execution
+//=============================================================================
+StatusCode CaloFutureShowerOverlap::execute() {
+
+  if ( UNLIKELY(msgLevel(MSG::DEBUG) ) )debug() << "==> Execute" << endmsg;
+  LHCb::CaloDataFunctor::EnergyTransverse<const DeCalorimeter*> eT(m_detector);
+
+  // locate data
+  LHCb::CaloClusters* clusters = get<LHCb::CaloClusters>( m_input );
+  if( 0 == clusters ) { return StatusCode::FAILURE ; }
+
+  LHCb::CaloDigits* spds = getIfExists<LHCb::CaloDigits>( LHCb::CaloDigitLocation::Spd );
+
+  for( LHCb::CaloClusters::iterator i1 = clusters->begin() ; clusters->end() != i1 ; ++i1 ){
+    double et1 = eT( *i1 );
+    if( et1 < m_etMin )continue; // neglect overlap from/to low ET clusters
+    const LHCb::CaloCellID id1=(*i1)->seed();
+    const LHCb::CaloDigit* spd1 = (spds == NULL) ? NULL : spds->object( (*i1)->seed() );
+    for( LHCb::CaloClusters::iterator i2 = i1+1 ; clusters->end() != i2 ; ++i2 ){
+      double et2=eT( *i2 );
+      if(  et2 < m_etMin )continue; // neglect overlap from/to low ET clusters
+      if(  et1 < m_etMin2 && et2 < m_etMin2 )continue; // require at least one cluster above threshold (speed-up)
+      const LHCb::CaloCellID id2=(*i2)->seed();
+      if( id1.area() != id2.area() ) continue;
+      if( abs( int(id1.col()) - int(id2.col()) ) > m_dMin || abs( int(id1.row()) - int(id2.row()) ) > m_dMin )continue;
+      const LHCb::CaloDigit* spd2 = (spds == NULL) ? NULL : spds->object( (*i2)->seed() );
+      int  s1= (spd1 == NULL) ? 0 : int(spd1->e() > 0.) ;
+      int  s2= (spd2 == NULL) ? 0 : int(spd2->e() > 0.) ;
+
+
+      // initial weights for shared cells
+      LHCb::CaloCluster* cl1 = *i1;
+      LHCb::CaloCluster* cl2 = *i2;
+      for( LHCb::CaloCluster::Entries::iterator e1 = cl1->entries().begin() ; cl1->entries().end() != e1 ; ++e1 ){
+        for( LHCb::CaloCluster::Entries::iterator e2 = cl2->entries().begin() ; cl2->entries().end() != e2 ; ++e2 ){
+          if( e1->digit()->cellID() == e2->digit()->cellID() ){
+            const auto totE = ( cl1->e() + cl2->e() );
+            e1->setFraction( cl1->e() / totE );
+            e2->setFraction( cl2->e() / totE );
+          }
+        }
+      }
+      // tag the cluster position to have correct corrections
+      const StatusCode sc = StatusCode{ m_tagger->tagPosition(  cl1  ) &&
+                                        m_tagger->tagPosition(  cl2  ) };
+      if( sc.isFailure() )Warning("Cluster tagging failed - keep the initial 3x3 tagging").ignore();
+      // correct entry weight for shower overlap (assuming EM cluster)
+      m_oTool->process(*i1,*i2, s1*10+s2, m_iter);
+    }
+  }
+  return StatusCode::SUCCESS;
+}
+
+//=============================================================================
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureShowerOverlap.h b/CaloFuture/CaloFutureReco/src/CaloFutureShowerOverlap.h
new file mode 100644
index 0000000000000000000000000000000000000000..5178b641b8d67aec777b0c370a871741e1823943
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureShowerOverlap.h
@@ -0,0 +1,50 @@
+#ifndef CALOFUTURESHOWEROVERLAP_H 
+#define CALOFUTURESHOWEROVERLAP_H 1
+
+// Include files 
+// from Gaudi
+#include "GaudiAlg/GaudiAlgorithm.h"
+#include "Event/CaloDataFunctor.h"
+#include "Event/CellID.h"
+#include "FutureSubClusterSelectorTool.h"
+#include "CaloDet/DeCalorimeter.h"
+#include "CaloFutureInterfaces/ICaloFutureShowerOverlapTool.h"
+#include "Event/CaloCluster.h"
+
+/** @class CaloFutureShowerOverlap CaloFutureShowerOverlap.h
+ *  
+ *
+ *  @author Olivier Deschamps
+ *  @date   2014-06-02
+ */
+class CaloFutureShowerOverlap : public GaudiAlgorithm 
+{
+
+public: 
+
+  /// Standard constructor
+  CaloFutureShowerOverlap( const std::string& name, ISvcLocator* pSvcLocator );
+
+  StatusCode initialize() override;    ///< Algorithm initialization
+  StatusCode execute() override;    ///< Algorithm execution
+
+private:
+
+  Gaudi::Property<int>   m_dMin   {this, "DistanceThreshold", 4};
+  Gaudi::Property<float> m_etMin  {this, "MinEtThreshold", 50., "( ET1 > x && ET2 > x)"};
+  Gaudi::Property<float> m_etMin2 {this, "MaxEtThreshold", 150., "( ET2 > y || ET2 > y)"};
+  Gaudi::Property<int>   m_iter   {this, "Iterations", 5};
+  Gaudi::Property<std::string> m_input {this, "InputData", LHCb::CaloClusterLocation::Ecal};
+  Gaudi::Property<std::string> m_det   {this, "Detector" , DeCalorimeterLocation::Ecal};
+  
+  // following properties are inherited by the selector tool when defined :
+  Gaudi::Property<std::vector<std::string>> m_taggerP {this, "PositionTags"};
+  Gaudi::Property<std::vector<std::string>> m_taggerE {this, "EnergyTags"};
+  
+  const DeCalorimeter*    m_detector = nullptr ;
+  ICaloFutureShowerOverlapTool* m_oTool    = nullptr ;
+  FutureSubClusterSelectorTool* m_tagger   = nullptr ;
+
+};
+
+#endif // CALOFUTURESHOWEROVERLAP_H
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureShowerOverlapTool.cpp b/CaloFuture/CaloFutureReco/src/CaloFutureShowerOverlapTool.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..afec30f4a49ebd61ff9effc496a56e882cbefc4f
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureShowerOverlapTool.cpp
@@ -0,0 +1,302 @@
+// Include files
+
+#include "CaloFutureUtils/CaloFutureAlgUtils.h"
+#include "Event/CaloDataFunctor.h"
+#include "CaloDet/DeCalorimeter.h"
+#include "CaloFutureUtils/CaloMomentum.h"
+
+// local
+#include "CaloFutureShowerOverlapTool.h"
+
+//-----------------------------------------------------------------------------
+// Implementation file for class : CaloFutureShowerOverlapTool
+//
+// 2014-06-02 : Olivier Deschamps
+//-----------------------------------------------------------------------------
+
+// Declaration of the Tool Factory
+DECLARE_COMPONENT( CaloFutureShowerOverlapTool )
+
+
+//=============================================================================
+// Standard constructor, initializes variables
+//=============================================================================
+CaloFutureShowerOverlapTool::CaloFutureShowerOverlapTool( const std::string& type,
+                                              const std::string& name,
+                                              const IInterface* parent )
+: GaudiTool ( type, name , parent )
+{
+  declareInterface<ICaloFutureShowerOverlapTool>(this);
+
+  // define type from instance name
+  const std::string uName ( LHCb::CaloFutureAlgUtils::toUpper( name ) ) ;
+  if ( uName.find( "MERGED" )  != std::string::npos   ||  uName.find( "SPLITPHOTON" )  != std::string::npos )m_type = "SplitPhoton";
+  else if (  uName.find( "PHOTON" ) )m_type="Photon";
+  else   m_type="Photon"; // the default
+}
+
+//=============================================================================
+
+StatusCode CaloFutureShowerOverlapTool::initialize() {
+  StatusCode sc = GaudiTool::initialize(); // must be executed first
+  if ( sc.isFailure() ) return sc;  // error printed already by GaudiAlgorithm
+  if ( UNLIKELY(msgLevel(MSG::DEBUG)) ) debug() << "==> Initialize" << endmsg;
+  m_det = getDet<DeCalorimeter> ( m_detLoc );
+
+  m_shape = tool<CaloFutureCorrectionBase>("CaloFutureCorrectionBase","ShowerProfile",this);
+  m_stool = tool<ICaloFutureHypoTool>("CaloFutureSCorrection",m_type+"SCorrection",this);
+  m_ltool = tool<ICaloFutureHypoTool>("CaloFutureLCorrection",m_type+"LCorrection",this);
+  counterStat = tool<IFutureCounterLevel>("FutureCounterLevel");
+  sc = setProfile(m_pcond);
+  return sc;
+}
+
+//=============================================================================
+
+StatusCode CaloFutureShowerOverlapTool::setProfile(std::string prof){
+  m_pcond=prof;
+  StatusCode sc = m_shape->setConditionParams(m_pcond,true);
+  return sc;
+}
+
+void CaloFutureShowerOverlapTool::storeInitialWeights(const LHCb::CaloCluster* cl1,const LHCb::CaloCluster* cl2){
+  m_weights.clear();
+  std::map<LHCb::CaloCellID,double> weights;
+  for( const auto& i1 : cl1->entries() ) {
+    weights[i1.digit()->cellID()]=i1.fraction();
+    //info() << " part1 " << i1.digit()->cellID() << " : " << i1.fraction() << endmsg;
+  }
+  for( const auto& i2 : cl2->entries()) {
+    LHCb::CaloCellID id2=i2.digit()->cellID();
+    auto it = weights.find(id2);
+    //info() << " part2 " << i2.digit()->cellID() << " : " << i2.fraction() << endmsg;
+    if( it == weights.end() ) weights[ id2 ]=i2.fraction();
+    else{
+      it->second += i2.fraction();
+    }
+  }
+  // check
+  for( const auto& it : weights ) {
+    if( it.second == 1.) continue;
+    m_weights[it.first]=it.second;
+    //info() << "storing weight " << it.first << " : " << it.second << endmsg;
+  }
+  //info() << " Stored weights " << m_weights.size() << endmsg;
+}
+
+double CaloFutureShowerOverlapTool::getInitialWeight(const LHCb::CaloCellID id){
+  if( m_weights.empty() ) return 1.;
+  auto it = m_weights.find(id);
+  return it != m_weights.end() ? it->second : 1. ;
+}
+
+
+
+void CaloFutureShowerOverlapTool::process(const LHCb::CaloCluster* cl1 , const LHCb::CaloCluster* cl2 ,
+                                    int spd, int niter,bool propagateInitialWeights){
+
+  if( cl1->entries().size() < m_minSize || cl2->entries().size() < m_minSize ){
+    if(counterStat->isQuiet())counter("Overlap correction skipped due to cluster size") += 1;
+    return;  // skip small clusters
+  }
+
+  m_a1=cl1->seed().area();
+  m_a2=cl2->seed().area();
+  m_s1= spd  /  10 ;
+  m_s2= spd  %  10 ;
+
+  m_weights.clear(); // clear initial weights
+  if( propagateInitialWeights )storeInitialWeights(cl1,cl2);
+
+  // 0 - evaluate parameters (applying photon hypo corrections for the position)
+  LHCb::CaloCluster* w1 = (LHCb::CaloCluster*) cl1;
+  LHCb::CaloCluster* w2 = (LHCb::CaloCluster*) cl2;
+  evaluate(w1);
+  evaluate(w2);
+
+  if( w1->e() <= 0. || w2->e() <= 0){
+    if(counterStat->isQuiet())counter("Overlap correction skipped due to cluster energy") += 1;
+    return;
+  }
+
+  if( m_verbose ){
+    info() << " ======== Shower Overlap =======" << endmsg;
+    info() << " CL1/CL2 : " << cl1->e() << " " << cl2->e() << " " << cl1->e()+cl2->e()<< endmsg;
+    info() << " seed    : " << cl1->seed()  << " " << cl2->seed() << endmsg;
+    info() << " area    : " << m_a1  << " " << m_a2 << endmsg;
+    info() << " Spd     : " << spd << " " << m_s1  << " " << m_s2 << endmsg;
+    info() << " params  : " << cl1->position().parameters() << " / " <<   cl2->position().parameters() << endmsg;
+  }
+
+  int iter = 0;
+
+  // 1 - determine the energy fractions of each entry
+  while( iter < niter ){
+
+    if( m_verbose )info() << " ------ iter = " << iter << endmsg;
+
+    subtract(w1,w2,propagateInitialWeights);
+
+    if( m_verbose )info() << " >> CL1/CL2 : " << w1->e() << " " << w2->e() << "  " << w1->e() + w2->e() << endmsg;
+    if( m_verbose )info() << " >> params  : " << w1->position().parameters() << " / " <<   w2->position().parameters() << endmsg;
+    //
+    if( m_verbose ){
+      LHCb::CaloMomentum momentum;
+      momentum.addCaloPosition(w1);
+      momentum.addCaloPosition(w2);
+      //info() << " >> Mass : "  << momentum.mass() << endmsg;
+    }
+
+    iter++;
+  }
+  // 3 - reset cluster-like parameters
+  evaluate(w1,false);
+  evaluate(w2,false);
+
+}
+
+
+double CaloFutureShowerOverlapTool::fraction(LHCb::CaloCluster* cluster, LHCb::CaloDigit* digit,int flag){
+
+  if( digit == NULL)return 1.;
+  const LHCb::CaloCellID cellID=digit->cellID();
+
+
+  double size  = m_det->cellSize( cellID ) ;
+  double xd    = m_det->cellX   ( cellID ) ;
+  double yd    = m_det->cellY   ( cellID ) ;
+  double xc = cluster->position().parameters()(  LHCb::CaloPosition::Index::X );
+  double yc = cluster->position().parameters()(  LHCb::CaloPosition::Index::Y );
+  double zc = cluster->position().z();
+  double zd = (xc*xc + yc*yc + zc*zc - xc*xd - yc* yd )/zc;
+  double d3d = std::sqrt( (xd - xc)*(xd - xc ) +
+                          (yd - yc)*(yd - yc ) +
+                          (zd - zc)*(zd - zc ) )/size;
+  int area = (flag == 1) ? m_a1 : m_a2;
+  int spd  = (flag == 1) ? m_s1 : m_s2;
+  double f = showerFraction( d3d, area, spd );
+  double ed = digit->e();
+  double ec = f * cluster->position().parameters()( LHCb::CaloPosition::Index::E );
+  double frac= (ed > ec ) ?  (ed - ec )/ ed : 0.;
+
+  // info() << "        --> Digit : " << cellID << "  fraction : " << frac << endmsg;
+  return frac;
+}
+
+
+
+void CaloFutureShowerOverlapTool::subtract(LHCb::CaloCluster* cl1, LHCb::CaloCluster* cl2,bool propagateInitialWeight){
+
+  // cluster1  -> cluster2 spillover
+  //info() << "     --- 1st cluster overlap ----- " << cl1->seed() <<  endmsg;
+  for( auto& i2 : cl2->entries() ) {
+    if( (LHCb::CaloDigitStatus::UseForEnergy & i2.status())==0 &&
+        (LHCb::CaloDigitStatus::UseForPosition & i2.status())==0 )continue;
+    double initialWeight = propagateInitialWeight ? getInitialWeight( i2.digit()->cellID() ) : 1.;
+    i2.setFraction( fraction( cl1,  i2.digit() , 1)*initialWeight );
+    //info() << "cl1 -> 2 : " << i2.digit()->cellID() << "  " << i2.digit()->e() << " " << i2.fraction() << endmsg;
+  }
+
+  // re-evaluate cluster2 accordingly
+  evaluate(cl2);
+  if( cl2->e() < 0)return; // skip negative energy "clusters"
+
+  //info() << "     --- 2nd cluster overlap ----- " << cl2->seed() << endmsg;
+  // cluster2  -> cluster1 spillover
+  for( auto& i1 : cl1->entries() ) {
+    const LHCb::CaloDigit* dig1 = i1.digit();
+    if( (LHCb::CaloDigitStatus::UseForEnergy & i1.status()) ==0 &&
+        (LHCb::CaloDigitStatus::UseForPosition & i1.status())==0 )continue;
+    double initialWeight = propagateInitialWeight ? getInitialWeight( i1.digit()->cellID() ) : 1.;
+    i1.setFraction( fraction( cl2, i1.digit() , 2)*initialWeight );
+    //info() << "cl2 -> 1 : " << i1.digit()->cellID() << "  " << i1.digit()->e() << " " << i1.fraction() << endmsg;
+    double eps = 1.e-4;
+    // normalize the sum of partial weights in case of  shared cells
+    for( auto& i2 : cl2->entries()) {
+      const LHCb::CaloDigit* dig2 = i2.digit();
+      if( !(dig2->cellID() == dig1->cellID()) )continue;
+      if( (LHCb::CaloDigitStatus::UseForEnergy & i2.status())==0 &&
+           (LHCb::CaloDigitStatus::UseForPosition & i2.status())==0 )continue;
+      double f1 = i1.fraction();
+      double f2 = i2.fraction();
+      double sum = f1 + f2 ;
+      if( fabs( sum - initialWeight) > eps ){
+        if( sum < initialWeight && f2 == 0. )i2.setFraction( initialWeight - f1 );
+        else if ( sum < initialWeight && f1  == 0.)i1.setFraction (initialWeight - f2);
+        else{
+          i1.setFraction( initialWeight*f1/(f1+f2) );
+          i2.setFraction( initialWeight*f2/(f1+f2) );
+        }
+        //info() << "  -> SHARED " << f1 << " -> " << i1.fraction() << " | " << f2 << " -> " << i2.fraction() << " => " << i1.fraction()+i2.fraction() << endmsg;
+      }
+    }
+  }
+
+  // reevaluate  cluster1 & 2 accordingly
+  evaluate(cl1);
+  evaluate(cl2);
+
+}
+
+double CaloFutureShowerOverlapTool::showerFraction(double d3d, unsigned int area ,int spd){
+  LHCb::CaloCellID cellID(2,area,0,0); //fake cell
+  double frac = m_shape->getCorrection( spd ? CaloFutureCorrection::profileC
+                                            : CaloFutureCorrection::profile, cellID , d3d ,0.) ;
+  return std::max( 0., std::min( frac, 1. ) );
+}
+
+void CaloFutureShowerOverlapTool::evaluate(LHCb::CaloCluster* cluster,bool hypoCorrection){
+
+
+  // 0 - reset z-position of cluster
+  LHCb::ClusterFunctors::ZPosition zPosition( m_det );
+  cluster->position().setZ( zPosition( cluster )  );
+
+  // 1 - 3x3 energy and energy-weighted barycenter
+  double E, X, Y;
+  StatusCode sc = LHCb::ClusterFunctors::calculateEXY( cluster->entries().begin() ,
+                                                       cluster->entries().end  () ,
+                                                       m_det , E , X , Y      );
+  if( sc.isSuccess() ){
+    cluster->position().parameters()( LHCb::CaloPosition::Index::E ) = E ;
+    cluster->position().parameters()( LHCb::CaloPosition::Index::X ) = X ;
+    cluster->position().parameters()( LHCb::CaloPosition::Index::Y ) = Y ;
+  }
+  else{
+    if ( UNLIKELY(msgLevel(MSG::DEBUG)) ) debug() << " E,X and Y of cluster could not be evaluated " << endmsg;
+    if(counterStat->isQuiet())counter("Cluster position failed") += 1;
+    //Warning( " E,X and Y of cluster could not be evaluated!",StatusCode::SUCCESS,1).ignore();
+  }
+
+
+  if( cluster->e() < 0)return; // skip correction for negative energy "clusters"
+
+  //-------------------------------------------------------------------
+  if( !hypoCorrection ) return; // do not apply 'photon' hypo correction
+
+  // 2 - apply 'photon hypothesis' corrections
+
+  // create a fake CaloHypo
+  LHCb::CaloHypo hypo{};
+  hypo.setHypothesis ( LHCb::CaloHypo::Hypothesis::Photon );
+  hypo.addToClusters ( cluster );
+  hypo.setPosition   ( std::make_unique<LHCb::CaloPosition>(cluster->position()) );
+
+  // Apply transversal corrections
+  sc=m_stool->process(&hypo);
+  if( sc.isSuccess() ){
+    cluster->position().parameters()( LHCb::CaloPosition::Index::X ) = hypo.position()->parameters()( LHCb::CaloPosition::Index::X) ;
+    cluster->position().parameters()( LHCb::CaloPosition::Index::Y ) = hypo.position()->parameters()( LHCb::CaloPosition::Index::Y) ;
+  }else
+    Error(" SCorrection could not be evaluated!",sc,1).ignore();
+
+  // Apply longitudinal correction
+  sc=m_ltool->process(&hypo);
+  if( sc.isSuccess() ){
+    cluster->position().setZ( hypo.position()->z() );
+  }  else
+    Error(" LCorrection could not be evaluated!",sc,1).ignore();
+
+}
+
+
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureShowerOverlapTool.h b/CaloFuture/CaloFutureReco/src/CaloFutureShowerOverlapTool.h
new file mode 100644
index 0000000000000000000000000000000000000000..d301bebdf730b20b360879071d28c22bfa5bbf93
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureShowerOverlapTool.h
@@ -0,0 +1,58 @@
+#ifndef CALOFUTURESHOWEROVERLAPTOOL_H
+#define CALOFUTURESHOWEROVERLAPTOOL_H 1
+
+// Include files
+// from Gaudi
+#include "GaudiAlg/GaudiTool.h"
+#include "CaloDet/DeCalorimeter.h"
+#include "Event/CaloCluster.h"
+#include "CaloFutureCorrectionBase.h"
+#include "CaloFutureInterfaces/ICaloFutureHypoTool.h"
+#include "CaloFutureInterfaces/ICaloFutureShowerOverlapTool.h"            // Interface
+#include "CaloFutureInterfaces/IFutureCounterLevel.h"
+
+
+/** @class CaloFutureShowerOverlapTool CaloFutureShowerOverlapTool.h
+ *
+ *
+ *  @author Olivier Deschamps
+ *  @date   2014-06-02
+ */
+class CaloFutureShowerOverlapTool : public GaudiTool, virtual public ICaloFutureShowerOverlapTool {
+public:
+  /// Standard constructor
+  CaloFutureShowerOverlapTool( const std::string& type,
+                         const std::string& name,
+                         const IInterface* parent);
+
+  StatusCode initialize() override;
+
+  StatusCode setProfile(std::string) override;
+  void process(const LHCb::CaloCluster* c1, const LHCb::CaloCluster* c2,
+               int spd=0, int niter=10,bool propagateInitialWeights=false) override;
+
+protected:
+  void storeInitialWeights(const LHCb::CaloCluster* cl1,const LHCb::CaloCluster* cl2);
+  double getInitialWeight(const LHCb::CaloCellID id);
+  double fraction(LHCb::CaloCluster* c, LHCb::CaloDigit* d,int flag);
+  void subtract(LHCb::CaloCluster* c1,LHCb::CaloCluster* c2,bool propagateInitialWeights);
+  double showerFraction(double d3d,unsigned int area,int spd);
+  void evaluate(LHCb::CaloCluster* c,bool hypoCorrection = true);
+private:
+  int m_a1 = 0;
+  int m_a2 = 0;
+  int m_s1 = 0;
+  int m_s2 = 0;
+  Gaudi::Property<std::string> m_detLoc {this, "Detector", DeCalorimeterLocation::Ecal};
+  Gaudi::Property<std::string> m_pcond {this, "Profile", "Conditions/Reco/Calo/PhotonShowerProfile"};
+  std::string m_type;
+  const DeCalorimeter* m_det = nullptr;
+  ICaloFutureHypoTool*      m_stool = nullptr;
+  ICaloFutureHypoTool*      m_ltool = nullptr;
+  CaloFutureCorrectionBase* m_shape = nullptr;
+  std::map<const LHCb::CaloCellID,double> m_weights;
+  Gaudi::Property<bool> m_verbose {this, "Verbose", false};
+  Gaudi::Property<unsigned int> m_minSize {this, "ClusterMinSize", 2};
+  IFutureCounterLevel* counterStat = nullptr;
+};
+#endif // CALOFUTURESHOWEROVERLAPTOOL_H
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureSinglePhotonAlg.cpp b/CaloFuture/CaloFutureReco/src/CaloFutureSinglePhotonAlg.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e98dd8a171d9f6850834442d0f79a2b988b86f4f
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureSinglePhotonAlg.cpp
@@ -0,0 +1,156 @@
+// ============================================================================
+// Include files
+// ============================================================================
+// STD & STL
+// ============================================================================
+#include <algorithm>
+// ============================================================================
+#include "GaudiKernel/SystemOfUnits.h"
+#include "CaloFutureUtils/CaloFutureDataFunctor.h"
+#include "Event/CellID.h"
+#include "CaloFutureInterfaces/ICaloFutureClusterSelector.h"
+#include "CaloFutureInterfaces/ICaloFutureHypoTool.h"
+#include "CaloFutureUtils/CaloFutureAlgUtils.h"
+#include "CaloFutureSinglePhotonAlg.h"
+#include "CaloFutureUtils/CaloMomentum.h"
+// ============================================================================
+/** @file
+ *
+ *  Implementation file for class : CaloFutureSinglePhotonAlg
+ *  The implementation is based on F.Machefert's codes.
+ *  @see CaloFutureSinglePhotonAlg
+ *
+ *  @author Frederic Machefert machefer@in2p3.fr
+ *  @author Vanya Belyaev Ivan.Belyaev@itep.ru
+ *  @date 31/03/2002
+ */
+// ============================================================================
+namespace
+{
+template <typename Container, typename Arg, typename Parent>
+bool apply(const Container& c, Arg& arg, const char* errmsg, const Parent& parent)
+{
+  bool r = std::all_of( std::begin(c), std::end(c),
+  [&](typename Container::const_reference elem) {
+    return (*elem)(&arg).isSuccess();
+  } );
+  if (UNLIKELY(!r)) parent.Error( errmsg, StatusCode::FAILURE ).ignore();
+  return r;
+}
+}
+
+DECLARE_COMPONENT( CaloFutureSinglePhotonAlg )
+// ============================================================================
+/*  Standard constructor
+ *  @param name algorithm name
+ *  @param pSvc service locator
+ */
+// ============================================================================
+CaloFutureSinglePhotonAlg::CaloFutureSinglePhotonAlg ( const std::string& name,
+    ISvcLocator*       pSvc )
+  : ScalarTransformer( name, pSvc,
+                       KeyValue("InputData", {}), // note: context can not be used here -- only _after_ the baseclass is initialized!
+KeyValue("OutputData", {}) )
+{
+  // context() is only available _after_ the baseclass is fully initialized -- so we cannot put
+  // the 'final' default which uses it  as argument to it...
+  // bit tricky: as these are datahandles, they have multiple options.... what to do with the
+  // not specified options? -- so we 'hide' the futuredetails inside 'updateHandleLocation'
+  updateHandleLocation( *this, "InputData", LHCb::CaloFutureAlgUtils::CaloFutureClusterLocation("Ecal", context() ));
+  updateHandleLocation( *this, "OutputData", LHCb::CaloFutureAlgUtils::CaloFutureHypoLocation("Photons", context() ));
+
+  setProperty ( "PropertiesPrint", true ) ;
+}
+// ============================================================================
+/*   standard Algorithm initialization
+ *   @return status code
+ */
+// ============================================================================
+StatusCode CaloFutureSinglePhotonAlg::initialize()
+{
+  StatusCode sc = ScalarTransformer::initialize();
+  if ( sc.isFailure() ) {
+    return Error("Could not initialize the base class!", sc);
+  }
+
+  // check the geometry information
+  m_det = getDet<DeCalorimeter>( m_detData ) ;
+  if ( !m_det ) return Error("Detector information is not available!");
+
+  m_eT = LHCb::CaloDataFunctor::EnergyTransverse<const DeCalorimeter*> { m_det } ; // TODO: can we combine this into Over_Et_Threshold and make it a property??
+
+  // locate selector tools
+  std::transform( m_selectorsTypeNames.begin(), m_selectorsTypeNames.end(),
+                  std::back_inserter(m_selectors),
+  [&](const std::string & name) {
+    return this->tool<ICaloFutureClusterSelector>( name, this );
+  } );
+  if ( m_selectors.empty() )info() << "No Cluster Selection tools are specified!" << endmsg ;
+  // locate correction tools
+  std::transform( m_correctionsTypeNames.begin(), m_correctionsTypeNames.end(),
+                  std::back_inserter(m_corrections),
+  [&](const std::string & name) {
+    return this->tool<ICaloFutureHypoTool>( name, this );
+  } );
+  if ( m_corrections.empty() )info() << "No Hypo Correction tools are specified!" << endmsg ;
+  // locate other hypo tools
+  std::transform( m_hypotoolsTypeNames.begin(), m_hypotoolsTypeNames.end(),
+                  std::back_inserter(m_hypotools),
+  [&](const std::string & name) {
+    return this->tool<ICaloFutureHypoTool>( name, this );
+  } );
+  if ( m_hypotools.empty() )info() << "No Hypo Processing tools are specified!" << endmsg ;
+  ///
+  return StatusCode::SUCCESS;
+}
+
+// ============================================================================
+/*   standard Algorithm finalization
+ *   @return status code
+ */
+// ============================================================================
+StatusCode
+CaloFutureSinglePhotonAlg::finalize()
+{
+  m_selectors.clear () ;
+  m_corrections.clear () ;
+  m_hypotools.clear () ;
+  m_selectorsTypeNames.clear () ;
+  m_correctionsTypeNames.clear () ;
+  m_hypotoolsTypeNames.clear () ;
+
+  return ScalarTransformer::finalize() ;
+}
+// ============================================================================
+//   Algorithm execution
+// ============================================================================
+boost::optional<LHCb::CaloHypo>
+CaloFutureSinglePhotonAlg::operator()(const LHCb::CaloCluster& cluster) const
+{
+  // loop over all selectors
+  bool select = ( m_eT(&cluster) >= m_eTcut &&
+                  std::all_of(m_selectors.begin(), 
+                              m_selectors.end(),
+                              [&] (Selectors::const_reference sel) {
+                                return (*sel)(&cluster);
+                              }));
+  if ( !select ) return boost::none;
+
+  LHCb::CaloHypo hypo;
+
+  hypo.setHypothesis( LHCb::CaloHypo::Hypothesis::Photon );
+  hypo.addToClusters( &cluster );
+  hypo.setPosition( std::make_unique<LHCb::CaloPosition>(cluster.position()) ); //@FIXME: why not CaloPosition by (optional) value?
+
+  return boost::make_optional(
+           apply( m_hypotools, hypo, "Error from Other Hypo Tool, skip the cluster  ", *this)    && // loop over other hypo tools (e.g. add extra digits)
+           apply( m_corrections, hypo,  "Error from Correction Tool skip the cluster", *this) && // loop over all corrections and apply corrections
+           LHCb::CaloMomentum(&hypo).pt() >= m_eTcut,  // check momentum after all corrections, and insert into container pass...
+           hypo );
+}
+
+void CaloFutureSinglePhotonAlg::postprocess(const LHCb::CaloHypos& hypos) const
+{
+  if (msgLevel(MSG::DEBUG)) debug() << " # of created Photon  Hypos is  " << hypos.size()  << endmsg;
+  m_counterHypos += hypos.size();
+}
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureSinglePhotonAlg.h b/CaloFuture/CaloFutureReco/src/CaloFutureSinglePhotonAlg.h
new file mode 100644
index 0000000000000000000000000000000000000000..ce13d409f72072cf3b377df8c9d5bb88528aaf5c
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureSinglePhotonAlg.h
@@ -0,0 +1,82 @@
+// ============================================================================
+#ifndef CALOFUTUREALGS_CALOFUTURESINGLEPHOTONALG_H
+#define CALOFUTUREALGS_CALOFUTURESINGLEPHOTONALG_H 1
+// ============================================================================
+#include <string>
+#include "GaudiAlg/ScalarTransformer.h"
+#include "CaloDet/DeCalorimeter.h"
+#include "Event/CaloHypo.h"
+#include "Event/CaloCluster.h"
+#include "GaudiKernel/Counters.h"
+struct ICaloFutureClusterSelector;
+struct ICaloFutureHypoTool;
+
+/** @class CaloFutureSinglePhotonAlg CaloFutureSinglePhotonAlg.h
+ *
+ *  The simplest algorithm of reconstruction of
+ *  single photon in electromagnetic calorimeter.
+ *  The implementation is based on F.Machefert's codes.
+ *
+ *  @author Frederic Machefert machefer@in2p3.fr
+ *  @author Vanya Belyaev      Ivan.Belyaev@itep.ru
+ *  @date   31/03/2002
+ */
+
+class CaloFutureSinglePhotonAlg
+  : public Gaudi::Functional::ScalarTransformer<CaloFutureSinglePhotonAlg, LHCb::CaloHypos(const LHCb::CaloClusters&)>
+{
+public:
+  CaloFutureSinglePhotonAlg( const std::string&  name, ISvcLocator* pSvc );
+
+  StatusCode initialize () override;
+  StatusCode finalize   () override;
+
+  using ScalarTransformer::operator();
+  boost::optional<LHCb::CaloHypo> operator()(const LHCb::CaloCluster& ) const;
+  void postprocess(const LHCb::CaloHypos&) const;
+
+private:
+
+  /// container of names
+  typedef std::vector<std::string> Names;
+  /// container of selector tools
+  typedef std::vector<ICaloFutureClusterSelector*> Selectors;
+  /// containers of hypo tools
+  typedef std::vector<ICaloFutureHypoTool*> HypoTools;
+  /// container of correction tools (S-,L-,...)
+  typedef HypoTools Corrections;
+
+  Selectors m_selectors;
+  Gaudi::Property<Names> m_selectorsTypeNames {
+    this, "SelectionTools", {
+      "CaloFutureSelectCluster/PhotonCluster",
+      "CaloFutureSelectNeutralClusterWithTracks/NeutralCluster"
+    }, "List of tools for selection of clusters"};
+
+  HypoTools m_hypotools;
+  Gaudi::Property<Names> m_hypotoolsTypeNames {
+    this, "HypoTools",
+    { "CaloFutureExtraDigits/SpdPrsExtraG" },
+    "List of generic Hypo-tools to apply to newly created hypos"};
+
+  Corrections m_corrections;
+  Gaudi::Property<Names> m_correctionsTypeNames {
+    this, "CorrectionTools2", {
+      "CaloFutureECorrection/ECorrection",
+      "CaloFutureSCorrection/SCorrection",
+      "CaloFutureLCorrection/LCorrection",
+    }, "List of tools for 'fine-corrections' "};
+
+  Gaudi::Property<std::string> m_detData
+  {this, "Detector", LHCb::CaloFutureAlgUtils::DeCaloFutureLocation("Ecal")};
+
+  Gaudi::Property<double> m_eTcut
+  {this, "EtCut", 0., "Threshold on cluster & hypo ET"};
+
+  LHCb::CaloDataFunctor::EnergyTransverse<const DeCalorimeter*> m_eT { nullptr } ; // TODO: can we combine this into Over_Et_Threshold and make it a property??
+
+  const DeCalorimeter* m_det = nullptr;
+  mutable Gaudi::Accumulators::StatCounter<> m_counterHypos{this, "hyposNumber"};
+};
+// ============================================================================
+#endif // CALOFUTURESINGLEPHOTONALG_H
diff --git a/CaloFuture/CaloFutureReco/src/CelAutoTaggedCell.h b/CaloFuture/CaloFutureReco/src/CelAutoTaggedCell.h
new file mode 100644
index 0000000000000000000000000000000000000000..6e7bdcd75be782af81691c9f8adb8fd843c12099
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/CelAutoTaggedCell.h
@@ -0,0 +1,109 @@
+// ============================================================================
+#ifndef CALOFUTURECA_CELAUTOTAGGEDCEL_H
+#define CALOFUTURECA_CELAUTOTAGGEDCEL_H 1 
+// ============================================================================
+// Include files
+// ============================================================================
+// STD & STL 
+// ============================================================================
+#include <vector>
+// ============================================================================
+// Kernel
+// ============================================================================
+#include "GaudiKernel/SystemOfUnits.h"
+#include "Kernel/CaloCellID.h"
+// ============================================================================
+/** @class CelAutoTaggedCell CelAutoTaggedCell.h
+ *
+ *  Object Tagged Cell 
+ *
+ *  @author  Nicole Brun 
+ *  @date    27/02/2001
+ */
+// ============================================================================
+class CelAutoTaggedCell final
+{  
+  // ==========================================================================  
+public:
+  // ==========================================================================  
+  enum Tag
+    {
+      DefaultFlag ,
+      Clustered   ,
+      Edge        
+    };
+  
+  enum FlagState
+    {
+      NotTagged ,
+      Tagged    
+    } ;
+  // ==========================================================================
+public:
+  // ==========================================================================  
+  // Constructor
+  CelAutoTaggedCell (  )
+  {
+    m_seeds.reserve( 3 )   ;
+  }
+  // ==========================================================================  
+  // Getters 
+  const LHCb::CaloDigit*  digit () const { return m_digit              ; }
+  const LHCb::CaloCellID& cellID() const { return digit() -> cellID () ; }
+  double            e     () const { return digit() -> e      () ; }  
+  bool isEdge() const{ return ( ( Tagged == m_status ) && ( Edge == m_tag ) ); }  
+  bool isClustered() const{ return ( ( Tagged == m_status ) && ( Clustered == m_tag ) ); }  
+  const LHCb::CaloCellID&   seedForClustered() const { return m_seeds[0]; }  
+  const std::vector<LHCb::CaloCellID>& seeds() const { return m_seeds; }  
+  size_t numberSeeds() const { return m_seeds.size(); }  
+  bool isSeed() const{ return ( ( m_seeds.size() != 1 ) ? false : cellID() ==  m_seeds [0] ); }  
+  bool isWithSeed ( const LHCb::CaloCellID& seed ){ return m_seeds.end() != std::find( m_seeds.begin() , m_seeds.end() , seed );}
+  Tag tag( ) const{return m_tag;}
+  FlagState status( ) const{return m_status;}
+  // ==========================================================================
+  // Setters
+  void setIsSeed()
+  {
+    m_tag = Clustered;
+    m_status = Tagged;
+    m_seeds.push_back ( cellID() );
+  }
+  // ==========================================================================
+  void setEdge      () { m_tag = Edge  ; } 
+  void setClustered () { m_tag = Clustered ; }
+  void setStatus    () { if ( ( Edge == m_tag ) || ( Clustered == m_tag ) ) 
+  { m_status = Tagged; } }  
+  void addSeed ( const LHCb::CaloCellID& seed ) { m_seeds.push_back ( seed ); }  
+  // ==========================================================================  
+  // operator
+  CelAutoTaggedCell& operator=( const LHCb::CaloDigit* digit )
+  {
+    reset() ;
+    m_digit    = digit ;    
+    return *this ;
+  }
+  // ==========================================================================  
+protected:
+  // ==========================================================================  
+  void reset()
+  {
+    m_seeds.clear()        ; 
+    m_seeds.reserve( 3 )   ;
+    m_tag    = DefaultFlag ;
+    m_status = NotTagged   ;
+    m_digit  = nullptr     ;
+  }
+  // ==========================================================================  
+private:
+  // ==========================================================================  
+  Tag              m_tag      = DefaultFlag ;
+  FlagState        m_status   = NotTagged;
+  const LHCb::CaloDigit* m_digit = nullptr;
+  // ==========================================================================
+  // Ident.seed(s)  
+  LHCb::CaloCellID::Vector m_seeds;
+  // ==========================================================================
+};
+// ============================================================================
+#endif // CALOFUTURECA_CELAUTOTAGGEDCELL_H
+// ============================================================================
diff --git a/CaloFuture/CaloFutureReco/src/FutureCellularAutomatonAlg.cpp b/CaloFuture/CaloFutureReco/src/FutureCellularAutomatonAlg.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6930d3b2f52ee7b825ec393a48a2bb9cd6ba52e9
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/FutureCellularAutomatonAlg.cpp
@@ -0,0 +1,145 @@
+// ============================================================================
+// Include files
+// ============================================================================
+#include "GaudiAlg/FunctionalUtilities.h"
+// ============================================================================
+// DetDesc
+// ============================================================================
+#include "DetDesc/IGeometryInfo.h"
+// ============================================================================
+// Event
+// ============================================================================
+#include "Event/CaloDigit.h"
+#include "Event/CaloCluster.h"
+#include "Event/CaloDataFunctor.h"
+#include "Event/CellID.h"
+// ============================================================================
+// CaloFutureUtils
+// ============================================================================
+#include "CaloFutureUtils/ClusterFunctors.h"
+#include "CaloFutureUtils/CaloFutureAlgUtils.h"
+// ============================================================================
+// local
+// ============================================================================
+#include "FutureCellularAutomatonAlg.h"
+// ============================================================================
+/** @file
+ *  Implementation file for class : FutureCellularAutomatonAlg
+ *
+ *  @date 2008-04-03
+ *  @author Victor Egorychev
+ */
+// ============================================================================
+// Declaration of the Algorithm Factory
+// ============================================================================
+DECLARE_COMPONENT( FutureCellularAutomatonAlg )
+// ============================================================================
+// Standard constructor, initializes variables
+// ============================================================================
+FutureCellularAutomatonAlg::FutureCellularAutomatonAlg( const std::string& name,
+                                            ISvcLocator*       pSvcLocator )
+: Transformer ( name, pSvcLocator,
+                KeyValue{"InputData" , LHCb::CaloDigitLocation::Ecal },
+                KeyValue{"OutputData", LHCb::CaloClusterLocation::Ecal } )
+{
+  // set default data as a function of detector
+  m_detData = LHCb::CaloFutureAlgUtils::DeCaloFutureLocation( name ) ;
+
+  updateHandleLocation(*this,"InputData" , LHCb::CaloFutureAlgUtils::CaloFutureDigitLocation  ( name , context() ));
+  updateHandleLocation(*this,"OutputData", LHCb::CaloFutureAlgUtils::CaloFutureClusterLocation( name , context() ));
+}
+
+// ============================================================================
+// Initialization
+// ============================================================================
+StatusCode FutureCellularAutomatonAlg::initialize()
+{
+  StatusCode sc = GaudiAlgorithm::initialize(); // must be executed first
+  if ( sc.isFailure() ) return sc;  // error printed already by GaudiAlgorithm
+
+  /// Retrieve geometry of detector
+  m_detector = getDet<DeCalorimeter>( m_detData );
+  if( !m_detector ) { return StatusCode::FAILURE; }
+
+  // Tool Interface
+  m_tool      = tool<ICaloFutureClusterization>(m_toolName, this);
+
+  return StatusCode::SUCCESS;
+}
+// ============================================================================
+// Main execution
+// ============================================================================
+LHCb::CaloCluster::Container
+FutureCellularAutomatonAlg::operator()(const LHCb::CaloDigits& digits) const   ///< Algorithm execution
+{
+  // Create the container of clusters
+  LHCb::CaloCluster::Container output;
+  // update the version number (needed for serialization)
+  output.setVersion( 2 ) ;
+
+  // create vector of pointers for CaloFutureCluster
+  std::vector<LHCb::CaloCluster*> clusters;
+
+  // clusterization tool which return the vector of pointers for CaloClusters
+  unsigned int stepPass;
+  if( m_neig_level> 0){
+    std::vector<LHCb::CaloCellID> seeds;
+    stepPass = m_tool->clusterize(clusters, digits, m_detector, seeds, m_neig_level) ;
+  } else{
+    stepPass = m_tool->clusterize(clusters, digits, m_detector) ;
+  }
+
+  // put to the container of clusters
+  for ( const auto& clus : clusters ) { output.insert( clus ) ; }
+
+  /** sort the sequence to simplify the comparison
+   *  with other clusterisation techniques
+   */
+  if ( m_sort )  {
+    if ( !m_sortByET ) {
+      // sorting criteria: Energy
+      // perform the sorting
+      std::stable_sort    ( clusters.begin()            ,
+                            clusters.end  ()            ,
+                            LHCb::CaloDataFunctor::inverse( LHCb::CaloDataFunctor::Less_by_Energy ) ) ;
+    } else {
+      // sorting criteria : Transverse Energy
+      LHCb::CaloDataFunctor::Less_by_TransverseEnergy<const DeCalorimeter*> Cmp ( m_detector ) ;
+      // perform the sorting
+      std::stable_sort   ( clusters.begin()            ,
+                           clusters.end  ()            ,
+                           LHCb::CaloDataFunctor::inverse( Cmp ) ) ;
+    }
+  }
+
+  // statistics
+  m_passes += stepPass;
+  m_clusters += output.size();
+
+  if (UNLIKELY( msgLevel( MSG::DEBUG) )){
+    debug() << "Built " << clusters.size() <<" cellular automaton clusters  with "
+            << stepPass << " iterations" <<endmsg;
+    debug() << " ----------------------- Cluster List : " << endmsg;
+    for(const auto& c : clusters ) {
+      debug() << " Cluster seed " << c->seed()
+              << " energy " << c->e()
+              << " #entries " << c->entries().size()
+              << endmsg;
+    }
+  }
+  return output;
+}
+// ============================================================================
+//  Finalize
+// ============================================================================
+StatusCode FutureCellularAutomatonAlg::finalize()
+{
+  info() << "Built <" << m_clusters.mean()
+         <<"> cellular automaton clusters/event  with <"
+         << m_passes.mean() << "> iterations (min,max)=(" << m_passes.min() << "," << m_passes.max() << ") on average " << endmsg;
+
+  return GaudiAlgorithm::finalize();  // must be called after all other actions
+}
+// =============================================================================
+// the END
+// =============================================================================
diff --git a/CaloFuture/CaloFutureReco/src/FutureCellularAutomatonAlg.h b/CaloFuture/CaloFutureReco/src/FutureCellularAutomatonAlg.h
new file mode 100644
index 0000000000000000000000000000000000000000..d1a6ccd828a084a1f7cf3f376a36da9a6305e733
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/FutureCellularAutomatonAlg.h
@@ -0,0 +1,45 @@
+#ifndef CELLULARAUTOMATONALG_H
+#define CELLULARAUTOMATONALG_H 1
+
+// Include files
+// from Gaudi
+#include "GaudiAlg/Transformer.h"
+#include "GaudiKernel/Counters.h"
+
+#include "CaloFutureInterfaces/ICaloFutureClusterization.h"
+
+/** @class FutureCellularAutomatonAlg FutureCellularAutomatonAlg.h
+ *
+ *
+ *  @author Victor Egorychev
+ *  @date   2008-04-03
+ */
+class FutureCellularAutomatonAlg
+: public Gaudi::Functional::Transformer<LHCb::CaloCluster::Container(const LHCb::CaloDigits&)>
+{
+
+public:
+  /// Standard constructor
+  FutureCellularAutomatonAlg( const std::string& name, ISvcLocator* pSvcLocator );
+
+  StatusCode initialize() override;    ///< Algorithm initialization
+  StatusCode finalize  () override;    ///< Algorithm finalization
+
+  LHCb::CaloCluster::Container operator()(const LHCb::CaloDigits&) const override;    ///< Algorithm execution
+
+private:
+  Gaudi::Property<std::string> m_detData {this, "Detector"  , DeCalorimeterLocation::Ecal};
+  const DeCalorimeter* m_detector = nullptr;
+
+  Gaudi::Property<bool> m_sort     {this, "Sort"    , true};
+  Gaudi::Property<bool> m_sortByET {this, "SortByET", false};
+
+  Gaudi::Property<std::string> m_toolName {this, "Tool", "CaloFutureClusterizationTool"};
+  ICaloFutureClusterization* m_tool = nullptr;
+
+  Gaudi::Property<unsigned int> m_neig_level {this, "Level", 0};
+
+  mutable Gaudi::Accumulators::StatCounter<> m_clusters{this, "# clusters"};
+  mutable Gaudi::Accumulators::StatCounter<> m_passes{this, "# clusterization passes"};
+};
+#endif // CELLULARAUTOMATONALG_H
diff --git a/CaloFuture/CaloFutureReco/src/FutureClusterCovarianceMatrixTool.cpp b/CaloFuture/CaloFutureReco/src/FutureClusterCovarianceMatrixTool.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b34a2c45b8f0074de0a5c63c0c732e42f38872de
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/FutureClusterCovarianceMatrixTool.cpp
@@ -0,0 +1,224 @@
+// ============================================================================
+// Include files
+#include "CaloDet/DeCalorimeter.h"
+#include "CaloFutureUtils/CaloFutureAlgUtils.h"
+#include "Event/CaloCluster.h"
+#include "FutureClusterCovarianceMatrixTool.h"
+
+// ============================================================================
+/** @file
+ *
+ *  Implementation file for class FutureClusterCovarianceMatrixTool
+ *
+ *  @date 02/11/2001 
+ *  @author Vanya Belyaev Ivan.Belyaev@itep.ru
+ *  modified 02/07/2014 by O. Deschamps
+ */
+// ============================================================================
+
+DECLARE_COMPONENT( FutureClusterCovarianceMatrixTool )
+
+// ============================================================================
+/** Standard constructor
+ *  @param type tool type (useless)
+ *  @param name tool name
+ *  @param parent pointer to parent object (service, algorithm or tool)  
+ */
+// ============================================================================
+FutureClusterCovarianceMatrixTool::FutureClusterCovarianceMatrixTool
+( const std::string& type   ,
+  const std::string& name   ,
+  const IInterface*  parent )
+  : GaudiTool( type , name , parent )
+{
+  // interface!
+  declareInterface<ICaloFutureClusterTool> (this);
+
+  // properties :
+  declareProperty("Parameters", m_parameters);
+
+  // set default configuration as a function of detector
+  using namespace CaloFutureCovariance;
+  m_detData    = LHCb::CaloFutureAlgUtils::DeCaloFutureLocation( name ) ;
+  std::string caloName =  LHCb::CaloFutureAlgUtils::CaloFutureNameFromAlg( name );
+  m_conditionName = "Conditions/Reco/Calo/"+caloName+"Covariance";
+
+
+  // get parameters from parent property when defined
+  ParameterProperty p("CovarianceParameters", m_parameters);
+  if( 0 != parent ){ const IProperty* prop = dynamic_cast<const IProperty*> ( parent );
+    if( 0 != prop ){
+      if( prop->getProperty( &p ).isSuccess() &&  p.value().size() != 0 ){
+        m_parameters = p.value();
+        m_useDB = false ;  // parent settings win !
+      }
+    }
+  }
+
+  // apply local parameters if not defined in parent algorithm
+  if(caloName == "Ecal"){
+    if(m_parameters.find(ParameterName[Stochastic])     ==m_parameters.end())m_parameters[ParameterName[Stochastic]]     .push_back( 0.10);
+    if(m_parameters.find(ParameterName[GainError])      ==m_parameters.end())m_parameters[ParameterName[GainError]]      .push_back( 0.01 );
+    if(m_parameters.find(ParameterName[IncoherentNoise])==m_parameters.end())m_parameters[ParameterName[IncoherentNoise]].push_back( 1.20 );
+    if(m_parameters.find(ParameterName[CoherentNoise])  ==m_parameters.end())m_parameters[ParameterName[CoherentNoise]]  .push_back( 0.30 );
+    if(m_parameters.find(ParameterName[ConstantE])      ==m_parameters.end())m_parameters[ParameterName[ConstantE]]      .push_back( 0. );
+    if(m_parameters.find(ParameterName[ConstantX])      ==m_parameters.end())m_parameters[ParameterName[ConstantX]]      .push_back( 0. );
+    if(m_parameters.find(ParameterName[ConstantY])      ==m_parameters.end())m_parameters[ParameterName[ConstantY]]      .push_back( 0. );
+  }else if( caloName == "Hcal"){
+    if(m_parameters.find(ParameterName[Stochastic])     ==m_parameters.end())m_parameters[ParameterName[Stochastic]]     .push_back( 0.70 );
+    if(m_parameters.find(ParameterName[GainError])      ==m_parameters.end())m_parameters[ParameterName[GainError]]      .push_back( 0.10 );
+    if(m_parameters.find(ParameterName[IncoherentNoise])==m_parameters.end())m_parameters[ParameterName[IncoherentNoise]].push_back( 1.20 );
+    if(m_parameters.find(ParameterName[CoherentNoise])  ==m_parameters.end())m_parameters[ParameterName[CoherentNoise]]  .push_back( 0.30 );
+    if(m_parameters.find(ParameterName[ConstantE])      ==m_parameters.end())m_parameters[ParameterName[ConstantE]]      .push_back( 0. );
+    if(m_parameters.find(ParameterName[ConstantX])      ==m_parameters.end())m_parameters[ParameterName[ConstantX]]      .push_back( 0. );
+    if(m_parameters.find(ParameterName[ConstantY])      ==m_parameters.end())m_parameters[ParameterName[ConstantY]]      .push_back( 0. );
+  }
+}
+
+//==============================================================================
+
+StatusCode FutureClusterCovarianceMatrixTool::getParamsFromOptions(){
+  m_source.clear();
+  unsigned int nareas = m_det->numberOfAreas();  
+  for(CaloFutureCovariance::ParameterMap::const_iterator imap = m_parameters.begin() ; m_parameters.end() != imap ; ++imap){
+    const std::vector<double>& pars = imap->second;
+    if( pars.size()    == 1)m_parameters[imap->first] = std::vector<double>( nareas , pars[0]   );
+    if( pars.size() != nareas )return Error("Parameters must be set for each calo area",StatusCode::FAILURE);
+  }
+  // check all expected parameters are defined
+  using namespace CaloFutureCovariance;
+  for(unsigned int index = 0 ; index < CaloFutureCovariance::Last ; ++index){
+    if( m_parameters.find(ParameterName[index]) == m_parameters.end() )
+      return Error("No default value for parameter '"+ParameterName[index]+"'", StatusCode::FAILURE);
+    m_source[index]="from options";
+  }
+  return StatusCode::SUCCESS;
+}
+
+//------
+StatusCode FutureClusterCovarianceMatrixTool::getParamsFromDB(){
+
+  unsigned int nareas = m_det->numberOfAreas();
+  // overwrite m_parameters using DB value
+  if( !m_useDB )return StatusCode::SUCCESS;
+  m_source.clear();
+  using namespace CaloFutureCovariance; 
+  ParameterMap parameters;
+  for( unsigned int area = 0 ; area < nareas ; ++area){  // loop over calo area
+    const LHCb::CaloCellID id(m_det->caloName(),area,0,0); // fake cell
+    const auto & params = m_dbAccessor->getParamVector(CaloFutureCorrection::ClusterCovariance,id);
+    if( params.size() > CaloFutureCovariance::Last )
+      Warning("Parameters vector exceeds the number of known parameters - only "
+              +Gaudi::Utils::toString(Last)+" parameters will be applied",StatusCode::SUCCESS).ignore();
+    for(unsigned int index = 0 ; index < CaloFutureCovariance::Last ; ++index){
+      if( index < params.size() ){
+        parameters[ParameterName[index]].push_back( params[index] );
+        m_source[index]="from Covariance DB";
+      }else{
+        if( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+          debug() << "Parameter '"<<ParameterName[index] << "' not found in DB - use default options value"<<endmsg;
+        if( m_parameters.find(ParameterName[index]) == m_parameters.end() )
+          return Error("No default value for parameter '"+ParameterName[ index ]+"'", StatusCode::FAILURE);
+        parameters[ParameterName[index]].push_back( m_parameters[ParameterName[index]][area] );
+        m_source[index]="from options";
+      }      
+    }
+  }
+  m_parameters=parameters;
+  if( m_parameters.size() == 0)return StatusCode::FAILURE; // no parameters set
+  return StatusCode::SUCCESS;
+}
+
+//-------
+void FutureClusterCovarianceMatrixTool::setEstimatorParams(bool init){  
+
+  // update DB parameters
+  if( !init && !m_useDB)return; // estimator setting via options :  at initialization only
+  if( !init && !m_dbAccessor-> hasConditionChanged())return; // estimator setting via DB : no need to update - condition has not changed
+  if( m_useDB && getParamsFromDB().isFailure() ){
+    Error("Failed updating the covariance parameters from DB",StatusCode::FAILURE).ignore(); // update DB parameters
+    return; // failed to update parameters from DB
+  }
+  using namespace CaloFutureCovariance;
+  m_estimator.setStochastic      ( m_parameters[ParameterName[Stochastic]]      ) ;
+  m_estimator.setGainError       ( m_parameters[ParameterName[GainError]]       ) ;
+  m_estimator.setIncoherentNoise ( m_parameters[ParameterName[IncoherentNoise]] ) ;
+  m_estimator.setCoherentNoise   ( m_parameters[ParameterName[CoherentNoise]]   ) ;
+  m_estimator.setConstantE       ( m_parameters[ParameterName[ConstantE]]       ) ;
+  m_estimator.setConstantX       ( m_parameters[ParameterName[ConstantX]]       ) ;
+  m_estimator.setConstantY       ( m_parameters[ParameterName[ConstantY]]       ) ;  
+  if(counterStat->isVerbose())counter("Parameter update") += 1;
+  //info() << "ESTIMATOR HAS BEEN UPDATED (" << m_conditionName << ") : init = " << init <<  endmsg;
+}
+
+//---------
+StatusCode FutureClusterCovarianceMatrixTool::initialize (){
+  StatusCode sc = GaudiTool::initialize ();
+  if( sc.isFailure() ){ return Error("Could not initialize the base class!") ; }
+  counterStat = tool<IFutureCounterLevel>("FutureCounterLevel");
+
+
+  // register to incident service
+  IIncidentSvc* inc = incSvc() ;
+  if ( 0 != inc )inc -> addListener  ( this , IncidentType::BeginEvent ) ;
+
+  // get detector
+  m_det = getDet<DeCalorimeter>( m_detData ) ;
+
+  // set DB accessor
+  m_dbAccessor = tool<CaloFutureCorrectionBase>("CaloFutureCorrectionBase","DBAccessor",this);
+  if( m_useDB && (m_conditionName == "" || m_dbAccessor->setConditionParams(m_conditionName,true).isFailure()) )
+    return Error("Cannot access DB",StatusCode::FAILURE);
+
+  // always set default parameters from options (will be updated by DB if requested)
+  sc= getParamsFromOptions();
+
+  // check the parameters consistency
+  for(CaloFutureCovariance::ParameterMap::const_iterator imap = m_parameters.begin() ; m_parameters.end() != imap ; ++imap){
+    std::string name = imap->first;
+    bool ok = false;
+    for(unsigned int index = 0 ; index < CaloFutureCovariance::Last ; ++index){
+      if( CaloFutureCovariance::ParameterName[index] == name ){ ok = true; break;}
+    }
+    if( !ok )return Error("Parameter type '"+name+"' is unknown",StatusCode::FAILURE);
+  }
+
+  // configure estimator (possibly from DB if requested)
+  m_estimator.setDetector( m_det ) ;
+  setEstimatorParams(true); // force initialization 
+  info()      << " Has initialized with parameters: "              << endmsg 
+              << " \t 'Detector'         = '" << m_detData.value() << "'"  << endmsg 
+    //            << " \t Estimator is          " << m_estimator       << endmsg;
+              << " \t ==  Parameters for covariance estimation ==" << endmsg;
+  using namespace CaloFutureCovariance;
+  for(unsigned int index = 0 ; index < CaloFutureCovariance::Last ; ++index){
+    info() << CaloFutureCovariance::ParameterName[index] << " \t : " 
+           << m_parameters[ParameterName[index]] 
+           << " " << ParameterUnit[index]
+           << "\t : "<< m_source[index]<<""<< endmsg;
+  }
+  return sc;
+}
+// ============================================================================
+StatusCode FutureClusterCovarianceMatrixTool::finalize   (){  
+  IIncidentSvc* inc = incSvc() ;
+  if ( 0 != inc ) { inc -> removeListener  ( this ) ; }
+  return GaudiTool::finalize ();
+}
+
+// ============================================================================
+StatusCode 
+FutureClusterCovarianceMatrixTool::operator() ( LHCb::CaloCluster* cluster ) const{
+  /// check the argument 
+  if( 0 == cluster                )return Error( "CaloCluster*   points to NULL!") ; 
+  if( 0 == m_estimator.detector() )return Error( "DeCalorimeter* points to NULL!") ; 
+  /// apply the estimator 
+  return m_estimator( cluster );
+}
+// ============================================================================
+
+StatusCode FutureClusterCovarianceMatrixTool::process ( LHCb::CaloCluster* cluster ) const { 
+  return (*this)( cluster ); 
+}
+// ============================================================================
+
diff --git a/CaloFuture/CaloFutureReco/src/FutureClusterCovarianceMatrixTool.h b/CaloFuture/CaloFutureReco/src/FutureClusterCovarianceMatrixTool.h
new file mode 100644
index 0000000000000000000000000000000000000000..848a0efd8a059a2116c1119a15d557d55a3ab5ac
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/FutureClusterCovarianceMatrixTool.h
@@ -0,0 +1,85 @@
+#ifndef CLUSTERCOVARIANCEMATRIXTOOL_H
+#define CLUSTERCOVARIANCEMATRIXTOOL_H 1
+// Include files
+#include  "GaudiAlg/GaudiTool.h"
+#include "GaudiKernel/IIncidentListener.h"
+#include "GaudiKernel/IIncidentSvc.h"
+#include "GaudiKernel/Incident.h"
+#include  "CaloFutureUtils/CovarianceEstimator.h"
+#include  "CaloFutureInterfaces/ICaloFutureClusterTool.h"
+#include  "CaloFutureInterfaces/IFutureCounterLevel.h"
+#include  "CaloFutureCorrectionBase.h"
+
+
+/** @class FutureClusterCovarianceMatrixTool
+ *         FutureClusterCovarianceMatrixTool.h
+ *
+ *  Concrete tool for calculation of covariance matrix
+ *  for the whole cluster object
+ *
+ *  @author Vanya Belyaev Ivan.Belyaev@itep.ru
+ *  @date   02/11/2001
+ */
+
+namespace CaloFutureCovariance{
+  enum Parameters{
+    Stochastic      = 0 ,  // stochastig term     Cov(EE)_i +=  [ S  * sqrt(E_i_GeV) ]^2
+    GainError       = 1 ,  // constant term       Cov(EE)_i +=  [ G  * E_i           ]^2
+    IncoherentNoise = 2 ,  // noise (inc.) term   Cov(EE)_i +=  [ iN * gain_i        ]^2
+    CoherentNoise   = 3 ,  // noise (coh.) term   Cov(EE)_i +=  [ cN * gain_i        ]^2
+    ConstantE       = 4 ,  // additional term     Cov(EE) +=  [ cE               ]^2
+    ConstantX       = 5 ,  // additional term     Cov(XX) +=  [ cX               ]^2
+    ConstantY       = 6 ,  // additional term     Cov(XX) +=  [ cY               ]^2
+    Last
+  };
+  static const int nParams=Last+1;
+  static const std::string ParameterName[nParams] = {"Stochastic","GainError","IncoherentNoise","CoherentNoise",
+                                                     "ConstantE" ,"ConstantX","ConstantY"};
+  static const std::string ParameterUnit[nParams] = {"Sqrt(GeV)" , "" , "ADC" , "ADC" , "MeV" , "mm" , "mm"};
+  typedef std::map<std::string,std::vector<double> > ParameterMap;
+  typedef SimplePropertyRef< ParameterMap >          ParameterProperty;
+}
+
+
+
+
+class FutureClusterCovarianceMatrixTool: public virtual ICaloFutureClusterTool , public GaudiTool , virtual public IIncidentListener{
+public:
+
+  StatusCode initialize() override;
+  StatusCode finalize() override;
+  StatusCode process    ( LHCb::CaloCluster* cluster ) const override;
+  StatusCode operator() ( LHCb::CaloCluster* cluster ) const override;
+
+
+  void handle(const Incident&  ) override {
+    if( UNLIKELY( msgLevel(MSG::DEBUG) ) )debug() << "IIncident Svc reset" << endmsg;
+    setEstimatorParams(); // reset estimator when parameters change
+  }
+
+
+protected:
+
+  StatusCode getParamsFromOptions();
+  StatusCode getParamsFromDB();
+  void setEstimatorParams(bool init=false);
+
+public:
+  FutureClusterCovarianceMatrixTool( const std::string& type   ,
+                               const std::string& name   ,
+                               const IInterface*  parent );
+
+private:
+
+  CovarianceEstimator     m_estimator ;
+  CaloFutureCovariance::ParameterMap m_parameters;
+  Gaudi::Property<std::string> m_detData {this, "Detector"};
+  const DeCalorimeter* m_det        = nullptr;
+  Gaudi::Property<bool> m_useDB {this, "UseDBParameters", true};
+  CaloFutureCorrectionBase*  m_dbAccessor = nullptr;
+  Gaudi::Property<std::string> m_conditionName {this, "ConditionName"};
+  std::map<unsigned int,std::string> m_source;
+  IFutureCounterLevel* counterStat = nullptr;
+}; ///< end of class FutureClusterCovarianceMatrixTool
+// ============================================================================
+#endif // CLUSTERCOVARIANCEMATRIXTOOL_H
diff --git a/CaloFuture/CaloFutureReco/src/FutureClusterSpreadTool.cpp b/CaloFuture/CaloFutureReco/src/FutureClusterSpreadTool.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f6b2f39a08a00ba3b66a02af50c1aa2173ac01ac
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/FutureClusterSpreadTool.cpp
@@ -0,0 +1,101 @@
+// ============================================================================
+// Include files
+#include "CaloDet/DeCalorimeter.h"
+#include "CaloFutureUtils/CaloFutureAlgUtils.h"
+#include "FutureClusterSpreadTool.h"
+// ============================================================================
+/** @file FutureClusterSpreadTool.cpp
+ *
+ *  Implementation file for class : FutureClusterSpreadTool
+ * 
+ *  @author Vanya Belyaev Ivan.Belyaev@itep.ru 
+ *  @date 23/11/2001
+ */
+// ============================================================================
+DECLARE_COMPONENT( FutureClusterSpreadTool )
+// ============================================================================
+/*  Standard constructor
+ *  @param type tool type (useless)
+ *  @param name tool name
+ *  @param parent pointer to parent object (service, algorithm or tool)  
+ */
+// ============================================================================
+FutureClusterSpreadTool::FutureClusterSpreadTool
+( const std::string& type   ,
+  const std::string& name   ,
+  const IInterface*  parent )
+  : GaudiTool    ( type , name , parent )
+{
+  // setup calo-dependent property
+  m_detData    = LHCb::CaloFutureAlgUtils::DeCaloFutureLocation( name ) ;
+
+  /// declare available interafces 
+  declareInterface<ICaloFutureClusterTool>(this);
+}
+// ============================================================================
+/*  standard initialization method 
+ *  @return status code 
+ */
+// ============================================================================
+StatusCode FutureClusterSpreadTool::initialize ()
+{
+  /// initialize the base class 
+  StatusCode sc = GaudiTool::initialize();
+  if( sc.isFailure() ) 
+    { return Error("Could not initialize the base class ",sc);}
+  ///  
+  m_det = getDet<DeCalorimeter>( m_detData) ;
+  /// configure the estimator 
+  m_estimator.setDetector( m_det ) ;
+  ///
+  return StatusCode::SUCCESS;
+}
+// ============================================================================
+/*  standard finalization method 
+ *  @return status code 
+ */
+// ============================================================================
+StatusCode FutureClusterSpreadTool::finalize   ()
+{  
+  if ( UNLIKELY(msgLevel ( MSG::DEBUG ) ) )
+  {
+    debug () << " Corrected Clusters, Ratio : " 
+             << m_estimator.invalidRatio  () << endmsg ;
+    debug () << " Corrected Clusters, Et    : " 
+             << m_estimator.invalidEnergy () << endmsg ;
+    debug () << " Corrected Clusters, Cells : " 
+             << m_estimator.invalidCells  () << endmsg ;
+  }
+  /// finalize the base class
+  return GaudiTool::finalize ();
+}
+// ============================================================================
+/*  The main processing method 
+ *  @param cluster pointer to CaloCluster object to be processed
+ *  @return status code 
+ */  
+// ============================================================================
+StatusCode FutureClusterSpreadTool::process    
+( LHCb::CaloCluster* cluster ) const { return (*this)( cluster ); }
+// ============================================================================
+/*  The main processing method (functor interface) 
+ *  @param cluster pointer to CaloCluster object to be processed
+ *  @return status code 
+ */  
+// ============================================================================
+StatusCode FutureClusterSpreadTool::operator() 
+  ( LHCb::CaloCluster* cluster ) const
+{
+  /// check the argument 
+  if( 0 == cluster                ) 
+    { return Error( "CaloCluster*   points to NULL!") ; }
+  if( 0 == m_estimator.detector() ) 
+    { return Error( "DeCalorimeter* points to NULL!") ; }
+  /// apply the estimator 
+  return m_estimator( cluster );
+}
+// ============================================================================
+// The END 
+// ============================================================================
+
+  
diff --git a/CaloFuture/CaloFutureReco/src/FutureClusterSpreadTool.h b/CaloFuture/CaloFutureReco/src/FutureClusterSpreadTool.h
new file mode 100644
index 0000000000000000000000000000000000000000..92dd5e6345f53bb74e8766d3f9f0a4aeb117093b
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/FutureClusterSpreadTool.h
@@ -0,0 +1,80 @@
+#ifndef CALOFUTURERECO_CLUSTERSPREADTOOL_H
+#define CALOFUTURERECO_CLUSTERSPREADTOOL_H 1
+// ============================================================================
+// Include files
+// ============================================================================
+// GaudiKernel
+// ============================================================================
+#include "GaudiKernel/Property.h"
+// ============================================================================
+// CaloFutureInterfaces
+// ============================================================================
+#include  "CaloFutureInterfaces/ICaloFutureClusterTool.h"
+// ============================================================================
+// GaudiAlg
+// ============================================================================
+#include  "GaudiAlg/GaudiTool.h"
+// ============================================================================
+// CaloFutureUtil
+// ============================================================================
+#include  "CaloFutureUtils/SpreadEstimator.h"
+// ============================================================================
+/** @class FutureClusterSpreadTool FutureClusterSpreadTool.h
+ *
+ *  Concrete tool for estimation of the
+ *  effective cluster size ("spread")
+ *
+ *  @author Vanya Belyaev Ivan.Belyaev@itep.ru
+ *  @date   22/11/2001
+ */
+// ============================================================================
+class FutureClusterSpreadTool:
+  public virtual ICaloFutureClusterTool ,
+  public                 GaudiTool
+{
+public:
+  // ==========================================================================
+  /** standard initialization method
+   *  @return status code
+   */
+  StatusCode initialize() override;
+  // ==========================================================================
+  /** standard finalization method
+   *  @return status code
+   */
+  StatusCode finalize() override;
+  // ==========================================================================
+  /** The main processing method
+   *  @param cluster pointer to CaloCluster object to be processed
+   *  @return status code
+   */
+  StatusCode process    ( LHCb::CaloCluster* cluster ) const override;
+  // ==========================================================================
+  /** The main processing method (functor interface)
+   *  @param cluster pointer to CaloCluster object to be processed
+   *  @return status code
+   */
+  StatusCode operator() ( LHCb::CaloCluster* cluster ) const override;
+  // ==========================================================================
+  /** Standard constructor
+   *  @param type tool type (useless)
+   *  @param name tool name
+   *  @param parent pointer to parent object (service, algorithm or tool)
+   */
+  FutureClusterSpreadTool
+  ( const std::string& type   ,
+    const std::string& name   ,
+    const IInterface*  parent );
+  // ==========================================================================
+private:
+  // ==========================================================================
+  SpreadEstimator    m_estimator ;
+  Gaudi::Property<std::string> m_detData {this, "Detector"};
+  const DeCalorimeter* m_det = nullptr;
+  // ==========================================================================
+};
+// ============================================================================
+// The End
+// ============================================================================
+#endif // CALOFUTURERECO_CLUSTERSPREADTOOL_H
+// ============================================================================
diff --git a/CaloFuture/CaloFutureReco/src/FutureSubClusterSelector2x2.cpp b/CaloFuture/CaloFutureReco/src/FutureSubClusterSelector2x2.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..983084f5e5df239fd8161f3d60d2f8d559e1e2ab
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/FutureSubClusterSelector2x2.cpp
@@ -0,0 +1,197 @@
+// ============================================================================
+// Include files
+// Event 
+#include "Event/CaloCluster.h"
+#include "Event/CaloDigit.h"
+// CaloFutureUtils 
+#include "CaloFutureUtils/ClusterFunctors.h"
+#include "CaloFutureUtils/CaloFutureDataFunctor.h"
+#include "CaloFutureUtils/CellMatrix2x2.h"
+// local
+#include "FutureSubClusterSelector2x2.h"
+
+// ============================================================================
+/** @file FutureSubClusterSelector2x2.cpp
+ *  
+ *  Implementation file for class : FutureSubClusterSelector2x2
+ * 
+ *  @author F. Machefert
+ *  @date 06/14/2014
+ */
+// ============================================================================
+
+DECLARE_COMPONENT( FutureSubClusterSelector2x2 )
+
+// ============================================================================
+/** Standard Tool Constructor
+ *  @param type type of the tool (useless ? )
+ *  @param name name of the tool 
+ *  @param parent the tool parent 
+ */
+// ============================================================================
+
+FutureSubClusterSelector2x2::FutureSubClusterSelector2x2( const std::string& type,
+                                              const std::string& name,
+                                              const IInterface* parent )
+  : FutureSubClusterSelectorBase ( type, name , parent ) 
+  , m_matrix ()
+{}
+
+// ============================================================================
+/** standard initiliazation 
+ *  @return status code 
+ */
+// ============================================================================
+StatusCode FutureSubClusterSelector2x2::initialize()
+{
+  /// initliaze the base class 
+  StatusCode sc = FutureSubClusterSelectorBase::initialize() ;
+  if( sc.isFailure() ) 
+    { return Error("Could not initialize the base class!",sc); }
+  if( 0 != det() )
+    {
+      m_det=det();
+      m_matrix.setDet( m_det ) ;
+    }
+  else 
+    { return Error("DeCalorimeter* ponts to NULL!"); }
+  ///
+  return StatusCode::SUCCESS ;
+}
+
+// ============================================================================
+/** The main processing method  
+ *  @param cluster pointer to CaloFutureCluster object to be processed
+ *  @return status code 
+ */  
+// ============================================================================
+StatusCode FutureSubClusterSelector2x2::tag ( LHCb::CaloCluster* cluster ) const{
+  double energy;
+  CellMatrix2x2::SubMatrixType type;
+  //
+  StatusCode sc = choice2x2( cluster , type, energy );
+  if( sc.isFailure() )return Error( "Error from 'choice2x2()'" , sc ); 
+  //
+  m_matrix.setType( type );
+  sc =LHCb::ClusterFunctors::
+      tagTheSubCluster( cluster  ,
+                        m_matrix ,
+                        modify() ,
+                        mask(),
+                        LHCb::CaloDigitStatus::ModifiedByMax2x2Tagger ) ;
+
+  //
+  if( sc.isFailure() ) 
+    { return Error( "Error from 'tagTheSubCluster()'" , sc ); }
+  //
+  return StatusCode::SUCCESS ;  }
+
+// ============================================================================
+/** The main processing method (untag) 
+ *  @param cluster pointer to CaloCluster object to be processed
+ *  @return status code 
+ */  
+// ============================================================================
+StatusCode FutureSubClusterSelector2x2::untag ( LHCb::CaloCluster* cluster ) const
+{
+  double energy;
+  CellMatrix2x2::SubMatrixType type;
+  //
+  StatusCode sc = choice2x2( cluster , type, energy );
+  if( sc.isFailure() ) 
+    { return Error( "Error from 'choice2x2()'" , sc ); }
+  //
+  m_matrix.setType( type );
+  sc = LHCb::ClusterFunctors::
+          untagTheSubCluster( cluster  , 
+                              m_matrix , 
+                              LHCb::CaloDigitStatus::ModifiedByMax2x2Tagger );
+  //
+  if( sc.isFailure() ) 
+    { return Error( "Error from 'untagTheSubCluster()'" , sc ); }
+  //
+  return StatusCode::SUCCESS ;
+}
+
+// ============================================================================
+/** The method that selects the 2x2 cluster out of the full cluster
+ *  @param cluster pointer to CaloCluster object to be processed
+ *  @param type the selected type of cluster
+ *  @param energy the energy of the selected cluster
+ *  @return status code
+ */
+// ============================================================================
+StatusCode FutureSubClusterSelector2x2::choice2x2 (
+    LHCb::CaloCluster* cluster ,
+    CellMatrix2x2::SubMatrixType &type,
+    double &energy) const
+{
+   // check the arguments
+   if( 0 == cluster               ) {
+       return Error ( "cluster points to NULL in 'choice 2x2()'" );
+   }
+   // get all entries
+   LHCb::CaloCluster::Entries& entries = cluster->entries() ;
+   // find seed digit
+   LHCb::CaloCluster::Entries::iterator seedEntry =
+     LHCb::ClusterFunctors::locateDigit( entries.begin ()          ,
+                  entries.end   ()          ,
+                  LHCb::CaloDigitStatus::SeedCell );
+   // check the seed
+   if( entries.end() == seedEntry ) {
+       return Error ( "could not find the seed of the cluster in 'choice2x2()'." );
+   }
+   const LHCb::CaloDigit* seed = seedEntry->digit() ;
+   if( 0             == seed      ) {
+       return Error ( "cluster seed points to NULL in 'choice2x2()'." );
+   }
+
+   LHCb::CaloCellID seedCell = seed->cellID();
+
+   // loop over all entried
+   CellMatrix2x2 matrix( m_det );
+
+   double e[4];
+   CellMatrix2x2::SubMatrixType mode[4];
+   
+   mode[0] = CellMatrix2x2::UpperLeft;
+   mode[1] = CellMatrix2x2::UpperRight;
+   mode[2] = CellMatrix2x2::LowerLeft;
+   mode[3] = CellMatrix2x2::LowerRight;
+
+//   std::cout << " * Running on a cluster e=" 
+//             << cluster->e() 
+//             << std::endl;
+   
+    for ( int j=0; j<4; ++j ){
+      e[j]=0.;
+      matrix.setType ( mode[j] );
+      //      std::cout << " Mode "<< mode[j] << " -> ";
+      for( LHCb::CaloCluster::Entries::iterator entry = entries.begin() ;
+	   entries.end() != entry ; ++entry )
+        {
+	  const LHCb::CaloDigit* digit = entry->digit() ;
+	  if( 0 == digit    ){ continue ; } // CONTINUE
+	  double tmp             = digit->e();
+	  LHCb::CaloCellID  cell = digit->cellID();
+	  double frac = matrix ( seedCell, cell ) ;
+	  e[j] +=  frac * tmp;
+	  //	  std::cout << " - " << frac << " " << tmp << "(" << e[j] <<")" ;
+        }
+      //      std::cout << " -> " << e[j] << std::endl;
+    }
+    // select the max energy case
+    type= mode[0]; energy = e[0];
+    for (int i=1; i<4; ++i) {
+      if (e[i]>energy) { energy = e[i] ; type = mode[i]; }
+    }
+    // std::cout   << " Summary 2x2 clusterisation: "
+    //             << e[0] << " " << e[1] << " " << e[2] << " " << e[3]
+    //             << " --> " << energy << "[" << type << "]" << std::endl;
+    return StatusCode::SUCCESS;
+}
+
+
+// ============================================================================
+// The End 
+// ============================================================================
diff --git a/CaloFuture/CaloFutureReco/src/FutureSubClusterSelector2x2.h b/CaloFuture/CaloFutureReco/src/FutureSubClusterSelector2x2.h
new file mode 100644
index 0000000000000000000000000000000000000000..823a7cb196465f3636631994f06e22ff227dde30
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/FutureSubClusterSelector2x2.h
@@ -0,0 +1,30 @@
+#ifndef CALOFUTURERECO_SUBCLUSTERSELECTOR2x2_H
+#define CALOFUTURERECO_SUBCLUSTERSELECTOR2x2_H 1
+// Include files
+#include "FutureSubClusterSelectorBase.h"
+#include "CaloFutureUtils/CellMatrix2x2.h"
+
+
+class FutureSubClusterSelector2x2: public FutureSubClusterSelectorBase{
+public:
+
+  StatusCode initialize() override;
+  StatusCode tag        ( LHCb::CaloCluster* cluster ) const override;
+  StatusCode untag      ( LHCb::CaloCluster* cluster ) const override;
+
+protected:
+  StatusCode choice2x2 (LHCb::CaloCluster* cluster,
+                        CellMatrix2x2::SubMatrixType &type,
+                        double &energy) const ;
+
+public:
+  FutureSubClusterSelector2x2( const std::string& type   ,
+                         const std::string& name   ,
+                         const IInterface*  parent );
+
+private:
+  const DeCalorimeter* m_det = NULL;
+  CellMatrix2x2        m_matrix;
+};
+
+#endif // SUBCLUSTERSELECTOR2X2_H
diff --git a/CaloFuture/CaloFutureReco/src/FutureSubClusterSelector3x3.cpp b/CaloFuture/CaloFutureReco/src/FutureSubClusterSelector3x3.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..23ff3431b1cedc9ee169fae7dc64c01e49c41187
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/FutureSubClusterSelector3x3.cpp
@@ -0,0 +1,98 @@
+// ============================================================================
+// Include files
+// Event 
+#include "Event/CaloCluster.h"
+#include "Event/CaloDigit.h"
+// CaloFutureUtils 
+#include "CaloFutureUtils/ClusterFunctors.h"
+// local
+#include "FutureSubClusterSelector3x3.h"
+
+// ============================================================================
+/** @file FutureSubClusterSelector3x3.cpp
+ *  
+ *  Implementation file for class : FutureSubClusterSelector3x3
+ * 
+ *  @author Vanya Belyaev Ivan.Belyaev@itep.ru
+ *  @date 07/11/2001 
+ */
+// ============================================================================
+
+DECLARE_COMPONENT( FutureSubClusterSelector3x3 )
+
+// ============================================================================
+/** Standard Tool Constructor
+ *  @param type type of the tool (useless ? )
+ *  @param name name of the tool 
+ *  @param parent the tool parent 
+ */
+// ============================================================================
+
+FutureSubClusterSelector3x3::FutureSubClusterSelector3x3( const std::string& type,
+                                              const std::string& name,
+                                              const IInterface* parent )
+  : FutureSubClusterSelectorBase ( type, name , parent ) 
+  , m_matrix ()
+{}
+
+// ============================================================================
+/** standard initiliazation 
+ *  @return status code 
+ */
+// ============================================================================
+StatusCode FutureSubClusterSelector3x3::initialize()
+{
+  /// initliaze the base class 
+  StatusCode sc = FutureSubClusterSelectorBase::initialize() ;
+  if( sc.isFailure() ) 
+    { return Error("Could not initialize the base class!",sc); }
+  if( 0 != det() )
+    { m_matrix.setDet( det() ) ; }
+  else 
+    { return Error("DeCalorimeter* ponts to NULL!"); }
+  ///
+  return StatusCode::SUCCESS ;
+}
+
+// ============================================================================
+/** The main processing method  
+ *  @param cluster pointer to CaloCluster object to be processed
+ *  @return status code 
+ */  
+// ============================================================================
+StatusCode FutureSubClusterSelector3x3::tag ( LHCb::CaloCluster* cluster ) const{
+
+
+  StatusCode sc = LHCb::ClusterFunctors::tagTheSubCluster( cluster  , 
+                                                           m_matrix , 
+                                                           modify() , 
+                                                           mask()   ,
+                                                           LHCb::CaloDigitStatus::ModifiedBy3x3Tagger) ;
+  //
+  if( sc.isFailure() ){ return Error( "Error from 'tagTheSubCluster()'" , sc ); }
+  //
+  return StatusCode::SUCCESS ;  
+}
+
+// ============================================================================
+/** The main processing method (untag) 
+ *  @param cluster pointer to CaloCluster object to be processed
+ *  @return status code 
+ */  
+// ============================================================================
+StatusCode FutureSubClusterSelector3x3::untag ( LHCb::CaloCluster* cluster ) const{
+  StatusCode sc = 
+    LHCb::ClusterFunctors::
+    untagTheSubCluster( cluster  , 
+                        m_matrix , 
+                        LHCb::CaloDigitStatus::ModifiedBy3x3Tagger );
+  //
+  if( sc.isFailure() ) 
+    { return Error( "Error from 'untagTheSubCluster()'" , sc ); }
+  //
+  return StatusCode::SUCCESS ;  
+}
+
+// ============================================================================
+// The End 
+// ============================================================================
diff --git a/CaloFuture/CaloFutureReco/src/FutureSubClusterSelector3x3.h b/CaloFuture/CaloFutureReco/src/FutureSubClusterSelector3x3.h
new file mode 100644
index 0000000000000000000000000000000000000000..cdf001f6b0f93473f02bf9aaf512b23bb56aefb6
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/FutureSubClusterSelector3x3.h
@@ -0,0 +1,63 @@
+#ifndef CALOFUTURERECO_SUBCLUSTERSELECTOR3x3_H
+#define CALOFUTURERECO_SUBCLUSTERSELECTOR3x3_H 1
+// Include files
+#include "FutureSubClusterSelectorBase.h"
+#include "CaloFutureUtils/CellMatrix3x3.h"
+
+/** @class FutureSubClusterSelector3x3 FutureSubClusterSelector3x3.h
+ *
+ *  The simplest concrete "subcluster selector" -
+ *  it just tag/select digits which form
+ *  3x3 sub-matrix centered with the seed cells
+ *
+ *  @author Vanya Belyaev Ivan.Belyaev@itep.ru
+ *  @date   07/11/2001
+ */
+
+class FutureSubClusterSelector3x3  : public FutureSubClusterSelectorBase{
+public:
+
+  StatusCode initialize() override;
+
+  /** The main processing method
+   *
+   *  @see ICaloFutureSubClusterTag
+   *
+   *  Error codes:
+   *    - 225   cluster points to NULL
+   *    - 226   empty cell/digit container for given cluster
+   *    - 227   SeedCell is not found
+   *    - 228   Seed points to NULL
+   *
+   *  @see ICaloFutureClusterTool
+   *  @see ICaloFutureSubClusterTag
+   *
+   *  @param cluster pointer to CaloFutureCluster object to be processed
+   *  @return status code
+   */
+
+  StatusCode tag ( LHCb::CaloCluster* cluster) const override;
+
+  /** The main method - "undo" of tagging from "tag" method
+   *  @see ICaloFutureSubClusterTag
+   *  @param cluster pointer to ClaoCluster object to be untagged
+   *  @return status code
+   */
+  StatusCode untag      ( LHCb::CaloCluster* cluster ) const override;
+
+  /** Standard Tool Constructor
+   *  @param type type of the tool (useless ? )
+   *  @param name name of the tool
+   *  @param parent the tool parent
+   */
+  FutureSubClusterSelector3x3( const std::string& type   ,
+                         const std::string& name   ,
+                         const IInterface*  parent );
+
+private:
+
+  CellMatrix3x3        m_matrix;
+
+};
+
+#endif // SUBCLUSTERSELECTOR3x3_H
diff --git a/CaloFuture/CaloFutureReco/src/FutureSubClusterSelectorBase.cpp b/CaloFuture/CaloFutureReco/src/FutureSubClusterSelectorBase.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..abcb5856c328737a5af4e502c66bb8f5acc2e511
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/FutureSubClusterSelectorBase.cpp
@@ -0,0 +1,93 @@
+// ============================================================================
+// Include files 
+// ============================================================================
+// CaloFutureInterfaces
+#include "CaloFutureInterfaces/ICaloFutureClusterTool.h"
+// CaloDet 
+#include "CaloDet/DeCalorimeter.h"
+// CaloFutureEvent 
+#include "Event/CaloCluster.h"
+// local
+#include "FutureSubClusterSelectorBase.h"
+
+// ============================================================================
+/** @file SubclusterSelectorBase.cpp
+ * 
+ *  Implementation file for class : FutureSubClusterSelectorBase
+ * 
+ *  @date 07/11/2001 
+ *  @author Vanya Belyaev Ivan.Belyaev@itep.ru 
+ */
+// ============================================================================
+
+// ============================================================================
+/** Standard Tool Constructor
+ *  @param type type of the tool (useless ? )
+ *  @param name name of the tool 
+ *  @param parent the tool parent 
+ */
+// ============================================================================
+FutureSubClusterSelectorBase::FutureSubClusterSelectorBase( const std::string& type,
+                                                const std::string& name,
+                                                const IInterface* parent )
+  : GaudiTool  ( type, name , parent ) 
+  , m_mask(defaultStatus)
+{
+  /// declare the available interfaces
+  declareInterface<ICaloFutureClusterTool>   ( this )    ;
+  declareInterface<ICaloFutureSubClusterTag> ( this )    ;
+}
+// ============================================================================
+
+// ============================================================================
+/** standard finalization method 
+ *  @return status code 
+ */
+// ============================================================================
+StatusCode FutureSubClusterSelectorBase::finalize   ()
+{ return GaudiTool::finalize(); }
+// ============================================================================
+
+// ============================================================================
+/** standard initialization method 
+ *  @return status code 
+ */
+// ============================================================================
+StatusCode FutureSubClusterSelectorBase::initialize ()
+{
+  // initialize the base class
+  StatusCode sc = GaudiTool::initialize() ;
+  if( sc.isFailure() ) 
+    { return Error("Could not initialize the base class!",sc);}
+  // load and set the  detector
+  m_det = getDet<DeCalorimeter>( m_detData ) ;
+  // 
+  return StatusCode::SUCCESS;
+}
+// ============================================================================
+
+// ============================================================================
+/** The main processing method (functor interface) 
+ *  @param cluster pointer to CaloCluster object to be processed
+ *  @return status code 
+ */  
+// ============================================================================
+StatusCode FutureSubClusterSelectorBase::process     ( LHCb::CaloCluster* cluster ) const{ 
+  return tag ( cluster ) ; 
+}  
+
+// ============================================================================
+
+// ============================================================================
+/** The main processing method 
+ *  @see ICaloFutureSubClusterTag
+ *  @see ICaloFutureClusterTool
+ *  @param cluster pointer to CaloCluster object to be processed
+ *  @return status code 
+ */  
+// ============================================================================
+StatusCode FutureSubClusterSelectorBase::operator() ( LHCb::CaloCluster* cluster ) const{ 
+  return tag ( cluster ) ; 
+}  
+// ============================================================================
+
diff --git a/CaloFuture/CaloFutureReco/src/FutureSubClusterSelectorBase.h b/CaloFuture/CaloFutureReco/src/FutureSubClusterSelectorBase.h
new file mode 100644
index 0000000000000000000000000000000000000000..a8245f3fdef46c5645a319b5422f9754552201d9
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/FutureSubClusterSelectorBase.h
@@ -0,0 +1,80 @@
+// $Id: FutureSubClusterSelectorBase.h,v 1.5 2010-03-08 01:19:40 odescham Exp $
+
+#ifndef CALOFUTURERECO_SUBCLUSTERSELECTORBASE_H
+#define CALOFUTURERECO_SUBCLUSTERSELECTORBASE_H 1
+// Include files
+#include "CaloFutureInterfaces/ICaloFutureSubClusterTag.h"
+#include "Event/CaloDigitStatus.h"
+#include "GaudiAlg/GaudiTool.h"
+class    CaloFutureCluster   ;
+
+
+class FutureSubClusterSelectorBase : public virtual  ICaloFutureSubClusterTag , public GaudiTool{
+
+public:
+
+  static const LHCb::CaloDigitStatus::Status defaultStatus =
+    LHCb::CaloDigitStatus::UseForEnergy |LHCb::CaloDigitStatus::UseForPosition | LHCb::CaloDigitStatus::UseForCovariance ;
+
+
+  StatusCode initialize() override;
+  StatusCode finalize() override;
+  StatusCode process(LHCb::CaloCluster* cluster)const override;
+  StatusCode operator()(LHCb::CaloCluster* cluster)const override;
+  void setMask(const LHCb::CaloDigitStatus::Status mask)const override {
+    m_mask=mask;
+    if ( UNLIKELY(msgLevel(MSG::DEBUG)) )debug() << "The default status tag is changed to " << m_mask
+                                                 << " -> use for Energy   : " << ((mask & LHCb::CaloDigitStatus::UseForEnergy) != 0)
+                                                 << " | for Position : " << ((mask & LHCb::CaloDigitStatus::UseForPosition) != 0)
+                                                 << " | for Covariance : " << ((mask & LHCb::CaloDigitStatus::UseForCovariance) != 0)
+                                                 << endmsg;
+  }
+  unsigned int mask()const override {return m_mask;};
+
+
+
+protected:
+
+
+  /**  return  flag to modify the fractions
+   *   @return flag to modify the fractions
+   */
+  inline bool modify() const { return m_modify ; }
+
+  /** set new value for "modify" parameter
+   *  @param value new value of modify parameter
+   */
+  inline void setModify( const bool value ) const { m_modify = value ; }
+
+  inline const DeCalorimeter* det()  {return m_det; }
+
+
+  protected:
+
+  /** Standard Tool Constructor
+   *  @param type type of the tool (useless ? )
+   *  @param name name of the tool
+   *  @param parent the tool parent
+   */
+  FutureSubClusterSelectorBase( const std::string& type   ,
+                          const std::string& name   ,
+                          const IInterface*  parent );
+
+private:
+
+  /// default constructor is private
+  FutureSubClusterSelectorBase();
+  /// copy    constructor is private
+  FutureSubClusterSelectorBase( const FutureSubClusterSelectorBase& );
+  /// assignement operator is private
+  FutureSubClusterSelectorBase& operator=( const FutureSubClusterSelectorBase& );
+
+private:
+  mutable LHCb::CaloDigitStatus::Status m_mask;
+  mutable Gaudi::Property<bool> m_modify {this, "ModifyFractions", false};
+  Gaudi::Property<std::string> m_detData {this, "Detector", DeCalorimeterLocation::Ecal};
+  const DeCalorimeter* m_det = nullptr;
+
+};
+// ============================================================================
+#endif // SUBCLUSTERSELECTORBASE_H
diff --git a/CaloFuture/CaloFutureReco/src/FutureSubClusterSelectorSwissCross.cpp b/CaloFuture/CaloFutureReco/src/FutureSubClusterSelectorSwissCross.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8bebb19b04f2bfb4df8de83b517c444981fb29da
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/FutureSubClusterSelectorSwissCross.cpp
@@ -0,0 +1,98 @@
+// ============================================================================
+// Include files
+// Event 
+#include "Event/CaloCluster.h"
+#include "Event/CaloDigit.h"
+// CaloFutureUtils 
+#include "CaloFutureUtils/ClusterFunctors.h"
+// local
+#include "FutureSubClusterSelectorSwissCross.h"
+
+// ============================================================================
+/** @file FutureSubClusterSelectorSwissCross.cpp
+ *  
+ *  Implementation file for class : FutureSubClusterSelectorSwissCross
+ * 
+ *  @author Vanya Belyaev Ivan.Belyaev@itep.ru
+ *  @date 07/11/2001 
+ */
+// ============================================================================
+
+DECLARE_COMPONENT( FutureSubClusterSelectorSwissCross )
+
+// ============================================================================
+/** Standard Tool Constructor
+ *  @param type type of the tool (useless ? )
+ *  @param name name of the tool 
+ *  @param parent the tool parent 
+ */
+// ============================================================================
+
+FutureSubClusterSelectorSwissCross::FutureSubClusterSelectorSwissCross( const std::string& type,
+                                              const std::string& name,
+                                              const IInterface* parent )
+  : FutureSubClusterSelectorBase ( type, name , parent ) 
+  , m_matrix ()
+{}
+
+// ============================================================================
+/** standard initiliazation 
+ *  @return status code 
+ */
+// ============================================================================
+StatusCode FutureSubClusterSelectorSwissCross::initialize()
+{
+  /// initliaze the base class 
+  StatusCode sc = FutureSubClusterSelectorBase::initialize() ;
+  if( sc.isFailure() ) 
+    { return Error("Could not initialize the base class!",sc); }
+  if( 0 != det() )
+    { m_matrix.setDet( det() ) ; }
+  else 
+    { return Error("DeCalorimeter* ponts to NULL!"); }
+  ///
+  return StatusCode::SUCCESS ;
+}
+
+// ============================================================================
+/** The main processing method  
+ *  @param cluster pointer to CaloCluster object to be processed
+ *  @return status code 
+ */  
+// ============================================================================
+StatusCode FutureSubClusterSelectorSwissCross::tag ( LHCb::CaloCluster* cluster ) const{
+
+
+  StatusCode sc = LHCb::ClusterFunctors::tagTheSubCluster( cluster  , 
+                                                           m_matrix , 
+                                                           modify() , 
+                                                           mask(),
+                                                           LHCb::CaloDigitStatus::ModifiedBySwissCrossTagger) ;
+  //
+  if( sc.isFailure() ){ return Error( "Error from 'tagTheSubCluster()'" , sc ); }
+  //
+  return StatusCode::SUCCESS ;  
+}
+
+// ============================================================================
+/** The main processing method (untag) 
+ *  @param cluster pointer to CaloCluster object to be processed
+ *  @return status code 
+ */  
+// ============================================================================
+StatusCode FutureSubClusterSelectorSwissCross::untag ( LHCb::CaloCluster* cluster ) const{
+  StatusCode sc = 
+    LHCb::ClusterFunctors::
+    untagTheSubCluster( cluster  , 
+                        m_matrix , 
+                        LHCb::CaloDigitStatus::ModifiedBySwissCrossTagger );
+  //
+  if( sc.isFailure() ) 
+    { return Error( "Error from 'untagTheSubCluster()'" , sc ); }
+  //
+  return StatusCode::SUCCESS ;  
+}
+
+// ============================================================================
+// The End 
+// ============================================================================
diff --git a/CaloFuture/CaloFutureReco/src/FutureSubClusterSelectorSwissCross.h b/CaloFuture/CaloFutureReco/src/FutureSubClusterSelectorSwissCross.h
new file mode 100644
index 0000000000000000000000000000000000000000..283871ebdd3596af42f90862d9f29b59ddd457eb
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/FutureSubClusterSelectorSwissCross.h
@@ -0,0 +1,27 @@
+#ifndef CALOFUTURERECO_SUBCLUSTERSELECTORSwissCross_H
+#define CALOFUTURERECO_SUBCLUSTERSELECTORSwissCross_H 1
+// Include files
+// CaloFutureTools
+#include "FutureSubClusterSelectorBase.h"
+// CaloFutureUtils
+#include "CaloFutureUtils/CellSwissCross.h"
+
+
+class FutureSubClusterSelectorSwissCross  : public FutureSubClusterSelectorBase{
+public:
+  StatusCode initialize() override;
+
+  StatusCode tag        ( LHCb::CaloCluster* cluster)const override;
+  StatusCode untag      ( LHCb::CaloCluster* cluster ) const override;
+
+  FutureSubClusterSelectorSwissCross( const std::string& type   ,
+                         const std::string& name   ,
+                         const IInterface*  parent );
+
+private:
+
+  CellSwissCross        m_matrix;
+
+};
+
+#endif
diff --git a/CaloFuture/CaloFutureReco/src/FutureSubClusterSelectorTool.cpp b/CaloFuture/CaloFutureReco/src/FutureSubClusterSelectorTool.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ceec0367a1738af6ec090bc8b477b0c12b8043fe
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/FutureSubClusterSelectorTool.cpp
@@ -0,0 +1,209 @@
+// Include files
+
+// local
+#include "FutureSubClusterSelectorTool.h"
+
+//-----------------------------------------------------------------------------
+// Implementation file for class : FutureSubClusterSelectorTool
+//
+// 2014-06-20 : Olivier Deschamps
+//-----------------------------------------------------------------------------
+
+// Declaration of the Tool Factory
+DECLARE_COMPONENT( FutureSubClusterSelectorTool )
+
+
+//=============================================================================
+// Standard constructor, initializes variables
+//=============================================================================
+FutureSubClusterSelectorTool::FutureSubClusterSelectorTool( const std::string& type,
+                                                  const std::string& name,
+                                                  const IInterface* parent )
+  : GaudiTool ( type, name , parent )
+{
+  declareInterface<FutureSubClusterSelectorTool>(this);
+  StringArrayProperty eTags( "EnergyTags"     , m_taggerE      ) ;
+  StringArrayProperty pTags( "PositionTags"   , m_taggerP      ) ;
+
+  // inherit properties from parents
+  if( 0 != parent ){
+    const IProperty* prop = dynamic_cast<const IProperty*> ( parent );
+    if( 0 != prop ){
+      StatusCode sc1=prop->getProperty( &eTags      );
+      if( sc1.isSuccess() )m_taggerE   = eTags.value();
+      StatusCode sc2=prop->getProperty( &pTags      );
+      if( sc2.isSuccess() )m_taggerP   = pTags.value();
+    }
+  }
+
+  // declare Properties
+  declareProperty("EnergyTags"    , m_taggerE   );
+  declareProperty("PositionTags"  , m_taggerP   );
+
+  // define calo-dependent property
+  m_det       = LHCb::CaloFutureAlgUtils::DeCaloFutureLocation( name ) ;
+  m_condition = "Conditions/Reco/Calo/"+ LHCb::CaloFutureAlgUtils::CaloFutureNameFromAlg( name ) + "ClusterMasks";
+
+  // apply local default setting if not defined by parent
+  if (m_taggerE.empty()) m_taggerE = std::vector<std::string>(1,"useDB");
+  if (m_taggerP.empty()) m_taggerP = std::vector<std::string>(1,"useDB");
+
+}
+
+//=============================================================================
+
+StatusCode FutureSubClusterSelectorTool::initialize() {
+  StatusCode sc = GaudiTool::initialize(); // must be executed first
+  if ( sc.isFailure() ) return sc;  // error printed already by GaudiTool
+  if ( msgLevel(MSG::DEBUG) ) debug() << "==> Initialize" << endmsg;
+
+  // register to incident service
+  IIncidentSvc* inc = incSvc() ;
+  if ( 0 != inc )inc -> addListener  ( this , IncidentType::BeginEvent ) ;
+
+  // get detector element
+  m_detector = getDet<DeCalorimeter> ( m_det   );
+  if( NULL == m_detector)return Error("Cannot access DetectorElement at '"+m_det,StatusCode::FAILURE);
+
+  // setup DB accessor tool
+  m_dbAccessor = tool<CaloFutureCorrectionBase>("CaloFutureCorrectionBase","DBAccessor",this);
+  sc = m_dbAccessor->setConditionParams(m_condition,true);// force access via DB - if not exist will return empty params
+  if(sc.isFailure())return Warning("Cannot access DB",StatusCode::FAILURE);
+  m_DBtaggerE=std::vector<std::string>(m_detector->numberOfAreas(),"unset");
+  m_DBtaggerP=std::vector<std::string>(m_detector->numberOfAreas(),"unset");
+  m_sourceE=" (none)";
+  m_sourceP=" (none)";
+
+  // always set options parameters first
+  sc=getParamsFromOptions();
+  if( sc.isFailure())return Error("Cannot setup initial parameters",StatusCode::FAILURE);
+
+
+  // then possibly update from DB
+  updateParamsFromDB();
+
+  info() << " Energy   mask : " << m_DBtaggerE << m_sourceE << endmsg;
+  info() << " Position mask : " << m_DBtaggerP << m_sourceP << endmsg;
+
+  return sc;
+}
+
+
+StatusCode FutureSubClusterSelectorTool::tagEnergy( LHCb::CaloCluster* cluster ){
+  // get the tagger
+  LHCb::CaloCellID id = cluster->seed();
+  ICaloFutureSubClusterTag* tagger = ( id.area() < m_tagE.size() ) ? m_tagE[id.area()] : NULL ;
+  if( NULL == tagger )return Warning( "Tagger not found" , StatusCode::FAILURE);
+  return tagger->tag(cluster);
+}
+
+StatusCode FutureSubClusterSelectorTool::tagPosition( LHCb::CaloCluster* cluster ){
+  // get the tagger
+  LHCb::CaloCellID id = cluster->seed();
+  ICaloFutureSubClusterTag* tagger = ( id.area() < m_tagP.size() ) ? m_tagP[id.area()] : NULL ;
+  if( NULL == tagger )return Warning( "Tagger not found" , StatusCode::FAILURE);
+  return tagger->tag(cluster);
+}
+
+StatusCode FutureSubClusterSelectorTool::tag( LHCb::CaloCluster* cluster ){
+  StatusCode sc;
+  sc = tagEnergy( cluster);
+  sc = tagPosition(cluster );
+  return sc;
+}
+
+
+void FutureSubClusterSelectorTool::updateParamsFromDB(){
+
+  using namespace CaloFutureClusterMask;
+  unsigned int narea = m_detector->numberOfAreas();
+  for( unsigned int area = 0 ; area < narea ; ++area){
+    LHCb::CaloCellID id = LHCb::CaloCellID(m_detector->caloName(), area ,0,0);
+
+    if( m_taggerE[area] == "useDB"){
+      m_sourceE=" (from DB) ";
+      Mask maskE = (Mask) m_dbAccessor->getParameter(CaloFutureCorrection::EnergyMask ,0, id , 0.); // default is 3x3 when no DB
+      std::string nameE=maskName[maskE];
+      if( nameE != m_DBtaggerE[area] ){  // DB has changed ! update !
+        std::string taggerE   = (m_clusterTaggers.find(nameE) != m_clusterTaggers.end()) ? m_clusterTaggers[nameE]  : "";
+        if(taggerE != ""){
+          ICaloFutureSubClusterTag* tE = tool<ICaloFutureSubClusterTag>(taggerE,id.areaName()+"EnergyTagger",this);
+          tE->setMask(m_energyStatus);
+          m_tagE.push_back( tE  );
+          m_DBtaggerE[area] = nameE;
+        }else
+          Warning("Cannot update energy mask from DB",StatusCode::FAILURE).ignore();
+      }
+    }
+
+    if( m_taggerP[area] == "useDB"){
+      m_sourceP=" (from DB) ";
+      Mask maskP = (Mask) m_dbAccessor->getParameter(CaloFutureCorrection::PositionMask ,0, id , 0.); // default is 3x3 when no DB
+      std::string nameP=maskName[maskP];
+      if( nameP != m_DBtaggerP[area] ){  // DB has changed ! update !
+        std::string taggerP   = (m_clusterTaggers.find(nameP) != m_clusterTaggers.end()) ? m_clusterTaggers[nameP]  : "";
+        if(taggerP != ""){
+          ICaloFutureSubClusterTag* tP = tool<ICaloFutureSubClusterTag>(taggerP,id.areaName()+"PositionTagger",this);
+          tP->setMask(m_positionStatus);
+          m_tagP.push_back( tP  );
+          m_DBtaggerP[area] = nameP;
+        }else
+          Warning("Cannot update position mask from DB",StatusCode::FAILURE).ignore();
+      }
+    }
+  }
+}
+
+
+
+
+StatusCode FutureSubClusterSelectorTool::getParamsFromOptions(){
+
+  unsigned int narea = m_detector->numberOfAreas();
+
+  // extend tagger per area when needed
+  if( m_taggerE.size() == 1)m_taggerE = std::vector<std::string>(narea , m_taggerE[0]);
+  if( m_taggerP.size() == 1)m_taggerP = std::vector<std::string>(narea , m_taggerP[0]);
+  if( m_taggerE.size() != m_detector->numberOfAreas() || m_taggerP.size() != m_detector->numberOfAreas())
+    return Error("You must define the tagger for each calo area");
+
+  using namespace CaloFutureClusterMask;
+  // == Define Energy tagger per area
+  m_DBtaggerE=std::vector<std::string>(narea,"unset");
+  m_DBtaggerP=std::vector<std::string>(narea,"unset");
+
+  for( unsigned int area = 0 ; area < narea ; ++area){
+    std::string areaName = LHCb::CaloCellID(m_detector->caloName(), area ,0,0).areaName();
+
+    std::string nameE = m_taggerE[area] ;
+    if( nameE != "useDB" ){
+      m_sourceE=" (from options) ";
+      std::string taggerE   = (m_clusterTaggers.find(nameE) != m_clusterTaggers.end()) ? m_clusterTaggers[nameE]  : "";
+      if(taggerE == "")
+        return Error("Cannot find a  '"+nameE+"' tagger - You must select or define a known tagging method",StatusCode::FAILURE);
+      ICaloFutureSubClusterTag* tE = tool<ICaloFutureSubClusterTag>(taggerE,areaName+"EnergyTagger",this);
+      tE->setMask(m_energyStatus);
+      m_tagE.push_back( tE  );
+      m_DBtaggerE[area]=nameE;
+    }
+
+    std::string nameP = m_taggerP[area] ;
+    if( nameP != "useDB" ){
+      m_sourceP=" (from options) ";
+      std::string taggerP   = (m_clusterTaggers.find(nameP) != m_clusterTaggers.end()) ? m_clusterTaggers[nameP]  : "";
+      if(taggerP == "")
+        return Error("Cannot find a  '"+nameP+"' tagger - You must select or define a known tagging method",StatusCode::FAILURE);
+      ICaloFutureSubClusterTag* tP= tool<ICaloFutureSubClusterTag>(taggerP,areaName+"PositionTagger",this);
+      tP->setMask(m_positionStatus);
+      m_tagP.push_back( tP  );
+      m_DBtaggerP[area]=nameP;
+    }
+  }
+
+  return StatusCode::SUCCESS;
+}
+
+
+StatusCode FutureSubClusterSelectorTool::finalize() {
+  return GaudiTool::finalize();  // must be called after all other actions
+}
diff --git a/CaloFuture/CaloFutureReco/src/FutureSubClusterSelectorTool.h b/CaloFuture/CaloFutureReco/src/FutureSubClusterSelectorTool.h
new file mode 100644
index 0000000000000000000000000000000000000000..412e8fce099490fb69a05f106994e107acd55b6b
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/FutureSubClusterSelectorTool.h
@@ -0,0 +1,92 @@
+#ifndef SUBCLUSTERSELECTORTOOL_H
+#define SUBCLUSTERSELECTORTOOL_H 1
+
+
+// Include files
+// from Gaudi
+#include  "GaudiAlg/GaudiTool.h"
+#include "GaudiKernel/IIncidentListener.h"
+#include "GaudiKernel/IIncidentSvc.h"
+#include "GaudiKernel/Incident.h"
+#include  "CaloDet/DeCalorimeter.h"
+#include  "Event/CaloCluster.h"
+#include  "CaloFutureCorrectionBase.h"
+#include  "CaloFutureInterfaces/ICaloFutureSubClusterTag.h"
+
+
+namespace CaloFutureClusterMask {
+  enum  Mask{area3x3        = 0 ,  // MUST BE 0 FOR BACKWARD COMPATIBILITY
+             area2x2        = 1 ,
+             SwissCross     = 2 ,
+             Last
+  };
+  static const int nMask = Last+1;
+  static const std::string maskName[nMask] = { "3x3", "2x2","SwissCross","Unknown" };
+}
+
+
+
+static const InterfaceID IID_FutureSubClusterSelectorTool ( "FutureSubClusterSelectorTool", 1, 0 );
+
+/** @class FutureSubClusterSelectorTool FutureSubClusterSelectorTool.h
+ *
+ *
+ *  @author Olivier Deschamps
+ *  @date   2014-06-20
+ */
+class FutureSubClusterSelectorTool : public GaudiTool, virtual public IIncidentListener {
+public:
+
+  // Return the interface ID
+  static const InterfaceID& interfaceID() { return IID_FutureSubClusterSelectorTool; }
+
+  /// Standard constructor
+  FutureSubClusterSelectorTool( const std::string& type,
+                          const std::string& name,
+                          const IInterface* parent);
+
+  StatusCode initialize() override;
+  StatusCode finalize() override;
+
+  void handle(const Incident&  ) override {
+    if( UNLIKELY( msgLevel(MSG::DEBUG) ) )debug() << "IIncident Svc reset" << endmsg;
+    updateParamsFromDB();
+  }
+
+  StatusCode getParamsFromOptions();
+  void updateParamsFromDB();
+
+  StatusCode tag(LHCb::CaloCluster* cluster);
+  StatusCode tagEnergy(LHCb::CaloCluster* cluster);
+  StatusCode tagPosition(LHCb::CaloCluster* cluster);
+
+private:
+
+  std::vector<std::string>          m_taggerE  ;
+  std::vector<std::string>          m_taggerP  ;
+  std::vector<ICaloFutureSubClusterTag*>  m_tagE      ;
+  std::vector<ICaloFutureSubClusterTag*>  m_tagP      ;
+  
+  // associate known cluster mask to tagger tool
+  Gaudi::Property<std::map<std::string,std::string>> m_clusterTaggers 
+    {this, "ClusterTaggers", {
+      {""          , "useDB"},
+      {"useDB"     , "useDB"},
+      {"3x3"       , "FutureSubClusterSelector3x3"},
+      {"2x2"       , "FutureSubClusterSelector2x2"},
+      {"SwissCross", "FutureSubClusterSelectorSwissCross"},
+    }, "associate known cluster mask to tagger tool"};
+  
+  Gaudi::Property<std::string> m_condition {this, "ConditionName", ""};
+  Gaudi::Property<std::string> m_det       {this, "Detector"};
+
+  DeCalorimeter*                    m_detector = nullptr;
+  CaloFutureCorrectionBase*               m_dbAccessor = nullptr;
+  std::vector<std::string>          m_DBtaggerE  ;
+  std::vector<std::string>          m_DBtaggerP  ;
+  LHCb::CaloDigitStatus::Status     m_energyStatus = LHCb::CaloDigitStatus::UseForEnergy   |  LHCb::CaloDigitStatus::UseForCovariance;
+  LHCb::CaloDigitStatus::Status     m_positionStatus = LHCb::CaloDigitStatus::UseForPosition |  LHCb::CaloDigitStatus::UseForCovariance;
+  std::string m_sourceE;
+  std::string m_sourceP;
+};
+#endif // SUBCLUSTERSELECTORTOOL_H
diff --git a/CaloFuture/CaloFutureReco/src/TaggedCellFunctor.h b/CaloFuture/CaloFutureReco/src/TaggedCellFunctor.h
new file mode 100644
index 0000000000000000000000000000000000000000..bc66193c10df17da2a3804169b7fd5ad4ef01c95
--- /dev/null
+++ b/CaloFuture/CaloFutureReco/src/TaggedCellFunctor.h
@@ -0,0 +1,102 @@
+#ifndef CALOFUTURECA_TAGGEDCELLFUNCTOR_H
+#define CALOFUTURECA_TAGGEDCELLFUNCTOR_H 1
+// ============================================================================
+// Include files
+// ============================================================================
+// STL
+// ============================================================================
+#include <vector>
+#include <iostream>
+// ============================================================================
+// local
+// ============================================================================
+#include "CelAutoTaggedCell.h"
+// ============================================================================
+/** @namespace TaggedCellFunctor TaggedCellFunctor.h CaloFutureCA/TaggedCellFunctor.h
+ *
+ * Algorithm of clustering
+ * Contain functors for use with STL algorithms
+ * for one CaloFutureTaggedCell*
+ *
+ *  @author  Nicole Brun
+ *  @date    27/02/2001
+ */
+// ============================================================================
+namespace TaggedCellFunctor
+{
+  struct isEdge;
+  struct isClustered;
+  struct isClusteredOrEdge;
+  struct isSeed;
+  class isWithSeed;
+  struct setStatus;
+}
+// ============================================================================
+struct TaggedCellFunctor::isEdge final {
+  // Function
+  inline bool operator() ( const CelAutoTaggedCell* taggedCell ) const {
+    return ( ( 0 == taggedCell ) ? false : taggedCell->isEdge() );
+  }
+
+
+};
+
+struct TaggedCellFunctor::isClustered final {
+  // Function
+
+  inline bool operator() ( const CelAutoTaggedCell* taggedCell ) const {
+    return ( ( 0 == taggedCell ) ? false : taggedCell->isClustered() );
+  }
+
+};
+
+struct TaggedCellFunctor::isClusteredOrEdge final {
+  // Function
+
+  inline bool operator() ( const CelAutoTaggedCell* taggedCell ) const {
+    return ( ( 0 == taggedCell ) ? false : taggedCell->isClustered() || taggedCell->isEdge() );
+  }
+
+};
+
+
+struct TaggedCellFunctor::isSeed final {
+  // Function
+
+  inline bool operator() ( const CelAutoTaggedCell* taggedCell ) const {
+    return ( ( 0 == taggedCell ) ? false : taggedCell->isSeed() );
+  }
+
+};
+
+class TaggedCellFunctor::isWithSeed final {
+
+  public:
+  // Constructor
+
+  isWithSeed( const LHCb::CaloCellID& seed ) :
+    m_seed ( seed ) {};
+
+  // Function
+
+  inline bool operator() ( CelAutoTaggedCell* taggedCell ) const {
+    return ( ( 0 == taggedCell ) ? false : taggedCell->isWithSeed( m_seed )  );
+  }
+
+  private:
+
+  LHCb::CaloCellID m_seed;
+
+};
+
+struct TaggedCellFunctor::setStatus final {
+
+  // Function
+
+  inline void operator() ( CelAutoTaggedCell* taggedCell ) const {
+    taggedCell->setStatus();
+  }
+
+};
+
+#endif // CALOFUTURECA_TAGGEDCELLFUNCTOR_H
diff --git a/CaloFuture/CaloFutureTools/CMakeLists.txt b/CaloFuture/CaloFutureTools/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..0e6d58a618d67c0fbeee1b41623137abc8499653
--- /dev/null
+++ b/CaloFuture/CaloFutureTools/CMakeLists.txt
@@ -0,0 +1,27 @@
+################################################################################
+# Package: CaloFutureTools
+################################################################################
+gaudi_subdir(CaloFutureTools v6r13)
+
+gaudi_depends_on_subdirs(CaloFuture/CaloFutureInterfaces
+                         CaloFuture/CaloFutureUtils
+                         CaloFuture/CaloFutureDAQ
+                         Det/CaloDet
+                         Event/LinkerEvent
+                         Event/RecEvent
+                         Event/TrackEvent
+                         GaudiAlg
+                         Kernel/LHCbKernel
+                         Kernel/LHCbMath
+                         Kernel/Relations
+                         Tr/TrackInterfaces)
+
+find_package(Boost)
+find_package(ROOT)
+find_package(XGBoost REQUIRED)
+include_directories(SYSTEM ${ROOT_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS})
+
+gaudi_add_module(CaloFutureTools
+                 src/*.cpp
+                 INCLUDE_DIRS Tr/TrackInterfaces XGBoost
+                 LINK_LIBRARIES CaloFutureUtils CaloDetLib LinkerEvent RecEvent TrackEvent GaudiAlgLib LHCbKernel LHCbMathLib RelationsLib XGBoost)
diff --git a/CaloFuture/CaloFutureTools/doc/release.notes b/CaloFuture/CaloFutureTools/doc/release.notes
new file mode 100755
index 0000000000000000000000000000000000000000..17cca1b7a90064436886e76ed45fa32d80d97875
--- /dev/null
+++ b/CaloFuture/CaloFutureTools/doc/release.notes
@@ -0,0 +1,333 @@
+!-------------------------------------------------------------------------------
+! Package     : CaloFutureTools
+! Responsible : Olivier Deschamps odescham@in2p3.fr
+!-------------------------------------------------------------------------------
+
+! 2016-06-07 - Olivier Deschamps
+ - CaloFuture2MC tool : fix bug that affect the merged-pi0 matching based on CaloFutureHypo Linker table
+
+! 2016-09-05 - Olivier Deschamps
+  - propagate saturation & barycenter information 
+
+! 2016-08-16 - Olivier Deschamps
+  - new tool : FutureCounterLevel
+  - implement counter() switch based on FutureCounterLevel tool
+
+!========================= CaloFutureTools v6r13 2016-03-17 =========================
+! 2016-02-29 - Olivier Deschamps
+  - fix coverity warning
+
+! 2016-02-22 - Marco Cattaneo
+ - Remove unnecessary friend ToolFactory declaration
+
+!========================= CaloFutureTools v6r12 2016-01-28 =========================
+! 2015-12-19 - O. Deschamps
+ - CaloFuture2MCTool : change default MC association to rely on CaloFutureHypo->MC Linker. In case the Linker doesn't exist
+   the chain CaloFutureHypo->CaloFutureCluster->CaloFutureDigit->MC is used (assuming the reconstruction version is consistent with the original CaloFutureHypos)
+
+! 2015-12-17 - Marco Cattaneo
+ - CaloFutureHypoEstimator.cpp: reorganise an if clause to avoid an FPE with clang
+
+!========================= CaloFutureTools v6r11 2015-11-23 =========================
+! 2015-11-06 - O. Deschamps
+ - fix clang compilation warnings
+
+!========================= CaloFutureTools v6r10p1 2015-10-13 =========================
+! 2015-08-12 - Gerhard Raven
+ - remove #include of obsolete Gaudi headers
+
+!========================= CaloFutureTools v6r10 2014-09-12 =========================
+! 2014-09-12 - O. Deschamps
+  - CaloFutureHypoEstimator.cpp : implement ClusterCode & ClusterFrac 
+
+!========================= CaloFutureTools v6r9 2014-07-14 =========================
+! 2014-06-30 - Olivier Deschamps
+  - FutureGammaPi0SeparationTool : improve & speed-up the evaluation of Prs-related variables 
+                             protect against unphysical value
+
+! 2014-06-29 - Olivier Deschamps
+  - fix FPE's, compilation warnings & verbosity excess
+
+! 2014-06-27 - Olivier Deschamps
+ - FutureNeutralIDTool.{cpp,h}       : (new) implementation for MLP-based neutralID
+ - CaloFutureHypoEstimator.h, FutureGammaPi0SeparationTool.h : update against reco changes
+
+
+!========================= CaloFutureTools v6r8 2014-06-10 =========================
+! 2014-05-23 - Olivier Deschamps
+ - FutureGammaPi0SeparationTool.cpp : fix FPE
+
+!========================= CaloFutureTools v6r7 2013-10-24 =========================
+! 2013-10-09 - Olivier Deschamps
+ - CaloFutureGetterTool, CaloFuture2CaloFuture, FutureGammaPi0SeparationTool, CaloFutureHypo2CaloFuture : protect against the upgrade configuration with no Spd/Prs
+
+! 2013-10-04 - Olivier Deschamps
+ - Add CaloFutureRelationsGetter implementation
+ - Instrument CaloFutureHypoEstimator with CaloFutureRelationsGetter to access relations table
+
+!========================= CaloFutureTools v6r6 2013-07-18 =========================
+! 2013-06-13 - Marco Cattaneo
+ - Fix Coverity DIVIDE_BY_ZERO and FORWARD_NULL defects
+
+!========================= CaloFutureTools v6r5p1 2013-06-03 =======================
+! 2013-05-27 - Marco Cattaneo
+ - Fix clang32 warning
+ - Remove 'do nothing' finalize methods
+
+!========================= CaloFutureTools v6r5 2012-11-28 =========================
+! 2012-11-21 - Marco Clemencic
+ - Added CMake configuration file.
+ - Fixed a warning (-pedantic).
+
+! 2012-10-19 - Marco Cattaneo
+ - Fix gcc -pedantic warnings
+ - Use getItExists where appropriate
+
+!========================= CaloFutureTools v6r4 2012-06-25 =========================
+! 2012-05-29 - Marco Cattaneo
+ - Fix unused variable in previous commit
+ - Fix UNINIT_CTOR defects
+
+! 2012-05-22 - Olivier Deschamps for Miriam Calvo 
+ - FutureGammaPi0SeparationTool  : new version of the tool (incl. Prs info)
+
+! 2012-05-14 - Olivier Deschamps
+ - new algorithm : CheckCaloFutureHypoRef - check CaloFutureHypo->CaloFutureCluster* smart 
+                                      reference backward compatibility 
+
+! 2012-05-10 - Olivier Deschamps
+ - L0CaloFuture2CaloFuture tool : default clusterization level set to 2 
+                      (5x5 area for merged pi0)
+
+!========================= CaloFutureTools v6r3p1 2011-12-14 =========================
+! 2011-11-23 - Marco Cattaneo
+ - Fix trivial gcc warnings and icc remarks
+
+!========================= CaloFutureTools v6r3 2011-07-27 =========================
+! 2011-07-22 - Marco Cattaneo
+ - Create debug() messages only when output level requires it,
+   also using UNLIKELY macro
+ - Replace all endreq by endmsg
+
+! 2011-06-17 - Olivier Deschamps
+  - fix window compilation warning
+
+!========================= CaloFutureTools v6r2 2011-06-15 =========================
+! 2011-06-14 - Olivier Deschamps
+ - extend CaloFutureHypoEstimator : more Prs info + Gamma/pi0 separation info
+ - new FutureGammaPi0SeparationTool + related MLP files
+
+! 2011-05-16 - Olivier Deschamps
+ - L0CaloFuture2CaloFuture tool : clusterize around right seedID
+
+! 2011-05-13 - Olivier Deschamps
+ - L0CaloFuture2CaloFuture tool : allow for managing the cluster on TES externally (new default)
+
+!========================= CaloFutureTools v6r1 2011-02-01 =========================
+! 2011-01-21 - Olivier Deschamps
+ - Fix CaloFuture2MCTool initialization
+
+! 2011-01-19 - Marco Cattaneo
+ - Fix ICC warnings and remarks
+
+!========================= CaloFutureTools v6r0 2010-10-25 =========================
+
+! 2010-10-07 - Dmitry Golubkov
+ - CaloFutureHypo2CaloFuture: change passing parameteres by value to const references
+ - increment version to v6r0 due to the change in the interface
+
+!========================== CaloFutureTools v5r17 2010-09-28 =========================
+! 2010-09-01 - Olivier Deschamps
+  - fix compilation error on windows
+  - improve Track2CaloFuture & CaloFutureHypoEstimator
+
+! 2010-08-31 - Olivier Deschamps
+  - fix compilation warning on slc4
+
+! 2010-08-27 - O. Deschamps
+ - new tool CaloFutureHypoEstimator + update CaloFutureHypo2CaloFuture
+
+!========================== CaloFutureTools v5r16p1 2010-06-21 =======================
+! 2010-06-10 - Marco Cattaneo
+ - Fix Windows compilation warnings
+
+!========================== CaloFutureTools v5r16 2010-03-18 =========================
+! 2010-03-08 - Olivier Deschamps
+	- CaloFutureHypoToCaloFuture: Implement new virtual method _setProperty
+
+!========================== CaloFutureTools v5r15 2010-02-15 =========================
+! 2010-02-13 - Olivier Deschamps
+	- Track2CaloFuture : switch HeraBExtrapolator to RungeKutta
+
+!========================== CaloFutureTools v5r14 2009-11-27 =========================
+! 2009-11-17 - Olivier Deschamps
+ - CaloFuture2MCTool : 
+  - new methods :
+      isCaloFuture(particle) 
+      isPureNeutralCaloFuture(particle) 
+      findMCOrBest(string/ParticleID,threshold)
+  - complete the code (still not fully completed)
+
+!========================== CaloFutureTools v5r13 2009-11-13 =========================
+! 2009-11-05 - Dmitry GOLUBKOV
+ - L0CaloFuture2CaloFutureTool : bugfix - make storage of all created clusters on TES the
+   only supported behaviour (therefore remove the 'DuplicateClustersOnTES' property),
+   use CaloFutureFunctors::neighbours() instead of look_neig()
+ - cmt/requirements version increment to v5r13
+
+!========================== CaloFutureTools v5r12 2009-10-20 =========================
+! 2009-12-21 - Olivier Deschamps
+  -  adapt to change in CaloFutureDAQ
+  -  improve CaloFuture2MCTool.{cpp,h} : not yet complete but usable 
+
+! 2009-09-15 - Olivier Deschamps
+  - new tool : CaloFuture2MCTool.{cpp,h} : handle CaloFuture object->MC relation
+							 (interface CaloFutureInterfaces/ICaloFuture2MCTool.h)
+      - preliminary (incomplete) version of the tool
+  - use Relations in requirements
+
+! 2009-09-14 - Olivier Deschamps
+  - adapt to change in CaloFutureDAQ/CaloFutureReadoutTool 
+    (->CaloFutureCosmicsTool & CaloFutureGetterTool & L0CaloFuture2CaloFutureTool)
+
+! 2009-09-11 - Olivier Deschamps
+ - CaloFuture2CaloFuture.cpp : 
+   - make use of CaloFutureAlgUtils.h to define context-dependent TES I/O 
+   - caloGetterTool : public -> private tool
+   - use caloGetterTool in isLocMax(id) method
+
+
+! 2009-09-11 - Olivier Deschamps
+ - CalOGetterTool.cpp : make use of CaloFutureAlgUtils.h to define context-dependent TES I/O 
+
+! 2009-09-04 - Dmitry Golubkov
+ - cmt/requirements version increment to v5r12
+ - release.notes : fix the order of the comments 2009-08-02
+ - L0CaloFuture2CaloFutureTool.cpp: decrease error level for invalid ur/dr/ul cells
+
+!========================== CaloFutureTools v5r11 2009-09-03 =========================
+! 2009-09-03 - Marco Cattaneo
+ - Remove obsolete file src/CaloFutureTools_dll.cpp
+
+! 2009-08-05 - Stephanie Hansmann-Menzemer
+ - remove filling of track-extra info, according to changes in Track.xml class
+
+!========================== CaloFutureTools v5r10p1 2009-09-07 =========================
+! 2009-09-04 - Dmitry Golubkov
+ - L0CaloFuture2CaloFutureTool.cpp: decrease error level for invalid ur/dr/ul cells
+
+!========================== CaloFutureTools v5r10 2009-08-31 =========================
+
+! 2009-12-10 - Olivier Deschamps
+ - adapt to change in CaloFutureDAQ
+
+! 2009-08-10 - Vanya BELYAEV
+ - CaloFuture2CaloFuture & CaloFutureGetter 
+    fix the problem of mandatory "update" 
+
+! 2009-08-05 - Vanya BELYAEV
+ - fix the signature 
+
+! 2009-08-02 - Dmitry GOLUBKOV
+ - L0CaloFuture2CaloFutureTool.cpp: method to return CaloFutureClusters around the CaloFutureCellID
+
+! 2009-07-31 - Dmitry Golubkov
+ - L0CaloFuture2CaloFutureTool.cpp - fix compilation warnings on slc4
+
+! 2009-07-29 - Dmitry GOLUBKOV
+ - Add a new tool to get a list of CaloFutureClusters for the input L0CaloFutureCandidate(s)
+  L0CaloFuture2CaloFutureTool.cpp, L0CaloFuture2CaloFutureTool.h
+ - cmt/requirements verison increment to v5r10
+
+!========================== CaloFutureTools v5r9 2009-06-03 =========================
+! 2009-06-03 - Marco Cattaneo
+ - Add missing CaloFutureTools_dll.cpp file
+
+! 2009-05-19 - Marco Cattaneo
+ - Add missing #include "Event/Particle.h" following removal from IPart2CaloFuture.h
+ - Replace endreq by endmsg
+
+! 2009-05-10 - Vanya Belyaev
+ - a bit more statistical prinout  
+ - cmt/requirements
+     verison increment to v5r9
+
+!========================== CaloFutureTools v5r8 2009-05-08 =========================
+! 2008-04-17 - Olivier Deschamps
+ - new tool CaloFutureGetterTool : helps to speed-up CaloFutureReco processing
+ - CaloFuture2CaloFuture/CaloFutureHypo2CaloFuture : get digits data via CaloFutureGetterTool
+
+! 2009-04-16 Olivier Deschamps
+ - CaloFuture2CaloFuture/CaloFutureHypo2CaloFuture : speed-up processing + new property ('IdealGeometry')
+   when perfect alignment is assumed
+
+!========================== CaloFutureTools v5r7 2009-03-10 =========================
+! 2009-03-09 Olivier Deschamps
+ - Fix bad default setting for CaloFutureHypo2CaloFuture.cpp (Seed=false -> true)  + minor bug fix
+
+! 2009-03-05 Olivier Deschamps
+ - improve verbosity for CaloFutureCosmics stuff
+
+!========================== CaloFutureTools v5r6 2009-01-12 =========================
+! 2008-12-10 - Marco Cattaneo
+ - Fix gcc 4.3 warnings
+
+! 2008-12-05 - Olivier Deschamps
+ - CaloFutureCosmicsTrackTool :: fix bug in Hcal timing 
+
+!========================== CaloFutureTools v5r5 2008-10-01 =========================
+! 2008-09-11 - Olivier Deschamps
+ - CaloFuture2CaloFuture :: add multiplicity method
+ - new tool : CaloFutureHypo2CaloFuture : specialized version of CaloFuture2CaloFuture
+
+!========================== CaloFutureTools v5r4 2008-09-04 =========================
+! 2008-08-21 - Olivier Deschamps
+ - CaloFutureCosmicsTrackAlg : add monitoring histo for cosmics track (theta,phi) parameters
+ - CaloFutureCosmicsTool : add cellId vector in the output ntuple
+
+!========================== CaloFutureTools v5r3 2008-07-29 =========================
+! 2008-07-21 - Marco Cattaneo
+ - Adapt to new location of IEventTimeDecoder.h (needs Gaudi v20r2)
+
+!========================== CaloFutureTools v5r2 2008-07-02 =========================
+! 2008-06-30 - Olivier Deschamps
+ - add asymmetry monitoring in CaloFutureCosmicsTrackAlg
+ - add 'kernel' variable computation in CaloFutureCosmicsTool 
+
+! 2008-06-26 - Juan PALACIOS
+ - cmt/requirements
+  . Increase version to v5r2
+ - src/CaloFutureCosmicsTool.cpp
+ - src/CaloFutureCosmicsTrackTool.cpp
+ - src/Track2CaloFuture.cpp
+  . Change all Gaudi::XYZLine and Gaudi::Line for Gaudi::Math::XYZLine and
+    Gaudi::Math::XYZLine respectively (adapting to Kernel/LHCbMath v3)
+
+!========================== CaloFutureTools v5r1 2008-06-05 =========================
+! 2008-06-05 - Marco Cattaneo
+  - Fix acos() for windows (cannot take an int argument)
+  
+! 2008-06-04 - Deschamps Olivier
+  - tune the verbosity
+
+! 2008-06-03 - Marco Cattaneo
+ - In CaloFutureCosmicsTool.cpp: fix compiler warning, add missing include
+ - In CaloFutureCosmicsTrackTool.cpp, CaloFutureCosmicsTrackAlg.cpp: add missing includes
+
+! 2008-05-29 - Deschamps Olivier
+  - use dedicated TrackEvent/Track flags
+
+! 2008-05-29 - Deschamps Olivier
+  - add more monitoring histo (split monitoring according to forward/backward cosmics tracks)
+
+! 2008-05-27 - Deschamps Olivier
+  - fix bug in CaloFutureCosmicsTrackTool.cpp (Hcal state replicated Ecal state)
+
+! 2008-05-22 - Deschamps Olivier
+  - Add new tools and alg for cosmics track reconstruction in calorimeter : 
+	CaloFutureCosmicsTool, CaloFutureCosmicsTrackTool, CaloFutureCosmicsTrackAlg
+
+!========================== CaloFutureTools v5r0 2008-05-08 =========================
+! 2008-05-08 - Marco Cattaneo
+ - Resurrect CaloFutureTools package (declared obsolete in 2002). It is now a
+   component library for CaloFuturerimeter Tools, previously in CaloFutureUtils link library
diff --git a/CaloFuture/CaloFutureTools/src/CaloFuture2CaloFuture.cpp b/CaloFuture/CaloFutureTools/src/CaloFuture2CaloFuture.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..593bb857fb18cfd4ccf7b000dfe2353143679c27
--- /dev/null
+++ b/CaloFuture/CaloFutureTools/src/CaloFuture2CaloFuture.cpp
@@ -0,0 +1,295 @@
+// ============================================================================
+// Include files 
+// ============================================================================
+#include "Kernel/CaloCellCode.h"
+// ============================================================================
+// CaloFutureUtils
+// ============================================================================
+#include "CaloFutureUtils/CaloFutureDataFunctor.h"
+#include "CaloFutureUtils/CaloFutureAlgUtils.h"
+// ============================================================================
+// local
+// ============================================================================
+#include "CaloFuture2CaloFuture.h"
+// ============================================================================
+/** @file 
+ *  Implementation file for class : CaloFuture2CaloFuture
+ *  @date 2007-05-29 
+ *  @author Olivier Deschamps
+ */
+// ============================================================================
+// Declaration of the Tool Factory
+DECLARE_COMPONENT( CaloFuture2CaloFuture )
+// ============================================================================
+
+
+//=============================================================================
+// Standard constructor, initializes variables
+//=============================================================================
+CaloFuture2CaloFuture::CaloFuture2CaloFuture( const std::string& type,
+                      const std::string& name,
+                      const IInterface* parent )
+  : base_class ( type, name , parent )
+{
+  declareInterface<ICaloFuture2CaloFuture>(this);
+}
+//=============================================================================
+StatusCode CaloFuture2CaloFuture::initialize()
+{
+  StatusCode sc = base_class::initialize();
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+    debug() << "Initialize CaloFuture2CaloFuture tool " << endmsg;
+  
+  // get getter tool : public tool
+  m_getter = tool<ICaloFutureGetterTool>("CaloFutureGetterTool",m_getterName);
+
+  // CaloDigit locations
+  m_loc["Ecal"]=  LHCb::CaloFutureAlgUtils::CaloFutureDigitLocation( "Ecal" , context() );
+  m_loc["Hcal"]=  LHCb::CaloFutureAlgUtils::CaloFutureDigitLocation( "Hcal" , context() );
+  m_loc["Prs"] =  LHCb::CaloFutureAlgUtils::CaloFutureDigitLocation( "Prs"  , context() );
+  m_loc["Spd"] =  LHCb::CaloFutureAlgUtils::CaloFutureDigitLocation( "Spd"  , context() );
+  // DeCalorimeter* pointers
+  int mask=m_getter->detectorsMask();
+  m_det["Ecal"]=getDet<DeCalorimeter>( DeCalorimeterLocation::Ecal );
+  m_det["Hcal"]=getDet<DeCalorimeter>( DeCalorimeterLocation::Hcal );
+  m_det["Prs"]=((mask&2)==0) ? NULL : getDetIfExists<DeCalorimeter>( DeCalorimeterLocation::Prs   );
+  m_det["Spd"]=((mask&1)==0) ? NULL : getDetIfExists<DeCalorimeter>( DeCalorimeterLocation::Spd   );
+  // CellSize reference (outer section)  Warning : factor 2 for Hcal
+  m_refSize["Hcal"] = (*(m_det["Hcal"]->cellParams().begin())).size()/2.;
+  m_refSize["Ecal"] = (*(m_det["Ecal"]->cellParams().begin())).size(); 
+  if(NULL != m_det["Prs"])m_refSize["Prs"]  = (*(m_det["Prs"]->cellParams().begin())).size(); 
+  if(NULL != m_det["Spd"])m_refSize["Spd"]  = (*(m_det["Spd"]->cellParams().begin())).size(); 
+  // CaloPlanes
+  m_plane["Hcal"] = m_det["Hcal"]->plane(CaloPlane::ShowerMax );
+  m_plane["Ecal"] = m_det["Ecal"]->plane(CaloPlane::ShowerMax );
+  if(NULL != m_det["Prs"])m_plane["Prs"]  = m_det["Prs"]->plane(CaloPlane::ShowerMax );
+  if(NULL != m_det["Spd"])m_plane["Spd"]  = m_det["Spd"]->plane(CaloPlane::ShowerMax );  
+
+  reset();
+
+  if((m_fromCaloFuture == "Hcal" || m_fromCaloFuture == "Ecal" || m_fromCaloFuture == "Prs" || m_fromCaloFuture == "Spd" ) &&  
+     (m_toCaloFuture   == "Hcal" || m_toCaloFuture   == "Ecal" || m_toCaloFuture   == "Prs" || m_toCaloFuture   == "Spd" ) )setCalos(m_fromCaloFuture,m_toCaloFuture);
+  // 
+
+  if( UNLIKELY( msgLevel(MSG::DEBUG) )){
+    if( NULL == m_det["Prs"] && (m_fromCaloFuture=="Prs" || m_toCaloFuture=="Prs"))
+      debug() << "Try to access non-existing Prs DetectorElement" << endmsg;
+    if( NULL == m_det["Spd"] && (m_fromCaloFuture=="Spd" || m_toCaloFuture=="Spd"))
+      debug() << "Try to access non-existing Spd DetectorElement" << endmsg;
+  }
+  return sc;
+}
+
+void CaloFuture2CaloFuture::reset(){
+  m_digits.clear();
+  m_cells.clear();
+  m_energy = 0;
+  m_count  = 0;
+}
+
+void CaloFuture2CaloFuture::setCalos
+( const std::string& fromCaloFuture ,
+  const std::string& toCaloFuture   )
+{ 
+
+  m_ok       = true;
+  if( NULL == m_det["Prs"] && (fromCaloFuture=="Prs" || toCaloFuture=="Prs")){    
+    if( UNLIKELY( msgLevel(MSG::DEBUG) ) )debug() <<"Try to access non-existing Prs DetectorElement"<<endmsg;    
+    m_ok = false;
+    return;
+  }
+  
+  if( NULL == m_det["Spd"] && (fromCaloFuture=="Spd" || toCaloFuture=="Spd")){
+    if( UNLIKELY( msgLevel(MSG::DEBUG) ) )debug() <<"Try to access non-existing Spd DetectorElement"<<endmsg;    
+    m_ok=false;
+    return;
+  }
+
+  m_fromCaloFuture = fromCaloFuture;
+  m_toCaloFuture   = toCaloFuture;
+  m_fromDet  = m_det[m_fromCaloFuture];
+  m_fromSize = m_refSize[m_fromCaloFuture];
+  m_toDet    = m_det[m_toCaloFuture];
+  m_toPlane  = m_plane[m_toCaloFuture];
+  m_toSize   = m_refSize[m_toCaloFuture];
+  m_toLoc    = m_loc[ m_toCaloFuture ];
+
+
+  
+
+ }
+//=======================================================================================================
+const std::vector<LHCb::CaloCellID>& CaloFuture2CaloFuture::cellIDs ( const LHCb::CaloCluster& fromCluster , 
+                                                          const std::string&       toCaloFuture      ){
+  
+  reset();
+  LHCb::CaloCellID seedID = fromCluster.seed();
+  std::string fromCaloFuture = CaloCellCode::CaloNameFromNum( seedID.calo() );
+  if( toCaloFuture != m_toCaloFuture || fromCaloFuture != m_fromCaloFuture)setCalos(fromCaloFuture,toCaloFuture);
+  if( !m_ok )return m_cells;
+
+  for(const auto& ent : fromCluster.entries() ) {
+    const LHCb::CaloDigit* digit = ent.digit();
+    if ( digit ) cellIDs( digit->cellID() , toCaloFuture, false );
+  }
+  return m_cells;
+}
+//=======================================================================================================
+const std::vector<LHCb::CaloCellID>& CaloFuture2CaloFuture::addCell( const LHCb::CaloCellID& id     , 
+                                                         const std::string&      toCaloFuture ){
+
+  if( !m_ok )return m_cells;
+  // consistency check
+  if( CaloCellCode::CaloNameFromNum(id.calo()) != m_toCaloFuture || toCaloFuture != m_toCaloFuture ){
+    Warning("CellID is not consistent with CaloFuture setting").ignore();
+    return m_cells;
+  }
+  // check duplicate
+  if ( m_cells.end() != std::find ( m_cells.begin() , m_cells.end() , id ) ) { return m_cells ; }
+  
+  // add the cells
+  m_cells.push_back( id );
+  
+  // added by VB.
+  if ( 0 == m_digs ) 
+  {
+    Error ( "Digits* points to NULL") ;
+    return m_cells ;
+  }
+
+  LHCb::CaloDigit* digit = m_digs->object( id );
+  if( NULL != digit ) {
+    m_digits.push_back( digit );
+    m_energy += digit->e();
+    m_count++;
+  }
+  return m_cells;
+}
+
+
+//=======================================================================================================
+const std::vector<LHCb::CaloCellID>& 
+CaloFuture2CaloFuture::cellIDs ( const LHCb::CaloCellID& fromId , 
+                     const std::string&      toCaloFuture , bool init ){
+  
+  if( init )reset();
+  std::string fromCaloFuture = CaloCellCode::CaloNameFromNum( fromId.calo() );
+  if( toCaloFuture != m_toCaloFuture || fromCaloFuture != m_fromCaloFuture)setCalos(fromCaloFuture,toCaloFuture);
+  if( !m_ok )return m_cells;
+
+  LHCb::CaloCellID toId = fromId;
+  // ---- Assume ideal geometry : trivial mapping for detectors having the same granularity (Prs/Spd/Ecal)
+  if( ( m_geo && (m_fromCaloFuture == "Ecal" || m_fromCaloFuture == "Prs" || m_fromCaloFuture == "Spd") 
+        && (m_toCaloFuture == "Ecal" || m_toCaloFuture == "Prs" || m_toCaloFuture == "Spd") ) 
+      || m_fromCaloFuture.value() == m_toCaloFuture.value() ){
+    toId.setCalo( CaloCellCode::CaloNumFromName( m_toCaloFuture ));
+    if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+      debug() << "Add cell from trivial mapping" << endmsg;
+    return addCell( toId , m_toCaloFuture);
+  }
+  
+  // ---- Else use the actual geometry to connet detectors
+  double scale = 1.;
+  Gaudi::XYZPoint  center = m_fromDet->cellCenter( fromId );
+  if( m_fromCaloFuture.value() != m_toCaloFuture.value() ){
+    // z-scaling
+    scale = m_toSize / m_fromSize ;
+    center  = m_toPlane.ProjectOntoPlane( m_fromDet->cellCenter( fromId )*scale );
+    // connect
+    toId  = m_toDet->Cell( center );
+  }
+  double fromSize = m_fromDet->cellSize( fromId )*scale;
+  //cell-center is outside 'toCaloFuture' - check corners  
+  if( LHCb::CaloCellID() == toId){
+    for( int i = 0 ; i != 2; ++i){
+      for( int j = 0 ; j != 2; ++j){
+        double x = m_fromDet->cellCenter( fromId ).X() + (i*2-1) * fromSize;        
+        double y = m_fromDet->cellCenter( fromId ).Y() + (j*2-1) * fromSize;
+        Gaudi::XYZPoint  corner = Gaudi::XYZPoint(x,y,center.Z());
+        LHCb::CaloCellID cornerId  = m_toDet->Cell( corner );
+        if( LHCb::CaloCellID() == cornerId)continue;
+        toId=cornerId;
+      }   
+    }
+  }
+  if( LHCb::CaloCellID() == toId)return m_cells;
+  int pad = 1;
+  double x0  = center.X();
+  double y0  = center.Y();
+  if( m_fromDet != m_toDet ){
+    double toSize   = m_toDet->cellSize( toId ) ;
+    pad =  (int) floor( fromSize  / toSize + 0.25); // warning int precision
+    if(pad < 1)pad=1;
+    x0 = center.X() - (pad-1)*fromSize/2./pad;
+    y0 = center.Y() - (pad-1)*fromSize/2./pad;  
+  }
+  for( int i = 0 ; i != pad; ++i){
+    for( int j = 0 ; j != pad; ++j){
+      double x = x0 + i * fromSize/pad;
+      double y = y0 + j * fromSize/pad;    
+      Gaudi::XYZPoint  pos(x,y,center.Z());
+      if( m_fromDet != m_toDet ) toId  = m_toDet->Cell( pos ) ;
+      if( LHCb::CaloCellID() == toId)continue;
+      addCell( toId, m_toCaloFuture);
+    }        
+  }
+  return m_cells;
+}
+
+
+// Digits
+const std::vector<LHCb::CaloDigit*>& CaloFuture2CaloFuture::digits( const LHCb::CaloCellID& fromId ,
+                                                        const std::string& toCaloFuture ){  
+  m_digs     = m_getter->digits( m_toLoc );  
+  cellIDs( fromId, toCaloFuture ) ;
+  return m_digits;
+}
+
+const std::vector<LHCb::CaloDigit*>& CaloFuture2CaloFuture::digits( const LHCb::CaloCluster& fromCluster , 
+                                                        const std::string& toCaloFuture ){  
+  m_digs     = m_getter->digits( m_toLoc );  
+  cellIDs( fromCluster, toCaloFuture);
+  return m_digits;
+}  
+
+// Energy
+double CaloFuture2CaloFuture::energy( const LHCb::CaloCellID& fromId , 
+                          const std::string&      toCaloFuture ){
+  m_digs     = m_getter->digits( m_toLoc );  
+  cellIDs ( fromId , toCaloFuture );
+  return m_energy;
+}
+
+
+int CaloFuture2CaloFuture::multiplicity( const LHCb::CaloCellID& fromId , 
+                             const std::string&      toCaloFuture ){
+  m_digs     = m_getter->digits( m_toLoc );  
+  cellIDs(fromId, toCaloFuture);
+  return m_count;
+}
+
+double CaloFuture2CaloFuture::energy( const LHCb::CaloCluster& fromCluster , 
+                          const std::string&  toCaloFuture ){
+  m_digs     = m_getter->digits( m_toLoc );  
+  cellIDs(fromCluster, toCaloFuture);
+  return m_energy;
+}
+
+
+int CaloFuture2CaloFuture::multiplicity( const LHCb::CaloCluster& fromCluster , 
+                             const std::string& toCaloFuture ){
+  m_digs     = m_getter->digits( m_toLoc );  
+  cellIDs(fromCluster, toCaloFuture);
+  return m_count;
+}
+
+// ============================================================================
+// Additional method : isLocalMax
+bool CaloFuture2CaloFuture::isLocalMax ( const LHCb::CaloDigit& digit){
+  const LHCb::CaloCellID& id = digit.cellID();
+  std::string    calo = CaloCellCode::CaloNameFromNum( id.calo() );
+  DeCalorimeter* det  = m_det[ calo ];
+  const LHCb::CaloDigits* digits = m_getter->digits( m_loc[ calo ] ); 
+  //
+  return LHCb::CaloFutureDataFunctor::isLocalMax ( &digit , det , digits ) ;
+}
diff --git a/CaloFuture/CaloFutureTools/src/CaloFuture2CaloFuture.h b/CaloFuture/CaloFutureTools/src/CaloFuture2CaloFuture.h
new file mode 100644
index 0000000000000000000000000000000000000000..4396771bc034b7832afce97bca0d8920afd1ba3c
--- /dev/null
+++ b/CaloFuture/CaloFutureTools/src/CaloFuture2CaloFuture.h
@@ -0,0 +1,90 @@
+#ifndef CALOFUTURE2CALOFUTURE_H
+#define CALOFUTURE2CALOFUTURE_H 1
+
+// Include files
+// from Gaudi
+#include "GaudiAlg/GaudiTool.h"
+#include "CaloFutureInterfaces/ICaloFuture2CaloFuture.h"            // Interface
+#include "CaloDet/DeCalorimeter.h"
+#include  "CaloFutureInterfaces/ICaloFutureGetterTool.h"
+/** @class CaloFuture2CaloFuture CaloFuture2CaloFuture.h
+ *
+ *
+ *  @author Olivier Deschamps
+ *  @date   2007-05-29
+ */
+
+class CaloFuture2CaloFuture : public extends<GaudiTool, ICaloFuture2CaloFuture> {
+public:
+  /// Standard constructor
+  CaloFuture2CaloFuture( const std::string& type,
+             const std::string& name,
+             const IInterface* parent);
+
+  StatusCode initialize() override;
+  // setting
+  void setCalos ( const std::string& fromCaloFuture ,
+                  const std::string& toCaloFuture   ) override;
+  // CaloCellIDs
+  const std::vector<LHCb::CaloCellID>&
+  cellIDs ( const LHCb::CaloCluster& fromCluster ,
+            const std::string&       toCaloFuture      ) override;
+  const std::vector<LHCb::CaloCellID>&
+  cellIDs ( const LHCb::CaloCellID&  fromId     ,
+            const std::string&       toCaloFuture, bool init=true) override;
+  const std::vector<LHCb::CaloCellID>& cellIDs() override {return m_cells;};
+  // Digits
+  const std::vector<LHCb::CaloDigit*>& digits
+  ( const LHCb::CaloCellID& fromId     ,
+    const std::string&      toCaloFuture     ) override;
+  const std::vector<LHCb::CaloDigit*>& digits
+  ( const LHCb::CaloCluster& fromCluster ,
+    const std::string&       toCaloFuture    ) override;
+  const std::vector<LHCb::CaloDigit*>& digits() override {return m_digits;};
+  // Energy
+  double energy ( const LHCb::CaloCellID&  fromId ,
+                  const std::string&       toCaloFuture ) override;
+  double energy ( const LHCb::CaloCluster& fromCluster ,
+                  const std::string&       toCaloFuture ) override;
+  double energy () override {return m_energy;};
+  // multiplicity
+  int multiplicity( const LHCb::CaloCellID&  fromId ,
+                    const std::string&       toCaloFuture ) override;
+  int multiplicity( const LHCb::CaloCluster& fromCluster ,
+                    const std::string&       toCaloFuture ) override;
+  int multiplicity() override {return m_count;};
+  // Additional
+  bool isLocalMax ( const LHCb::CaloDigit& digit) override;
+
+protected:
+  //
+  void reset();
+  const std::vector<LHCb::CaloCellID>& addCell
+  ( const LHCb::CaloCellID& id, const std::string& toCaloFuture);
+  // CaloFuture Maps
+  std::map<std::string,DeCalorimeter*> m_det;
+  std::map<std::string,std::string> m_loc;
+  std::map<std::string,double>m_refSize;
+  std::map<std::string,Gaudi::Plane3D> m_plane;
+  //
+  Gaudi::Property<std::string> m_fromCaloFuture {this, "FromCaloFuture", "??"};
+  Gaudi::Property<std::string> m_toCaloFuture {this, "ToCaloFuture", "??"};
+  std::vector<LHCb::CaloCellID> m_cells;
+  std::vector<LHCb::CaloDigit*>  m_digits;
+  double m_energy = 0.;
+  int m_count = 0;
+  DeCalorimeter* m_fromDet = nullptr;
+  DeCalorimeter* m_toDet = nullptr;
+  double m_fromSize = 0.;
+  double m_toSize = 0.;
+  std::string m_toLoc;
+  Gaudi::Plane3D m_toPlane;
+  LHCb::CaloDigits* m_digs = nullptr;
+  ICaloFutureGetterTool* m_getter = nullptr;
+  bool m_ok = true;
+private:
+  Gaudi::Property<bool> m_geo {this, "IdealGeometry", true};
+  Gaudi::Property<std::string> m_getterName {this, "GetterName", "CaloFutureGetter"};
+
+};
+#endif // CALOFUTURE2CALOFUTURE_H
diff --git a/CaloFuture/CaloFutureTools/src/CaloFuture2MCTool.cpp b/CaloFuture/CaloFutureTools/src/CaloFuture2MCTool.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7f31d715d0d8a60a842277fca1a402ce0dbcf651
--- /dev/null
+++ b/CaloFuture/CaloFutureTools/src/CaloFuture2MCTool.cpp
@@ -0,0 +1,559 @@
+// Include files
+#include "boost/algorithm/string.hpp"
+
+// from LHCb
+#include "Relations/RelationWeighted1D.h"
+#include "CaloFutureUtils/CaloFutureParticle.h"
+#include "CaloFutureUtils/CaloFuture2MC.h"
+#include "GaudiKernel/IRegistry.h"
+#include "Linker/LinkedTo.h"
+#include "Linker/LinkedFrom.h"
+
+// local
+#include "CaloFuture2MCTool.h"
+
+//-----------------------------------------------------------------------------
+// Implementation file for class : CaloFuture2MCTool
+//
+// 2009-07-27 : Olivier Deschamps
+//-----------------------------------------------------------------------------
+
+// Declaration of the Tool Factory
+DECLARE_COMPONENT( CaloFuture2MCTool )
+
+//=============================================================================
+// Standard constructor, initializes variables
+//=============================================================================
+CaloFuture2MCTool::CaloFuture2MCTool( const std::string& type,
+                          const std::string& name,
+                          const IInterface* parent )
+  : base_class ( type, name , parent )
+{
+  declareInterface<ICaloFuture2MCTool>(this);
+  m_cluster2MCLoc = "Relations/" + ( boost::iequals( context(), "HLT")
+                                     ? LHCb::CaloClusterLocation::DefaultHlt
+                                     : LHCb::CaloClusterLocation::Default );
+}
+
+//=============================================================================
+
+
+StatusCode CaloFuture2MCTool::initialize(){
+  StatusCode sc = base_class::initialize();
+  if (sc.isFailure()) return Error("Failed to initialize", sc);
+  m_ppsvc = service( "LHCb::ParticlePropertySvc", true);
+  if( !m_ppsvc )return StatusCode::FAILURE;
+
+  // incidentSvc
+  IIncidentSvc* inc = incSvc() ;
+  if ( 0 != inc )inc -> addListener  ( this , IncidentType::BeginEvent ) ;
+
+
+  // init
+  counterStat = tool<IFutureCounterLevel>("FutureCounterLevel");
+  m_digit   = nullptr;
+  m_cluster = nullptr;
+  m_hypo    = nullptr;
+  m_proto   = nullptr;
+  m_part    = nullptr;
+  m_digit2MC= nullptr;
+  m_cluster2MC=nullptr;
+  m_category = 0 ;
+  m_depth    = -1 ;
+  //m_hypo2MC = nullptr;
+  // get fragment tool and propagate properties
+  m_tool = tool<ICaloFuture2MCTool>("CaloFuture2MCTool/CaloFutureFragment2MCTool"); // CAUTION : THE TOOL CANNOT BE PRIVATE !!
+  //@TODO: dynamic_cast to IProperty... remove IProperty from ICaloFuture2MCTool...
+  m_tool->setProperty ( "Cluster2MCTable" , m_cluster2MCLoc ) ;
+  m_tool->setProperty ( "Digit2MCTable"   , m_digit2MCLoc   ) ;
+  m_tool->setProperty ( "Cluster2Digits"  , Gaudi::Utils::toString( m_cluster2Digit.value() ) );
+  m_tool->setProperty ( "Hypo2Cluster"    , Gaudi::Utils::toString( m_hypo2Cluster.value()  ) );
+  m_tool->setProperty ( "Merged2Split"    , Gaudi::Utils::toString( m_merged2Split.value()  ) );
+  m_tool->setProperty ( "DigitStatusFilter"  , Gaudi::Utils::toString( m_sFilter.value()    ) );
+
+  m_sum = 0.;
+  m_maxMC  = nullptr ;
+  m_bestMC = nullptr ;
+
+  //
+  if( m_hypo2Cluster) {
+    Warning(" ... Hypo->Cluster reference is used in CaloFuture2MC  ", StatusCode::SUCCESS).ignore();
+    Warning(" ... CaloFutureCluster  will be re-processed (require full DST)", StatusCode::SUCCESS).ignore();
+    Warning(" ... assume an identical reconstruction version  ", StatusCode::SUCCESS).ignore();
+  }
+  //
+  clear();
+  return StatusCode::SUCCESS;
+}
+
+
+
+
+/*-------------------------- from Part to MC  ------------------------*/
+// associate single particle
+ICaloFuture2MCTool* CaloFuture2MCTool::from(const LHCb::Particle*   part  ){
+  if( part == m_part)return this; // process only if needed
+
+  clear();
+  m_depth = 4; // particle level
+  if( !part )return this;
+
+  // check the particle is full calorimetric (using caloParticle functionalities)
+  LHCb::CaloFutureParticle cPart = LHCb::CaloFutureParticle( (LHCb::Particle*) part );
+  if( !cPart.isCaloFuture() ){
+    Warning("Cannot associate non-pure calorimetric particle to MC").ignore();
+    return this;
+  }
+
+
+  // register final state particles
+  m_parts = cPart.caloEndTree();
+  m_part = const_cast<LHCb::Particle*>(part);
+  if( m_parts.empty())m_parts.push_back( part );
+
+
+
+  // particle->protoparticle cascade (mandatory)
+  m_depth=3; // protoparticle level
+  for(const auto& fs : m_parts ) {
+    const LHCb::ProtoParticle* proto = fs->proto();
+    if( !proto){
+      Warning("ProtoParticle point to NULL (should not)").ignore();
+      continue;
+    }
+    addProto( proto , fs );
+  }
+ StatusCode sc = process();
+  if ( sc.isFailure() )Warning("Processing CaloFuture2MCTool from Particle failed").ignore();
+  return this;
+}
+
+
+/*-------------------------- from Proto to MC  ------------------------*/
+// Accumulate protos->hypo()s [->clusters]
+void CaloFuture2MCTool::addProto(const LHCb::ProtoParticle* proto, const LHCb::Particle* parent ){
+  if( !proto)return;
+
+  // register proto if not yet done
+  bool ok = std::none_of( m_protos.begin(), m_protos.end(),
+                          [&](const LHCb::ProtoParticle* p) { return p == proto; } );
+  if(!ok){
+    if( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+      debug() << "ProtoParticle appears twice in the same decay chain" << endmsg;
+    if(counterStat->isQuiet())counter("ProtoParticle appears twice in the same decay chain" ) += 1.;
+    return;
+  }
+  m_protos.push_back( proto ) ;
+
+
+  // proto->hypo cascade (mandatory)
+  m_depth = 2; // hypo level
+  const auto& hypos = proto->calo();
+  if( hypos.empty() )return;
+
+  // special treatment for Bremstrahlung electrons
+  bool charged = ( proto->track() );/* charged part->proto */
+  if (!charged) {
+    for( const auto& hypo : hypos ) addHypo( hypo );
+  } else {
+    bool brem = ( parent && ( std::abs(parent->momentum().P() - proto->track()->firstState().p())> 1E-4 ) );/* bremstrahlung corrected particle */
+    for( const auto& hypo : hypos ) {
+       if ( hypo->hypothesis() == LHCb::CaloHypo::Hypothesis::EmCharged  ||
+          ( brem && hypo->hypothesis() == LHCb::CaloHypo::Hypothesis::Photon ) ) addHypo(hypo);
+    }
+  }
+}
+
+// associate single protoParticle
+ICaloFuture2MCTool* CaloFuture2MCTool::from(const LHCb::ProtoParticle*   proto  ){
+  if( proto == m_proto)return this; // process only if needed
+  clear();
+  m_depth = 3; // proto level
+  if( !proto  )return this;
+  m_proto = const_cast<LHCb::ProtoParticle*>(proto);
+  addProto( proto );
+  StatusCode sc = process();
+  if ( sc.isFailure() )Warning("Processing CaloFuture2MCTool from ProtoParticle failed").ignore();
+  return this;
+}
+
+
+/*-------------------------- from Hypo to MC  ------------------------*/
+// Accumulate hypos [->clusters]
+void CaloFuture2MCTool::addHypo(const LHCb::CaloHypo* hypo){
+  if( !hypo  )return;
+  // register hypo if not yet done
+  bool ok = std::none_of( m_hypos.begin(), m_hypos.end(),
+                          [&](const auto& h) { return h==hypo; } );
+  if(!ok){
+    if( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+      debug() << "CaloFutureHypo appears twice in the same decay chain" << endmsg;
+    if(counterStat->isQuiet())counter("CaloFutureHypo appears twice in the same decay chain" )+=1;
+    return;
+  }
+  m_hypos.push_back( hypo ) ;
+  m_depth=2;
+
+  // ----- hypo->MC association :
+  if( ! m_hypo2Cluster ){
+    // 2 - get the relevant linker
+    std::string loc = ( hypo->parent() && hypo->parent()->registry() ) ? hypo->parent()->registry()->identifier() : "";
+    LHCb::CaloFuture2MC::HypoLinkTo linker( evtSvc() , msgSvc() , loc ) ;
+    if ( linker.notFound() ){
+      Warning( "No Hypo2MC link at '" + loc + "' ",StatusCode::SUCCESS,1 ).ignore() ;
+      Warning(" ... try using Hypo->Cluster reference  ", StatusCode::SUCCESS,1).ignore();
+      Warning(" ... CaloFutureCluster  will be re-processed (require full DST)", StatusCode::SUCCESS,1).ignore();
+      Warning(" ... assume an identical reconstruction version  ", StatusCode::SUCCESS,1).ignore();
+      if(counterStat->isQuiet())counter("!! Hypo->Cluster")+=1;
+      m_hypo2Cluster=true;
+    } // ===> force hypo->cluster cascade
+    else{
+      //debug() << "Linker found at " << loc << endmsg;
+      // - built (particle,weight) map
+      for ( const LHCb::MCParticle* particle = linker.first( hypo ) ; particle; particle = linker.next() ) {
+        m_mcMap[particle] += linker.weight();
+      }
+      if( hypo->hypothesis() == LHCb::CaloHypo::Hypothesis::Pi0Merged )
+        m_sum+=LHCb::CaloMomentum(hypo).e();
+      else
+        m_sum += hypo->e();
+      if(counterStat->isQuiet())counter("CaloFutureHypo->MC matching") += 1;
+    }
+  }
+
+  // hypo->cluster->MC cascade if requested/needed
+  if( m_hypo2Cluster ){
+    m_depth = 1; // cluster level
+    const SmartRefVector<LHCb::CaloCluster> clusters = hypo->clusters();
+    if( clusters.empty() )return;
+    const LHCb::CaloCluster* cluster =
+      ( clusters.size() > 1 && hypo->hypothesis() == LHCb::CaloHypo::Hypothesis::PhotonFromMergedPi0 ) ?
+      *(clusters.begin() + 1 ) : *(clusters.begin()); //@ToDO use cluster::Type (when defined)
+    if( !cluster )return ;
+    if( counterStat->isQuiet() &&
+        clusters.size() !=1 && hypo->hypothesis() != LHCb::CaloHypo::Hypothesis::PhotonFromMergedPi0 )counter("ill-defined CaloFutureHypo") += 1;
+    addCluster( cluster );
+  }
+  return;
+}
+// associate single hypo
+ICaloFuture2MCTool* CaloFuture2MCTool::from(const LHCb::CaloHypo*   hypo  ){
+  if( hypo == m_hypo)return this; // process only if needed
+  clear();
+  m_depth = 2; // hypo level
+  if( !hypo )return this;
+  m_hypo = const_cast<LHCb::CaloHypo*>(hypo);
+  // special case for MergedPi0
+  if(  hypo->hypothesis() == LHCb::CaloHypo::Hypothesis::Pi0Merged&& m_merged2Split){
+    const auto& hyps = hypo->hypos();
+    if( hyps.empty() )return this;
+    addHypo( hyps.front() ); // splitPhoton1
+    addHypo( *std::next(hyps.begin()) ); // splitPhoton2
+  } else{
+    addHypo( hypo ); // mother CaloFutureHypo
+  }
+  StatusCode sc = process();
+  if ( sc.isFailure() )Warning("Processing CaloFuture2MCTool from CaloFutureHypo failed").ignore();
+  return this;
+}
+
+/*-------------------------- from Cluster to MC  ------------------------*/
+// Accumulate clusters [->digits]
+void CaloFuture2MCTool::addCluster(const LHCb::CaloCluster*   cluster  ){
+  if( !cluster )return;
+
+  // register cluster (if not yet done)
+  bool ok = std::none_of( m_clusters.begin(), m_clusters.end(),
+                          [&](const auto& c) { return c == cluster; } );
+  if(!ok){
+    if( UNLIKELY( msgLevel(MSG::DEBUG) ) )debug() << "Warning : CaloFutureCluster appears twice in the same decay chain" << endmsg;
+    if(counterStat->isQuiet())counter( "Warning : CaloFutureCluster appears twice in the same decay chain" )+=1;
+    return;
+  }
+  m_clusters.push_back( cluster ) ;
+
+  m_depth=1;
+  // -- Cluster->MC mapping
+  if( ! m_cluster2Digit ){
+    if(  exist<LHCb::CaloFuture2MC::IClusterTable>(m_cluster2MCLoc ) )m_cluster2MC  = get<LHCb::CaloFuture2MC::IClusterTable>( m_cluster2MCLoc );
+    if( !m_cluster2MC ){
+      Warning("No Cluster2MC table at " + m_cluster2MCLoc , StatusCode::SUCCESS,1);
+      if(counterStat->isQuiet())counter("!! Cluster->Digit")+=1;
+      m_cluster2Digit = true;
+    } // ===> force clsuter->digit cascade
+    else{
+      // - built (particle,weight) map
+      for( const auto& ir : m_cluster2MC->relations( cluster )) {
+          m_mcMap[ir.to()] += ir.weight();
+      }
+      m_sum += cluster->e();
+      if(counterStat->isQuiet())counter("CaloFutureCluster->MC matching") += 1;
+    }
+  }
+
+  // cluster->digit cascade if requested
+  if(m_cluster2Digit){
+    m_depth = 0;
+    for( const auto& entry : cluster->entries() ) {
+      if ( m_sFilter >= 0 && ( entry.status() & m_sFilter) == 0 ){ continue ; }
+      const LHCb::CaloDigit* digit = entry.digit();
+      if( !digit )continue;
+      // check digit is not yet registered
+      ok = std::none_of( m_digits.begin(), m_digits.end(),
+                         [&](const auto& d) { return d == digit; } );
+      if(ok)addDigit(digit);
+    }
+  }
+  return;
+}
+// associate single cluster
+ICaloFuture2MCTool* CaloFuture2MCTool::from(const LHCb::CaloCluster*   cluster  ){
+  if( cluster == m_cluster)return this; // process only if needed
+  clear();
+  m_depth = 1;// cluster level
+  if( !cluster )return this;
+  m_cluster = (LHCb::CaloCluster*) cluster;
+  //
+  addCluster( cluster );
+  //
+  StatusCode sc = process();
+  if ( sc.isFailure() )Warning("Processing CaloFuture2MCTool from CaloFutureCluster failed").ignore();
+  return this;
+}
+
+/*-------------------------- from Digit to MC  ------------------------*/
+void CaloFuture2MCTool::addDigit(const LHCb::CaloDigit*   digit  ){
+  if( !digit )return;
+  m_digits.push_back( digit );
+  // -- CaloDigit->MC association
+  m_digit2MC  = getIfExists<LHCb::CaloFuture2MC::DigitTable>( m_digit2MCLoc );
+  if( !m_digit2MC ){
+    Warning(" Digit <-> MC relation table not found at " + m_digit2MCLoc , StatusCode::FAILURE,10).ignore();
+    return;
+  }
+  // - built (particle,weight) map
+  for( const auto& ir : m_digit2MC->relations( digit ) ){
+    m_mcMap[ir.to()] += ir.weight();
+  }
+  m_sum += digit->e();
+}
+
+
+// associate single digit
+ICaloFuture2MCTool* CaloFuture2MCTool::from(const LHCb::CaloDigit*   digit  ){
+  if( digit == m_digit)return this; // process only if needed
+  clear();
+  m_depth = 0; // digit level
+  if( !digit )return this;
+  m_digit = const_cast<LHCb::CaloDigit*>(digit);
+  m_digits.push_back( digit ) ;
+  StatusCode sc = process();
+  if ( sc.isFailure() )Warning("Processing CaloFuture2MCTool from CaloDigit failed").ignore();
+  return this;
+}
+
+/*-------------------------- Generic processing ------------------------*/
+StatusCode CaloFuture2MCTool::process(){
+  mcDigest();
+  verbose() << " Processing CaloFuture2MCTool " << std::endl << descriptor() << endmsg;
+  return StatusCode::SUCCESS;
+}
+
+void CaloFuture2MCTool::clear(){
+  m_mcMap.clear();
+  m_treeMap.clear();
+  m_digits.clear();
+  m_clusters.clear();
+  m_hypos.clear();
+  m_protos.clear();
+  m_parts.clear();
+  m_nFrag = 0;
+  m_sum = 0.;
+  m_maxMC  = nullptr ;
+  m_bestMC = nullptr ;
+  m_digit   = nullptr;
+  m_cluster = nullptr;
+  m_hypo    = nullptr;
+  m_proto   = nullptr;
+  m_part    = nullptr;
+  m_digit2MC= nullptr;
+  m_cluster2MC=nullptr;
+  m_category = 0 ;
+  m_depth    = -1 ;
+}
+
+
+void CaloFuture2MCTool::mcDigest(){
+
+  double mcMax = 0.;
+  double mcBest = 0.;
+  m_maxMC  = nullptr ;
+  m_bestMC = nullptr ;
+
+  if( m_sum <= 0 ) return;
+  // loop over contributing particle :
+  for( const auto& imap : m_mcMap ) {
+    const LHCb::MCParticle* mcPart = imap.first;
+    double w  = weight( mcPart );
+    double q  = quality( mcPart );
+    double m = mcPart->momentum().M();
+    // the most contributing MCParticle (with smallest mass when several MCPart with same weight)
+    if( w >= mcMax ){
+      bool ok = true;
+      if( m_maxMC  &&  w == mcMax && m > m_maxMC->momentum().M() )ok= false;
+      if(ok){
+        mcMax = w;
+        m_maxMC = mcPart ;
+      }
+    }
+    // the best matching MCParticle
+    if( q >= mcBest ){
+      mcBest = q;
+      m_bestMC = mcPart;
+    }
+
+  } // end loop over MCParticles
+  // build MC tree
+  // 1- get related MC particle (seed) without any descendant listed in the related mcParticles
+  std::vector<const LHCb::MCParticle*> seeds;
+  for( const auto& imap : m_mcMap ) {
+    const LHCb::MCParticle* mcPart = imap.first;
+    int _pID =  mcPart->particleID().abspid() ;
+
+    auto hasProd = [&]( const LHCb::MCParticle* mcp ) {
+      const auto& vertices = mcp->endVertices();
+      return std::any_of( vertices.begin(), vertices.end(),
+                                [&](const auto& v) {
+        return std::any_of( v->products().begin(), v->products().end(),
+                            [&](const auto& p)
+                            { return m_mcMap.find(p)!=m_mcMap.end(); } );
+      });
+    };
+
+    // include electron with brems and converted photons as seeds
+    if ( _pID == 11 || _pID == 22 || !hasProd(mcPart) ) seeds.push_back( mcPart );
+  }
+
+  // 2- build the seed upstream tree
+  for( const LHCb::MCParticle* seed : seeds ) {
+    std::vector<const LHCb::MCParticle*> tree;
+    std::string sTree ;
+    mcTree( seed , tree, sTree);
+    std::stringstream ss;
+    ss << format(" %6.1f %% from : ", weight( seed ) *100. )
+       << sTree
+       << " ( " << format(" %6.1f %% of the MC particle energy contributing",
+                          (weight( seed ) == 0)?0: quality(seed) /weight( seed )*100.) << " )";
+    m_treeMap[ ss.str() ] = std::move(tree);
+  }
+}
+
+void CaloFuture2MCTool::mcTree(const LHCb::MCParticle* part, std::vector<const LHCb::MCParticle*>& tree , std::string& sTree){
+  if( !part ) return;
+  tree.push_back( part );
+  const LHCb::ParticleProperty* prop = m_ppsvc->find( part->particleID() );
+  sTree = ( prop ? prop->name() : "??" ) + sTree;
+  if( part->mother() ){
+    sTree = " -> " + sTree;
+    mcTree( part->mother() , tree, sTree );
+  }
+}
+
+double CaloFuture2MCTool::weight(const LHCb::MCParticle* part) const {
+  return ( part && m_sum>0 ) ? m_mcMap[part]/m_sum : 0.;
+}
+
+double CaloFuture2MCTool::quality(const LHCb::MCParticle* part) const {
+  return ( part && part->momentum().E() != 0) ? weight(part) * m_mcMap[part]/part->momentum().E() : 0.;
+}
+
+
+std::string CaloFuture2MCTool::descriptor() const {
+  std::stringstream ss;
+  ss  << "\n     ---------- CaloFuture MC contribution " ;
+  if( m_part  ) ss << "to particle (pid = " << m_part->particleID().pid() << ")\n" ;
+  if( m_parts.size() > 1 ) ss << " -> to " << m_parts.size() << " particle(s) -------- \n" ;
+  if( !m_protos.empty() ) ss << "to " << m_protos.size() << " protoParticle(s) -------- \n" ;
+  if( !m_hypos.empty() ) ss << "to " << m_hypos.size() << " hypo(s) -------- \n" ;
+  if( !m_digits.empty() ) ss << "to " << m_digits.size() << " digit(s) -------- \n" ;
+  if( !m_clusters.empty() ) ss << "to " << m_clusters.size() << " cluster(s) ------- \n" ;
+  ss  << "     ---- Total calo energy deposit : " << m_sum << " MeV \n" ;
+  for( const auto& im : m_treeMap ) ss  << "        -- " << im.first << '\n';
+
+  if( bestMC() ){
+    const LHCb::ParticleProperty* prop = m_ppsvc->find( bestMC()->particleID() );
+    std::string p = ( prop ? prop->name() : "??" );
+    ss << "      --> Best matching MCParticle : [" << p << "] ==  (Quality/Weight : "
+       << quality( bestMC() ) <<" / " << weight( bestMC() )<< ")\n" ;
+  }
+
+  if( maxMC() ){
+    const LHCb::ParticleProperty* prop = m_ppsvc->find( maxMC()->particleID() );
+    std::string p = ( prop ? prop->name() : "??" );
+    ss << "      --> Maximum weight MCParticle : [" << p << "] == (Quality/Weight : "
+       << quality( maxMC() ) <<" / " << weight( maxMC() )<<")\n" ;
+  }
+
+  ss << "      -------------------------------- ";
+  return ss.str();
+}
+
+
+const LHCb::MCParticle* CaloFuture2MCTool::findMCOrBest(LHCb::ParticleID id, double threshold ) const {
+  const LHCb::MCParticle* found = findMC(id,threshold);
+  return found ? found : bestMC();
+}
+const LHCb::MCParticle* CaloFuture2MCTool::findMCOrBest(std::string name, double threshold ) const {
+  const LHCb::MCParticle* found = findMC(name,threshold);
+  return found ? found : bestMC();
+}
+const LHCb::MCParticle* CaloFuture2MCTool::findMC(std::string name, double threshold ) const{
+  const LHCb::ParticleProperty* prop = m_ppsvc->find( name );
+  return prop ? findMC( prop->particleID() , threshold) : nullptr;
+}
+const LHCb::MCParticle* CaloFuture2MCTool::findMC(LHCb::ParticleID id, double threshold ) const {
+  double t = threshold;
+  const LHCb::MCParticle* best  = nullptr;
+  for( const auto& imap : m_mcMap ) {
+    const LHCb::MCParticle* mcPart = imap.first;
+    if( mcPart->particleID().abspid() != id.abspid() )continue;
+    double q = quality( mcPart );
+    if( q < t )continue;
+    t = q;
+    best =  mcPart;
+  }
+  return best;
+}
+const LHCb::MCParticle* CaloFuture2MCTool::bestMC() const {
+  return m_bestMC;
+}
+const LHCb::MCParticle* CaloFuture2MCTool::maxMC() const {
+  return m_maxMC;
+}
+
+
+ICaloFuture2MCTool* CaloFuture2MCTool::fragment(unsigned int i){
+  m_nFrag = 0;
+  /* CaloFutureHypo level */
+  if( m_depth == 2 ){
+    m_nFrag = m_hypos.size();
+    if( i >= m_nFrag)return nullptr;
+    if(m_nFrag == 1)return this;
+    return m_tool->from( m_hypos[i] );
+  }
+  /* CaloFutureCluster level */
+  if( m_depth == 1 ){
+    m_nFrag = m_clusters.size();
+    if( i >= m_nFrag)return nullptr;
+    if(m_nFrag == 1)return this;
+    return m_tool->from( m_clusters[i] );
+  }
+  /* CaloDigit level */
+  if( m_depth == 0 ){
+    m_nFrag = m_digits.size();
+    if( i >= m_nFrag)return nullptr;
+    if(m_nFrag == 1)return this;
+    return m_tool->from( m_digits[i] );
+  }
+  return nullptr;
+}
diff --git a/CaloFuture/CaloFutureTools/src/CaloFuture2MCTool.h b/CaloFuture/CaloFutureTools/src/CaloFuture2MCTool.h
new file mode 100644
index 0000000000000000000000000000000000000000..afc9e6e446a4a16e19f5626c099accdd1ce92b83
--- /dev/null
+++ b/CaloFuture/CaloFutureTools/src/CaloFuture2MCTool.h
@@ -0,0 +1,155 @@
+#ifndef CALOFUTURE2MCTOOL_H
+#define CALOFUTURE2MCTOOL_H 1
+
+// Include files
+// from Gaudi
+#include "GaudiAlg/GaudiTool.h"
+#include "CaloFutureInterfaces/ICaloFuture2MCTool.h"            // Interface
+#include "CaloFutureInterfaces/IFutureCounterLevel.h"
+#include "GaudiKernel/IIncidentListener.h"
+#include "GaudiKernel/IIncidentSvc.h"
+#include "GaudiKernel/Incident.h"
+// from LHCb : the calo->particle stream
+#include "Event/CaloDigit.h"
+#include "Event/CaloCluster.h"
+#include "Event/CaloHypo.h"
+#include "Event/ProtoParticle.h"
+#include "Event/Particle.h"
+#include "Event/MCParticle.h"
+#include "Kernel/IParticlePropertySvc.h"
+#include "Kernel/ParticleProperty.h"
+#include "CaloFutureUtils/CaloMomentum.h"
+// from LHCb : some  typedef and utilities
+#include "CaloFutureUtils/CaloFuture2MC.h"
+#include "CaloFutureUtils/CaloFutureMCTools.h"
+
+
+
+/** @class CaloFuture2MCTool CaloFuture2MCTool.h
+ *
+ *
+ *  @author Olivier Deschamps
+ *  @date   2009-07-27
+ */
+class CaloFuture2MCTool : public extends<GaudiTool , ICaloFuture2MCTool , IIncidentListener > {
+
+public:
+  // category enum
+
+  enum MCCategory  {
+    /* Single cluster/hypo categories */
+    UnMatched           = 0,
+    Photon              = 1,
+    BremStrahlung       = 2,
+    Electron            = 3,
+    ConvertedPhoton     = 4,
+    MergedPi0           = 5,
+    ChargedHadron       = 6,
+    NeutralHadron       = 7,
+    Spillover           = 8
+  };
+
+
+  /// Standard constructor
+  CaloFuture2MCTool( const std::string& type,
+               const std::string& name,
+               const IInterface* parent);
+
+  StatusCode initialize( ) override;
+
+  //
+  ICaloFuture2MCTool* from(const LHCb::CaloDigit*     digit    ) override;
+  ICaloFuture2MCTool* from(const LHCb::CaloCluster*   cluster  ) override;
+  ICaloFuture2MCTool* from(const LHCb::CaloHypo*      hypo     ) override;
+  ICaloFuture2MCTool* from(const LHCb::ProtoParticle* proto    ) override;
+  ICaloFuture2MCTool* from(const LHCb::Particle*      particle ) override;
+  const LHCb::MCParticle* bestMC() const override;
+  const LHCb::MCParticle* maxMC() const override;
+  double weight(const LHCb::MCParticle*) const override;
+  const LHCb::MCParticle* findMC(LHCb::ParticleID id, double threshold = 0 ) const override;
+  const LHCb::MCParticle* findMCOrBest(LHCb::ParticleID id, double threshold = 0 ) const override;
+  const LHCb::MCParticle* findMC(std::string name, double threshold = 0 ) const override;
+  const LHCb::MCParticle* findMCOrBest(std::string name, double threshold = 0 ) const override;
+  double quality(const LHCb::MCParticle*) const override;
+  std::string descriptor() const override;
+  bool isCaloFuture(LHCb::Particle* particle) const override {
+    return particle && LHCb::CaloFutureParticle( particle ).isCaloFuture();
+  }
+  bool isPureNeutralCaloFuture(const LHCb::Particle* particle) const override {  // SHOULD BE IN CALOFUTUREPARTICLE
+    return particle && LHCb::CaloFutureParticle( const_cast<LHCb::Particle*>(particle) ).isPureNeutralCaloFuture();// non pure calorimetric object
+  }
+
+
+
+  /// Inform that a new incident has occurred
+  void handle(const Incident& /* inc */ ) override { clear();}
+
+
+  // TO BE INTERFACED :
+  int MCCategory(){return m_category;};
+  ICaloFuture2MCTool* fragment(unsigned int i);
+  unsigned int numberOfFragments(){return m_nFrag;}
+  //ostream << category
+  // clusters()
+  // hypos()
+  // protos()
+
+private:
+  IFutureCounterLevel* counterStat = nullptr;
+  StatusCode process();
+  void addDigit   (const LHCb::CaloDigit* digit);
+  void addCluster (const LHCb::CaloCluster* cluster);
+  void addHypo    (const LHCb::CaloHypo* hypo);
+  void addProto   (const LHCb::ProtoParticle* proto, const LHCb::Particle* parent = NULL);
+  void clear();
+  void mcDigest();
+  void mcTree(const LHCb::MCParticle* part, std::vector<const LHCb::MCParticle*>& tree , std::string& sTree);
+
+
+  std::vector<const LHCb::CaloDigit*>     m_digits;
+  std::vector<const LHCb::CaloCluster*>   m_clusters;
+  std::vector<const LHCb::CaloHypo*>      m_hypos;
+  std::vector<const LHCb::ProtoParticle*> m_protos;
+  std::vector<const LHCb::Particle*>      m_parts;
+  LHCb::CaloDigit* m_digit = nullptr;
+  LHCb::CaloCluster* m_cluster = nullptr;
+  LHCb::CaloHypo* m_hypo = nullptr;
+  LHCb::ProtoParticle* m_proto = nullptr;
+  LHCb::Particle* m_part = nullptr;
+  CaloFutureMCTools::CaloFutureMCMap m_mcMap;
+  //
+  Gaudi::Property<std::string> m_cluster2MCLoc 
+    {this, "Cluster2MCTable", "", "Cluster->MC relation table location"};
+
+  Gaudi::Property<std::string> m_digit2MCLoc 
+    {this, "Digit2MCTable", "Relations/" + LHCb::CaloDigitLocation::Default, 
+    "Digit->MC relation table location"};
+
+  LHCb::CaloFuture2MC::IClusterTable* m_cluster2MC  = nullptr;
+  LHCb::CaloFuture2MC::IDigitTable*   m_digit2MC  = nullptr;
+  double m_sum = 0.;
+  const LHCb::MCParticle* m_maxMC = nullptr;
+  const LHCb::MCParticle* m_bestMC = nullptr;
+  std::map<std::string,std::vector<const LHCb::MCParticle*> > m_treeMap;
+  SmartIF<LHCb::IParticlePropertySvc> m_ppsvc;
+
+  //
+  Gaudi::Property<bool> m_hypo2Cluster 
+    {this, "Hypo2Cluster", false, "(part->protoP)->hypo->cluster cascade ( or use  hypo->MC linker tables)"};
+
+  Gaudi::Property<bool> m_cluster2Digit 
+    {this, "Cluster2Digits", false, "(part->protoP)->hypo->cluster->digit cascade ( or use cluster->MC relation tables)"};
+
+  Gaudi::Property<bool> m_merged2Split 
+    {this, "Merged2Split", false, "expert usage (merged->split->cluster - NOT IMPLEMENTED so far)"};
+
+  Gaudi::Property<int> m_sFilter 
+    {this, "DigitStatusFilter", LHCb::CaloDigitStatus::UseForEnergy,
+    "digit filter in case of ..->digit->MC table is used"};
+
+  int m_category = 0;
+  int m_depth = -1;
+  unsigned int m_nFrag = 0;
+  ICaloFuture2MCTool* m_tool = nullptr;
+};
+#endif // CALOFUTURE2MCTOOL_H
diff --git a/CaloFuture/CaloFutureTools/src/CaloFutureCosmicsTool.cpp b/CaloFuture/CaloFutureTools/src/CaloFutureCosmicsTool.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1de94112f7f721a91e950aecd10be0e42c12c402
--- /dev/null
+++ b/CaloFuture/CaloFutureTools/src/CaloFutureCosmicsTool.cpp
@@ -0,0 +1,591 @@
+// Include files 
+
+// from LHCb
+#include "GaudiKernel/Plane3DTypes.h"
+#include "LHCbMath/LineTypes.h"
+#include "LHCbMath/GeomFun.h"
+#include "CaloDet/DeCalorimeter.h"
+
+// local
+#include "CaloFutureCosmicsTool.h"
+
+//-----------------------------------------------------------------------------
+// Implementation file for class : CaloFutureCosmicsTool
+//
+// 2008-04-02 : Olivier Deschamps
+//-----------------------------------------------------------------------------
+
+// Declaration of the Tool Factory
+DECLARE_COMPONENT( CaloFutureCosmicsTool )
+
+
+//=============================================================================
+// Standard constructor, initializes variables
+//=============================================================================
+CaloFutureCosmicsTool::CaloFutureCosmicsTool( const std::string& type,
+                                    const std::string& name,
+                                    const IInterface* parent )
+: base_class ( type, name , parent )
+{
+  declareInterface<ICaloFutureCosmicsTool>(this);
+
+  // set default detectorName
+  int index = name.find_last_of(".") +1 ; // return 0 if '.' not found --> OK !!
+  m_det = name.substr( index, 4 ); 
+  if ( name.substr(index,3) == "Prs" ) m_det = "Prs";
+  if ( name.substr(index,3) == "Spd" ) m_det = "Spd";
+
+  //
+  if(m_det == "Ecal"){ m_zSup = 100;}
+  else if(m_det == "Hcal"){ m_zSup = 10;  }
+  else { m_zSup = 0;  }
+}
+
+//=============================================================================
+StatusCode CaloFutureCosmicsTool::initialize(){
+  StatusCode sc = base_class::initialize();
+  if (sc.isFailure()) return Error("Failed to initialize", sc);
+
+
+  
+  // Fill vector with requested time slots from sequence and asymmetry settings
+  for(std::vector<std::string>::iterator iseq = m_seq.begin(); iseq != m_seq.end() ;  ++iseq){
+    m_slots.push_back( *iseq );
+  }
+  int k =0;
+  for(std::map<std::string,std::vector<std::string> >::iterator iasy = m_asy.begin();m_asy.end() != iasy ; iasy++){
+    std::vector<std::string> asy = (*iasy).second;
+    if( asy.size() != 2){
+      Error("AsymmetrySlot must be a vector of pairs of entries").ignore();
+      return StatusCode::FAILURE;
+    }else{
+      std::string a = *(asy.begin());
+      std::string b = *(asy.begin()+1);
+ 
+      std::stringstream str("");
+      str << (*iasy).first;
+      double offset;
+      str>> offset;
+
+      info() << "Asymmetry ( id = '" << (*iasy).first
+             << "') is define as R = [ADC("<< a <<")-ADC("<< b <<")]/[ADC("<< a <<")+ADC("<< b <<")]"<<endmsg;
+      info() << "Corresponding Time offset : "<< offset << " ns" << endmsg;
+    }
+    for(std::vector<std::string>::iterator islot = asy.begin(); islot != asy.end();islot++){
+      bool isReg = false;
+      for(std::vector<std::string>::iterator is = m_slots.begin(); is != m_slots.end() ;  ++is){
+        if( *is == *islot){
+          isReg = true;
+          continue;
+        }
+      }
+      if( !isReg )m_slots.push_back( *islot );
+    }
+    k++;
+  }
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+    debug() << "Requested time slots : " << m_slots << endmsg;
+  
+
+  // get detector element
+  if ( "Ecal" == m_det ) {
+    m_calo     = getDet<DeCalorimeter>( DeCalorimeterLocation::Ecal );
+  } else if ( "Hcal" == m_det ) {
+    m_calo     = getDet<DeCalorimeter>( DeCalorimeterLocation::Hcal );
+  } else if ( "Prs" == m_det ) {
+    m_calo     = getDet<DeCalorimeter>( DeCalorimeterLocation::Prs );
+  } else {
+    error() << "Unknown detector name " << m_det << endmsg;
+    return StatusCode::FAILURE;
+  }
+
+  // some detector geometry
+  m_plane = m_calo->plane(CaloPlane::Middle);
+  m_delta = m_calo->plane(CaloPlane::Front).HesseDistance()-
+    m_calo->plane(CaloPlane::Back).HesseDistance();
+  m_delta *= m_calo->plane(CaloPlane::Front).Normal().Z();
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+    debug() << " m_det : " << m_det << " m_delta = " << m_delta << " cos(tilt) = " 
+            <<  m_calo->plane(CaloPlane::Front).Normal().Z() << endmsg;
+
+  // get the decoding tool for each time slot
+  for(std::vector<std::string>::iterator islot = m_slots.begin(); islot != m_slots.end() ;  ++islot){
+    if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+      debug() << "Loading : decoding tool for slot " << *islot << " : '"
+              << m_det << "ReadoutTool" <<  *islot << "'" <<endmsg;
+    this->setProperty("RootInTES","");
+    if(*islot != "T0")this->setProperty("RootInTES",*islot);
+     m_daqs[*islot] = tool<ICaloFutureDataProvider>( m_readoutTool , m_det + "ReadoutTool" + *islot , this );
+  }
+  this->setProperty("RootInTES","");// reset
+
+  //
+  return StatusCode::SUCCESS;
+}
+
+//=============================================================================
+StatusCode CaloFutureCosmicsTool::processing(){
+
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+    debug() << " Process " << name() << endmsg;
+
+  // default
+  m_phi      = -999;
+  m_sPhi     = 999;
+  m_refPoint = Gaudi::XYZPoint();
+  m_eRefPoint = Gaudi::XYZPoint();
+  m_cosmicsADCs.clear();
+  m_zsupADCs.clear();
+  m_maxLoc = "none";
+  m_offset = -99999;
+  m_bound = std::make_pair(Gaudi::XYZPoint(),Gaudi::XYZPoint());
+  m_time     = -999;
+  m_stime    = -999;
+  m_timed   = false;
+  m_tracked   = false;
+  for(std::map<std::string,std::vector<std::string> >::iterator iasy = m_asy.begin(); iasy != m_asy.end() ; iasy++){
+    std::string id = (*iasy).first;
+    m_Rmean[id]    = -999.;
+    m_Rmean2[id]   = -999.;
+    m_R[id]        = -999.;
+    m_slotSum[id]   = -999.;
+    m_td[id] = -999.;
+  }
+  m_kernel = -1.;
+
+  // 1) get banks
+  if( getBanks().isFailure() )return StatusCode::FAILURE;
+
+  // 2) apply 0-suppression
+  if( zSup().isFailure() )return StatusCode::SUCCESS;
+
+  // 3) reconstruct 2D trajectory
+  if( fit2D().isFailure() )return StatusCode::SUCCESS;
+
+  // 4) reconstruct time 
+  if( timing().isFailure() )return StatusCode::SUCCESS;
+
+  // 5) produce ntuple
+  if(m_tuple){
+    
+    unsigned int unit=100;
+    if(m_det == "Prs")unit = 100;
+    else if(m_det == "Ecal")unit = 200;
+    else if(m_det == "Hcal")unit = 300;
+    if( tupling(unit).isFailure())return StatusCode::FAILURE;
+  }
+  return StatusCode::SUCCESS;
+}
+
+
+//=============================================================================
+StatusCode CaloFutureCosmicsTool::getBanks(){
+
+  // get rawBank from TES
+  for(std::vector<std::string>::iterator islot = m_slots.begin(); islot != m_slots.end() ;  ++islot){
+    if(!m_daqs[*islot]->ok()) return StatusCode::FAILURE;
+  }
+  return StatusCode::SUCCESS;
+}
+//=============================================================================
+StatusCode CaloFutureCosmicsTool::zSup(){
+
+  // apply 0-suppression
+
+  m_max = LHCb::CaloAdc(LHCb::CaloCellID(), -9999 );
+  m_zsupADCs.clear();
+
+  std::string slot = *(m_slots.begin());
+  const CaloVector<LHCb::CaloAdc>& adcs = m_daqs[slot]->adcs() ;
+  for(CaloVector<LHCb::CaloAdc>::const_iterator iadc = adcs.begin(); iadc!= adcs.end(); ++iadc){
+    long sum = 0;
+    LHCb::CaloCellID cell = (*iadc).cellID();
+    if(cell.area() == m_calo->pinArea())continue;
+    for(std::vector<std::string>::iterator islot = m_seq.begin(); islot != m_seq.end() ;  ++islot){
+      int adc = m_daqs[*islot]->adc(cell);
+      if(adc>0)sum += adc;
+    }
+    if( sum <= m_zSup )continue;
+
+    // Collect 0-suppresed data
+    LHCb::CaloAdc sumADC(cell , sum);
+    m_zsupADCs.push_back( sumADC );                // vector of ADC sum over consecutive BX (after Z-sup)
+    if( sum > m_max.adc() )m_max = sumADC;    // maximal ADC
+    if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+      debug() << name() 
+              << " : cell = " << sumADC.cellID() 
+              << " ADCsum =  " << sumADC.adc() 
+              << " max =  " << m_max.adc() 
+              << endmsg;
+    
+  }
+
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+    debug() << "Zero suppression : " << m_zsupADCs.size() << " among "
+            << adcs.size() << " digits " << endmsg;
+
+  if( m_zsupADCs.size() == 0){
+    info() << "No digit left after Zero-suppression" <<endmsg;
+    return StatusCode::FAILURE;
+  }
+  
+  return StatusCode::SUCCESS;
+}
+//=============================================================================
+StatusCode CaloFutureCosmicsTool::fit2D(){
+
+  m_refPoint  = Gaudi::XYZPoint(0.,0.,-999);
+  m_eRefPoint = Gaudi::XYZVector();
+  m_cosmicsADCs.clear();
+
+  // get the position of highest deposit
+  Gaudi::XYZPoint  ref = m_calo->cellCenter( m_max.cellID() );
+
+  //  Best 2D slope fit  (minimize   Chi2 = Sum_i  [ADC_i (phi_i - phi)^2/sigma_i^2)
+  double swa  = 0;
+  double sw   = 0;
+  {for(std::vector<LHCb::CaloAdc>::iterator id = m_zsupADCs.begin(); id != m_zsupADCs.end(); ++id){
+    LHCb::CaloCellID cell = (*id).cellID();
+    if( m_max.cellID() == cell)continue;    
+    Gaudi::XYZPoint pos = m_calo->cellCenter( cell );
+    double size = m_calo->cellSize( cell );
+    double sx2  = size*size/12;
+    double dx = pos.X()-ref.X();
+    double dy = pos.Y()-ref.Y();
+    double a = acos(0.);                    // a = pi/2
+    if(dx != 0 )a =  atan(dy/dx) ;             // tan( phi_i )= y_i/x_i
+    if(a<0)a += acos(-1.);
+    double s2 = sx2;
+      ///(dx*dx + dy*dy);          // sigma(phi_i)
+    int val =  (*id).adc();
+    if( val < 0)val = 0;
+    s2 = 1;
+    Gaudi::XYZVector vec = pos-ref;
+    double adc = (double) val/vec.rho() ;
+    double w = adc  / s2;   // weight = ADC_i/sigma_i^2    
+    sw  += w;
+    swa += w*a;
+  }}
+
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+    debug() << "Point : " << ref.X()  << " " << ref.Y() << endmsg;
+
+
+  if( sw<=0 ){
+    Warning( "Weight = 0 - fit failed ").ignore();
+    return StatusCode::FAILURE;
+  }
+  else{
+    if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+      debug() << "1st pass " << swa/sw << endmsg;
+  }
+  
+  // Built the 2D line
+  // best phi = swa/sw (assuming the 2D line passing through the highest deposit)
+  double norm = sqrt(1.+tan(swa/sw)*tan(swa/sw));
+  Gaudi::XYZVector vec(1./norm, tan(swa/sw)/norm , 0.);
+  Gaudi::Math::XYZLine   line(ref, vec);
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+    debug() << "Line parameters " << vec.X() << " " << vec.Y() << " " << vec.Z() << endmsg;
+  // Collect data along the 2D cosmics line (+- tolerance)
+  double x   = 0;
+  double y   = 0;
+  double ssx2= 0;
+  m_adcSum = 0;
+  double kernel = 0.;
+  {for(std::vector<LHCb::CaloAdc>::iterator id =m_zsupADCs.begin(); id != m_zsupADCs.end(); ++id){
+    LHCb::CaloCellID cell = (*id).cellID();
+    double size = m_calo->cellSize( cell );
+    double sx2  = size*size/12;
+    Gaudi::XYZPoint pos = m_calo->cellCenter( cell );
+    pos.SetZ( ref.Z() );
+    double ip = Gaudi::Math::impactParameter<Gaudi::XYZPoint, Gaudi::Math::XYZLine>(pos, line)/size;
+    if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+      debug() << "--> " << cell << " ip = " << ip << " x = "<<  pos.X()
+              << " y = " << pos.Y() << " z=  " << pos.Z() << endmsg;
+    if(fabs(ip) < m_tol){
+      m_cosmicsADCs.push_back( *id );
+      m_adcSum += (*id).adc();
+      kernel+= (*id).adc();
+      for(std::vector<std::string>::iterator ik = m_kern.begin();ik!=m_kern.end();++ik){
+        kernel -= m_daqs[*ik]->adc( cell );
+      }    
+      x += pos.X();
+      y += pos.Y();
+      ssx2 += sx2;
+    }
+  }}
+
+  if( 0 == m_adcSum ) {
+    m_kernel = 0;
+  }
+  else {
+    m_kernel = kernel / (double) m_adcSum;  
+  }
+  
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+    debug() << " m_cosmicsADCs.size() " << m_cosmicsADCs.size() << endmsg;
+  if(m_cosmicsADCs.size()== 0){
+    return Warning( "Empty 2D segment - fit failed", StatusCode::FAILURE );
+  }
+
+  // ADC sum thresholds
+  if( m_adcSum < m_minD || m_adcSum > m_maxD){
+    if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+      debug() << "ADC sum " << m_adcSum << " outside the requested range ["
+              << m_minD << "," << m_maxD <<"]" <<endmsg;
+    return StatusCode::FAILURE;
+  }
+
+  // Multiplicity thresholds
+  if( (int) m_cosmicsADCs.size() < m_minM || (int) m_cosmicsADCs.size() > m_maxM ){
+    if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+      debug() << "Segment #digits " << m_cosmicsADCs.size()
+              << " outside the requested range " 
+              << m_minM << "," << m_maxM << "]" << endmsg;
+    return StatusCode::FAILURE;
+  }  
+
+  // average position
+  double N = (double) m_cosmicsADCs.size();
+  x /= N;
+  y /= N;
+  // Z (middle of active area) - take the tilt into account for the fun
+  double z  = ( -m_plane.Normal().X()*x -m_plane.Normal().Y()*y - m_plane.HesseDistance() )/m_plane.Normal().Z();  
+  double ex = ssx2/N/N;   // error on x
+  double ey = ssx2/N/N;   // error on y
+  double ez =  m_delta*m_delta/12./N; // error on z
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) {
+    debug() << "Delta = " << m_delta << " z  = " << z <<  "+-" << sqrt(ez) << endmsg;
+    debug() << "x = " << x << " +- " << sqrt(ex) << endmsg;
+    debug() << "y = " << y << " +- " << sqrt(ey) << endmsg;  
+  }
+  
+  m_refPoint.SetX(x);
+  m_refPoint.SetY(y);
+  m_refPoint.SetZ(z);
+  m_eRefPoint.SetX(ex);
+  m_eRefPoint.SetY(ey);
+  m_eRefPoint.SetZ(ez);
+
+
+  // (re-)Evaluate the parameters wrt the average (x,y)
+  swa  = 0;
+  sw   = 0;
+  double sws2 = 0;
+  std::vector<LHCb::CaloAdc>::iterator id = m_cosmicsADCs.begin();
+  LHCb::CaloCellID idMin = (*id).cellID();
+  LHCb::CaloCellID idMax = (*id).cellID();
+  for(id = m_cosmicsADCs.begin() ; id != m_cosmicsADCs.end(); ++id){
+    LHCb::CaloCellID cell = (*id).cellID();
+    Gaudi::XYZPoint pos = m_calo->cellCenter( cell );
+    if( pos.Y() < m_calo->cellCenter( idMin ).Y() )idMin = cell;
+    if( pos.Y() > m_calo->cellCenter( idMax ).Y() )idMax = cell;
+    double adc  = (double) (*id).adc();
+    if(adc<0)adc = 0;
+    vec = pos-m_refPoint;
+    if(vec.rho()!=0)adc /= vec.rho();
+    double size = m_calo->cellSize( cell );
+    double sx2  = size*size/12;
+    double dx = pos.X()-m_refPoint.X();
+    double dy = pos.Y()-m_refPoint.Y();
+    double a = acos(0.);
+    if(dx != 0 )a =  atan(dy/dx) ;         // tan( phi_i )= y_i/x_i
+    double s2;
+    if(dx*dx+dy*dy != 0){
+      s2 = sx2/(dx*dx + dy*dy);           // sigma(phi_i)
+    }else{
+      a = 0;
+      s2= acos(-1.);
+    }
+    if(a<0)a += acos(-1.);
+    double w = adc / s2;
+    sw  += w;
+    swa += w*a;
+    sws2 += w*w*s2;
+    if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+      debug() << "a = " << a << " w = " << w << " sw = " << sw << " swa = " << swa << endmsg;
+  }
+  m_phi   = swa / sw;          // best phi
+  if(m_phi<0)m_phi += acos(-1.);
+  m_sPhi = sws2 /sw/sw; //  phi variance
+
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+    debug() << "2nd pass " << m_phi << " +- " << sqrt(m_sPhi) << endmsg;
+  m_bound = std::make_pair(m_calo->cellCenter( idMin), m_calo->cellCenter( idMax) );   // extrema of the track segment
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+    debug() << "END OF TRAJECTORY RECONSTRUCTION" << endmsg;
+  m_tracked = true;
+  return StatusCode::SUCCESS;
+}
+
+
+
+
+
+
+//=============================================================================
+StatusCode CaloFutureCosmicsTool::timing(){
+
+  // Compute the asymmetries
+  double maxSum = -99999;
+  m_maxLoc = "none";
+
+
+  // compute asymmetries
+  
+  for(std::map<std::string,std::vector<std::string> >::iterator iasy = m_asy.begin(); iasy != m_asy.end() ; iasy++){
+    std::vector<std::string> asym = (*iasy).second;
+    std::string id = (*iasy).first;
+    std::string a1 = *(asym.begin());
+    std::string a2 = *(asym.begin()+1);
+    double sb1 = 0;
+    double sb2 = 0;
+    double rm  = 0;
+    double rm2 = 0;
+    double td  = 0;
+    double tdm = 0;
+    double dl  = 0;
+    int N = 0;
+    for(std::vector<LHCb::CaloAdc>::iterator it = m_cosmicsADCs.begin();it!=m_cosmicsADCs.end();it++){
+      LHCb::CaloCellID cell = (*it).cellID();
+      double b1 = (double) m_daqs[a1]->adc( cell );
+      double b2 = (double) m_daqs[a2]->adc( cell );
+      if(b1<0)b1=0;
+      if(b2<0)b2=0;
+      if(b1+b2 == 0 )continue;
+      N++;
+      double asy = ( b1 -  b2 ) / ( b1 + b2 );
+      if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+        debug() << "R = " << asy << " b1 = " << b1 << "b2 = " << b2 << endmsg;
+      sb1 += b1;
+      sb2 += b2;
+      rm  += asy;
+      rm2 += asy*asy;
+      // timing dispersion
+      Gaudi::XYZPoint  pos = m_calo->cellCenter( cell );
+      Gaudi::XYZVector vec = pos - m_refPoint;
+      double sign = 0;
+      if(vec.Y() != 0)sign = vec.Y()/fabs(vec.Y());
+      td += asy * vec.rho() * sign;
+      tdm+= vec.rho() * sign;
+      dl += vec.Perp2();
+    }
+
+    if( N != 0) m_Rmean[id]   = rm / (double) N;
+    if( N != 0) m_Rmean2[id]   = rm2 / (double) N;
+
+    tdm *= m_Rmean[id];
+    m_td[id] = (dl>0) ?  (td-tdm)/dl : 0.;
+    m_Rmean2[id] -= m_Rmean[id]*m_Rmean[id];
+    if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) {
+      debug() << "<R>(  " << id << ") = "<< m_Rmean[id] << endmsg;
+      debug() << "sigma(R)^2("<< id << ") = " << m_Rmean2[id] << endmsg;
+    }
+    if(sb1+sb2!=0)m_R[id]      = (sb1-sb2)/(sb1+sb2)      ;  // asymmetry of the average
+    m_slotSum[id] = sb1+sb2;
+    if(  sb1+sb2 >= maxSum){
+      maxSum=sb1+sb2;
+      m_maxLoc = id;
+    } 
+  }
+
+  
+  // convert asymmetry into time  (@todo - apply Yasmine's method)
+  m_time = -999;
+  if(m_maxLoc == "none")return StatusCode::SUCCESS;
+  std::stringstream str("");
+  str << m_maxLoc;
+  double offset;
+  str>> offset;
+  m_offset = offset;
+  if(fabs(offset)>999.)return StatusCode::SUCCESS;
+  double R = m_Rmean[m_maxLoc];
+  if(fabs(R) > m_minR && fabs(R) < m_maxR ){
+    m_timed = true;
+    double u = R / ( 1+ m_par[3]*sqrt(1-R*R));
+    m_time = m_offset + m_par[0] + m_par[1]*R*R + m_par[2]/acos(-1.) * acos( u );
+    //    double d = -2*m_par[1] + m_par[2]/acos(-1.) 
+    //      * ( - 1/sqrt(1-u*u) * ( 1+ m_par[3]*sqrt(1-R*R) - R * 0.5 *  m_par[3] / sqrt(1-R*R)))*u*u/R/R;
+    //m_stime = d*d* m_Rmean2[m_maxLoc] + m_tRes*m_tRes;
+  }
+  return StatusCode::SUCCESS;
+}
+
+
+
+//=============================================================================
+StatusCode CaloFutureCosmicsTool::tupling(unsigned int unit){
+
+
+  Tuple ntp = nTuple(unit, m_det + "Cosmics" ,CLID_ColumnWiseTuple);
+  StatusCode sc;
+  // Ecal
+  sc = ntp->column("deposit"    , deposit() );
+  sc = ntp->column("phi"    , phi() );
+  sc = ntp->column("phiVar" , phiVariance()  );
+  sc = ntp->column("refX" , referencePoint().X() );
+  sc = ntp->column("refY" , referencePoint().Y() );
+  std::vector<LHCb::CaloAdc>& eAdcs = m_cosmicsADCs;
+  if(m_full) eAdcs = m_zsupADCs;
+  std::vector<float> x;
+  std::vector<float> y;
+  std::vector<int> a;
+  std::vector<int> ids;
+  for(auto iadc = eAdcs.begin();iadc!=eAdcs.end();iadc++){
+    if(iadc-eAdcs.begin() > m_maxAdc){
+      Warning("Ntupling :  digits vector too large - will be truncated").ignore();
+      break;
+    }
+    
+    LHCb::CaloCellID id = (*iadc).cellID();
+    ids.push_back(  id.all()  );
+    x.push_back( det()->cellCenter( id ).X() );
+    y.push_back( det()->cellCenter( id ).Y() );
+    a.push_back( (*iadc).adc() );
+  }
+  sc = ntp->farray("id"   , ids      ,"NAdcs", m_maxAdc);
+  sc = ntp->farray("x"   , x      ,"NAdcs", m_maxAdc);
+  sc = ntp->farray("y"   , y      ,"NAdcs", m_maxAdc);
+  sc = ntp->farray("adc" , a      ,"NAdcs", m_maxAdc);
+
+  std::vector<double> rMean;
+  std::vector<double> rSig;
+  std::vector<double> rGlob;
+  std::vector<double> sSum;
+  std::vector<double> td;
+  for(const auto& iasy : m_asy ) {
+    const auto& id = iasy.first;
+    rMean.push_back( m_Rmean[id] );
+    rSig.push_back(  m_Rmean2[id] );
+    rGlob.push_back( m_R[id] );
+    sSum.push_back( m_slotSum[id] );
+    td.push_back(m_td[id]);
+  }
+  sc = ntp->farray("RMean" , rMean , "NAsymmetries" , m_Rmean.size() );
+  sc = ntp->farray("RVar"  , rSig  , "NAsymmetries" , m_Rmean.size() );
+  sc = ntp->farray("RGlob" , rGlob , "NAsymmetries" , m_Rmean.size() );
+  sc = ntp->farray("Sum"   , sSum  , "NAsymmetries" , m_Rmean.size() );
+  sc = ntp->farray("dTime" , td    , "NAsymmetries" , m_Rmean.size() );
+
+
+  std::stringstream str("");
+  double offset = -9999.;
+  if(m_maxLoc != "none"){
+    str << m_maxLoc; 
+    double off;
+    str>> off;
+    offset = off;
+  }
+  
+  sc = ntp->column("slot"               , offset);
+  sc = ntp->column("time"               , m_time);
+  sc = ntp->column("timeVariance"       , m_stime);
+  sc = ntp->column("istimed"            , (int)m_timed);
+  sc = ntp->column("istracked"          , (int)m_tracked);
+
+  sc=ntp->write();
+  if(sc.isFailure())Warning( name() + " Ntupling failed").ignore();
+  return StatusCode::SUCCESS;
+}
+  
diff --git a/CaloFuture/CaloFutureTools/src/CaloFutureCosmicsTool.h b/CaloFuture/CaloFutureTools/src/CaloFutureCosmicsTool.h
new file mode 100644
index 0000000000000000000000000000000000000000..77172cc8b32d2ebc60b1062ab5c8da519e503e0e
--- /dev/null
+++ b/CaloFuture/CaloFutureTools/src/CaloFutureCosmicsTool.h
@@ -0,0 +1,130 @@
+#ifndef CALOFUTURECOSMICSTOOL_H
+#define CALOFUTURECOSMICSTOOL_H 1
+
+// Include files
+// from Gaudi
+#include "GaudiAlg/GaudiTupleTool.h"
+// from LHCb
+#include "CaloFutureInterfaces/ICaloFutureCosmicsTool.h"            // Interface
+#include "CaloFutureDAQ/ICaloFutureDataProvider.h"
+#include "CaloKernel/CaloVector.h"
+
+
+/** @class CaloFutureCosmicsTool CaloFutureCosmicsTool.h
+ *
+ *
+ *  @author Olivier Deschamps
+ *  @date   2008-04-07
+ */
+class CaloFutureCosmicsTool : public extends<GaudiTupleTool, ICaloFutureCosmicsTool> {
+public:
+  /// Standard constructor
+  CaloFutureCosmicsTool( const std::string& type,
+               const std::string& name,
+               const IInterface* parent);
+
+
+  StatusCode initialize() override;
+
+  Gaudi::XYZPoint referencePoint() override {return m_refPoint;}
+  Gaudi::XYZPoint referencePointVariance() override {return m_eRefPoint;}
+  const std::pair<Gaudi::XYZPoint,Gaudi::XYZPoint>& extrema() override {return m_bound;}
+  double deposit() override {return m_adcSum;}
+  double phi() override {return m_phi;}
+  double phiVariance() override {return m_sPhi;}
+  double asymmetry() override {return (m_maxLoc != "none") ? m_Rmean[m_maxLoc] : -99.;}
+  double asymmetryVariance() override {return (m_maxLoc !="none") ? m_Rmean2[m_maxLoc] : -99.;}
+  double slot() override {return m_offset;}
+  double time() override {return m_time;}
+  double timeVariance() override {return m_stime;}
+  double timeDispersion() override {return (m_maxLoc !="none") ? m_td[m_maxLoc] : -99.;;}
+  DeCalorimeter* det() override {return m_calo;}
+  StatusCode processing() override;
+  StatusCode tupling(unsigned int unit) override;
+  bool tracked() override {return m_tracked;}
+  bool timed() override {return m_timed;}
+  double kernel() override {return m_kernel;};
+
+
+protected:
+
+private:
+  // private methods
+  StatusCode getBanks();
+  StatusCode zSup();
+  StatusCode fit2D();
+  StatusCode timing();
+  //
+  DeCalorimeter* m_calo = nullptr;
+  Gaudi::Plane3D m_plane;
+  double m_delta;
+  std::map<std::string, ICaloFutureDataProvider*> m_daqs;          // decoding tool per time-slot
+  LHCb::CaloAdc m_max;                        // highest deposit (sum over time-slots)
+  std::vector<LHCb::CaloAdc> m_zsupADCs;      // vector of ADC sum over time-slots (after Zsup)
+  std::vector<LHCb::CaloAdc> m_cosmicsADCs;   // vector of cellID associated to cosmics 2D track
+
+  std::map<std::string,double> m_Rmean; // mean asymmetry
+  std::map<std::string,double> m_Rmean2;// dispersion of the asymmetry
+  std::map<std::string,double> m_R;     // global asymetry
+  std::map<std::string,double> m_slotSum;
+  std::map<std::string,double> m_td;
+
+
+  double m_time = -999;  // m_Rmean converted to time
+  double m_stime = -999;
+  Gaudi::XYZPoint m_refPoint;    // reference point on the cosmics 2D track
+  Gaudi::XYZPoint m_eRefPoint;   // error on reference point
+  std::pair<Gaudi::XYZPoint,Gaudi::XYZPoint> m_bound; // extrema of the 2D track segment
+  double m_phi = -999;
+  double m_sPhi = 999;
+  bool m_timed = false;
+  bool m_tracked = false;
+  long m_adcSum;
+  std::vector<std::string> m_slots;        // full list of requested time slots
+  std::string m_maxLoc;
+  double m_offset = -99999;
+  double m_kernel = -1.;
+
+  // properties
+  Gaudi::Property<std::string> m_det {this, "Detector"};
+  
+  Gaudi::Property<std::string> m_readoutTool 
+    {this, "ReadoutTool", "CaloFutureDataProvider", "Name of the readout tool"};
+  
+  Gaudi::Property<std::vector<std::string>> m_seq
+    {this, "TrajectorySlots", {"Prev1", "T0", "Next1"},
+    "sequence of time-slots to be used for trajectory computation"};
+
+  Gaudi::Property<std::vector<std::string>> m_kern
+    {this, "RemoveSlotForKernel", {"T0"}, 
+    "sequence of time-slots to be removed from kernel"};
+
+  Gaudi::Property<std::map<std::string, std::vector<std::string> >> m_asy
+    {this, "AsymmetrySlots",
+    { 
+      {"-25.", {"Prev1", "T0"}}, 
+      {"0.", {"T0", "Next1"}} 
+    }, 
+    "pairs of time-slots to be used for asymmetry computation"};
+
+  //
+  Gaudi::Property<long> m_zSup    {this, "ZeroSuppression", 0, "Zero suppression threshold for hits ADC (sum over BX)"};
+  Gaudi::Property<long> m_zInf    {this, "MaxSuppression", 99999, "Remove largest ADC"};
+  Gaudi::Property<long> m_minD    {this, "MinCosmicsDeposit", 0, "minimal ADC sum over hits in cosmics track"};
+  Gaudi::Property<long> m_maxD    {this, "MaxCosmicsDeposit", 99999, "maximal ADC sum over hits in cosmics track"};
+  Gaudi::Property<long> m_minM    {this, "MinCosmicsMult", 0, "minimal multiplicity of hits in cosmics track"};
+  Gaudi::Property<long> m_maxM    {this, "MaxCosmicsMult", 6156, "minimal multiplicity of hits in cosmics track"};
+  Gaudi::Property<float> m_tol   {this, "MaxDistance2Line", 2.0, "maximal distance between hit and cosmics track (cellSize unit)"};
+
+  // Timing
+  Gaudi::Property<float> m_minR  {this, "MinR", 0., "minimal asymmetry range to compute time (absolute value)"};
+  Gaudi::Property<float> m_maxR  {this, "MaxR", 0.8, "maximal asymmetry range to compute time (absolute value)"};
+  Gaudi::Property<std::vector<float>> m_par {this, "RtoTime", {1.4, -0.7, 25.0, 0.19}, "parameters to convert R to time "};
+  Gaudi::Property<float> m_tRes {this, "TRes", 0, "time resolution parameter"};
+
+  // Tupling setup
+  Gaudi::Property<bool> m_tuple  {this, "Ntupling"    , false, "produce ntuple"};
+  Gaudi::Property<int>  m_maxAdc {this, "MaxArraySize", 500, "ntuple max array (# cosmics ADCs)"};
+  Gaudi::Property<bool> m_full   {this, "AllDigits"   , false, "fill digit vector with all 0-sup ADC"};
+};
+#endif // CALOFUTURECOSMICSTOOL_H
diff --git a/CaloFuture/CaloFutureTools/src/CaloFutureCosmicsTrackAlg.cpp b/CaloFuture/CaloFutureTools/src/CaloFutureCosmicsTrackAlg.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..362c39a4604ff167e80c190eea190283bbdb5c7d
--- /dev/null
+++ b/CaloFuture/CaloFutureTools/src/CaloFutureCosmicsTrackAlg.cpp
@@ -0,0 +1,143 @@
+// Include files
+
+// from LHCb
+#include "GaudiKernel/Vector3DTypes.h"
+#include "GaudiKernel/Plane3DTypes.h"
+#include "LHCbMath/LineTypes.h"
+#include "LHCbMath/GeomFun.h"
+#include "Event/Track.h"
+#include "CaloFutureInterfaces/ICaloFutureCosmicsTool.h"
+
+// local
+#include "CaloFutureCosmicsTrackAlg.h"
+
+//-----------------------------------------------------------------------------
+// Implementation file for class : CaloFutureCosmicsTrackAlg
+//
+// 2008-04-08 : Olivier Deschamps
+//-----------------------------------------------------------------------------
+
+// Declaration of the Algorithm Factory
+DECLARE_COMPONENT( CaloFutureCosmicsTrackAlg )
+
+//=============================================================================
+// Initialization
+//=============================================================================
+StatusCode CaloFutureCosmicsTrackAlg::initialize() {
+  StatusCode sc = GaudiTupleAlg::initialize(); // must be executed first
+  if ( sc.isFailure() ) return sc;  // error printed already by GaudiTupleeAlg
+
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) debug() << "==> Initialize" << endmsg;
+
+  // tools
+  m_caloTrack = tool<ICaloFutureCosmicsTrackTool>(m_trackToolType , "TrackTool", this);
+
+  if(m_monitor){
+    book1D( "Rec/1"   ,  "Reconstruction performance"   ,  0. , 5.   , 5);
+    book2D( "Rec/2"   ,  "Ecal versus Hcal timing slot" ,  -25 , 25. , 2  , -25. , 25. , 2 );
+    book1D( "Rec/Forward/1"   ,  "Reconstruction performance (forward)"   ,  0. , 5.   , 5);
+    book2D( "Rec/Forward/2"   ,  "Ecal versus Hcal timing slot (forward)" ,  -25 , 25. , 2  , -25. , 25. , 2 );
+    book1D( "Rec/Backward/1"  ,  "Reconstruction performance (backward)"   ,  0. , 5.   , 5);
+    book2D( "Rec/Backward/2"  ,  "Ecal versus Hcal timing slot (backward)" ,  -25 , 25. , 2  , -25. , 25. , 2 );
+    book2D( "Rec/3"  ,  "Cosmics track (phi,theta)" ,  -3.2 , 0 , 50  , 0 , 3.2 , 50 );
+    book1D( "Asymmetry/1",  " Ecal asymmetry" ,  -1., 1.,50);
+    book1D( "Asymmetry/2",  " Hcal asymmetry" ,  -1., 1.,50);
+    book1D( "Kernel/1",  " Ecal Kernel" ,  0., 1., 50);
+    book1D( "Kernel/2",  " Hcal Kernel" ,  0., 1., 50);
+  }
+  return StatusCode::SUCCESS;
+}
+
+//=============================================================================
+// Main execution
+//=============================================================================
+StatusCode CaloFutureCosmicsTrackAlg::execute() {
+
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) debug() << "==> Execute" << endmsg;
+  setFilterPassed(false);
+
+  if(m_monitor){
+    fill( histo1D(HistoID("Rec/1"))  ,  0. , 1.); // bin0 = counter
+    fill( histo1D(HistoID("Rec/Forward/1"))  ,  0. , 1.); // bin0 = counter
+    fill( histo1D(HistoID("Rec/Backward/1"))  ,  0. , 1.); // bin0 = counter
+  }
+
+
+  // create and store container
+  LHCb::Tracks* forwards = new LHCb::Tracks();
+  LHCb::Tracks* backwards = new LHCb::Tracks();
+  put(forwards, m_forward);
+  put(backwards, m_backward);
+
+  // process tracking
+  StatusCode esc = m_caloTrack->processing();
+  if(!m_caloTrack->tracked()){
+    if( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+      debug() << "No track reconstructed" << endmsg;
+    return StatusCode::SUCCESS;
+  }
+
+
+  //store tracks
+  LHCb::Track* track = new LHCb::Track();
+  track->copy( m_caloTrack->track() );
+  ( m_caloTrack->forward() ) ?  forwards->insert( track ) : backwards->insert( track );
+
+
+  // Checks
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) {
+    debug() << " Track ---- " << endmsg;
+    debug() << " backward  : "<< track->checkFlag(LHCb::Track::Flags::Backward) << endmsg;
+    debug() << " Timed : " << track->checkFlag(LHCb::Track::Flags::Selected) << " / " << m_caloTrack->timed() << endmsg;
+    debug() << " firstState : "<< track->firstState() << endmsg;
+    // commented out by VB. 8.8.2k+9
+    // debug() << " Time : " << track->likelihood()<< endmsg;
+    debug() << " Chi2 : " << track->info(LHCb::Track::AdditionalInfo::FitMatchChi2, 999.)<< endmsg;
+    double z = 8000;
+    m_caloTrack->propagate( z );
+    debug() << "Propagated track ---" << endmsg;
+    debug() << "Position : " << m_caloTrack->referencePoint() << endmsg;
+    debug() << "Position Error : " << sqrt(m_caloTrack->referencePointCovariance()) << endmsg;
+    debug() << "Time : " << m_caloTrack->time() << endmsg;
+  }
+
+
+
+  // Monitoring
+  std::stringstream dir("");
+  dir << ( m_caloTrack->forward()  ?  "Forward/" : "Backward/" );
+  if(m_monitor && m_caloTrack->tracked()){
+    fill( histo1D(HistoID("Rec/"+dir.str()+"1"))  ,  1. , 1.); // bin1 = reconstructed
+    fill( histo1D(HistoID("Rec/1"))  ,  1. , 1.); // bin1 = reconstructed
+    fill( histo1D(HistoID("Asymmetry/1")), m_caloTrack->ecal()->asymmetry(), 1.);
+    fill( histo1D(HistoID("Asymmetry/2")), m_caloTrack->hcal()->asymmetry(), 1.);
+    fill( histo1D(HistoID("Kernel/1")), m_caloTrack->ecal()->kernel(), 1.);
+    fill( histo1D(HistoID("Kernel/2")), m_caloTrack->hcal()->kernel(), 1.);
+
+
+    double phi   =  m_caloTrack->phi();
+    double theta =  m_caloTrack->theta();
+    if( !m_caloTrack->forward() ){
+      phi   += acos(-1.);
+      if( phi > acos(-1.)) phi -= 2*acos(-1.); // phi in [-pi,pi]
+      theta = acos(-1.) - theta; // theta in [0,pi]
+    }
+    fill( histo2D(HistoID("Rec/3")), phi, theta, 1.);
+  }
+  if(m_monitor && m_caloTrack->timed()){
+    fill( histo1D(HistoID("Rec/"+dir.str()+"1"))  ,  2. , 1.); // bin2 = timed (ecal or hcal)
+    fill( histo1D(HistoID("Rec/1"))  ,  2. , 1.); // bin2 = timed (ecal or hcal)
+  }
+  if(m_monitor && m_caloTrack->ecal()->timed() && m_caloTrack->hcal()->timed()){
+    fill( histo1D(HistoID("Rec/"+dir.str()+"1"))  ,  3. , 1.); // bin2 = ecal+hcal timing
+    fill( histo2D(HistoID("Rec/"+dir.str()+"2"))  , m_caloTrack->ecal()->slot()+12.5, m_caloTrack->hcal()->slot()+12.5, 1. );
+    fill( histo1D(HistoID("Rec/1"))  ,  3. , 1.); // bin2 = ecal+hcal timing
+    fill( histo2D(HistoID("Rec/2"))  , m_caloTrack->ecal()->slot()+12.5, m_caloTrack->hcal()->slot()+12.5, 1. );
+  }
+
+
+
+  if( m_caloTrack->tracked())setFilterPassed(true);
+
+  return StatusCode::SUCCESS;
+}
diff --git a/CaloFuture/CaloFutureTools/src/CaloFutureCosmicsTrackAlg.h b/CaloFuture/CaloFutureTools/src/CaloFutureCosmicsTrackAlg.h
new file mode 100644
index 0000000000000000000000000000000000000000..f4b6281ad33d87277350274fb30c04a71a55f8e0
--- /dev/null
+++ b/CaloFuture/CaloFutureTools/src/CaloFutureCosmicsTrackAlg.h
@@ -0,0 +1,40 @@
+#ifndef CALOFUTURECOSMICSTRACKALG_H 
+#define CALOFUTURECOSMICSTRACKALG_H 1
+
+// Include files
+// from Gaudi
+#include "GaudiAlg/GaudiTupleAlg.h"
+// from LHCb
+#include "CaloFutureInterfaces/ICaloFutureCosmicsTrackTool.h"       
+
+
+/** @class CaloFutureCosmicsTrackAlg CaloFutureCosmicsTrackAlg.h
+ *  
+ *
+ *  @author Olivier Deschamps
+ *  @date   2008-05-17
+ */
+class CaloFutureCosmicsTrackAlg : public GaudiTupleAlg {
+public: 
+  /// Standard constructor
+  using GaudiTupleAlg::GaudiTupleAlg;
+
+  StatusCode initialize() override;    ///< Algorithm initialization
+  StatusCode execute() override;    ///< Algorithm execution
+
+private:
+  ICaloFutureCosmicsTrackTool* m_caloTrack = nullptr;
+
+  Gaudi::Property<std::string> m_trackToolType 
+    {this, "TrackTool", "CaloFutureCosmicsTrackTool"};
+  
+  Gaudi::Property<std::string> m_forward 
+    {this, "ForwardTrackContainer", LHCb::TrackLocation::CaloCosmicsForward};
+
+  Gaudi::Property<std::string> m_backward 
+    {this, "BackwardTrackContainer", LHCb::TrackLocation::CaloCosmicsBackward};
+
+  Gaudi::Property<bool> m_monitor {this, "Monitor", false};
+
+};
+#endif // CALOFUTURECOSMICSTRACKALG_H
diff --git a/CaloFuture/CaloFutureTools/src/CaloFutureCosmicsTrackTool.cpp b/CaloFuture/CaloFutureTools/src/CaloFutureCosmicsTrackTool.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..399969fa31b77f2ce7193feb53ac5dd7ddb03003
--- /dev/null
+++ b/CaloFuture/CaloFutureTools/src/CaloFutureCosmicsTrackTool.cpp
@@ -0,0 +1,569 @@
+// Include files
+
+// From std
+#include <math.h>
+
+// from Gaudi
+#include "GaudiKernel/PhysicalConstants.h"
+
+// from LHCb
+#include "GaudiKernel/Vector3DTypes.h"
+#include "GaudiKernel/Plane3DTypes.h"
+#include "LHCbMath/LineTypes.h"
+#include "LHCbMath/GeomFun.h"
+#include "Event/ODIN.h"
+#include "Event/Track.h"
+#include "CaloDet/DeCalorimeter.h"
+#include "CaloFutureInterfaces/ICaloFutureCosmicsTool.h"
+
+// local
+#include "CaloFutureCosmicsTrackTool.h"
+
+//-----------------------------------------------------------------------------
+// Implementation file for class : CaloFutureCosmicsTrackTool
+//
+// 2008-05-17 : Olivier Deschamps
+//-----------------------------------------------------------------------------
+
+// Declaration of the Tool Factory
+DECLARE_COMPONENT( CaloFutureCosmicsTrackTool )
+
+
+//=============================================================================
+// Standard constructor, initializes variables
+//=============================================================================
+CaloFutureCosmicsTrackTool::CaloFutureCosmicsTrackTool( const std::string& type,
+                                            const std::string& name,
+                                            const IInterface* parent )
+  : base_class ( type, name , parent )
+{
+  declareInterface<ICaloFutureCosmicsTrackTool>(this);
+}
+
+//=============================================================================
+// Initialization
+//=============================================================================
+StatusCode CaloFutureCosmicsTrackTool::initialize() {
+  StatusCode sc = base_class::initialize(); // must be executed first
+  if ( sc.isFailure() ) return sc;
+
+  if ( msgLevel(MSG::DEBUG) ) debug() << "==> Initialize" << endmsg;
+
+  // tools
+  m_eCosmics = tool<ICaloFutureCosmicsTool>(m_cosmics , "Ecal", this);
+  m_hCosmics = tool<ICaloFutureCosmicsTool>(m_cosmics , "Hcal", this);
+  // odin
+  m_odin = tool<IEventTimeDecoder>("OdinTimeDecoder","OdinDecoder",this);
+
+  return StatusCode::SUCCESS;
+}
+
+//=============================================================================
+// Main execution
+//=============================================================================
+StatusCode CaloFutureCosmicsTrackTool::processing() {
+
+  if ( msgLevel(MSG::DEBUG) ) debug() << "==> Execute" << endmsg;
+
+
+  m_odin->getTime();
+  m_run = -1;
+  m_evt = -1;
+  m_bx  = -1;
+  LHCb::ODIN* odin = getIfExists<LHCb::ODIN> (LHCb::ODINLocation::Default);
+  if( odin ){
+    m_run = odin->runNumber();
+    m_evt = (long) odin->eventNumber()  ;
+    m_bx  = odin->bunchId() ;
+  }
+
+  // init
+  m_track.reset();
+  m_tracked=false;
+  m_timed = false;
+  m_time  = -999.;
+  m_stime = 999.;
+  m_chi2  = 9999.;
+  m_phi   = -999.;
+  m_sPhi  = 999.;
+  m_theta = -999.;
+  m_sTheta  = 999.;
+  m_dir = 0;
+  m_ref = 0; // Ecal is reference by default
+  m_refPoint[0] = Gaudi::XYZPoint();
+  m_refPointCov[0]=Gaudi::SymMatrix3x3();
+  m_refPt = Gaudi::XYZPoint();
+  m_refPtCov=Gaudi::SymMatrix3x3();
+  //
+  StatusCode esc = ecal()->processing();
+  StatusCode hsc = hcal()->processing();
+  if(esc.isFailure() )
+    if( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+      debug() << "EcalCosmic processing failed"<<endmsg;
+  if(hsc.isFailure() )
+    if( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+      debug() << "HcalCosmic processing failed"<<endmsg;
+
+
+  if( !ecal()->tracked() || !hcal()->tracked() ){
+    if( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+      debug() << "Cannot reconstruct Cosmics (Ecal/Hcal):("
+              <<ecal()->tracked()<<"/"<<hcal()->tracked()<<")"<<endmsg;
+    return StatusCode::SUCCESS;
+  }
+
+
+  // 1) ecal-hcal matching
+  if( matching().isFailure() )return StatusCode::SUCCESS;
+
+  // 2) reconstruct 3D trajectory
+  if( fit3D().isFailure() )return StatusCode::SUCCESS;
+
+  // 3) Produce Track object
+  if( buildTrack().isFailure() )return StatusCode::SUCCESS;
+  m_tracked = true;
+
+
+  // 4) Timing
+  m_timed = true;
+  if(m_timer == "Ecal"  ){
+    if(ecal()->timed()){
+      m_time = ecal()->time();
+      m_stime = ecal()->timeVariance();
+    }else{
+      m_timed = false;
+    }
+  }
+  else if(m_timer == "Hcal" ){
+    if(hcal()->timed()){
+      m_time = hcal()->time();
+      m_stime = hcal()->timeVariance();
+    }else{
+      m_timed = false;
+    }
+  }
+  else if(m_timer == "EcalElseHcal" ){
+    if(ecal()->timed() ){
+      m_time = ecal()->time();
+      m_stime = ecal()->timeVariance();
+    }else if(hcal()->timed() ){
+      m_time=hcal()->time();
+      m_stime = hcal()->timeVariance();
+    } else m_timed = false;
+  } else{
+    warning() << "Unexpected timer : '" << m_timer << "' -> NO TIMING INFORMATION" << endmsg;
+    m_timed = false;
+  }
+  // Update track info
+  if( timed() ){
+    m_track.setFlag( LHCb::Track::Flags::Selected , true );
+    // not stored anymore in Track class SHM
+    //m_track.addInfo( LHCb::Track::CaloFutureTimeInfo, m_time );
+  }
+
+
+  // 5) Ntupling
+  if(m_tuple){
+    if( tupling(500).isFailure())return StatusCode::FAILURE;
+  }
+
+  return StatusCode::SUCCESS;
+}
+
+
+//=============================================================================
+StatusCode CaloFutureCosmicsTrackTool::matching(){
+
+  // match Ecal and Hcal
+  // return phi and Chi2
+
+  m_chi2 = 9999;
+
+
+  Gaudi::XYZVector vec = ecal()->referencePoint()-hcal()->referencePoint();
+  m_dir = (vec.Y() > 0) ? +1 : -1;
+  // Phi = atan(DX/DY)
+  double dX  = vec.X();
+  double dY  = vec.Y();
+  double s2X = ecal()->referencePointVariance().X()+ hcal()->referencePointVariance().X();
+  double s2Y = ecal()->referencePointVariance().Y()+ hcal()->referencePointVariance().Y();
+  m_phi  = (dX != 0) ?    atan( dY/dX ) :  acos( 0. );
+  double d2 = (dX*dX+dY*dY);
+  m_sPhi = (d2 !=0) ? dY*dY/d2/d2*s2X + dX*dX/d2/d2*s2Y :  acos(-1.)*acos(-1.);
+
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+    debug() << " Phi = " << m_phi << " +- " << m_sPhi << endmsg;
+  // Chi2 = (phi-phi_eca<l)^2/sig^2 + (phi-phi_hcal)^2/sig^2
+  double ePhi = ecal()->phi();
+  double hPhi = hcal()->phi();
+  double s2ePhi = ecal()->phiVariance();
+  double s2hPhi = hcal()->phiVariance();
+
+  if(m_phi<0)m_phi += acos(-1.);
+  if(ePhi<0)ePhi += acos(-1.);
+  if(hPhi<0)hPhi += acos(-1.);
+
+  m_chi2 =  (m_phi-ePhi)*(m_phi-ePhi)/(s2ePhi+m_sPhi) + (m_phi-hPhi)*(m_phi-hPhi)/(s2hPhi+m_sPhi);
+  m_chi2 /= 2.;
+
+  //
+  if(m_dir == 1)m_phi -= acos(-1.);
+
+
+
+
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+    debug() << " Chi2 = " << m_chi2 << endmsg;
+
+  if(m_chi2 > m_chi2max)return StatusCode::FAILURE;
+  if(m_chi2 < m_chi2min)return StatusCode::FAILURE;
+  return StatusCode::SUCCESS;
+}
+
+
+
+
+
+//=============================================================================
+StatusCode CaloFutureCosmicsTrackTool::fit3D(){
+
+  Gaudi::Plane3D backEcal  = ecal()->det()->plane(CaloPlane::Back);
+  Gaudi::Plane3D frontHcal = hcal()->det()->plane(CaloPlane::Front);
+  Gaudi::Plane3D frontEcal = ecal()->det()->plane(CaloPlane::Front);
+  //  Gaudi::Plane3D middleEcal  = ecal()->det()->plane(CaloPlane::Middle);
+  //  Gaudi::Plane3D middleHcal  = hcal()->det()->plane(CaloPlane::Middle);
+  Gaudi::Plane3D backHcal  = hcal()->det()->plane(CaloPlane::Back);
+
+  // Assign closest Ecal/Hcal cells to the back/front plane respectively
+  typedef std::pair<Gaudi::XYZPoint,Gaudi::XYZPoint> pointPair;
+  pointPair eBound =  ecal()->extrema();
+  pointPair hBound =  hcal()->extrema();
+  Gaudi::XYZPoint eP = eBound.first;
+  Gaudi::XYZPoint hP = hBound.first;
+  Gaudi::XYZPoint eM = eBound.second;
+  Gaudi::XYZPoint hM = hBound.second;
+  if( dist2D(eBound.first ,hBound.second) < dist2D(eP,hP)){eP=eBound.first;hP=hBound.second;eM=eBound.second;hM=hBound.first;}
+  if( dist2D(eBound.second,hBound.second) < dist2D(eP,hP)){eP=eBound.second;hP=hBound.second;eM=eBound.first;hM=hBound.first;}
+  if( dist2D(eBound.second,hBound.first)  < dist2D(eP,hP)){eP=eBound.second;hP=hBound.first;eM=eBound.first;hM=hBound.second;}
+  //
+  double ePZ=( -backEcal.Normal().X()*eP.X()-backEcal.Normal().Y()*eP.Y() - backEcal.HesseDistance() )/backEcal.Normal().Z();
+  double hPZ=(-frontHcal.Normal().X()*hP.X()-frontHcal.Normal().Y()*hP.Y()-frontHcal.HesseDistance() )/frontHcal.Normal().Z();
+  eP.SetZ(ePZ);
+  hP.SetZ(hPZ);
+  double eMZ=(-frontEcal.Normal().X()*eM.X()-frontEcal.Normal().Y()*eM.Y()-frontEcal.HesseDistance() )/frontEcal.Normal().Z();
+  double hMZ=(-backHcal.Normal().X()*hM.X()-backHcal.Normal().Y()*hM.Y()-backHcal.HesseDistance() )/backHcal.Normal().Z();
+  eM.SetZ(eMZ);
+  hM.SetZ(hMZ);
+  const LHCb::CaloCellID ePId =  ecal()->det()->Cell( eP );
+  const LHCb::CaloCellID hPId =  hcal()->det()->Cell( hP );
+  const LHCb::CaloCellID eMId =  ecal()->det()->Cell( eM );
+  const LHCb::CaloCellID hMId =  hcal()->det()->Cell( hM );
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) {
+    debug() << "Closest Points " << eP << "/" << hP <<endmsg;
+    debug() << "--> " << ePId << "/" << hPId <<endmsg;
+    debug() << "Farest Points " << eM << "/" << hM <<endmsg;
+    debug() << "--> " << eMId << "/" << hMId <<endmsg;
+  }
+  //
+  std::vector<pointPair> points; // position and variance
+  double ePSig = ecal()->det()->cellSize(ePId)*m_fac;
+  double hPSig = hcal()->det()->cellSize(hPId)*m_fac;
+  double eMSig = ecal()->det()->cellSize(eMId)*m_fac;
+  double hMSig = hcal()->det()->cellSize(hMId)*m_fac;
+  ePSig *= ePSig/12.;
+  hPSig *= hPSig/12.;
+  eMSig *= eMSig/12.;
+  hMSig *= hMSig/12.;
+
+  // closest point
+  if(m_intern){
+    points.push_back(std::make_pair(eP , Gaudi::XYZPoint(ePSig,ePSig,0.)));
+    points.push_back(std::make_pair(hP , Gaudi::XYZPoint(hPSig,hPSig,0.)));
+  }
+
+  // middle plane (should depend on the trajectory.vs.acceptance)
+  points.push_back( std::make_pair( ecal()->referencePoint(),ecal()->referencePointVariance()));
+  points.push_back( std::make_pair( hcal()->referencePoint(),hcal()->referencePointVariance()));
+
+  if(m_extern){
+    // maxima (should depend on the trajectory.vs.acceptance)
+    points.push_back( std::make_pair(eM, Gaudi::XYZPoint(eMSig,eMSig,0.)));
+    points.push_back( std::make_pair(hM, Gaudi::XYZPoint(hMSig,hMSig,0.)));
+  }
+
+  /*
+  // @TODO TAKE THE TRAJECTORY.vs.ACCEPTANCE INTO ACCOUNT
+  Gaudi::Math::XYZLine   line(eP, hP-eP); // 3D line
+  // if the 3D line is in the whole Ecal acceptance add Ecal middle and front plane points
+  Gaudi::XYZPoint  point;
+  double mu;
+  Gaudi::Math::intersection<Gaudi::Math::XYZLine,Gaudi::Plane3D>(line,frontEcal,point,mu);
+  if( ecal()()->det()->geometry()->isInside(point) ){
+    debug() << " cosmics cross the whole Ecal" << endmsg;
+    const LHCb::CaloCellID id =  ecal()->det()->Cell( point );
+    points.push_back( std::make_pair(eM, Gaudi::XYZPoint(eMsig,eMsig,0.)));
+  }
+  Gaudi::Math::intersection<Gaudi::Math::XYZLine,Gaudi::Plane3D>(line,backHcal,point,mu);
+  if( hcal()()->det()->geometry()->isInside(point) ){
+    debug() << " cosmics cross the whole Hcal" << endmsg;
+    const LHCb::CaloCellID id =  hcal()->det()->Cell( point );
+    points.push_back( std::make_pair(hM, Gaudi::XYZPoint(hMsig,hMsig,0.)));
+  }
+  */
+
+  //
+  double Ax = 0;
+  double Bx = 0;
+  double Cx = 0;
+  double Dx = 0;
+  double Ex = 0;
+  double Ay = 0;
+  double By = 0;
+  double Cy = 0;
+  double Dy = 0;
+  double Ey = 0;
+
+  Gaudi::XYZVector d = ecal()->referencePoint()-hcal()->referencePoint();
+
+  for(std::vector<pointPair>::iterator ip = points.begin() ; ip != points.end() ; ip++){
+    pointPair p = *ip;
+    double sig2X= p.second.X()+ d.X()/d.Z()*p.second.Z();
+    double sig2Y= p.second.Y()+ d.Y()/d.Z()*p.second.Z();
+    Ax += p.first.Z()*p.first.Z()/sig2X;
+    Bx += p.first.Z()/sig2X;
+    Cx += -(p.first.X()*p.first.Z())/sig2X;
+    Dx += 1./sig2X;
+    Ex += -p.first.X()/sig2X;
+    //
+    Ay += p.first.Z()*p.first.Z()/sig2Y;
+    By += p.first.Z()/sig2Y;
+    Cy += -(p.first.Y()*p.first.Z())/sig2Y;
+    Dy += 1./sig2Y;
+    Ey += -p.first.Y()/sig2Y;
+  }
+
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) {
+    debug() << "(A->E)x " << Ax << " " << Bx << " " << Cx << " " << Dx << " " << Ex << endmsg;
+    debug() << "(A->E)y " << Ay << " " << By << " " << Cy << " " << Dy << " " << Ey << endmsg;
+  }
+
+  m_tx = -(Dx*Cx-Bx*Ex)/(Ax*Dx-Bx*Bx);
+  m_ty = -(Dy*Cy-By*Ey)/(Ay*Dy-By*By);
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+    debug() << "tx = " << m_tx << "  ty = " << m_ty << endmsg;
+  double x0   =  (Bx*Cx-Ax*Ex)/(Ax*Dx-Bx*Bx);
+  double y0   =  (By*Cy-Ay*Ey)/(Ay*Dy-By*By);
+
+  // Theta
+  double tth = sqrt( m_tx*m_tx + m_ty*m_ty);
+  m_theta = atan( tth );
+  // Approximate error
+  Gaudi::XYZVector sD = hcal()->referencePointVariance() - (-1.)*ecal()->referencePointVariance();
+  m_stx = m_tx*m_tx * (sD.X()/d.X()/d.X() + sD.Z()/d.Z()/d.Z() );
+  m_sty = m_ty*m_ty * (sD.Y()/d.Y()/d.Y() + sD.Z()/d.Z()/d.Z() );
+  double sTth  = (m_tx/tth)*(m_tx/tth) * m_stx + (m_ty/tth)*(m_ty/tth) * m_sty;
+  m_sTheta     = sTth / (1+tth*tth)/(1+tth*tth);
+
+  // Phi
+  double tphi = m_ty/m_tx;
+  m_phi = atan(tphi);
+  if(m_phi<0.)m_phi += acos(-1.);
+  if(m_dir == 1)m_phi -= acos(-1.);
+
+  // Ecal reference
+  double ex = x0 + m_tx *ecal()->referencePoint().Z();
+  double ey = y0 + m_ty *ecal()->referencePoint().Z();
+  m_refPoint[0].SetX(ex);
+  m_refPoint[0].SetY(ey);
+  m_refPoint[0].SetZ( ecal()->referencePoint().Z() );
+  m_refPointCov[0](0,0) = ecal()->referencePointVariance().X();  // APPROXIMATIVE ERROR
+  m_refPointCov[0](1,1) = ecal()->referencePointVariance().Y();  // APPROXIMATIVE ERROR
+  // Hcal reference
+  double hx = x0 + m_tx *hcal()->referencePoint().Z();
+  double hy = y0 + m_ty *hcal()->referencePoint().Z();
+  m_refPoint[1].SetX(hx);
+  m_refPoint[1].SetY(hy);
+  m_refPoint[1].SetZ( hcal()->referencePoint().Z() );
+  m_refPointCov[1](0,0)= hcal()->referencePointVariance().X();  // APPROXIMATIVE ERROR
+  m_refPointCov[1](1,1)= hcal()->referencePointVariance().Y();  // APPROXIMATIVE ERROR
+
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) {
+    debug() << " Ecal Reference Point : ("
+            << ecal()->referencePoint().X() << ","
+            << ecal()->referencePoint().Y() << ","
+            << ecal()->referencePoint().Z() << ") "
+            << "  -> Fit3D : ("
+            << ex << ","
+            << ey  << ","
+            << ecal()->referencePoint().Z() << ") " << endmsg;
+    debug() << " Theta = " << m_theta << endmsg;
+  }
+
+  m_slopes = Gaudi::XYZVector( m_tx, m_ty , m_dir );
+  m_slopesCov(0,0) = m_stx;
+  m_slopesCov(1,1) = m_sty;
+
+  return StatusCode::SUCCESS;
+}
+//=============================================================================
+double CaloFutureCosmicsTrackTool::dist2D(Gaudi::XYZPoint p1 ,Gaudi::XYZPoint p2){
+  Gaudi::XYZVector v = p1-p2;
+  return v.rho();
+}
+//=============================================================================
+StatusCode CaloFutureCosmicsTrackTool::buildTrack(){
+
+
+  //  Gaudi::XYZVector  direction = hcal()->referencePoint() - ecal()->referencePoint();
+
+  Gaudi::TrackVector eTrV ;
+  Gaudi::TrackSymMatrix eTrM;
+  eTrV(0) = m_refPoint[0].X();
+  eTrV(1) = m_refPoint[0].Y();
+  eTrV(2) = m_tx;
+  eTrV(3) = m_ty;
+  eTrV(4) = 1./ ecal()->deposit() ;
+  eTrM(0,0) = m_refPointCov[0](0,0);
+  eTrM(1,1) = m_refPointCov[0](1,1);
+  eTrM(2,2) = m_stx;
+  eTrM(3,3) = m_sty;
+  LHCb::State eState = LHCb::State( eTrV , eTrM , ecal()->referencePoint().Z() , LHCb::State::Location::MidECal);
+
+
+  Gaudi::TrackVector hTrV ;
+  Gaudi::TrackSymMatrix hTrM;
+  hTrV(0) = m_refPoint[1].X();
+  hTrV(1) = m_refPoint[1].Y();
+  hTrV(2) = m_tx;
+  hTrV(3) = m_ty;
+  hTrV(4) = 1./ hcal()->deposit() ;
+  hTrM(0,0) = m_refPointCov[1](0,0);
+  hTrM(1,1) = m_refPointCov[1](1,1);
+  hTrM(2,2) = m_stx;
+  hTrM(3,3) = m_sty;
+
+  LHCb::State hState = LHCb::State( hTrV , hTrM , hcal()->referencePoint().Z() , LHCb::State::Location::MidHCal);
+
+  // Track
+  m_track.setType(LHCb::Track::Types::Calo);
+  // Default reference position is Ecal
+  m_ref = 0; // reference is Ecal by default
+  // Set first state according to 'timer'
+  if(m_timer == "Ecal"){
+    m_track.addToStates( eState ); // 1st state is Ecal
+    m_track.addToStates( hState );
+  }
+  else if(m_timer == "Hcal"){
+    m_ref = 1; // reference is Hcal
+    m_track.addToStates( hState ); // 1st state is Hcal
+    m_track.addToStates( eState );
+  }
+  else if(m_timer == "EcalElseHcal"){
+    if( !ecal()->timed() && hcal()->timed()){
+      m_ref = 1; // reference is Hcal
+      m_track.addToStates( hState ); // 1st state is Hcal
+      m_track.addToStates( eState );
+    }else{
+      m_track.addToStates( eState ); // 1st state is Ecal
+      m_track.addToStates( hState );
+    }
+  }
+  else{
+    warning() << "Unexpected timer : '" << m_timer << "' -> 1st state is Ecal by default" << endmsg;
+    m_track.addToStates( eState ); // 1st state is Ecal
+    m_track.addToStates( hState );
+  }
+
+  // not stored anymore in Track class
+  //m_track.addInfo( LHCb::Track::CaloFutureMatchChi2, m_chi2);
+  if( !forward())m_track.setFlag( LHCb::Track::Flags::Backward, true );
+
+
+  // Global reference
+  m_refPt = m_refPoint[m_ref];
+  m_refPtCov = m_refPointCov[m_ref];
+
+  return StatusCode::SUCCESS;
+}
+
+
+//=============================================================================
+StatusCode CaloFutureCosmicsTrackTool::tupling(unsigned int unit){
+
+
+  if( ecal()->tupling(unit+1).isFailure())return StatusCode::FAILURE;
+  if( hcal()->tupling(unit+2).isFailure())return StatusCode::FAILURE;
+
+
+  Tuple ntp = nTuple(unit, "CosmicsTrack" ,CLID_ColumnWiseTuple);
+  StatusCode sc;
+  Gaudi::XYZVector vec = hcal()->referencePoint()-ecal()->referencePoint();
+  sc = ntp->column("Run"    , m_run );
+  sc = ntp->column("Event"  , m_evt );
+  sc = ntp->column("BCID"   , m_bx  );
+  sc = ntp->column("L"      , vec.R() );
+  sc = ntp->column("eTime"  , ecal()->time());
+  sc = ntp->column("hTime"  , hcal()->time());
+  sc = ntp->column("eSlot"  , ecal()->slot() );
+  sc = ntp->column("hSlot"  , hcal()->slot() );
+  sc = ntp->column("eDep"  , ecal()->deposit() );
+  sc = ntp->column("hDep"  , hcal()->deposit() );
+  sc = ntp->column("direction"   , m_dir);
+  sc = ntp->column("L"      , vec.R() );
+  sc = ntp->column("chi2"   , m_chi2 );
+  sc = ntp->column("phi"    , m_phi );
+  sc = ntp->column("phiVariance", sqrt( m_sPhi ) );
+  sc = ntp->column("theta"  , m_theta );
+  sc = ntp->column("thetaVariance", m_sTheta );
+  sc = ntp->column("th"  , vec.theta( ));
+  sc = ntp->column("ph"  , vec.phi( ));
+  sc = ntp->column("ecalRefX"   , m_refPoint[0].X() );
+  sc = ntp->column("ecalRefY"   , m_refPoint[0].Y() );
+  sc = ntp->column("ecalRefZ"   , m_refPoint[0].Z() );
+  sc = ntp->column("hcalRefX"   , m_refPoint[1].X() );
+  sc = ntp->column("hcalRefY"   , m_refPoint[1].Y() );
+  sc = ntp->column("hcalRefZ"   , m_refPoint[1].Z() );
+  sc = ntp->column("eTimed"  ,  (int)ecal()->timed());
+  sc = ntp->column("hTimed"  ,  (int)hcal()->timed());
+  sc = ntp->column("eR"  , ecal()->asymmetry());
+  sc = ntp->column("hR"  , hcal()->asymmetry());
+  sc = ntp->column("dX"  , vec.X());
+  sc = ntp->column("dY"  , vec.Y());
+  sc = ntp->column("dZ"  , vec.Z());
+
+  sc=ntp->write();
+
+
+  if(sc.isFailure())Warning(name() + " Ntupling failed").ignore();
+  return sc;
+}
+
+
+
+StatusCode CaloFutureCosmicsTrackTool::propagate(double z){
+  Gaudi::XYZPoint  ref = m_refPoint[m_ref];
+  Gaudi::SymMatrix3x3 refCov = m_refPointCov[m_ref];
+  m_refPt.SetX( ref.X() + slopes().X() * (z-ref.Z()) );
+  m_refPt.SetY( ref.Y() + slopes().Y() * (z-ref.Z()) );
+  m_refPt.SetZ( z );
+  m_refPtCov(0,0) = (refCov(0,0) + slopesCovariance()(0,0) * (z-ref.Z()) * (z-ref.Z()));
+  m_refPtCov(1,1) = (refCov(1,1) + slopesCovariance()(1,1) * (z-ref.Z()) * (z-ref.Z()));
+  if( !timed() )return StatusCode::SUCCESS;
+  double time = (m_ref == 0) ? ecal()->time() : hcal()->time();
+  Gaudi::XYZVector vec = m_refPt - m_refPoint[m_ref];
+  double sign = 0;
+  if( vec.Z() != 0)sign = vec.Z()/fabs(vec.Z())*m_dir;
+  m_time = time + (vec.R() / Gaudi::Units::c_light) *sign;
+  return StatusCode::SUCCESS;
+}
+
+
+StatusCode CaloFutureCosmicsTrackTool::propagate(Gaudi::Plane3D plane){
+  Gaudi::XYZPoint  ref = m_refPoint[m_ref];
+  Gaudi::XYZVector vec = slopes()/slopes().R();
+  Gaudi::Math::XYZLine   line(ref, vec);
+  Gaudi::XYZPoint  point;
+  double mu;
+  Gaudi::Math::intersection<Gaudi::Math::XYZLine,Gaudi::Plane3D>(line,plane,point,mu);
+  return propagate( point.Z() );
+}
diff --git a/CaloFuture/CaloFutureTools/src/CaloFutureCosmicsTrackTool.h b/CaloFuture/CaloFutureTools/src/CaloFutureCosmicsTrackTool.h
new file mode 100644
index 0000000000000000000000000000000000000000..5d9dd1ef60742bf0c8f024b6160881a6cd16ab96
--- /dev/null
+++ b/CaloFuture/CaloFutureTools/src/CaloFutureCosmicsTrackTool.h
@@ -0,0 +1,95 @@
+#ifndef CALOFUTURECOSMICSTRACKTOOL_H
+#define CALOFUTURECOSMICSTRACKTOOL_H 1
+
+// Include files
+// from Gaudi
+#include "GaudiKernel/IEventTimeDecoder.h"
+#include "GaudiAlg/GaudiTupleTool.h"
+
+// from LHCb
+#include "CaloFutureInterfaces/ICaloFutureCosmicsTrackTool.h"            // Interface
+
+/** @class CaloFutureCosmicsTrackTool CaloFutureCosmicsTrackTool.h
+ *
+ *
+ *  @author Olivier Deschamps
+ *  @date   2008-05-17
+ */
+class CaloFutureCosmicsTrackTool : public extends<GaudiTupleTool, ICaloFutureCosmicsTrackTool> {
+public:
+  /// Standard constructor
+  CaloFutureCosmicsTrackTool( const std::string& type,
+                        const std::string& name,
+                        const IInterface* parent);
+
+  StatusCode initialize() override;
+  //
+  StatusCode processing() override;
+  StatusCode tupling(unsigned int unit) override;
+  double phi() override {return m_phi;}
+  double phiVariance() override {return m_sPhi;}
+  double theta() override {return m_theta;}
+  double thetaVariance() override {return m_sTheta;}
+  const Gaudi::XYZVector slopes() override {return m_slopes;}
+  const Gaudi::XYZPoint  referencePoint() override { return m_refPt;}
+  const Gaudi::SymMatrix3x3 slopesCovariance() override {return m_slopesCov;}
+  const Gaudi::SymMatrix3x3 referencePointCovariance() override { return m_refPtCov;}
+  bool   forward() override {return (m_dir == 1) ? true : false;}
+  bool   tracked() override {return m_tracked;}
+  double time() override {return m_time;}
+  double timeVariance() override {return m_stime;}
+  bool   timed() override {return  m_timed;}
+  ICaloFutureCosmicsTool* ecal() override {return m_eCosmics;}
+  ICaloFutureCosmicsTool* hcal() override {return m_hCosmics;}
+  const LHCb::Track& track() override {return m_track;}
+  StatusCode propagate(Gaudi::Plane3D plane) override;
+  StatusCode propagate(double z ) override;
+
+private:
+  StatusCode matching();
+  StatusCode fit3D();
+  double dist2D(Gaudi::XYZPoint,Gaudi::XYZPoint);
+  StatusCode buildTrack();
+
+  //
+  ICaloFutureCosmicsTool* m_eCosmics = nullptr;
+  ICaloFutureCosmicsTool* m_hCosmics = nullptr;
+  IEventTimeDecoder* m_odin = nullptr;
+  //
+  long m_run;
+  long m_evt;
+  long m_bx;
+  double m_tx;
+  double m_ty;
+  Gaudi::XYZVector m_slopes;
+  Gaudi::SymMatrix3x3 m_slopesCov;
+  double m_stx;
+  double m_sty;
+  double m_theta;
+  double m_sTheta;
+  double m_phi;
+  double m_sPhi;
+  double m_chi2;
+  Gaudi::Property<bool> m_intern {this, "UseInternalPlanes", false};
+  Gaudi::Property<bool> m_extern {this, "UseExternalPlanes", false};
+  double m_time;
+  double m_stime;
+  Gaudi::XYZPoint m_refPoint[2];
+  Gaudi::SymMatrix3x3 m_refPointCov[2];
+  Gaudi::XYZPoint m_refPt;
+  Gaudi::SymMatrix3x3 m_refPtCov;
+  int m_ref;
+
+  int m_dir;
+  bool m_tracked;
+  bool m_timed;
+  LHCb::Track m_track;
+  // properties
+  Gaudi::Property<std::string> m_cosmics {this, "CosmicsTool", "CaloFutureCosmicsTool"};
+  Gaudi::Property<float> m_chi2max {this, "MaxChi2", 15};
+  Gaudi::Property<float> m_chi2min {this, "MinChi2", 0};
+  Gaudi::Property<float> m_fac {this, "Factor", 1.5};
+  Gaudi::Property<bool> m_tuple {this, "Ntupling", false, "produce ntuple"};
+  Gaudi::Property<std::string> m_timer {this, "Timer", "EcalElseHcal"};
+};
+#endif // CALOFUTURECOSMICSTRACKTOOL_H
diff --git a/CaloFuture/CaloFutureTools/src/CaloFutureElectron.cpp b/CaloFuture/CaloFutureTools/src/CaloFutureElectron.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..44c67e6b53284a15f3e7f151d498e667225ba818
--- /dev/null
+++ b/CaloFuture/CaloFutureTools/src/CaloFutureElectron.cpp
@@ -0,0 +1,128 @@
+// Include files 
+
+// LHCb
+#include "GaudiKernel/Point3DTypes.h"
+#include "GaudiKernel/Vector3DTypes.h"
+#include "Event/Particle.h"
+
+// local
+#include "CaloFutureElectron.h"
+
+//-----------------------------------------------------------------------------
+// Implementation file for class : CaloFutureElectron
+//
+// 2006-11-30 : Olivier Deschamps
+//-----------------------------------------------------------------------------
+
+// Declaration of the Tool Factory
+DECLARE_COMPONENT( CaloFutureElectron )
+
+
+//=============================================================================
+// Standard constructor, initializes variables
+//=============================================================================
+CaloFutureElectron::CaloFutureElectron( const std::string& type,
+                            const std::string& name,
+                            const IInterface* parent )
+: base_class ( type, name , parent )
+{
+  declareInterface<ICaloFutureElectron>(this);
+}
+
+//=============================================================================
+bool CaloFutureElectron::set(const LHCb::Particle* particle, std::string det,CaloPlane::Plane plane , double delta){
+  m_status = setting(particle) && caloSetting();
+  if( m_status )return Part2CaloFuture::match(particle , det, plane, delta );
+  return m_status;
+}
+bool CaloFutureElectron::set(const LHCb::ProtoParticle* proto, std::string det,CaloPlane::Plane plane , double delta){
+  m_status = setting(proto) && caloSetting();
+  if( m_status )return Part2CaloFuture::match(proto , det, plane, delta );
+  return m_status;
+}
+//=============================================================================
+LHCb::CaloHypo* CaloFutureElectron::electron(){
+  return m_electron;
+}
+//=============================================================================
+LHCb::CaloHypo* CaloFutureElectron::bremstrahlung(){
+  return m_bremstrahlung;
+}
+//=============================================================================
+LHCb::CaloMomentum CaloFutureElectron::bremCaloFutureMomentum(){
+  if(!m_status || NULL == m_bremstrahlung )return LHCb::CaloMomentum();
+  Gaudi::XYZPoint point;
+  Gaudi::SymMatrix3x3 matrix;
+  m_track->position(point,matrix);  
+  LHCb::CaloMomentum bremPhoton( m_bremstrahlung ,point, matrix);
+  return bremPhoton;
+}
+
+//=============================================================================
+double CaloFutureElectron::ecalE(){
+  if( !m_status )return 0.;
+  return (double) m_electron->e() ;
+}
+//=============================================================================
+double CaloFutureElectron::eOverP(){
+  if( !m_status )return 0.;
+  return (double) m_electron->e()/m_track->p();
+}
+//=============================================================================
+LHCb::State CaloFutureElectron::closestState(std::string toWhat ){
+  LHCb::State state; // empty state
+  if( !m_status ) return state;
+  // get hypo position
+  double x = 0. ;
+  double y = 0. ;
+  if( "hypo" == toWhat ){
+    x = m_calopos->parameters()(LHCb::CaloPosition::Index::X);
+    y = m_calopos->parameters()(LHCb::CaloPosition::Index::Y);
+  }else if("cluster" == toWhat ){
+    x = m_calopos->center()(LHCb::CaloPosition::Index::X);
+    y = m_calopos->center()(LHCb::CaloPosition::Index::Y);
+  }else{
+    return state;
+  }
+  // default to electron
+  LHCb::Tr::PID pid = ( m_particle ?  LHCb::Tr::PID(m_particle->particleID().abspid()) : LHCb::Tr::PID::Electron() );
+  return Part2CaloFuture::closestState(x,y, pid);
+}
+//=============================================================================
+double CaloFutureElectron::caloTrajectoryZ(CaloPlane::Plane refPlane , std::string toWhat ){
+  LHCb::State theState = closestState( toWhat );
+  LHCb::State refState = caloState( refPlane );
+  return m_zOffset + theState.z() - refState.z();
+}
+//=============================================================================
+double CaloFutureElectron::caloTrajectoryL(CaloPlane::Plane refPlane , std::string toWhat ){
+  LHCb::State theState = closestState( toWhat );
+  LHCb::State refState = caloState( refPlane );
+  Gaudi::XYZVector depth = theState.position()-refState.position();
+  ROOT::Math::Plane3D plane = m_calo->plane( refPlane );
+  double dist = plane.Distance( theState.position() );//signed distance to refPlane
+  return depth.R() * dist/fabs(dist);
+}
+
+//=============================================================================
+bool CaloFutureElectron::caloSetting(){
+  // CaloFuture setting
+  m_electron = NULL;
+  m_bremstrahlung = NULL;
+  m_calopos = NULL;
+
+  SmartRefVector<LHCb::CaloHypo> hypos = m_proto->calo();
+  if(0 == hypos.size())return false;
+
+  for(SmartRefVector<LHCb::CaloHypo>::const_iterator ihypo =  hypos.begin(); ihypo != hypos.end() ; ++ihypo){
+    const LHCb::CaloHypo* hypo =  *ihypo;
+    if(NULL == hypo)continue;
+    if( LHCb::CaloHypo::Hypothesis::EmCharged == hypo->hypothesis() ) m_electron      = (LHCb::CaloHypo*)  hypo;
+    if( LHCb::CaloHypo::Hypothesis::Photon ==   hypo->hypothesis() )  m_bremstrahlung = (LHCb::CaloHypo*) hypo;
+  }
+  if( NULL == m_electron )return false; // Electron hypo is mandatory - brem. not
+  m_calopos = m_electron->position();
+  if( NULL == m_calopos) return false;
+  return true;  
+}
+
diff --git a/CaloFuture/CaloFutureTools/src/CaloFutureElectron.h b/CaloFuture/CaloFutureTools/src/CaloFutureElectron.h
new file mode 100644
index 0000000000000000000000000000000000000000..d65dfef59aeefda6d2fed1b2d1cbbf56a772fd21
--- /dev/null
+++ b/CaloFuture/CaloFutureTools/src/CaloFutureElectron.h
@@ -0,0 +1,61 @@
+#ifndef CALOFUTUREELECTRON_H
+#define CALOFUTUREELECTRON_H 1
+
+// Include files
+#include "Part2CaloFuture.h"
+
+//from LHCb
+#include "CaloFutureUtils/ICaloFutureElectron.h"
+#include "CaloFutureUtils/CaloMomentum.h"
+
+// Forward declarations
+namespace LHCb
+{
+  class ProtoParticle;
+}
+
+
+/** @class CaloFutureElectron CaloFutureElectron.h
+ *
+ *
+ *  @author Olivier Deschamps
+ *  @date   2006-11-30
+ */
+class CaloFutureElectron : public extends<Part2CaloFuture, ICaloFutureElectron> {
+public:
+  /// Standard constructor
+  CaloFutureElectron( const std::string& type,
+              const std::string& name,
+              const IInterface* parent);
+
+  bool  set(const  LHCb::Particle* particle,
+            std::string det = DeCalorimeterLocation::Ecal,
+            CaloPlane::Plane plane = CaloPlane::ShowerMax,
+            double delta =0 ) override;
+  bool  set(const  LHCb::ProtoParticle* proto,
+            std::string det = DeCalorimeterLocation::Ecal,
+            CaloPlane::Plane plane = CaloPlane::ShowerMax,
+            double delta =0 ) override;
+
+  LHCb::CaloHypo*    electron() override;
+  LHCb::CaloHypo*    bremstrahlung() override;
+  LHCb::CaloMomentum bremCaloFutureMomentum() override;
+  double ecalE() override;
+  double eOverP() override;
+  using ICaloFutureElectron::closestState;
+  LHCb::State closestState(std::string toWhat = "hypo") override;
+  double caloTrajectoryZ(CaloPlane::Plane refPlane = CaloPlane::ShowerMax ,std::string toWhat = "hypo") override;
+  double caloTrajectoryL(CaloPlane::Plane refPlane = CaloPlane::ShowerMax ,std::string toWhat = "hypo") override;
+
+
+
+protected:
+  bool caloSetting ();
+private:
+  LHCb::CaloHypo*            m_electron = nullptr;
+  LHCb::CaloHypo*            m_bremstrahlung = nullptr;
+  const LHCb::CaloPosition*  m_calopos = nullptr;
+  Gaudi::Property<float> m_zOffset
+    {this, "zOffset", 0, "Should be 0.0 if ShowerMax plane is correctly defined in condDB"};
+};
+#endif // CALOFUTUREELECTRON_H
diff --git a/CaloFuture/CaloFutureTools/src/CaloFutureGetterTool.cpp b/CaloFuture/CaloFutureTools/src/CaloFutureGetterTool.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..813e522722c1e2be4f3c8f9fe8eb8fdfff9ff0c0
--- /dev/null
+++ b/CaloFuture/CaloFutureTools/src/CaloFutureGetterTool.cpp
@@ -0,0 +1,246 @@
+// ============================================================================
+// Include files
+// ============================================================================
+// from Gaudi
+// ============================================================================
+#include "GaudiKernel/IIncidentSvc.h"
+#include "GaudiKernel/Incident.h"
+#include "CaloFutureUtils/CaloFutureAlgUtils.h"
+// ============================================================================
+// local
+// ============================================================================
+#include "CaloFutureGetterTool.h"
+// ============================================================================
+/** @file
+ *  Implementation file for class : CaloFutureGetterTool
+ *
+ *  @date 2009-04-17
+ *  @author Olivier Deschamps
+ */
+// ============================================================================
+// Declaration of the Tool Factory
+DECLARE_COMPONENT( CaloFutureGetterTool )
+// ============================================================================
+// Standard constructor, initializes variables
+// ============================================================================
+CaloFutureGetterTool::CaloFutureGetterTool ( const std::string& type, const std::string& name,
+                                 const IInterface* parent )
+: base_class ( type, name , parent )
+{
+  declareInterface<ICaloFutureGetterTool>(this);
+
+  std::string flag = context();
+  if( std::string::npos != name.find ("HLT") ||
+      std::string::npos != name.find ("Hlt") )flag="Hlt";
+
+  // digits
+  if((m_detMask&8)!=0)m_digiLoc.value().push_back( LHCb::CaloFutureAlgUtils::CaloFutureDigitLocation( "Hcal" , flag ) ) ;
+  if((m_detMask&4)!=0)m_digiLoc.value().push_back( LHCb::CaloFutureAlgUtils::CaloFutureDigitLocation( "Ecal" , flag ) ) ;
+  if((m_detMask&2)!=0)m_digiLoc.value().push_back( LHCb::CaloFutureAlgUtils::CaloFutureDigitLocation( "Prs"  , flag ) ) ;
+  if((m_detMask&1)!=0)m_digiLoc.value().push_back( LHCb::CaloFutureAlgUtils::CaloFutureDigitLocation( "Spd"  , flag ) ) ;
+
+  if((m_detMask&8)!=0)m_clusLoc.value().push_back( LHCb::CaloFutureAlgUtils::CaloFutureClusterLocation( "Hcal" , flag ) ) ;
+  if((m_detMask&4)!=0)m_clusLoc.value().push_back( LHCb::CaloFutureAlgUtils::CaloFutureClusterLocation( "Ecal" , flag ) ) ;
+  m_clusLoc.value().push_back( LHCb::CaloFutureAlgUtils::CaloFutureSplitClusterLocation( flag ) ) ;
+
+  m_hypoLoc.value().push_back( LHCb::CaloFutureAlgUtils::CaloFutureHypoLocation("Photons"      , flag ) );
+  m_hypoLoc.value().push_back( LHCb::CaloFutureAlgUtils::CaloFutureHypoLocation("Electrons"    , flag ) );
+  m_hypoLoc.value().push_back( LHCb::CaloFutureAlgUtils::CaloFutureHypoLocation("SplitPhotons" , flag ) );
+  m_hypoLoc.value().push_back( LHCb::CaloFutureAlgUtils::CaloFutureHypoLocation("MergedPi0s"   , flag ) );
+}
+
+// ============================================================================
+
+StatusCode CaloFutureGetterTool::initialize()
+{
+  StatusCode sc = base_class::initialize();
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) )debug() << "Initialize CaloFuture2CaloFuture tool " << endmsg;
+
+  counterStat = tool<IFutureCounterLevel>("FutureCounterLevel");
+
+  if( m_detMask != 0xF) info() << "Incomplete calorimeter detector is requested - mask = " << m_detMask.value() << endmsg;
+  //
+  if((m_detMask&8)!=0)m_provider["Hcal"] = tool<ICaloFutureDataProvider>( "CaloFutureDataProvider" , "FutureHcalDataProvider" );
+  if((m_detMask&4)!=0)m_provider["Ecal"] = tool<ICaloFutureDataProvider>( "CaloFutureDataProvider" , "FutureEcalDataProvider" );
+  if((m_detMask&2)!=0)m_provider["Prs"]  = tool<ICaloFutureDataProvider>( "CaloFutureDataProvider" , "FuturePrsDataProvider"  );
+  if((m_detMask&1)!=0)m_provider["Spd"]  = tool<ICaloFutureDataProvider>( "CaloFutureDataProvider" , "FutureSpdDataProvider"  );
+  //
+  // subscribe to the incidents
+  IIncidentSvc* inc = incSvc() ;
+  if ( 0 != inc )
+  {
+    inc -> addListener  ( this , IncidentType::BeginEvent ) ;
+    inc -> addListener  ( this , IncidentType::EndEvent   ) ;
+  }
+  // prepare the known locations:
+  //
+  // digits
+  if ( m_digiUpd ){
+    m_digits.clear() ;
+    for ( std::vector<std::string>::iterator iloc = m_digiLoc.begin() ;m_digiLoc.end() != iloc; ++iloc ){
+      m_digits[ *iloc ] = 0 ;
+    }
+  }
+  // clusters
+  if ( m_clusUpd ){
+    m_clusters.clear() ;
+    for ( std::vector<std::string>::iterator iloc = m_clusLoc.begin() ;m_clusLoc.end() != iloc; ++iloc){
+      m_clusters[ *iloc ] = 0 ;
+    }
+  }
+  // hypos
+  if ( m_hypoUpd ){
+    m_hypos.clear() ;
+    for ( std::vector<std::string>::iterator iloc = m_hypoLoc.begin() ;m_hypoLoc.end() != iloc; ++iloc){
+      m_hypos[ *iloc ] = 0 ;
+    }
+  }
+  //
+  return StatusCode::SUCCESS;
+}
+// ============================================================================
+StatusCode CaloFutureGetterTool::finalize()
+{
+  // un-subscribe to the incidents
+  IIncidentSvc* inc = incSvc() ;
+  if ( 0 != inc ) { inc -> removeListener  ( this ) ; }
+  // clear data
+  nullify () ;
+  m_provider . clear () ;
+  // finalize the base
+  return base_class::finalize () ;
+}
+// ============================================================================
+namespace
+{
+  // =========================================================================
+  template <class TYPE>
+  void __nullify ( std::map<std::string,TYPE*>& _map )
+  {
+    for ( typename std::map<std::string,TYPE*>::iterator ientry = _map.begin() ;
+          _map.end() != ientry ; ++ientry ) { ientry->second = 0 ; }
+  }
+  // ==========================================================================
+}
+// ============================================================================
+void CaloFutureGetterTool::nullify()
+{
+  __nullify ( m_digits   ) ;
+  __nullify ( m_clusters ) ;
+  __nullify ( m_hypos    ) ;
+}
+// ============================================================================
+// getters
+// ============================================================================
+LHCb::CaloDigits* CaloFutureGetterTool::digits ( const std::string& loc )
+{
+  std::map<std::string,LHCb::CaloDigits*>::iterator it = m_digits.find( loc );
+  //
+  if ( m_digits.end () == it ){
+    Error ( "Illegal Attempt to retrive digits   from '" + loc + "'" ).ignore() ;
+    return 0 ;
+  }
+  //
+  if ( 0 != it->second ) { return it -> second ; }
+  //
+  it -> second = getIfExists<LHCb::CaloDigits>( loc );
+  if ( NULL != it->second ){
+    if(counterStat->isQuiet())counter ("#Digits   @ " + loc ) += it->second->size() ;
+    return it->second ;
+  }
+  //
+  Error ("No Digits   at " + loc ).ignore() ;
+  return 0 ;
+}
+// ============================================================================
+LHCb::CaloClusters* CaloFutureGetterTool::clusters ( const std::string& loc )
+{
+  std::map<std::string,LHCb::CaloClusters*>::iterator it = m_clusters.find( loc );
+  //
+  if ( m_clusters.end () == it )
+  {
+    Error ( "Illegal attempt to retrive clusters from '" + loc + "'" ).ignore() ;
+    return 0 ;
+  }
+  //
+  if ( 0 != it->second ) { return it->second ; }
+  //
+  it -> second = getIfExists<LHCb::CaloClusters>( loc );
+  if ( NULL != it->second )
+  {
+    if(counterStat->isQuiet())counter ("#Clusters @ " + loc  ) += it->second->size() ;
+    return it->second ;
+  }
+  //
+  Error ("No Clusters at " + loc ).ignore() ;
+  return 0 ;
+}
+// ============================================================================
+LHCb::CaloHypos*    CaloFutureGetterTool::hypos    ( const std::string& loc )
+{
+  std::map<std::string,LHCb::CaloHypos*>::iterator it = m_hypos.find( loc );
+  //
+  if ( m_hypos.end () == it )
+  {
+    Error ( "Illegal attempt to retrive hypos    from '" + loc + "'" ).ignore() ;
+    return 0 ;
+  }
+  //
+  if ( 0 != it->second ) { return it->second ; }
+  //
+  it -> second = getIfExists<LHCb::CaloHypos>( loc );
+  if ( NULL != it->second )
+  {
+    if(counterStat->isQuiet())counter ("#Hypos    @ " + loc  ) += it->second->size() ;
+    return it->second ;
+  }
+  //
+  Error ("No Hypos    at " + loc ).ignore() ;
+  return 0 ;
+}
+// ============================================================================
+void CaloFutureGetterTool::update()
+{
+  // digits
+  if ( m_digiUpd )
+  {
+    for(std::vector<std::string>::iterator iloc = m_digiLoc.begin();m_digiLoc.end() != iloc; ++iloc){
+      if ( exist<LHCb::CaloDigits>(*iloc) && 0 == m_digits[*iloc] ){
+        LHCb::CaloDigits* digits = get<LHCb::CaloDigits>( *iloc );
+        m_digits[ *iloc ] =  digits ;
+        if(counterStat->isQuiet())counter ("#Digits   @ " + (*iloc) ) += digits->size() ;
+      }
+    }
+  }
+  // clusters
+  if( m_clusUpd ) {
+    for(const auto& iloc : m_clusLoc) {
+      LHCb::CaloClusters* clusters = getIfExists<LHCb::CaloClusters>( iloc );
+      if ( clusters ) {
+        m_clusters[ iloc ] = clusters ;
+        if(counterStat->isQuiet())counter ("#Clusters @ " + iloc ) += clusters->size() ;
+      }
+    }
+  }
+  // hypos
+  if( m_hypoUpd ) {
+    for(const auto& iloc : m_hypoLoc) {
+      LHCb::CaloHypos* hypos = getIfExists<LHCb::CaloHypos>( iloc );
+      if ( hypos ) {
+        m_hypos[ iloc ] = hypos ;
+        if(counterStat->isQuiet())counter ("#Hypos    @ " + iloc ) += hypos->size() ;
+      }
+    }
+  }
+  // provider
+  //  if( m_provUpd)
+  // {
+  //  for(std::map<std::string,ICaloFutureDataProvider*>::iterator ip = m_provider.begin();m_provider.end()!=ip;++ip)
+  //  {
+  //    const std::string& det = ip->first;
+  //    ICaloFutureDataProvider* provider = ip->second;
+  //    m_prov[det] = provider->getBanks();
+  //  }
+  //  }
+
+}
diff --git a/CaloFuture/CaloFutureTools/src/CaloFutureGetterTool.h b/CaloFuture/CaloFutureTools/src/CaloFutureGetterTool.h
new file mode 100644
index 0000000000000000000000000000000000000000..d2cc900c1cfce2bf494c653732bdb75c7405cfc0
--- /dev/null
+++ b/CaloFuture/CaloFutureTools/src/CaloFutureGetterTool.h
@@ -0,0 +1,153 @@
+// ============================================================================
+#ifndef CALOFUTUREGETTERTOOL_H
+#define CALOFUTUREGETTERTOOL_H 1
+// ============================================================================
+// Include files
+// ============================================================================
+// STD & STL
+// ============================================================================
+#include <algorithm>
+// ============================================================================
+// GaudiKernel
+// ============================================================================
+#include "GaudiKernel/IIncidentListener.h"
+// ============================================================================
+// GaudiAlg
+// ============================================================================
+#include "GaudiAlg/GaudiTool.h"
+// ============================================================================
+// Event
+// ============================================================================
+#include "Event/CaloDigit.h"
+#include "Event/CaloCluster.h"
+#include "Event/CaloHypo.h"
+// ============================================================================
+// Calo
+// ============================================================================
+#include "CaloFutureDAQ/ICaloFutureDataProvider.h"
+#include "CaloFutureInterfaces/ICaloFutureGetterTool.h"            // Interface
+#include "CaloFutureInterfaces/IFutureCounterLevel.h"
+// ============================================================================
+/** @class CaloFutureGetterTool CaloFutureGetterTool.h
+ *
+ *
+ *  @author Olivier Deschamps
+ *  @date   2009-04-17
+ */
+class CaloFutureGetterTool : public extends<GaudiTool , ICaloFutureGetterTool , IIncidentListener >
+{
+public:
+  /// Standard constructor
+  CaloFutureGetterTool( const std::string& type,
+                  const std::string& name,
+                  const IInterface* parent);
+
+  // ==========================================================================
+  StatusCode initialize() override;
+  StatusCode finalize() override;
+  // ==========================================================================
+
+  // update
+  void update() override;
+  int detectorsMask() override {return m_detMask;}
+
+
+
+  // setters
+  void addToDigits ( const std::string&loc,bool clear ) override
+  {
+    if ( clear )
+    {
+      m_digiLoc.clear () ;
+      m_digits.clear  () ;
+    }
+    //
+    if ( m_digiLoc.end() == std::find ( m_digiLoc.begin() ,
+                                        m_digiLoc.end  () , loc ) )
+    { m_digiLoc.value().push_back( loc ) ; }
+    //
+    if ( m_digits.end() == m_digits.find( loc ) )
+    { m_digits[loc] = 0 ; }
+    //
+  }
+  void addToClusters(const std::string& loc,bool clear ) override
+  {
+    if ( clear )
+    {
+      m_clusLoc.clear  () ;
+      m_clusters.clear () ;
+    }
+    //
+    if ( m_clusLoc.end() == std::find ( m_clusLoc.begin () ,
+                                        m_clusLoc.end   () ,  loc ) )
+    { m_clusLoc.value().push_back( loc ) ; }
+    //
+    if ( m_clusters.end() == m_clusters.find( loc ) )
+    { m_clusters[loc] = 0 ; }
+    //
+  }
+  void addToHypos  (const std::string& loc,bool clear ) override
+  {
+    if ( clear )
+    {
+      m_hypoLoc.clear () ;
+      m_hypos.clear   () ;
+    }
+    //
+    if ( m_hypoLoc.end() == std::find ( m_hypoLoc.begin () ,
+                                        m_hypoLoc.end   () , loc ) )
+    { m_hypoLoc.value().push_back( loc ) ; }
+    //
+    if ( m_hypos.end() == m_hypos.find( loc ) )
+    { m_hypos[loc] = 0 ; }
+    //
+  }
+
+  //getters
+  LHCb::CaloDigits*   digits   ( const std::string& loc ) override;
+  LHCb::CaloClusters* clusters ( const std::string& loc ) override;
+  LHCb::CaloHypos*    hypos    ( const std::string& loc ) override;
+
+  bool hasData(const std::string& det) override
+  {
+    std::map<std::string,bool>::iterator it = m_prov.find(det);
+    return (it == m_prov.end()) ? false : (*it).second;
+  }
+  ICaloFutureDataProvider* provider( const std::string& det) override
+  {
+    std::map<std::string,ICaloFutureDataProvider*>::iterator it = m_provider.find(det);
+    return (it == m_provider.end()) ? NULL : (*it).second;
+  }
+
+public:
+  // =========================================================================
+  /// Inform that a new incident has occurred
+  void handle(const Incident& /* inc */ ) override { nullify() ; }
+  // =========================================================================
+protected:
+  // =========================================================================
+  /// nullify the pointers
+  void nullify() ;
+  // =========================================================================
+private:
+  IFutureCounterLevel* counterStat = nullptr;
+  // =========================================================================
+  std::map<std::string,LHCb::CaloDigits*>   m_digits;
+  std::map<std::string,LHCb::CaloClusters*> m_clusters;
+  std::map<std::string,LHCb::CaloHypos*>    m_hypos;
+  std::map<std::string,ICaloFutureDataProvider*>  m_provider;
+  std::map<std::string,bool> m_prov;
+  Gaudi::Property<bool> m_digiUpd {this, "GetDigits", true};
+  Gaudi::Property<bool> m_clusUpd {this, "GetClusters", false};
+  Gaudi::Property<bool> m_hypoUpd {this, "GetHypos", false};
+  //  bool m_provUpd;
+  Gaudi::Property<std::vector<std::string>> m_digiLoc {this, "DigitLocations"};
+  Gaudi::Property<std::vector<std::string>> m_clusLoc {this, "ClusterLocations"};
+  Gaudi::Property<std::vector<std::string>> m_hypoLoc {this, "HypoLocations"};
+  Gaudi::Property<int> m_detMask {this, "DetectorMask", 0xF};
+};
+// ============================================================================
+// The END
+// ============================================================================
+#endif // CALOFUTUREGETTERTOOL_H
+// ============================================================================
diff --git a/CaloFuture/CaloFutureTools/src/CaloFutureHypo2CaloFuture.cpp b/CaloFuture/CaloFutureTools/src/CaloFutureHypo2CaloFuture.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..fc305456944e67bd49408d52b4c51807b73db463
--- /dev/null
+++ b/CaloFuture/CaloFutureTools/src/CaloFutureHypo2CaloFuture.cpp
@@ -0,0 +1,192 @@
+// Include files 
+
+// from Gaudi
+#include "GaudiKernel/SystemOfUnits.h"
+// from LHCb
+#include "GaudiKernel/Vector3DTypes.h"
+#include "GaudiKernel/Plane3DTypes.h"
+#include "LHCbMath/LineTypes.h"
+#include "LHCbMath/GeomFun.h"
+#include "CaloFutureUtils/CaloFutureAlgUtils.h"
+// local
+#include "CaloFutureHypo2CaloFuture.h"
+
+
+//-----------------------------------------------------------------------------
+// Implementation file for class : CaloFutureHypo2CaloFuture
+//
+// 2008-09-11 : Olivier Deschamps
+//-----------------------------------------------------------------------------
+
+// Declaration of the Tool Factory
+DECLARE_COMPONENT( CaloFutureHypo2CaloFuture )
+
+
+//=============================================================================
+// Standard constructor, initializes variables
+//=============================================================================
+CaloFutureHypo2CaloFuture::CaloFutureHypo2CaloFuture( const std::string& type,
+                            const std::string& name,
+                            const IInterface* parent )
+  : CaloFuture2CaloFuture ( type, name , parent )
+{
+  declareInterface<ICaloFutureHypo2CaloFuture>(this);
+}
+
+//=============================================================================
+StatusCode CaloFutureHypo2CaloFuture::initialize(){
+  StatusCode sc = CaloFuture2CaloFuture::initialize();
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+    debug() << "Initialize CaloFutureHypo2CaloFuture tool " << endmsg;
+  m_lineID = LHCb::CaloCellID(); // initialize
+  m_point  = Gaudi::XYZPoint();
+  return sc;
+}
+
+
+//=============================================================================
+const std::vector<LHCb::CaloCellID>& CaloFutureHypo2CaloFuture::cellIDs(const LHCb::CaloHypo &fromHypo, const std::string &toCaloFuture){
+
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+    debug() << "Matching CaloHypo to " << toCaloFuture << " hypo energy = " << fromHypo.e() << endmsg;
+
+  // get the cluster 
+  const LHCb::CaloCluster* cluster = LHCb::CaloFutureAlgUtils::ClusterFromHypo( &fromHypo );
+
+  if(cluster == 0){
+    Error("No valid cluster!").ignore() ;
+    return m_cells;
+  }
+
+  LHCb::CaloCellID seedID = cluster->seed();
+  std::string fromCaloFuture = CaloCellCode::CaloNameFromNum( seedID.calo() );
+  if( toCaloFuture != m_toCaloFuture || fromCaloFuture != m_fromCaloFuture)setCalos(fromCaloFuture,toCaloFuture);
+  if( !m_ok )return m_cells;
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+    debug() << "Cluster seed " << seedID << " " << m_fromDet->cellCenter( seedID ) << endmsg;
+
+  if(m_whole){
+    return CaloFuture2CaloFuture::cellIDs( *cluster, toCaloFuture);
+  }
+
+  m_point  = Gaudi::XYZPoint();
+  m_lineID = LHCb::CaloCellID();
+  if(m_line && fromHypo.position() != NULL){
+    const Gaudi::XYZPoint  ref( fromHypo.position()->x(), fromHypo.position()->y(),fromHypo.position()->z() );
+    const Gaudi::XYZVector vec = (ref-Gaudi::XYZPoint(0,0,0));
+    const Gaudi::Plane3D   plane = m_toPlane;
+    Gaudi::Math::XYZLine   line(ref, vec);
+    double mu;
+    Gaudi::Math::intersection<Gaudi::Math::XYZLine,Gaudi::Plane3D>(line,plane,m_point,mu);
+    m_lineID = m_toDet->Cell( m_point );
+    if( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+      debug() << "Matching cell " << m_lineID << endmsg;
+  }
+  return cellIDs( *cluster, toCaloFuture);
+}
+
+
+
+const std::vector<LHCb::CaloCellID>& CaloFutureHypo2CaloFuture::cellIDs(const LHCb::CaloCluster &fromCluster, const std::string &toCaloFuture){
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+    debug() << " toCaloFuture " << toCaloFuture << endmsg;
+  reset();
+  LHCb::CaloCellID seedID = fromCluster.seed();
+  std::string fromCaloFuture = CaloCellCode::CaloNameFromNum( seedID.calo() );
+  if( toCaloFuture != m_toCaloFuture || fromCaloFuture != m_fromCaloFuture)setCalos(fromCaloFuture,toCaloFuture);
+  if( !m_ok)return m_cells;
+  
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+    debug() << "-----  cluster energy " <<  fromCluster.e()<< " " << seedID << endmsg;
+  m_neighbour.setDet ( m_fromDet );
+
+  // get data
+  m_digs     = m_getter->digits( m_toLoc );  
+
+  //matching cluster  
+  const LHCb::CaloCluster::Entries& entries = fromCluster.entries();
+  for(LHCb::CaloCluster::Entries::const_iterator ent = entries.begin(); ent != entries.end(); ++ent){
+    LHCb::CaloClusterEntry entry = *ent;
+    LHCb::CaloCellID cellID = entry.digit()->cellID();
+    if( !(m_seed      &&  (LHCb::CaloDigitStatus::SeedCell & entry.status())    != 0 ) &&
+        !(m_seed && m_neighb &&   m_neighbour(seedID , cellID)  != 0.                ) &&
+        !( (m_status & entry.status()) != 0                                          ) &&
+        !(m_whole) )continue;
+    SmartRef<LHCb::CaloDigit> digit = (*ent).digit();
+    CaloFuture2CaloFuture::cellIDs( digit->cellID() , toCaloFuture, false );
+    if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+      debug() << toCaloFuture << ":  digit is selected in front of the cluster : " 
+              << cellID << "/" << seedID << " " << m_digits.size() << endmsg;
+  }
+  // photon line
+  if(m_line ){
+    if( m_lineID == LHCb::CaloCellID() ){
+      const Gaudi::XYZPoint  ref( fromCluster.position().x(), fromCluster.position().y(),fromCluster.position().z() );
+      const Gaudi::XYZVector vec = (ref-Gaudi::XYZPoint(0,0,0));
+      const Gaudi::Plane3D   plane = m_toPlane;
+      Gaudi::Math::XYZLine   line(ref, vec);
+      double mu;
+      Gaudi::Math::intersection<Gaudi::Math::XYZLine,Gaudi::Plane3D>(line,plane,m_point,mu);
+      m_lineID = m_toDet->Cell( m_point );
+    }
+    if( !(m_lineID == LHCb::CaloCellID()) ){
+      addCell( m_lineID , toCaloFuture );
+      if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+        debug() << toCaloFuture << " : digit is selected in the photon line : " 
+                << m_lineID << "/" << seedID << " " << m_digits.size() << endmsg;
+      if(m_neighb){
+        const std::vector<LHCb::CaloCellID>&  neighbors = m_toDet->neighborCells( m_lineID );
+        for( std::vector<LHCb::CaloCellID>::const_iterator n = neighbors.begin();n!=neighbors.end();n++){
+          double halfCell = m_toDet->cellSize( *n )*0.5;
+          const Gaudi::XYZPoint cellCenter = m_toDet -> cellCenter ( *n ) ;
+          if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+            debug() << *n 
+                    << " Point : (" << m_point.X() << "," << m_point.Y() 
+                    << " Cell :  ( " << cellCenter.X()<< "," << cellCenter.Y()
+                    << " size/2  : " << halfCell << " Tolerance : " << m_x << "/" << m_y << endmsg;
+          if( fabs(m_point.X() - cellCenter.X()) < (halfCell+m_x) &&
+              fabs(m_point.Y() - cellCenter.Y()) < (halfCell+m_y) ){
+            addCell( *n , toCaloFuture );
+            if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+              debug() << toCaloFuture << " : digit is selected in the photon line neighborhood : " 
+                      << *n << "/" << seedID  << " " << m_digits.size() << endmsg;
+          } 
+        }
+      }
+    }
+  }
+
+  m_lineID = LHCb::CaloCellID();//reset
+  return m_cells;
+}
+
+
+
+const std::vector<LHCb::CaloDigit*>& CaloFutureHypo2CaloFuture::digits(const LHCb::CaloHypo &fromHypo, const std::string &toCaloFuture){  
+  cellIDs( fromHypo, toCaloFuture);
+  return m_digits;
+}  
+
+double CaloFutureHypo2CaloFuture::energy(const LHCb::CaloHypo &fromHypo, const std::string &toCaloFuture){
+  cellIDs(fromHypo, toCaloFuture);
+  return m_energy;
+}
+const std::vector<LHCb::CaloDigit*>& CaloFutureHypo2CaloFuture::digits(const LHCb::CaloCluster &fromCluster, const std::string &toCaloFuture){  
+  cellIDs( fromCluster, toCaloFuture);
+  return m_digits;
+}  
+
+double CaloFutureHypo2CaloFuture::energy(const LHCb::CaloCluster &fromCluster, const std::string &toCaloFuture){
+  cellIDs(fromCluster, toCaloFuture);
+  return m_energy;
+}
+
+int CaloFutureHypo2CaloFuture::multiplicity(const LHCb::CaloCluster &fromCluster, const std::string &toCaloFuture){
+  cellIDs(fromCluster, toCaloFuture);
+  return m_count;
+}
+int CaloFutureHypo2CaloFuture::multiplicity(const LHCb::CaloHypo &fromHypo, const std::string &toCaloFuture){
+  cellIDs(fromHypo, toCaloFuture);
+  return m_count;
+}
+
diff --git a/CaloFuture/CaloFutureTools/src/CaloFutureHypo2CaloFuture.h b/CaloFuture/CaloFutureTools/src/CaloFutureHypo2CaloFuture.h
new file mode 100644
index 0000000000000000000000000000000000000000..2ca57130df7ed1855b8a0a8a1cc26284d428b45d
--- /dev/null
+++ b/CaloFuture/CaloFutureTools/src/CaloFutureHypo2CaloFuture.h
@@ -0,0 +1,70 @@
+// $Id: CaloFutureHypo2CaloFuture.h,v 1.4 2010-03-08 01:58:39 odescham Exp $
+#ifndef CALOFUTUREHYPO2CALOFUTURE_H
+#define CALOFUTUREHYPO2CALOFUTURE_H 1
+
+// Include files
+// from Gaudi
+#include "GaudiAlg/GaudiTool.h"
+#include "CaloFutureInterfaces/ICaloFutureHypo2CaloFuture.h"            // Interface
+#include "CaloFuture2CaloFuture.h"
+#include "CaloFutureUtils/CellNeighbour.h"
+
+#ifdef __INTEL_COMPILER        // Disable ICC remark from ROOT
+  #pragma warning(disable:654) // overloaded virtual function is only partially overridden
+#endif
+
+/** @class CaloFutureHypo2CaloFuture CaloFutureHypo2CaloFuture.h
+ *
+ *
+ *  @author Olivier Deschamps
+ *  @date   2008-09-11
+ */
+class CaloFutureHypo2CaloFuture : public CaloFuture2CaloFuture, virtual public ICaloFutureHypo2CaloFuture {
+public:
+  /// Standard constructor
+  CaloFutureHypo2CaloFuture( const std::string& type,
+                 const std::string& name,
+                 const IInterface* parent);
+
+  StatusCode initialize() override;
+  // cellIDs
+  using CaloFuture2CaloFuture::cellIDs;
+  const std::vector<LHCb::CaloCellID>& cellIDs(const LHCb::CaloHypo    &fromHypo,    const std::string &toCaloFuture) override;
+  const std::vector<LHCb::CaloCellID>& cellIDs(const LHCb::CaloCluster &fromCluster, const std::string &toCaloFuture) override;
+  const std::vector<LHCb::CaloCellID>& cellIDs() override {return m_cells;};
+  // digits
+  using CaloFuture2CaloFuture::digits;
+  const std::vector<LHCb::CaloDigit*>& digits(const LHCb::CaloCluster &fromCluster, const std::string &toCaloFuture) override;
+  const std::vector<LHCb::CaloDigit*>& digits(const LHCb::CaloHypo    &fromHypo,    const std::string &toCaloFuture) override;
+  const std::vector<LHCb::CaloDigit*>& digits() override {return m_digits;};
+  // energy
+  using CaloFuture2CaloFuture::energy;
+  double energy(const LHCb::CaloCluster &fromCluster, const std::string &toCaloFuture) override;
+  double energy(const LHCb::CaloHypo    &fromHypo,    const std::string &toCaloFuture) override;
+  double energy() override {return m_energy;};
+  // multiplicity
+  using CaloFuture2CaloFuture::multiplicity;
+  int multiplicity(const LHCb::CaloCluster &fromCluster, const std::string &toCaloFuture) override;
+  int multiplicity(const LHCb::CaloHypo    &fromHypo,    const std::string &toCaloFuture) override;
+  int multiplicity() override {return m_count;};
+  void setCalos(const std::string &from, const std::string &to) override {CaloFuture2CaloFuture::setCalos(from,to); };
+
+  // external setting
+  StatusCode  _setProperty(const std::string& p,const std::string& v) override {return  setProperty(p,v);};
+
+
+protected:
+
+private:
+  Gaudi::Property<bool> m_seed {this, "Seed", true};
+  Gaudi::Property<bool> m_neighb {this, "AddNeighbors", true};
+  Gaudi::Property<bool> m_line {this, "PhotonLine", true};
+  Gaudi::Property<bool> m_whole {this, "WholeCluster", false};
+  Gaudi::Property<int> m_status {this, "StatusMask", 0x0};
+  Gaudi::Property<float> m_x {this, "xTolerance", 5.*Gaudi::Units::mm};
+  Gaudi::Property<float> m_y {this, "yTolerance", 5.*Gaudi::Units::mm};
+  CellNeighbour m_neighbour;
+  LHCb::CaloCellID m_lineID ;
+  Gaudi::XYZPoint  m_point;
+};
+#endif // CALOFUTUREHYPO2CALOFUTURE_H
diff --git a/CaloFuture/CaloFutureTools/src/CaloFutureHypoEstimator.cpp b/CaloFuture/CaloFutureTools/src/CaloFutureHypoEstimator.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7d51285ccf02b1322714d8e6bcc9f88e13703b75
--- /dev/null
+++ b/CaloFuture/CaloFutureTools/src/CaloFutureHypoEstimator.cpp
@@ -0,0 +1,485 @@
+// Include files 
+
+// local
+#include "CaloFutureHypoEstimator.h"
+#include "Event/ProtoParticle.h"
+#include "GaudiKernel/IRegistry.h"
+#include "Event/Track.h"
+
+//-----------------------------------------------------------------------------
+// Implementation file for class : CaloFutureHypoEstimator
+//
+// 2010-08-18 : Olivier Deschamps
+//-----------------------------------------------------------------------------
+
+// Declaration of the Tool Factory
+DECLARE_COMPONENT( CaloFutureHypoEstimator )
+
+
+//=============================================================================
+// Standard constructor, initializes variables
+//=============================================================================
+CaloFutureHypoEstimator::CaloFutureHypoEstimator( const std::string& type,
+                                      const std::string& name,
+                                      const IInterface* parent )
+  : GaudiTool ( type, name , parent )
+{
+  declareInterface<ICaloFutureHypoEstimator>(this);
+
+  m_cmLoc= LHCb::CaloFutureAlgUtils::CaloFutureIdLocation("ClusterMatch", context());
+  m_emLoc= LHCb::CaloFutureAlgUtils::CaloFutureIdLocation("ElectronMatch", context());
+  m_bmLoc= LHCb::CaloFutureAlgUtils::CaloFutureIdLocation("BremMatch", context());
+  using namespace LHCb::CaloFutureIdLocation;
+  m_pidLoc["Photon"]    = LHCb::CaloFutureAlgUtils::PathFromContext( context() , PhotonID );
+  m_pidLoc["Pi0Merged"]  = LHCb::CaloFutureAlgUtils::PathFromContext( context() , MergedID );
+  m_pidLoc["PhotonFromMergedPi0"]  = LHCb::CaloFutureAlgUtils::PathFromContext( context() , PhotonFromMergedID );
+}
+
+StatusCode CaloFutureHypoEstimator::finalize(){
+  IIncidentSvc* inc = incSvc() ;
+  if ( 0 != inc ) { inc -> removeListener  ( this ) ; }
+  return GaudiTool::finalize();
+}
+
+StatusCode CaloFutureHypoEstimator::initialize() {
+  StatusCode sc = GaudiTool::initialize(); // must be executed first
+  IIncidentSvc* inc = incSvc() ;
+  if ( 0 != inc )inc -> addListener  ( this , IncidentType::BeginEvent ) ;
+  counterStat = tool<IFutureCounterLevel>("FutureCounterLevel");
+  m_toCaloFuture = tool<ICaloFutureHypo2CaloFuture> ("CaloFutureHypo2CaloFuture", "CaloFutureHypo2CaloFuture", this); 
+  m_tables = tool<ICaloFutureRelationsGetter>("CaloFutureRelationsGetter","CaloFutureRelationsGetter",this);
+  std::string seed = m_seed ? "true" : "false";
+  std::string line = m_extrapol ? "true" : "false";
+  std::string neig = m_neig ? "true" : "false";
+  hypo2CaloFuture()->_setProperty("Seed", seed).ignore();
+  hypo2CaloFuture()->_setProperty("PhotonLine", line).ignore();
+  hypo2CaloFuture()->_setProperty("AddNeighbors", neig).ignore();
+
+  m_electron = tool<ICaloFutureElectron>("CaloFutureElectron","CaloFutureElectron",this);
+  m_GammaPi0  = tool<IFutureGammaPi0SeparationTool>("FutureGammaPi0SeparationTool" , "FutureGammaPi0SeparationTool", this);
+  m_GammaPi0XGB = tool<IFutureGammaPi0SeparationTool>("FutureGammaPi0XGBoostTool" , "FutureGammaPi0XGBoostTool");
+  m_neutralID = tool<IFutureNeutralIDTool>("FutureNeutralIDTool" , "FutureNeutralIDTool", this);
+
+  m_ecal = getDet<DeCalorimeter>( DeCalorimeterLocation::Ecal );
+
+  clean();
+  m_status = true;
+  return sc;
+}
+
+//=============================================================================
+
+
+// ------------
+double CaloFutureHypoEstimator::data(const LHCb::CaloCluster* cluster,CaloFutureDataType::DataType type, double def ){  
+  double val = def;
+  if ( cluster != m_cluster || NULL == cluster){
+    clean();
+    m_status = estimator(cluster);
+    if( !m_status ){
+      if(counterStat->isQuiet())counter("Cluster estimation failed") += 1;
+      clean();
+    }
+  }
+  caloDataType::iterator it = m_data.find( type );
+  if( it != m_data.end() )val = m_data[type];  
+  if( val == CaloFutureDataType::Default)return def;
+  return val;
+  
+}
+
+// ------------
+double CaloFutureHypoEstimator::data(const LHCb::CaloHypo* hypo,CaloFutureDataType::DataType type, double def){
+  double val = def;
+  if ( hypo != m_hypo || NULL == hypo ){
+    clean();
+    m_status = estimator(hypo);
+    if( !m_status){
+      if(counterStat->isQuiet())counter("Hypo estimation failed") += 1;
+      clean();
+    }
+  }
+  caloDataType::iterator it = m_data.find( type );
+  if( it != m_data.end() )val = m_data[type];  
+  if( val == CaloFutureDataType::Default)return def;
+  return val;  
+}
+
+
+// ------------ FROM HYPO
+bool CaloFutureHypoEstimator::estimator(const LHCb::CaloHypo* hypo){
+  using namespace CaloFutureDataType;
+  if( NULL == hypo)return false;
+  m_hypo = (LHCb::CaloHypo*) hypo;
+
+  LHCb::CaloMomentum mom(hypo);
+  m_data[HypoE] = mom.e();
+  m_data[HypoEt] = mom.pt();
+  m_data[HypoM] = mom.mass(); // for mergedPi0 hypothesis only (->for all clusters - toDo in CaloFutureMergedPi0Alg)
+  m_data[ToPrsE] = m_toCaloFuture->energy(*hypo, "Prs");
+  m_data[ToPrsM] = m_toCaloFuture->multiplicity(*hypo, "Prs");
+  m_data[ToSpdM] = m_toCaloFuture->multiplicity(*hypo, "Spd");    
+  // using extra-digits
+  const LHCb::CaloHypo::Digits& digits = hypo->digits();
+  LHCb::CaloDataFunctor::IsFromCalo isSpd { DeCalorimeterLocation::Spd };
+  LHCb::CaloDataFunctor::IsFromCalo isPrs { DeCalorimeterLocation::Prs };
+  m_data[HypoSpdM]= std::count_if ( digits.begin(),digits.end(),isSpd );
+  m_data[HypoPrsM]= std::count_if ( digits.begin(),digits.end(),isPrs );
+  double sumPrs = 0;
+  for( LHCb::CaloHypo::Digits::const_iterator id = digits.begin(); id != digits.end() ; ++id){ 
+    if ( 0 != *id && isPrs ( *id ) ) { sumPrs += (*id)->e(); } 
+  }
+  m_data[HypoPrsE]=sumPrs;
+
+
+
+  
+  // electron matching
+  if( !m_skipC ){
+    double chi2e = CaloFutureDataType::Default;
+    double trajL = CaloFutureDataType::Default;
+    const LHCb::Track* etrack = NULL;
+    //LHCb::CaloFuture2Track::ITrHypoTable2D* etable = getIfExists<LHCb::CaloFuture2Track::ITrHypoTable2D> (m_emLoc);
+    LHCb::CaloFuture2Track::ITrHypoTable2D* etable = m_tables->getTrHypoTable2D( m_emLoc);
+    if ( NULL != etable ) {
+      const LHCb::CaloFuture2Track::ITrHypoTable2D::InverseType::Range range = etable -> inverse()->relations(hypo);
+      if ( !range.empty() ){
+        chi2e= range.front().weight();   
+        etrack = range.front();
+        if( NULL != etrack ){
+          LHCb::ProtoParticle* dummy = new LHCb::ProtoParticle();
+          dummy->setTrack( etrack );
+          dummy->addToCalo ( hypo );
+          //CaloFutureElectron->caloTrajectory must be after addToCalo
+          if ( m_electron->set(dummy) )
+            trajL =m_electron->caloTrajectoryL(CaloPlane::ShowerMax,"hypo");
+          delete dummy;
+        }
+      } 
+    }else
+      if(counterStat->isQuiet())counter( "Missing "+ m_emLoc) += 1;
+
+    m_track[CaloFutureMatchType::ElectronMatch]=etrack;
+    m_data[ElectronMatch] = chi2e;
+    m_data[TrajectoryL]= trajL;
+
+    // brem matching
+    double chi2b = CaloFutureDataType::Default;
+    const LHCb::Track* btrack = NULL;
+    //LHCb::CaloFuture2Track::ITrHypoTable2D* btable = getIfExists<LHCb::CaloFuture2Track::ITrHypoTable2D> (m_bmLoc);
+    LHCb::CaloFuture2Track::ITrHypoTable2D* btable = m_tables->getTrHypoTable2D(m_bmLoc);
+    if ( NULL != btable ) {
+      const LHCb::CaloFuture2Track::ITrHypoTable2D::InverseType::Range range = btable -> inverse()->relations(hypo);
+      if ( !range.empty() ){
+        chi2b= range.front().weight(); 
+        btrack = range.front();
+      }
+    }else
+      if(counterStat->isQuiet())counter( "Missing "+ m_bmLoc) += 1; 
+
+    m_track[CaloFutureMatchType::BremMatch]=btrack;
+    m_data[BremMatch] = chi2b;
+  }
+  
+  // NeutralID (warning : protect against infinite loop from CaloFuturePhotonIDAlg using this tools with DoD active)
+  if( !m_skipN ){
+    for( std::map<std::string,std::string>::iterator l = m_pidLoc.begin(); m_pidLoc.end()!=l; ++l){
+      std::string loc = l->second;
+      std::string  hypothesis =  l->first;
+      if ( exist<LHCb::CaloFuture2Track::IHypoEvalTable>( loc ) )
+        //m_idTable[hypothesis] = get<LHCb::CaloFuture2Track::IHypoEvalTable> ( loc ) ;
+        m_idTable[hypothesis] = m_tables->getHypoEvalTable( loc );
+      else
+        if(counterStat->isQuiet())counter( "Missing "+ loc) += 1; 
+    }
+    std::ostringstream type("");
+    type << hypo->hypothesis();
+    std::string hypothesis = type.str();
+    const LHCb::CaloFuture2Track::IHypoEvalTable* idTable =  NULL ;
+    std::map<std::string, LHCb::CaloFuture2Track::IHypoEvalTable*>::iterator it = m_idTable.find(hypothesis);
+    if( it != m_idTable.end())idTable = it->second;
+    if( NULL != idTable ){
+      const LHCb::CaloFuture2Track::IHypoEvalTable::Range range = idTable->relations( hypo ) ;
+      if ( !range.empty()  )m_data[NeutralID]= range.front().to();
+    }  
+  }
+  // link 2 cluster :
+  const LHCb::CaloCluster* cluster = LHCb::CaloFutureAlgUtils::ClusterFromHypo( hypo );
+  m_clusters[CaloFutureClusterType::SplitOrMain]=cluster;
+  m_clusters[CaloFutureClusterType::Main]=  LHCb::CaloFutureAlgUtils::ClusterFromHypo( hypo , false); // get the main cluster
+
+  //Prs info
+  if( cluster == NULL ){
+    Warning("Cluster point to NULL",StatusCode::SUCCESS).ignore();
+  }else{
+    // Ecal seed
+    LHCb::CaloCluster::Entries::const_iterator iseed = 
+      LHCb::ClusterFunctors::locateDigit(cluster->entries().begin(),cluster->entries().end(), LHCb::CaloDigitStatus::SeedCell);
+    if (iseed != cluster->entries().end()) {
+      const LHCb::CaloDigit* seed = iseed->digit();
+      const LHCb::CaloCellID idseed=seed->cellID();
+      double sum9 = 0.;
+      double sum1 = 0.;
+      // PrsE4
+      std::vector<double> Prse4s;
+      Prse4s.reserve(4);
+      Prse4s.push_back(0.);
+      Prse4s.push_back(0.);
+      Prse4s.push_back(0.);
+      Prse4s.push_back(0.);
+      std::vector<double> Prse9;
+      Prse9.reserve(9);
+      Prse9.push_back(0.);
+      Prse9.push_back(0.);
+      Prse9.push_back(0.);
+      Prse9.push_back(0.);
+      Prse9.push_back(0.);
+      Prse9.push_back(0.);
+      Prse9.push_back(0.);
+      Prse9.push_back(0.);
+      Prse9.push_back(0.);
+      
+      for( LHCb::CaloHypo::Digits::const_iterator id = digits.begin(); id != digits.end() ; ++id){ 
+        
+        if ( 0 == *id || !isPrs ( *id ) )continue;
+        LHCb::CaloCellID id2 = (*id)->cellID();
+        if( abs((int)(*id)->cellID().row() - (int)idseed.row())<2 && abs( (int)(*id)->cellID().col() - (int)idseed.col())<2 ){
+          // Build sum1 and sum9
+          //
+          sum9 += (*id)->e(); 
+          if( (*id)->cellID().row() == idseed.row() &&  (*id)->cellID().col() == idseed.col() ) sum1=(*id)->e();
+          // Prs4
+          //
+          if(id2.col() <= idseed.col() && id2.row() >= idseed.row() )Prse4s[0] += (*id)->e();
+          if(id2.col() >= idseed.col() && id2.row() >= idseed.row() )Prse4s[1] += (*id)->e(); 
+          if(id2.col() >= idseed.col() && id2.row() <= idseed.row() )Prse4s[2] += (*id)->e();
+          if(id2.col() <= idseed.col() && id2.row() <= idseed.row() )Prse4s[3] += (*id)->e();
+          // Select the 3X3 cluster
+          // 
+          int dcol = (int)id2.col()-(int)idseed.col()+1;
+          int drow = (int)id2.row()-(int)idseed.row()+1;
+          int indexPrs = drow*3+dcol; 
+          Prse9[indexPrs] += (*id)->e();
+        }
+      }
+      //    Build E19 and E49
+      //
+      double Prse4max = 0;
+      for( std::vector<double>::iterator ih = Prse4s.begin();Prse4s.end() != ih;++ih){
+        if( *ih >= Prse4max ) Prse4max=*ih;
+      }
+      m_data[PrsE4Max]  = Prse4max;
+      double sum9Inv = 0.;
+      if( sum9 > 0. ) {
+        sum9Inv = 1./sum9;
+        m_data[PrsE49] = Prse4max * sum9Inv;
+        m_data[PrsE19] = sum1 * sum9Inv;
+      }
+      else 
+      {
+        m_data[PrsE49] = 0.;
+        m_data[PrsE19] = 0.;
+      }
+      m_data[PrsE1]= Prse9[0]; 
+      m_data[PrsE2]= Prse9[1]; 
+      m_data[PrsE3]= Prse9[2]; 
+      m_data[PrsE4]= Prse9[3]; 
+      m_data[PrsE5]= Prse9[4]; 
+      m_data[PrsE6]= Prse9[5];
+      m_data[PrsE7]= Prse9[6]; 
+      m_data[PrsE8]= Prse9[7]; 
+      m_data[PrsE9]= Prse9[8];  
+    }
+  }
+    
+  // gamma/pi0 separation
+  m_data[CaloFutureDataType::DataType::isPhoton]= m_GammaPi0->isPhoton( hypo );
+  m_data[CaloFutureDataType::DataType::isPhotonXGB] = m_GammaPi0XGB->isPhoton( hypo );
+
+
+  // 1- Ecal variables :
+  std::map<std::string,double> isPhotonData = m_GammaPi0->inputDataMap();
+  for(   std::map<std::string,double>::iterator idata = isPhotonData.begin() ; isPhotonData.end() != idata; ++idata){
+    std::string name = "isPhoton_"+idata->first;
+    double val = idata->second;
+    bool ok =false;
+    for( int i = 0; i < Last ; ++i){
+      if( Name[i] == name){
+        m_data[(DataType)i]=val;
+        ok=true;
+        break;
+      }
+    }
+    if( !ok )Warning("DataType '" + name + "' is undefined",StatusCode::SUCCESS).ignore();
+  }
+  // 2- Prs variables :
+  std::map<std::string,double> isPhotonPrsData = m_GammaPi0->inputPrsDataMap();
+  for(   std::map<std::string,double>::iterator idata = isPhotonPrsData.begin() ; isPhotonPrsData.end() != idata; ++idata){
+    std::string name = "isPhoton_"+idata->first;
+    double val = idata->second;
+    bool ok =false;
+    for( int i = 0; i < Last ; ++i){
+      if( Name[i] == name){
+        m_data[(DataType)i]=val;
+        ok=true;
+        break;
+      }
+    }
+    if( !ok )Warning("DataType '" + name + "' is undefined",StatusCode::SUCCESS).ignore();
+  }
+  //
+  bool ok =  ( 0 != cluster ) ? estimator( cluster , hypo) : false;
+  
+
+  // Estimator MUST be at the end (after all inputs are loaded)
+  m_data[isNotH]= m_neutralID->isNotH( hypo,this );
+  m_data[isNotE]= m_neutralID->isNotE( hypo,this );
+
+
+  return ok;
+}
+
+// ------------ FROM CLUSTER
+bool CaloFutureHypoEstimator::estimator(const LHCb::CaloCluster* cluster, const LHCb::CaloHypo* fromHypo){
+  using namespace CaloFutureDataType;
+  if( NULL ==cluster)return false;
+  m_cluster = (LHCb::CaloCluster*) cluster;
+  
+
+  if (cluster->entries().empty()) {
+    if(counterStat->isQuiet())counter("Empty cluster") += 1;
+    return false;
+  }
+  LHCb::CaloCluster::Entries::const_iterator iseed = 
+    LHCb::ClusterFunctors::locateDigit(cluster->entries().begin(),cluster->entries().end(), LHCb::CaloDigitStatus::SeedCell);
+
+  if (iseed != cluster->entries().end()) {
+
+    const LHCb::CaloDigit* seed = iseed->digit();
+    if (0 == seed) {
+      if(counterStat->isQuiet())counter("Seed points to NULL") += 1;
+      return false;
+    }
+
+    double eEcal = cluster->e();
+    m_data[ClusterE]  = eEcal;
+    //
+    double cSize =  m_ecal->cellSize(cluster->seed());
+    Gaudi::XYZPoint cCenter=m_ecal->cellCenter( cluster->seed() );
+    double  asX = ( cluster->position().x() - cCenter.x() )/cSize;
+    double  asY = ( cluster->position().y() - cCenter.y() )/cSize;
+    m_data[ClusterAsX]=asX;
+    m_data[ClusterAsY]=asY;
+
+    m_data[E1]  = seed->e();
+    caloDataType::iterator it = m_data.find( HypoE );
+    double eHypo = ( it != m_data.end() ) ? m_data[HypoE] : 0;
+    m_data[E1Hypo] = eHypo > 0. ? (seed->e()) / eHypo : -1.;
+    LHCb::CaloCellID sid = seed->cellID();
+    m_data[CellID] = (double) sid.all();
+    m_data[Spread] = cluster->position().spread()(1,1)+cluster->position().spread()(0,0);
+    // E4
+    std::vector<double> e4s;
+    e4s.reserve(4);
+    e4s.push_back(0);
+    e4s.push_back(0);
+    e4s.push_back(0);
+    e4s.push_back(0);
+    double e9 = 0.;
+    double ee9 =0.; // full cluster energy without fraction applied
+    double e2  = 0.;
+    bool hasShared=false;
+    int code = 0.;
+    int mult = 0.;
+    int nsat = 0; // number of saturated cells
+    for( LHCb::CaloCluster::Entries::const_iterator ie = cluster->entries().begin() ; cluster->entries().end() != ie ; ++ie){
+      const LHCb::CaloDigit* dig = (*ie).digit();
+      if( NULL == dig)continue;
+      double ecel = dig->e()*ie->fraction();
+      if( ( ( ie->status() & LHCb::CaloDigitStatus::UseForEnergy) != 0 ||  
+            ( ie->status() & LHCb::CaloDigitStatus::UseForCovariance) != 0) && m_ecal->isSaturated(dig->e(),dig->cellID()))nsat++;
+      LHCb::CaloCellID id = dig->cellID();
+      if( id.area() != sid.area() || abs((int)id.col() - (int)sid.col()) > 1 ||  abs((int)id.row() - (int)sid.row()) > 1)continue;
+      if(id.col() <= sid.col() && id.row() >= sid.row() )e4s[0] += ecel;
+      if(id.col() >= sid.col() && id.row() >= sid.row() )e4s[1] += ecel;
+      if(id.col() >= sid.col() && id.row() <= sid.row() )e4s[2] += ecel;
+      if(id.col() <= sid.col() && id.row() <= sid.row() )e4s[3] += ecel;    
+      e9 += ecel;
+      // new info
+      ee9+= dig->e();
+      mult++;
+      if( ie->status() & LHCb::CaloDigitStatus::SharedCell)hasShared=true;
+      if( !(id == sid) && ecel > e2){
+        e2 = ecel;
+        int dc  =  (int)id.col() - (int)sid.col()+1;
+        int dr  =  (int)id.row() - (int)sid.row()+1;
+        code =  3*dr + dc;
+      }
+    }
+    m_data[Saturation]=(double) nsat;
+    double e4max = 0;
+    for( std::vector<double>::iterator ih = e4s.begin();e4s.end() != ih;++ih){
+      if( *ih >= e4max)e4max=*ih;
+    }
+
+    code = mult * 10 + code;
+    if( hasShared )code *= -1;
+    m_data[ClusterCode] = (double) code;
+    m_data[ClusterFrac] = (e9 > 0.) ? e9/ee9 : -1;
+
+    m_data[E4]  = e4max;
+    m_data[E9]  = e9;
+    m_data[E49] = (e9>0.) ? e4max /e9 : 0.;
+    m_data[E19] = (e9>0.) ? seed->e() / e9 : -1.;
+
+    
+    
+    if( NULL == fromHypo){
+      // hypo and cluster parameters may produce small difference according to m_toCaloFuture setting (due to extrapolation)
+      m_data[ToPrsE] = m_toCaloFuture->energy(*cluster, "Prs");
+      m_data[ToPrsM] = m_toCaloFuture->multiplicity(*cluster, "Prs");
+      m_data[ToSpdM] = m_toCaloFuture->multiplicity(*cluster, "Spd");    
+    }
+    double eHcal = m_toCaloFuture->energy(*cluster, "Hcal");
+    m_data[ToHcalE]= eHcal;
+    m_data[Hcal2Ecal] = (eEcal > 0) ? eHcal/eEcal : 0.;
+  }
+
+  // cluster-match chi2
+  if( !m_skipCl ){
+    const LHCb::CaloCluster* clus = cluster ;
+    // special trick for split cluster : use full cluster matching
+    if (NULL != fromHypo && fromHypo->hypothesis() == LHCb::CaloHypo::Hypothesis::PhotonFromMergedPi0)
+      clus = LHCb::CaloFutureAlgUtils::ClusterFromHypo( fromHypo , false); // get the main cluster
+    double chi2 = CaloFutureDataType::Default;    const LHCb::Track* ctrack = NULL;
+    //LHCb::CaloFuture2Track::IClusTrTable* ctable = getIfExists<LHCb::CaloFuture2Track::IClusTrTable> (m_cmLoc);
+    LHCb::CaloFuture2Track::IClusTrTable* ctable = m_tables->getClusTrTable( m_cmLoc );
+    if ( NULL != ctable ) {
+      const LHCb::CaloFuture2Track::IClusTrTable::Range range = ctable -> relations(clus);
+
+
+      if ( !range.empty() ){
+        chi2= range.front().weight();
+        ctrack = range.front();
+      }
+    }else
+      if(counterStat->isQuiet())counter( "Missing "+ m_cmLoc) += 1;
+
+    m_track[CaloFutureMatchType::ClusterMatch]=ctrack;
+    m_data[ClusterMatch] = chi2;
+  }
+  return true;
+}
+
+
+
+void CaloFutureHypoEstimator::clean(){
+  m_data.clear();
+  m_cluster=NULL;
+  m_hypo=NULL;
+  m_track.clear();
+  return;
+}
+
+
+
diff --git a/CaloFuture/CaloFutureTools/src/CaloFutureHypoEstimator.h b/CaloFuture/CaloFutureTools/src/CaloFutureHypoEstimator.h
new file mode 100644
index 0000000000000000000000000000000000000000..f414b34d8f59eb222d28aa1d4642acca86230707
--- /dev/null
+++ b/CaloFuture/CaloFutureTools/src/CaloFutureHypoEstimator.h
@@ -0,0 +1,103 @@
+#ifndef CALOFUTUREHYPOESTIMATOR_H
+#define CALOFUTUREHYPOESTIMATOR_H 1
+
+// Include files
+// from Gaudi
+#include "GaudiAlg/GaudiTool.h"
+#include "GaudiKernel/IIncidentListener.h"
+#include "GaudiKernel/IIncidentSvc.h"
+#include "GaudiKernel/Incident.h"
+#include "Event/CaloDataFunctor.h"
+#include "CaloFutureUtils/ClusterFunctors.h"
+#include "CaloFutureUtils/CaloMomentum.h"
+#include "CaloFutureUtils/CaloFutureAlgUtils.h"
+#include "CaloFutureUtils/CaloFuture2Track.h"
+#include "Relations/Relation2D.h"
+#include "Relations/IRelationWeighted.h"
+#include "Relations/IRelationWeighted2D.h"
+#include "Event/Track.h"
+#include "CaloFutureInterfaces/ICaloFutureHypoEstimator.h"            // Interface
+#include "CaloFutureInterfaces/IFutureCounterLevel.h"
+#include "CaloFutureInterfaces/IFutureGammaPi0SeparationTool.h"
+#include "CaloFutureInterfaces/IFutureNeutralIDTool.h"
+#include "CaloFutureUtils/ICaloFutureElectron.h"
+#include "CaloFutureInterfaces/ICaloFutureRelationsGetter.h"
+#include "CaloDet/DeCalorimeter.h"
+
+/** @class CaloFutureHypoEstimator CaloFutureHypoEstimator.h
+ *
+ *
+ *  @author Olivier Deschamps
+ *  @date   2010-08-18
+ */
+
+class CaloFutureHypoEstimator : public GaudiTool, virtual public ICaloFutureHypoEstimator, virtual public IIncidentListener {
+public:
+  /// Standard constructor
+  CaloFutureHypoEstimator( const std::string& type,
+                     const std::string& name,
+                     const IInterface* parent);
+
+  StatusCode initialize() override;
+  StatusCode finalize() override;
+
+  double data(const LHCb::CaloCluster* cluster ,CaloFutureDataType::DataType type, double def = CaloFutureDataType::Default) override;
+  double data(const LHCb::CaloHypo* hypo ,CaloFutureDataType::DataType type, double def = CaloFutureDataType::Default) override;
+
+  void handle(const Incident&  ) override {
+    if( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+      debug() << "IIncident Svc reset" << endmsg;
+    clean();
+  }
+  ICaloFutureHypo2CaloFuture* hypo2CaloFuture() override {return m_toCaloFuture;};
+  const LHCb::Track* toTrack(CaloFutureMatchType::MatchType match) override {
+    caloMatchType::iterator it = m_track.find( match );
+    if( it == m_track.end() )return NULL;
+    return (*it).second;
+  }
+  const LHCb::CaloCluster* toCluster(CaloFutureClusterType::ClusterType clus=CaloFutureClusterType::SplitOrMain) override {
+    caloClusterType::iterator it = m_clusters.find( clus );
+    if( it == m_clusters.end() )return NULL;
+    return (*it).second;
+  }
+
+
+  StatusCode  _setProperty(const std::string& p,const std::string& v) override {return  setProperty(p,v);};
+  bool status() override {return m_status;}
+
+
+private:
+  IFutureCounterLevel* counterStat = nullptr;
+  bool estimator(const LHCb::CaloCluster* cluster,const LHCb::CaloHypo* fromHypo=NULL);
+  bool estimator(const LHCb::CaloHypo* hypo);
+  void clean();
+  
+  Gaudi::Property<bool> m_extrapol {this, "Extrapolation", true};
+  Gaudi::Property<bool> m_seed {this, "AddSeed", false};
+  Gaudi::Property<bool> m_neig {this, "AddNeighbors", false};
+  
+  ICaloFutureHypo2CaloFuture* m_toCaloFuture = nullptr;
+  caloDataType m_data;
+  caloMatchType m_track;
+  caloClusterType m_clusters;
+  LHCb::CaloHypo* m_hypo = nullptr;
+  LHCb::CaloCluster* m_cluster = nullptr;
+  
+  Gaudi::Property<std::map<std::string,std::string>> m_pidLoc {this, "NeutralIDLocations"};
+  Gaudi::Property<std::string> m_cmLoc {this, "ClusterMatchLocation"};
+  Gaudi::Property<std::string> m_emLoc {this, "ElectronMatchLocation"};
+  Gaudi::Property<std::string> m_bmLoc {this, "BremMatchLocation"};
+  Gaudi::Property<bool> m_skipC {this, "SkipChargedID", false};
+  Gaudi::Property<bool> m_skipN {this, "SkipNeutralID", false};
+  Gaudi::Property<bool> m_skipCl {this, "SkipClusterMatch", false};
+
+  std::map<std::string,LHCb::CaloFuture2Track::IHypoEvalTable*> m_idTable;
+  bool m_status = true;
+  ICaloFutureElectron * m_electron = nullptr;
+  IFutureGammaPi0SeparationTool* m_GammaPi0 = nullptr;
+  IFutureGammaPi0SeparationTool* m_GammaPi0XGB = nullptr;
+  IFutureNeutralIDTool* m_neutralID = nullptr;
+  ICaloFutureRelationsGetter*    m_tables = nullptr;
+  DeCalorimeter* m_ecal = nullptr;
+};
+#endif // CALOFUTUREHYPOESTIMATOR_H
diff --git a/CaloFuture/CaloFutureTools/src/CaloFutureRelationsGetter.cpp b/CaloFuture/CaloFutureTools/src/CaloFutureRelationsGetter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..779b36c3c4a8819c4e29ecefcab3bcd1c08c4bdc
--- /dev/null
+++ b/CaloFuture/CaloFutureTools/src/CaloFutureRelationsGetter.cpp
@@ -0,0 +1,80 @@
+// Include files
+
+// from Gaudi
+#include "GaudiKernel/IIncidentSvc.h"
+#include "GaudiKernel/Incident.h"
+
+
+// local
+#include "CaloFutureRelationsGetter.h"
+
+//-----------------------------------------------------------------------------
+// Implementation file for class : CaloFutureRelationsGetter
+//
+// 2013-10-04 : Olivier Deschamps
+//-----------------------------------------------------------------------------
+
+// Declaration of the Tool Factory
+DECLARE_COMPONENT( CaloFutureRelationsGetter )
+
+
+//=============================================================================
+// Standard constructor, initializes variables
+//=============================================================================
+CaloFutureRelationsGetter::CaloFutureRelationsGetter( const std::string& type,
+                                          const std::string& name,
+                                          const IInterface* parent )
+: GaudiTool ( type, name , parent )
+{
+  declareInterface<ICaloFutureRelationsGetter>(this);
+  declareInterface<IIncidentListener>(this);
+}
+
+//=============================================================================
+
+
+StatusCode CaloFutureRelationsGetter::initialize(){
+  StatusCode sc = GaudiTool::initialize();
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) )debug() << "Initialize CaloFutureRelationsGetter tool " << endmsg;
+  // subscribe to the incidents
+  IIncidentSvc* inc = incSvc() ;
+  if ( inc )inc -> addListener  ( this , IncidentType::BeginEvent ) ;
+  return sc;
+}
+
+StatusCode CaloFutureRelationsGetter::finalize(){
+  IIncidentSvc* inc = incSvc() ;
+  if ( inc ) { inc -> removeListener  ( this ) ; }
+  return GaudiTool::finalize();
+}
+
+LHCb::CaloFuture2Track::ITrHypoTable2D* CaloFutureRelationsGetter::getTrHypoTable2D(std::string location){
+  auto it = m_hypoTr.find(location);
+  if( it == m_hypoTr.end() ) m_hypoTr[location] = getIfExists<LHCb::CaloFuture2Track::IHypoTrTable2D> (location);
+  
+  auto links = m_hypoTr[location]->relations();
+  m_trHypo.i_clear().ignore(); 
+  for(const auto& l : links) m_trHypo.i_push( l.to(), l.from(), l.weight() );
+  m_trHypo.i_sort();
+  return &m_trHypo;
+}
+
+LHCb::CaloFuture2Track::IHypoEvalTable* CaloFutureRelationsGetter::getHypoEvalTable(std::string location){
+  auto it = m_hypoEval.find(location);
+  if( it == m_hypoEval.end()) m_hypoEval[location] = getIfExists<LHCb::CaloFuture2Track::IHypoEvalTable> (location);
+  return m_hypoEval[location];
+}
+
+LHCb::CaloFuture2Track::IClusTrTable* CaloFutureRelationsGetter::getClusTrTable(std::string location){
+  auto it = m_clusTr.find(location);
+  if( it == m_clusTr.end()) m_clusTr[location] = getIfExists<LHCb::CaloFuture2Track::IClusTrTable> (location);
+  return m_clusTr[location];
+}
+
+void CaloFutureRelationsGetter::clean(){
+  m_clusTr.clear();
+  m_hypoEval.clear();
+  m_hypoTr.clear();
+
+}
+
diff --git a/CaloFuture/CaloFutureTools/src/CaloFutureRelationsGetter.h b/CaloFuture/CaloFutureTools/src/CaloFutureRelationsGetter.h
new file mode 100644
index 0000000000000000000000000000000000000000..c00507e6750599c9b2a735ba3187bb25cead363b
--- /dev/null
+++ b/CaloFuture/CaloFutureTools/src/CaloFutureRelationsGetter.h
@@ -0,0 +1,56 @@
+#ifndef CALOFUTURERELATIONSGETTER_H
+#define CALOFUTURERELATIONSGETTER_H 1
+
+// Include files
+// from Gaudi
+#include "GaudiAlg/GaudiTool.h"
+#include "CaloFutureInterfaces/ICaloFutureRelationsGetter.h"            // Interface
+#include "GaudiKernel/IIncidentListener.h"
+#include "GaudiKernel/IIncidentSvc.h"
+#include "GaudiKernel/Incident.h"
+// from LHCb
+#include "Relations/Relation2D.h"
+#include "Relations/IRelationWeighted.h"
+#include "Relations/IRelationWeighted2D.h"
+#include "Event/Track.h"
+#include "Event/CaloHypo.h"
+#include "CaloFutureUtils/CaloFuture2Track.h"
+
+
+#include "Relations/RelationWeighted2D.h"
+
+
+/** @class CaloFutureRelationsGetter CaloFutureRelationsGetter.h
+ *
+ *
+ *  @author Olivier Deschamps
+ *  @date   2013-10-04
+ */
+class CaloFutureRelationsGetter : public GaudiTool, virtual public ICaloFutureRelationsGetter, virtual public IIncidentListener   {
+public:
+  /// Standard constructor
+  CaloFutureRelationsGetter( const std::string& type,
+                       const std::string& name,
+                       const IInterface* parent);
+
+  StatusCode initialize() override;
+  StatusCode finalize() override;
+  void handle(const Incident&  ) override {
+    if( UNLIKELY( msgLevel(MSG::DEBUG) ) )debug() << "IIncident Svc reset" << endmsg;
+    clean();
+  }
+
+  // getters
+  LHCb::CaloFuture2Track::ITrHypoTable2D* getTrHypoTable2D(std::string location) override;
+  LHCb::CaloFuture2Track::IHypoEvalTable* getHypoEvalTable(std::string location) override;
+  LHCb::CaloFuture2Track::IClusTrTable*   getClusTrTable  (std::string location) override;
+
+private:
+
+  LHCb::RelationWeighted2D<LHCb::Track, LHCb::CaloHypo, float> m_trHypo;
+  std::map<std::string,LHCb::CaloFuture2Track::IHypoTrTable2D*> m_hypoTr;
+  std::map<std::string,LHCb::CaloFuture2Track::IHypoEvalTable*> m_hypoEval;
+  std::map<std::string,LHCb::CaloFuture2Track::IClusTrTable*>   m_clusTr;
+  void clean();
+};
+#endif // CALOFUTURERELATIONSGETTER_H
diff --git a/CaloFuture/CaloFutureTools/src/CheckCaloFutureHypoRef.cpp b/CaloFuture/CaloFutureTools/src/CheckCaloFutureHypoRef.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..188d7db7b655e684fa4baa9e675a7fa6cdbdb124
--- /dev/null
+++ b/CaloFuture/CaloFutureTools/src/CheckCaloFutureHypoRef.cpp
@@ -0,0 +1,58 @@
+// Include files
+
+// from  LHCb
+#include "CaloFutureUtils/CaloFutureAlgUtils.h"
+#include "Event/CaloHypo.h"
+// local
+#include "CheckCaloFutureHypoRef.h"
+
+//-----------------------------------------------------------------------------
+// Implementation file for class : CheckCaloFutureHypoRef
+//
+// 2012-05-14 : Olivier Deschamps
+//-----------------------------------------------------------------------------
+
+// Declaration of the Algorithm Factory
+DECLARE_COMPONENT( CheckCaloFutureHypoRef )
+
+
+//=============================================================================
+// Standard constructor, initializes variables
+//=============================================================================
+CheckCaloFutureHypoRef::CheckCaloFutureHypoRef( const std::string& name,
+                                    ISvcLocator* pSvcLocator)
+: GaudiAlgorithm ( name , pSvcLocator )
+{
+  using namespace LHCb::CaloFutureAlgUtils;
+  m_inputs.value() = {
+    CaloFutureHypoLocation("Photons"   , context()),
+    CaloFutureHypoLocation("Electrons" , context()),
+    CaloFutureHypoLocation("MergedPi0s", context()) 
+  };
+}
+
+//=============================================================================
+// Main execution
+//=============================================================================
+StatusCode CheckCaloFutureHypoRef::execute() {
+
+ if ( msgLevel(MSG::DEBUG) ) debug() << "==> Execute" << endmsg;
+
+ for (const auto& loc :  m_inputs ) {
+    const LHCb::CaloHypos* hypos = getIfExists<LHCb::CaloHypos> (loc);
+    if ( !hypos ) continue;
+    if(counterStat->isQuiet()) counter("#Hypos in " + loc) += hypos->size();
+    int bLink=0;
+    for (const auto& h : *hypos ) {
+      for( const auto&  cluster : h->clusters() ) {
+        if( !cluster ) bLink++;
+        else if(counterStat->isVerbose())counter("Cluster energy " +loc)+=cluster->e();
+      }
+    }
+    if(counterStat->isQuiet())counter("Broken SmarRef " +loc) += bLink;
+    if(bLink != 0)Warning("CaloHypo -> CaloCluster* SmartReference is broken for "+loc,StatusCode::SUCCESS).ignore();
+ }
+  return StatusCode::SUCCESS;
+}
+
+//=============================================================================
diff --git a/CaloFuture/CaloFutureTools/src/CheckCaloFutureHypoRef.h b/CaloFuture/CaloFutureTools/src/CheckCaloFutureHypoRef.h
new file mode 100644
index 0000000000000000000000000000000000000000..542aa748f74d3a3c86b48427def80294628cd309
--- /dev/null
+++ b/CaloFuture/CaloFutureTools/src/CheckCaloFutureHypoRef.h
@@ -0,0 +1,26 @@
+#ifndef CHECKCALOFUTUREHYPOREF_H
+#define CHECKCALOFUTUREHYPOREF_H 1
+
+// Include files
+// from Gaudi
+#include "GaudiAlg/GaudiAlgorithm.h"
+#include "CaloFutureInterfaces/IFutureCounterLevel.h"
+
+/** @class CheckCaloFutureHypoRef CheckCaloFutureHypoRef.h
+ *
+ *
+ *  @author Olivier Deschamps
+ *  @date   2012-05-14
+ */
+class CheckCaloFutureHypoRef : public GaudiAlgorithm {
+public:
+  /// Standard constructor
+  CheckCaloFutureHypoRef( const std::string& name, ISvcLocator* pSvcLocator );
+
+  StatusCode execute() override;    ///< Algorithm execution
+
+private:
+  Gaudi::Property<std::vector<std::string>> m_inputs {this, "CaloHypos"};
+  IFutureCounterLevel* counterStat = nullptr;
+};
+#endif // CHECKCALOFUTUREHYPOREF_H
diff --git a/CaloFuture/CaloFutureTools/src/FutureCounterLevel.cpp b/CaloFuture/CaloFutureTools/src/FutureCounterLevel.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1a6fb46037eac18ce72a38b1bcae20e2f990d89b
--- /dev/null
+++ b/CaloFuture/CaloFutureTools/src/FutureCounterLevel.cpp
@@ -0,0 +1,32 @@
+#include "FutureCounterLevel.h"
+
+//-----------------------------------------------------------------------------
+// Implementation file for class : FutureCounterLevel
+//
+// 2016-08-13 : Olivier Deschamps
+//-----------------------------------------------------------------------------
+
+// Declaration of the Tool Factory
+DECLARE_COMPONENT( FutureCounterLevel )
+
+
+//=============================================================================
+// Standard constructor, initializes variables
+//=============================================================================
+FutureCounterLevel::FutureCounterLevel( const std::string& type,
+                            const std::string& name,
+                            const IInterface* parent )
+: base_class ( type, name , parent )
+{
+  declareInterface<IFutureCounterLevel>(this);
+
+  // sync m_isQuiet and m_isVerbose with m_clevel
+  m_clevel.declareUpdateHandler(
+    [=](const Property&) {
+        this->m_isQuiet   = ( this->m_clevel > 0 );
+        this->m_isVerbose = ( this->m_clevel > 1 );
+  });
+  m_clevel.useUpdateHandler();
+}
+
+//=============================================================================
diff --git a/CaloFuture/CaloFutureTools/src/FutureCounterLevel.h b/CaloFuture/CaloFutureTools/src/FutureCounterLevel.h
new file mode 100644
index 0000000000000000000000000000000000000000..ab49b410559e358c97c4da7cd6b0f5d0fc6f5e30
--- /dev/null
+++ b/CaloFuture/CaloFutureTools/src/FutureCounterLevel.h
@@ -0,0 +1,34 @@
+#ifndef FUTURECOUNTERLEVEL_H 
+#define FUTURECOUNTERLEVEL_H 1
+
+// Include files
+// from Gaudi
+#include "GaudiAlg/GaudiTool.h"
+#include "CaloFutureInterfaces/IFutureCounterLevel.h"            // Interface
+
+
+/** @class FutureCounterLevel FutureCounterLevel.h
+ *  
+ *
+ *  @author Olivier Deschamps
+ *  @date   2016-08-13
+ */
+class FutureCounterLevel final : public extends<GaudiTool, IFutureCounterLevel> {
+public: 
+  /// Standard constructor
+  FutureCounterLevel( const std::string& type, 
+                const std::string& name,
+                const IInterface* parent);
+
+  bool isQuiet()      const override {return m_isQuiet;     };
+  bool isVerbose()    const override {return m_isVerbose;   };
+  bool isLevel(int l) const override {return m_clevel >= l; };
+  int  level()        const override {return m_clevel     ; };
+    
+private:
+
+  Gaudi::Property<int> m_clevel {this, "SetLevel", 1, "quiet mode is the default"};
+  bool m_isQuiet = true;
+  bool m_isVerbose = false;
+};
+#endif // FUTURECOUNTERLEVEL_H
diff --git a/CaloFuture/CaloFutureTools/src/FutureGammaPi0SeparationTool.cpp b/CaloFuture/CaloFutureTools/src/FutureGammaPi0SeparationTool.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..282fcd021cd34bf6af5583ee61811f848c53e4b7
--- /dev/null
+++ b/CaloFuture/CaloFutureTools/src/FutureGammaPi0SeparationTool.cpp
@@ -0,0 +1,381 @@
+// Include files
+
+#include <cmath>
+
+#include "CaloFutureUtils/CaloMomentum.h"
+#include "CaloFutureUtils/CaloFutureAlgUtils.h"
+// from Event
+#include "Event/RecHeader.h"
+#include "Event/CaloHypo.h"
+#include "Event/CaloCluster.h"
+
+// local
+#include "FutureGammaPi0SeparationTool.h"
+
+using namespace LHCb;
+using namespace Gaudi::Units;
+//-----------------------------------------------------------------------------
+// Implementation file for class : FutureGammaPi0SeparationTool
+//
+// 2010-03-24 : Miriam Calvo Gomez
+//-----------------------------------------------------------------------------
+
+// Declaration of the Tool Factory
+DECLARE_COMPONENT( FutureGammaPi0SeparationTool )
+
+//=============================================================================
+// Standard constructor, initializes variables
+//=============================================================================
+FutureGammaPi0SeparationTool::FutureGammaPi0SeparationTool( const std::string& type,
+                                                const std::string& name,
+                                                const IInterface* parent )
+: base_class ( type, name , parent )
+{
+  declareInterface<IFutureGammaPi0SeparationTool>(this);
+}
+
+//=============================================================================
+// Initialization
+//=============================================================================
+StatusCode FutureGammaPi0SeparationTool::initialize() {
+
+  StatusCode sc = base_class::initialize(); // must be executed first
+  if ( sc.isFailure() ) return sc;  // error printed already by GaudiAlgorithm
+
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) debug() << "==> Initialize" << endmsg;
+
+  /// Retrieve geometry of detector
+  m_ecal = getDetIfExists<DeCalorimeter>( DeCalorimeterLocation::Ecal );
+
+  // TMVA discriminant
+  static const std::vector<std::string> inputVars = {
+           "fr2", "fr2r4", "abs(asym)",
+           "kappa", "Eseed/Ecl", "(E2+Eseed)/Ecl",
+           "eSumPS>0?eMaxPS/eSumPS:0",
+           "eSumPS>0?e2ndPS/eSumPS:0",
+           "r2PS", "abs(asymPS)",
+           "multiPS", "multiPS15",
+           "multiPS30", "multiPS45" } ;
+
+  m_reader0 = std::make_unique<ReadMLPOuter>(inputVars);
+  m_reader1 = std::make_unique<ReadMLPMiddle>(inputVars);
+  m_reader2 = std::make_unique<ReadMLPInner>(inputVars);
+
+  return StatusCode::SUCCESS;
+}
+
+//=============================================================================
+//  Finalize
+//=============================================================================
+StatusCode FutureGammaPi0SeparationTool::finalize() {
+
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) debug() << "==> Finalize" << endmsg;
+
+  m_reader0.reset();
+  m_reader1.reset();
+  m_reader2.reset();
+
+  return base_class::finalize(); // must be executed last
+}
+
+//=============================================================================
+// Main execution
+//=============================================================================
+
+
+double FutureGammaPi0SeparationTool::isPhoton(const LHCb::CaloHypo* hypo){
+
+  // clear all data
+  m_data.clear();
+  m_prsdata.clear();
+
+  if ( !m_ecal ) return m_def;
+  if ( LHCb::CaloMomentum(hypo).pt() < m_minPt) return m_def;
+
+  double fr2 = 0;
+  double fasym = 0;
+  double fkappa = 0;
+  double fr2r4 = 0;
+  double Eseed = 0;
+  double E2 = 0;
+  double Ecl = 0;
+  int area =0;
+
+  double r2PS = 0.;
+  double r2r4PS = 0;
+  double asymPS = 0;
+  double kappaPS = 0;
+  double ePrs = 0;
+  double eMaxPS = 0;
+  double e2ndPS = 0;
+  double ecornerPS = 0;
+  double eSumPS = 0.;
+  int multiPS = 0;
+  int multiPS15 = 0;
+  int multiPS30 = 0;
+  int multiPS45 = 0;
+
+  // evaluate the NN inputs
+  bool ecalV = ClusterVariables(hypo, fr2, fasym, fkappa, fr2r4, Ecl, Eseed, E2, area);
+  bool prsV  = PrsVariables(hypo, r2PS, asymPS, kappaPS, r2r4PS, eSumPS, ePrs, eMaxPS, e2ndPS, ecornerPS,
+                            multiPS, multiPS15, multiPS30, multiPS45);
+  if( !ecalV || !prsV )return m_def;
+  // return NN output
+  return photonDiscriminant(area, fr2, fr2r4, fasym, fkappa, Eseed, E2,
+                            r2PS, asymPS, eMaxPS, e2ndPS, multiPS, multiPS15, multiPS30, multiPS45);
+}
+
+
+bool FutureGammaPi0SeparationTool::ClusterVariables(const LHCb::CaloHypo* hypo,
+                                              double& fr2, double& fasym, double& fkappa, double& fr2r4, double& etot,
+                                              double& Eseed, double& E2, int& area) {
+  m_data.clear();
+
+  if ( !hypo ) return false;
+  const LHCb::CaloCluster* cluster = LHCb::CaloFutureAlgUtils::ClusterFromHypo( hypo );   // OD 2014/05 - change to Split Or Main  cluster
+  if ( !cluster ) return false;
+
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) )debug()<<"Inside ClusterVariables ------"<<endmsg;
+
+  const auto cxx = cluster->position().spread()(0,0);
+  const auto cyy = cluster->position().spread()(1,1);
+  const auto cxy = cluster->position().spread()(0,1);
+  fr2 = cxx + cyy ;
+  fasym = ( cxx > 0 && cyy > 0 ? cxy / std::sqrt( cxx*cyy ) : 0 );
+  const auto arg = ( fr2 > 0. ? 1. - 4.* ( cxx*cyy - cxy*cxy ) / ( fr2 * fr2 ) : 0. );
+  fkappa = std::sqrt( arg > 0. ? arg : 0. );
+
+  const auto xmean = cluster->position().x();
+  const auto ymean = cluster->position().y();
+
+  // OD : WARNING cluster->e() is cluster-shape dependent (3x3 / 2x2 ...) RE-EVALUATE E3x3 instead for back. compatibility
+  // etot = cluster->e(); //same as position.e
+  etot = 0.;
+
+  const Gaudi::XYZPoint position ( xmean, ymean, cluster->position().z() );
+
+  double r4 = 0.;
+  area = -1;
+  int ncells = 0;
+  double secondE = 0.;
+
+  const auto & entries = cluster->entries() ;
+  for ( auto entry = entries.begin() ; entries.end() != entry ; ++entry ){
+    const LHCb::CaloDigit* digit = entry->digit()  ;
+    if ( !digit ) { continue ; }
+    const auto fraction = entry->fraction();
+    const auto energy   = digit->e() * fraction ;
+
+    if( abs( (int)digit->cellID().col() - (int)cluster->seed().col() ) <= 1 &&
+        abs( (int)digit->cellID().row() - (int)cluster->seed().row() ) <= 1 &&
+        digit->cellID().area() == cluster->seed().area() ) { etot += energy; }
+
+    if ( entry->status() & LHCb::CaloDigitStatus::SeedCell ){
+      area = digit->cellID().area();
+      Eseed = energy;
+    }else{
+      if(energy>secondE) {
+        secondE = energy;
+      }
+    }
+
+    const auto& pos =  m_ecal->cellCenter( digit->cellID() );
+    const auto x =  pos.x() ;
+    const auto y =  pos.y() ;
+
+    if ( energy <= 0 ) { continue ; }
+    const double weight = energy > 0.0 ? energy : 0.0 ;
+
+    auto rr = std::pow(x-xmean,2) + std::pow(y-ymean,2);
+    if ( entries.size() <= 1 || rr < 1.e-10 ) { rr=0; } // to avoid huge unphysical value due to machine precision
+    r4 += weight * rr*rr;
+
+    ncells++;
+  }//loop cluster cells
+
+  if( etot > 0. ){
+    r4 /= etot;
+    fr2r4 = (r4 !=0) ? (r4 - fr2*fr2)/r4 : 0.;
+    E2 = (secondE+Eseed)/etot;
+    Eseed = Eseed/etot;
+  }else{
+    // should never happen
+    r4 = 0;
+    fr2r4 = 0.;
+    E2 = 0.;
+    Eseed = 0.;
+  }
+
+  m_data["Ecl"]   = etot;
+  m_data["Fr2"]   = fr2;
+  m_data["Fr2r4"] = fr2r4;
+  m_data["Asym"] = fasym;
+  m_data["Kappa"] = fkappa;
+  m_data["Eseed"] = Eseed;
+  m_data["E2"]    = E2;
+  return true;
+}
+
+bool FutureGammaPi0SeparationTool::PrsVariables(const LHCb::CaloHypo* hypo,
+                                          double& r2PS, double& asymPS, double& kappaPS, double& r2r4PS,
+                                          double& eSumPS, double& ePrs, double& eMaxPS, double& e2ndPS, double& ecornerPS,
+                                          int& multiPS, int& multiPS15, int& multiPS30, int& multiPS45) {
+
+  // clear prs data
+  m_prsdata.clear();
+  e2ndPS = 0.;
+  ePrs = 0.;
+  eSumPS=0.;
+  eMaxPS=0.;
+  multiPS=0;
+  multiPS15=0;
+  multiPS30=0;
+  multiPS45=0;
+  asymPS=0.;
+  r2PS=0.;
+  kappaPS=0.;
+  r2r4PS=0.;
+  ecornerPS=0.;
+
+  if( !hypo)return false;
+  const LHCb::CaloCluster* cluster = LHCb::CaloFutureAlgUtils::ClusterFromHypo( hypo );
+  if( !cluster)return false;
+
+
+  LHCb::CaloCellID cellPrs = cluster->seed();  // use cluster seed projection (mostly the same as line projection + faster access)
+  cellPrs.setCalo(1);
+
+  if( LHCb::CaloCellID() == cellPrs  )return true; // no valid Prs info
+
+  // compute energy sum / max / ...
+  const LHCb::CaloHypo::Digits& digits = hypo->digits();
+  double xPs = 0.;
+  double yPs = 0.;
+  for( auto d = digits.begin() ; digits.end() != d ; ++d ){
+    const LHCb::CaloDigit* digit = *d;
+    if     ( !digit ) continue           ;
+    if ((int) digit->cellID().calo() != 1 )continue;  // select Prs digits
+    int dcol = int(digit->cellID().col()) - int(cellPrs.col());
+    int drow = int(digit->cellID().row()) - int(cellPrs.row());
+    if( abs(dcol) > 1 || abs(drow)> 1 )continue; // keep only neighbors
+
+    double e = digit->e();
+
+    // energy
+    eSumPS  += e ;
+    if( cellPrs == digit->cellID() )ePrs = e ;
+
+    // barycenter
+    xPs += double(dcol) * digit->e();
+    yPs += double(drow) * digit->e();
+
+    // multiplicities
+    if( e > eMaxPS ) eMaxPS = e;
+    if( e > 0.0    ) multiPS++;
+    if( e > 15.0   ) multiPS15++;
+    if( e > 30.0   ) multiPS30++;
+    if( e > 45.0   ) multiPS45++;
+  }
+
+
+  if(  eSumPS <= 0. )return true;
+  xPs = xPs/eSumPS;
+  yPs = yPs/eSumPS;
+
+  // spread and related shape variables
+  double cxxPS = 0.;
+  double cyyPS = 0.;
+  double cxyPS = 0.;
+  double r4PS    = 0.;
+  double c1 = 0.0;
+  double c2 = 0.0;
+  double c3 = 0.0;
+  double c4 = 0.0;
+  for (const auto& digit : digits) {
+    if ( !digit ) continue           ;
+    if ((int) digit->cellID().calo() != 1 )continue;  // select Prs digits
+    int dcol = ( int(digit->cellID().col()) - int(cellPrs.col()) );
+    int drow = ( int(digit->cellID().row()) - int(cellPrs.row()) );
+    if( abs(dcol) > 1 || abs(drow)> 1 )continue; // keep only neighbors
+
+    // 2Nd max
+    double e = digit->e();
+    if( e > e2ndPS && e < eMaxPS )e2ndPS = e;
+
+    // spread
+    double dxPS = (xPs - double(dcol));
+    double dyPS = (yPs - double(drow));
+    cxxPS += dxPS * dxPS * e;
+    cyyPS += dyPS * dyPS * e;
+    cxyPS += dxPS * dyPS * e;
+
+    // shape variables
+    r4PS += e * ( dxPS * dxPS + dyPS * dyPS) * ( dxPS * dxPS + dyPS * dyPS);
+
+    // corner energy
+    if(dcol==-1 && drow== 1 ){ c1 += e;}
+    if(dcol==-1 && drow== 0 ){ c1 += e; c3 += e;}
+    if(dcol==-1 && drow==-1 ){ c3 += e;}
+    if(dcol== 0 && drow== 1 ){ c1 += e; c2 += e;}
+    if(dcol== 0 && drow==-1 ){ c3 += e; c4 += e;}
+    if(dcol== 1 && drow== 1 ){ c2 += e;}
+    if(dcol== 1 && drow== 0 ){ c2 += e; c4 += e;}
+    if(dcol== 1 && drow==-1 ){ c4 += e;}
+  }
+  cxxPS = cxxPS/eSumPS;
+  cxyPS = cxyPS/eSumPS;
+  cyyPS = cyyPS/eSumPS;
+  r2PS    = cxxPS + cyyPS;
+  asymPS  = ( cxxPS > 0.0 && cyyPS > 0.0) ? cxyPS / std::sqrt( cxxPS * cyyPS) : 0.;
+  const auto arg = ( r2PS > 0.0 ? 1.0 - 4.0 *  (cxxPS * cyyPS - cxyPS * cxyPS) / ( r2PS * r2PS ) : 0. );
+  kappaPS = std::sqrt( arg > 0. ? arg : 0. );
+  r4PS = r4PS/eSumPS;
+  if( r4PS!=0.0) r2r4PS = ( r4PS - r2PS * r2PS) /r4PS;
+
+  ecornerPS = std::max( { c1, c2, c3, c4 } );
+  eMaxPS = eMaxPS/eSumPS;
+  e2ndPS = e2ndPS/eSumPS;
+
+
+  // === store the data
+  m_prsdata["PrsFr2"]     = r2PS;
+  m_prsdata["PrsAsym"]    = asymPS;
+  m_prsdata["PrsM"]       = multiPS;
+  m_prsdata["PrsM15"]     = multiPS15;
+  m_prsdata["PrsM30"]     = multiPS30;
+  m_prsdata["PrsM45"]     = multiPS45;
+  m_prsdata["PrsEmax"]    = eMaxPS;
+  m_prsdata["PrsE2"]      = e2ndPS;
+  return true;
+}
+
+
+double FutureGammaPi0SeparationTool::photonDiscriminant(int area,
+                                                  double r2, double r2r4, double asym,
+                                                  double kappa, double Eseed, double E2,
+                                                  double r2PS, double asymPS, double eMaxPS, double e2ndPS,
+                                                  int multiPS, int multiPS15, int multiPS30, int multiPS45)
+{
+        std::vector<double> input = {
+                            r2,
+                            r2r4,
+                            std::abs(asym),
+                            kappa,
+                            Eseed, //already divided by Ecl
+                            E2,    //means (e2+eseed)/ecl
+                            eMaxPS,//divided by Esum
+                            e2ndPS,//divided by Esum
+                            r2PS,
+                            std::abs(asymPS),
+                            double(multiPS),
+                            double(multiPS15),
+                            double(multiPS30),
+                            double(multiPS45) };
+
+        double value = ( area == 0 ? m_reader0->GetMvaValue(input)
+                       : area == 1 ? m_reader1->GetMvaValue(input)
+                       : area == 2 ? m_reader2->GetMvaValue(input)
+                       : -1e10 );
+        //info() << " INPUT TO GAMMA/PI0 : NN[" << input << "]= " << value << " (area="<<area<<")"<< endmsg;
+        return value;
+}
diff --git a/CaloFuture/CaloFutureTools/src/FutureGammaPi0SeparationTool.h b/CaloFuture/CaloFutureTools/src/FutureGammaPi0SeparationTool.h
new file mode 100644
index 0000000000000000000000000000000000000000..d4e13cbac08e992975ba1ff0da566a9d053419f7
--- /dev/null
+++ b/CaloFuture/CaloFutureTools/src/FutureGammaPi0SeparationTool.h
@@ -0,0 +1,93 @@
+#ifndef FUTUREGAMMAPI0SEPARATIONTOOL_H
+#define FUTUREGAMMAPI0SEPARATIONTOOL_H 1
+
+// Include files
+// from Gaudi
+#include "GaudiAlg/GaudiTool.h"
+#include "CaloDet/DeCalorimeter.h"
+#include "CaloFutureInterfaces/IFutureGammaPi0SeparationTool.h"
+
+// Math
+#include "GaudiKernel/Point3DTypes.h"
+#include "GaudiKernel/Vector3DTypes.h"
+#include "LHCbMath/Line.h"
+#include "LHCbMath/GeomFun.h"
+
+//using namespace LHCb;
+
+#include "TMV_MLP_inner.C"
+#include "TMV_MLP_middle.C"
+#include "TMV_MLP_outer.C"
+
+
+/** @class FutureGammaPi0SeparationTool FutureGammaPi0SeparationTool.h
+ *
+ *
+ *  @author Miriam Calvo Gomez
+ *  @date   2010-03-29
+ */
+
+class FutureGammaPi0SeparationTool : public extends<GaudiTool, IFutureGammaPi0SeparationTool>{
+public:
+
+  /// Standard constructor
+  FutureGammaPi0SeparationTool( const std::string& type,
+                          const std::string& name,
+                          const IInterface* parent);
+
+  StatusCode initialize() override;
+  StatusCode finalize() override;
+
+  //double isPhoton(const LHCb::Particle* gamma);
+  double isPhoton(const LHCb::CaloHypo* hypo) override;
+
+  bool ClusterVariables(const LHCb::CaloHypo* hypo,
+                        double& fr2, double& fasym, double& fkappa, double& fr2r4, double& etot,
+                        double& Eseed, double& E2, int& area) override;
+
+  bool PrsVariables(const LHCb::CaloHypo* hypo,
+                    double& r2PS, double& asymPS, double& kappaPS, double& r2r4PS,
+                    double& eSumPS, double& ePrs, double& eMaxPS, double& e2ndPS, double& ecornerPS,
+                    int& multiPS, int& multiPS15, int& multiPS30, int& multiPS45) override;
+
+  double inputData(std::string data) override { //@TODO: const-ify
+    // try ecal data
+    auto it = m_data.find(data);
+    if( it != m_data.end() )return it->second;
+    // else try prs data :
+    auto itp = m_prsdata.find(data);
+    if( itp != m_prsdata.end() )return itp->second;
+    // yapa
+    return 0.;
+  }
+  std::map<std::string,double> inputDataMap() override {return m_data;}
+  std::map<std::string,double> inputPrsDataMap() override {return m_prsdata;}
+  double isPhoton(const double* v) override {
+    return photonDiscriminant(int(v[0]),
+                              v[1],v[2],v[3],
+                              v[4],v[5],v[6],
+                              v[7],v[8],v[9],v[10],
+                              int(v[11]),int(v[12]),int(v[13]),int(v[14]));
+  }
+
+private:
+
+  Gaudi::Property<float> m_minPt {this, "MinPt", 2000.};
+
+  std::unique_ptr<IClassifierReader> m_reader0;
+  std::unique_ptr<IClassifierReader> m_reader1;
+  std::unique_ptr<IClassifierReader> m_reader2;
+
+  const DeCalorimeter* m_ecal = nullptr;
+
+  double photonDiscriminant(int area,
+                            double r2, double r2r4, double asym,
+                            double kappa, double Eseed, double E2,
+                            double r2PS, double asymPS, double eMaxPS, double e2ndPS,
+                            int multiPS, int multiPS15, int multiPS30, int multiPS45);
+
+  std::map<std::string,double> m_data;
+  std::map<std::string,double> m_prsdata;
+  double m_def = -1.e+06;
+};
+#endif // FUTUREGAMMAPI0SEPARATIONTOOL_H
diff --git a/CaloFuture/CaloFutureTools/src/FutureGammaPi0XGBoostTool.cpp b/CaloFuture/CaloFutureTools/src/FutureGammaPi0XGBoostTool.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e94d6fe4521bd8edd2fef2ce35d3036deb019e08
--- /dev/null
+++ b/CaloFuture/CaloFutureTools/src/FutureGammaPi0XGBoostTool.cpp
@@ -0,0 +1,216 @@
+// Include files
+
+#include "CaloFutureUtils/CaloMomentum.h"
+#include "CaloFutureUtils/CaloFutureAlgUtils.h"
+// from Event
+#include "Event/RecHeader.h"
+#include "Event/CaloHypo.h"
+#include "Event/CaloCluster.h"
+#include <unordered_map>
+#include <iostream>
+#include <iomanip>
+#include <string>
+#include <cstdlib>
+
+// local
+#include "FutureGammaPi0XGBoostTool.h"
+#include <fstream>
+
+using namespace LHCb;
+using namespace Gaudi::Units;
+//-----------------------------------------------------------------------------
+// Implementation file for class : FutureGammaPi0XGBoostTool
+//
+// 2018-03-24 : author @sayankotor
+//-----------------------------------------------------------------------------
+
+//Declare nessesary help functionality
+namespace {
+
+size_t getClusterType (const CaloCellID& id) {
+
+  const int CaloFutureNCol[4] = {64, 32, 16, 16};
+  const int CaloFutureNRow[4] = {52, 20, 12, 12};
+  const unsigned Granularity[3] = {1, 2, 3};
+
+  const unsigned ClusterSize = 5;
+  int type (id.area());
+  int xOffsetOut = std::min (int(id.col() - (32 - CaloFutureNCol[type]*Granularity[type]/2)), // left edge
+                 int(31 + CaloFutureNCol[type]*Granularity[type]/2 - id.col())); // right edge
+  int yOffsetOut = std::min (int(id.row() - (32 - CaloFutureNRow[type]*Granularity[type]/2)),
+                 int(31 + CaloFutureNRow[type]*Granularity[type]/2 - id.row()));
+  int innerWidth = CaloFutureNCol[type+1] * (type != 2 ? Granularity[type] : 1); // process inner hole specially
+  int innerHeight = CaloFutureNRow[type+1] * (type != 2 ? Granularity[type] : 1); // process inner hole specially
+
+  int xOffsetIn = std::min (int(id.col() - (31 - innerWidth/2)),
+                int(32 + innerWidth/2 - id.col()));
+  int yOffsetIn = std::min (int(id.row() - (31 - innerHeight/2)),
+                int(32 + innerHeight/2 - id.row()));
+  const int margin = (ClusterSize-1)/2;
+  bool outerBorder = xOffsetOut < margin || yOffsetOut < margin;
+  bool innerBorder = xOffsetIn > -margin && yOffsetIn > -margin;
+  if (innerBorder) return type+3;
+  else if (outerBorder) return type+6;
+  return type;
+}
+
+}
+
+// Declaration of the Tool Factory
+DECLARE_COMPONENT( FutureGammaPi0XGBoostTool )
+
+//=============================================================================
+// Initialization
+//=============================================================================
+StatusCode FutureGammaPi0XGBoostTool::initialize() {
+
+  StatusCode sc = base_class::initialize(); // must be executed first
+  if ( sc.isFailure() ) return sc;  // error printed already by GaudiAlgorithm
+
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) debug() << "==> Initialize" << endmsg;
+
+  /// Retrieve geometry of detector
+  m_ecal = getDet<DeCalorimeter>( DeCalorimeterLocation::Ecal );
+
+
+  const std::string paramEnv = "PARAMFILESROOT";   
+  std::string paramRoot = std::string(getenv(paramEnv.c_str()));    
+
+  m_xgb0 = std::make_unique<FutureXGBClassifierPhPi0>(paramRoot + "/data/GammaPi0XgbTool_simpl0.model");
+  m_xgb1 = std::make_unique<FutureXGBClassifierPhPi0>(paramRoot + "/data/GammaPi0XgbTool_simpl1.model");
+  m_xgb2 = std::make_unique<FutureXGBClassifierPhPi0>(paramRoot + "/data/GammaPi0XgbTool_simpl2.model");
+  m_xgb03_b = std::make_unique<FutureXGBClassifierPhPi0>(paramRoot + "/data/GammaPi0XgbTool_bound03.model");
+  m_xgb06_b = std::make_unique<FutureXGBClassifierPhPi0>(paramRoot + "/data/GammaPi0XgbTool_bound06.model");
+  m_xgb14_b = std::make_unique<FutureXGBClassifierPhPi0>(paramRoot + "/data/GammaPi0XgbTool_bound14.model");
+  m_xgb17_b = std::make_unique<FutureXGBClassifierPhPi0>(paramRoot + "/data/GammaPi0XgbTool_bound17.model");
+  m_xgb25_b = std::make_unique<FutureXGBClassifierPhPi0>(paramRoot + "/data/GammaPi0XgbTool_bound25.model");
+  m_xgb28_b = std::make_unique<FutureXGBClassifierPhPi0>(paramRoot + "/data/GammaPi0XgbTool_bound28.model");
+
+  return StatusCode::SUCCESS;
+}
+
+//=============================================================================
+//  Finalize
+//=============================================================================
+StatusCode FutureGammaPi0XGBoostTool::finalize() {
+
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) debug() << "==> Finalize" << endmsg;
+
+  m_xgb0.reset();
+  m_xgb1.reset();
+  m_xgb2.reset();
+  m_xgb03_b.reset();
+  m_xgb06_b.reset();
+  m_xgb14_b.reset();
+  m_xgb17_b.reset();
+  m_xgb25_b.reset();
+  m_xgb28_b.reset();
+
+  return base_class::finalize(); // must be executed last
+}
+
+//=============================================================================
+// Main execution
+//=============================================================================
+
+
+double FutureGammaPi0XGBoostTool::isPhoton(const LHCb::CaloHypo* hypo){
+
+  if ( !m_ecal ) return m_def;
+  if ( LHCb::CaloMomentum(hypo).pt() < m_minPt) return m_def;
+  const LHCb::CaloCluster* cluster = LHCb::CaloFutureAlgUtils::ClusterFromHypo( hypo );
+  if (!cluster) return m_def;
+
+  std::vector<double> rawEnergyVector(25, 0.0);
+
+  int cluster_type = getClusterType(cluster->seed());
+  bool rawEnergy = GetRawEnergy(hypo, cluster_type, rawEnergyVector);
+
+  if(!rawEnergy) return m_def;
+  
+  double prediction_xgb = XGBDiscriminant(cluster_type, rawEnergyVector);
+  return prediction_xgb;
+}
+
+
+double FutureGammaPi0XGBoostTool::XGBDiscriminant(int cluster_type, std::vector<double>& row_energies)
+{
+
+        double value = -1e10;
+        switch (cluster_type) {
+            case 0: value = m_xgb0->getClassifierValues(row_energies);
+                    break;
+            case 1: value = m_xgb1->getClassifierValues(row_energies);
+                    break;
+            case 2: value = m_xgb2->getClassifierValues(row_energies);
+                    break;
+            case 3: value = m_xgb03_b->getClassifierValues(row_energies);
+                    break;
+            case 4: value = m_xgb14_b->getClassifierValues(row_energies);
+                    break;
+            case 5: value = m_xgb25_b->getClassifierValues(row_energies);
+                    break;
+            case 6: value = m_xgb06_b->getClassifierValues(row_energies);
+                    break;
+            case 7: value = m_xgb17_b->getClassifierValues(row_energies);
+                    break;
+            case 8: value = m_xgb28_b->getClassifierValues(row_energies);
+                    break;
+            default: warning() << "FutureGammaPi0XGBoostTool: Unsupperted cluster type" << endmsg;
+
+        }
+        return value;
+}
+
+bool FutureGammaPi0XGBoostTool::GetRawEnergy(const LHCb::CaloHypo* hypo, int& cluster_type, std::vector<double>& rowEnergy) const{
+  if( nullptr == hypo)return false;
+
+  const LHCb::CaloDigits * digits_full = getIfExists<LHCb::CaloDigits>(LHCb::CaloDigitLocation::Ecal);
+  const LHCb::CaloCluster* cluster = LHCb::CaloFutureAlgUtils::ClusterFromHypo( hypo );   // OD 2014/05 - change to Split Or Main  cluster
+  
+  if( nullptr == digits_full || nullptr == cluster) return false;
+  
+  LHCb::CaloCellID centerID = cluster->seed();
+
+  std::vector<std::vector<double>> vector_cells (5, std::vector<double>(5, 0.0));
+  
+  std::vector<int> col_numbers = {(int)centerID.col() - 2, (int)centerID.col() - 1, (int)centerID.col(), (int)centerID.col() + 1, (int)centerID.col() + 2};
+  std::vector<int> row_numbers = {(int)centerID.row() - 2, (int)centerID.row() - 1, (int)centerID.row(), (int)centerID.row() + 1, (int)centerID.row() + 2};
+
+  if (cluster_type > 2)
+  {
+    for (auto& col_number: col_numbers){
+        for (auto& row_number: row_numbers){
+            const auto id_ = LHCb::CaloCellID(centerID.calo(), centerID.area(), row_number, col_number);
+            auto * test = digits_full->object(id_);
+            if (test) {
+                vector_cells[col_number - (int)centerID.col() + 2][row_number - (int)centerID.row() + 2] = test->e();
+            } else {
+                continue;
+            }
+        }
+    }
+  }
+
+  else 
+  { 
+    for (auto& col_number: col_numbers){
+        for (auto& row_number: row_numbers){
+            const auto id_ = LHCb::CaloCellID(centerID.calo(), centerID.area(), row_number, col_number);
+            auto * test = digits_full->object(id_);
+            if (test) {
+                vector_cells[col_number - (int)centerID.col() + 2][row_number - (int)centerID.row() + 2] = test->e();
+            } else {
+                continue;
+            }
+        }
+    }
+  }
+
+  for (int i = 0; i < 5; i++){
+      for (int j = 0; j < 5; j++){
+      rowEnergy[i*5 + j] = vector_cells[i][j];
+    }
+  }
+  return true;
+}
diff --git a/CaloFuture/CaloFutureTools/src/FutureGammaPi0XGBoostTool.h b/CaloFuture/CaloFutureTools/src/FutureGammaPi0XGBoostTool.h
new file mode 100644
index 0000000000000000000000000000000000000000..4a26ee010687de605c320a0a63fcca0220b737c5
--- /dev/null
+++ b/CaloFuture/CaloFutureTools/src/FutureGammaPi0XGBoostTool.h
@@ -0,0 +1,87 @@
+#ifndef FutureGammaPi0XGBoostTool_H
+#define FutureGammaPi0XGBoostTool_H
+
+// Include files
+// from Gaudi
+#include "GaudiAlg/GaudiTool.h"
+#include "CaloDet/DeCalorimeter.h"
+#include "CaloFutureInterfaces/IFutureGammaPi0SeparationTool.h"
+
+// Math
+#include "GaudiKernel/Point3DTypes.h"
+#include "GaudiKernel/Vector3DTypes.h"
+#include "LHCbMath/Line.h"
+#include "LHCbMath/GeomFun.h"
+
+//using xgb in c++
+
+#include "FutureXGBClassifierPhPi0.h"
+
+
+/** @class FutureGammaPi0XGBoostTool FutureGammaPi0XGBoostTool.h
+ *
+ *
+ *  @author @sayankotor
+ *  @date   2018-03-24
+ */
+
+
+class FutureGammaPi0XGBoostTool : public extends<GaudiTool, IFutureGammaPi0SeparationTool>{
+
+
+public:
+
+  FutureGammaPi0XGBoostTool( const std::string& type,
+                       const std::string& name,
+                       const IInterface* parent):base_class ( type, name , parent ){};
+  StatusCode initialize() override;
+  StatusCode finalize() override;
+
+  //double isPhoton(const LHCb::Particle* gamma);
+  double isPhoton(const LHCb::CaloHypo* hypo) override;
+
+  bool GetRawEnergy(const LHCb::CaloHypo* hypo, int& cluster_type, std::vector<double>& rowEnergy) const;
+  std::vector<std::vector<double>> GetCluster(const LHCb::CaloCellID & centerID, const LHCb::CaloDigits * digits_full) const;
+
+  double inputData(std::string) override { //@TODO: const-ify
+    /* // try ecal data */
+    /* auto it = m_data.find(data); */
+    /* if( it != m_data.end() )return it->second; */
+    /* // else try prs data : */
+    /* auto itp = m_prsdata.find(data); */
+    /* if( itp != m_prsdata.end() )return itp->second; */
+    /* // yapa */
+    return 0.;
+  }
+  
+  std::map<std::string,double> inputDataMap() override {return std::map<std::string,double>();}
+  std::map<std::string,double> inputPrsDataMap() override {return std::map<std::string,double>();}
+  bool ClusterVariables(const LHCb::CaloHypo*, double&, double&, double&, double&, double&, 
+      double&, double&, int&) override {return true;} 
+  bool PrsVariables(const LHCb::CaloHypo*, double&, double&, double&, double&,
+        double&, double&, double&, double&, double&, 
+        int&, int&, int&, int&) override {return true;}
+  double isPhoton(const double*) override {return 0.0;};
+
+private:
+
+  Gaudi::Property<float> m_minPt {this, "MinPt", 2000.};
+
+  std::unique_ptr<FutureXGBClassifierPhPi0> m_xgb0;
+  std::unique_ptr<FutureXGBClassifierPhPi0> m_xgb1;
+  std::unique_ptr<FutureXGBClassifierPhPi0> m_xgb2;
+  std::unique_ptr<FutureXGBClassifierPhPi0> m_xgb03_b;
+  std::unique_ptr<FutureXGBClassifierPhPi0> m_xgb14_b;
+  std::unique_ptr<FutureXGBClassifierPhPi0> m_xgb25_b;
+  std::unique_ptr<FutureXGBClassifierPhPi0> m_xgb06_b;
+  std::unique_ptr<FutureXGBClassifierPhPi0> m_xgb17_b;
+  std::unique_ptr<FutureXGBClassifierPhPi0> m_xgb28_b;
+
+  const DeCalorimeter* m_ecal = nullptr;
+
+
+  double XGBDiscriminant(int cluster_type, std::vector<double>& row_energies);
+
+  const double m_def = -1.e+06;
+};
+#endif // FutureGammaPi0XGBoostTool_H
\ No newline at end of file
diff --git a/CaloFuture/CaloFutureTools/src/FutureNeutralIDTool.cpp b/CaloFuture/CaloFutureTools/src/FutureNeutralIDTool.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d4fd6c0d7aed95ff5dbac042c6ed4014032ee44c
--- /dev/null
+++ b/CaloFuture/CaloFutureTools/src/FutureNeutralIDTool.cpp
@@ -0,0 +1,275 @@
+// Include files
+
+// from Gaudi
+#include "CaloFutureUtils/CaloMomentum.h"
+#include "CaloFutureUtils/CaloFutureAlgUtils.h"
+// from Event
+#include "Event/RecHeader.h"
+#include "Event/CaloHypo.h"
+#include "Event/CaloCluster.h"
+
+// local
+#include "FutureNeutralIDTool.h"
+
+
+using namespace LHCb;
+using namespace Gaudi::Units;
+
+//-----------------------------------------------------------------------------
+// Implementation file for class : FutureNeutralIDTool
+//
+// 2013-07-25 : Mostafa HOBALLAH
+//-----------------------------------------------------------------------------
+
+// Declaration of the Tool Factory
+DECLARE_COMPONENT( FutureNeutralIDTool )
+
+
+//=============================================================================
+// Standard constructor, initializes variables
+//=============================================================================
+FutureNeutralIDTool::FutureNeutralIDTool( const std::string& type,
+                                                const std::string& name,
+                                                const IInterface* parent )
+  : GaudiTool ( type, name , parent )
+{
+  declareInterface<IFutureNeutralIDTool>(this);
+}
+
+//=============================================================================
+// Initialization
+//=============================================================================
+StatusCode FutureNeutralIDTool::initialize() {
+
+  StatusCode sc = GaudiTool::initialize(); // must be executed first
+  if ( sc.isFailure() ) return sc;  // error printed already by GaudiAlgorithm
+
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) debug() << "==> Initialize" << endmsg;
+
+
+  // TMVA discriminant
+  std::vector<std::string> inputVars;
+
+  inputVars.push_back("TMath::TanH(CaloHypo_ClusterMatch/2000)");
+  inputVars.push_back("CaloHypo_ToPrsE");
+  inputVars.push_back("CaloHypo_E19");
+  inputVars.push_back("CaloHypo_Hcal2Ecal");
+  inputVars.push_back("CaloHypo_PrsE19");
+  inputVars.push_back("CaloHypo_PrsE49");
+  inputVars.push_back("CaloHypo_Spread");
+  inputVars.push_back("CaloHypo_PrsE4Max");
+  inputVars.push_back("CaloHypo_HypoPrsM");
+  inputVars.push_back("CaloHypo_HypoSpdM");
+
+  std::vector<std::string> inputVars1;
+
+  inputVars1.push_back("CaloHypo_ClusterMatch");
+  inputVars1.push_back("CaloHypo_ToPrsE");
+  inputVars1.push_back("CaloHypo_E19");
+  inputVars1.push_back("CaloHypo_Hcal2Ecal");
+  inputVars1.push_back("CaloHypo_PrsE19");
+  inputVars1.push_back("CaloHypo_PrsE49");
+  inputVars1.push_back("CaloHypo_Spread");
+  inputVars1.push_back("CaloHypo_PrsE4Max");
+  inputVars1.push_back("CaloHypo_HypoPrsM");
+  inputVars1.push_back("CaloHypo_HypoSpdM");
+
+
+
+  m_reader1 = std::make_unique<ReadMLPH>(inputVars);
+  m_reader0 = std::make_unique<ReadMLPE>(inputVars1);
+
+
+  return StatusCode::SUCCESS;
+
+}
+
+//=============================================================================
+//  Finalize
+//=============================================================================
+StatusCode FutureNeutralIDTool::finalize() {
+
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) debug() << "==> Finalize" << endmsg;
+  StatusCode sc = GaudiTool::finalize(); // must be executed first
+
+  m_reader0.reset();
+  m_reader1.reset();
+
+
+  return sc;
+}
+
+//=============================================================================
+// Main execution
+//=============================================================================
+
+
+double FutureNeutralIDTool::isNotE(const LHCb::CaloHypo* hypo,ICaloFutureHypoEstimator* estimator){
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+    debug()<<"Inside NeutralID ------"<<endmsg;
+
+  if( estimator != NULL)m_estimator=estimator;
+
+  double pt = LHCb::CaloMomentum(hypo).pt();
+
+  double tmva_outputE = CaloFutureDataType::Default;
+
+  if (pt>m_minPt){
+
+    double clmatch = 0;
+    double prse = 0;
+    double e19 = 0;
+    double hclecl = 0;
+    double prse19 = 0;
+    double prse49 = 0;
+    double sprd = 0;
+    double prse4mx = 0;
+    double prsm = 0;
+    double spdm = 0;
+
+
+
+    const LHCb::CaloCluster* cluster = LHCb::CaloFutureAlgUtils::ClusterFromHypo( hypo , false);
+    if (cluster!=0){
+
+      Variables(hypo,clmatch,prse, e19, hclecl,prse19,prse49, sprd, prse4mx, prsm, spdm);
+
+      tmva_outputE = photonDiscriminantE(clmatch, prse, e19, hclecl, prse19,prse49, sprd, prse4mx, prsm, spdm);
+
+    }//cluster exists
+    else{
+      tmva_outputE = CaloFutureDataType::Default;
+    }
+  }
+  else{
+    tmva_outputE = CaloFutureDataType::Default;
+    if( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+      debug()<<"Outside range of pt"<<endmsg;
+  }
+
+  return tmva_outputE;
+}
+
+double FutureNeutralIDTool::isNotH(const LHCb::CaloHypo* hypo,ICaloFutureHypoEstimator* estimator){
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+    debug()<<"Inside NeutralID ------"<<endmsg;
+
+  if( estimator != NULL)m_estimator=estimator;
+
+
+  double pt = LHCb::CaloMomentum(hypo).pt();
+
+  double tmva_outputH = CaloFutureDataType::Default;
+
+  if (pt>m_minPt){
+
+    double clmatch = 0;
+    double prse = 0;
+    double e19 = 0;
+    double hclecl = 0;
+    double prse19 = 0;
+    double prse49 = 0;
+    double sprd = 0;
+    double prse4mx = 0;
+    double prsm = 0;
+    double spdm = 0;
+
+    const LHCb::CaloCluster* cluster = LHCb::CaloFutureAlgUtils::ClusterFromHypo( hypo , false);
+    if (cluster!=0){
+      Variables(hypo,clmatch,prse, e19, hclecl,prse19,prse49, sprd, prse4mx, prsm, spdm);
+
+      tmva_outputH = photonDiscriminantH(clmatch, prse, e19, hclecl, prse19,prse49, sprd, prse4mx, prsm, spdm);
+
+    }//cluster exists
+    else{
+      tmva_outputH = CaloFutureDataType::Default;
+    }
+  }
+  else{
+    tmva_outputH = CaloFutureDataType::Default;
+    if( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+      debug()<<"Outside range of pt"<<endmsg;
+  }
+
+  return tmva_outputH;
+}
+
+
+
+double FutureNeutralIDTool::photonDiscriminantE(double clmatch, double prse, double e19, double hclecl, double prse19,
+                                         double prse49, double sprd, double prse4mx, double prsm, double spdm) {
+
+
+        std::vector<double> input;
+
+        input.push_back(tanh(clmatch/2000));
+        input.push_back(prse);
+        input.push_back(e19);
+        input.push_back(hclecl);
+        input.push_back(prse19);
+        input.push_back(prse49);
+        input.push_back(sprd);
+        input.push_back(prse4mx);
+        input.push_back(prsm);
+        input.push_back(spdm);
+
+        double valueE = -1e10;
+        valueE = m_reader0->GetMvaValue(input);
+
+
+        return valueE;
+}
+
+
+
+
+double FutureNeutralIDTool::photonDiscriminantH(double clmatch, double prse, double e19, double hclecl, double prse19,
+                                          double prse49, double sprd, double prse4mx, double prsm, double spdm) {
+
+
+        std::vector<double> input;
+
+        input.push_back(tanh(clmatch/2000));
+        input.push_back(prse);
+        input.push_back(e19);
+        input.push_back(hclecl);
+        input.push_back(prse19);
+        input.push_back(prse49);
+        input.push_back(sprd);
+        input.push_back(prse4mx);
+        input.push_back(prsm);
+        input.push_back(spdm);
+
+        double valueH = -1e10;
+        valueH = m_reader1->GetMvaValue(input);
+
+
+        return valueH;
+}
+
+
+
+void FutureNeutralIDTool::Variables(const LHCb::CaloHypo* hypo,  double& clmatch, double& prse,
+                             double& e19, double& hclecl, double& prse19,double& prse49, double& sprd, double& prse4mx,
+                             double& prsm, double& spdm) {
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+    debug()<<"Inside Variables ------"<<endmsg;
+
+  using namespace CaloFutureDataType;
+
+  // load the estimator tool only when not passed in argument (to avoid circular initialization with the estimator itself)
+  if( m_estimator == NULL)m_estimator = tool<ICaloFutureHypoEstimator>("CaloFutureHypoEstimator","CaloFutureHypoEstimatorForNeutralID",this);
+
+  clmatch =   m_estimator->data(hypo ,  ClusterMatch ,0.);
+  prse    =   m_estimator->data(hypo ,  ToPrsE ,0.);
+  e19     =   m_estimator->data(hypo ,  E19 ,0.);
+  hclecl  =   m_estimator->data(hypo ,  Hcal2Ecal ,0.);
+  prse19  =   m_estimator->data(hypo ,  PrsE19 ,0.);
+  prse49  =   m_estimator->data(hypo ,  PrsE49 ,0.);
+  sprd    =   m_estimator->data(hypo ,  Spread ,0.);
+  prse4mx =   m_estimator->data(hypo ,  PrsE4Max ,0.);
+  prsm    =   m_estimator->data(hypo ,  HypoPrsM ,0.);
+  spdm    =   m_estimator->data(hypo ,  HypoSpdM ,0.);
+
+}
+
diff --git a/CaloFuture/CaloFutureTools/src/FutureNeutralIDTool.h b/CaloFuture/CaloFutureTools/src/FutureNeutralIDTool.h
new file mode 100644
index 0000000000000000000000000000000000000000..8a1695b84c868bde3ba56e5eafaa66c2a9cf9d49
--- /dev/null
+++ b/CaloFuture/CaloFutureTools/src/FutureNeutralIDTool.h
@@ -0,0 +1,79 @@
+// $Id: $
+#ifndef FUTURENEUTRALIDTOOL_H
+#define FUTURENEUTRALIDTOOL_H 1
+
+// Include files
+// from Gaudi
+#include "GaudiAlg/GaudiTool.h"
+#include "CaloDet/DeCalorimeter.h"
+#include "CaloFutureInterfaces/IFutureNeutralIDTool.h"
+#include "CaloFutureInterfaces/ICaloFutureHypoEstimator.h"
+// Math
+#include "GaudiKernel/Point3DTypes.h"
+#include "GaudiKernel/Vector3DTypes.h"
+#include "LHCbMath/Line.h"
+#include "LHCbMath/GeomFun.h"
+
+//using namespace LHCb;
+
+#include "TMV_MLP_H.C"
+#include "TMV_MLP_E.C"
+
+/** @class neutralIDTool neutralIDTool.h
+ *
+ *
+ *  @author Mostafa HOBALLAH
+ *  @date   2013-07-25
+ */
+class FutureNeutralIDTool : public GaudiTool, virtual public IFutureNeutralIDTool{
+public:
+
+  // Return the interface ID
+  //  static const InterfaceID& interfaceID() { return IID_FutureNeutralIDTool; }
+
+  /// Standard constructor
+  FutureNeutralIDTool( const std::string& type,
+                          const std::string& name,
+                          const IInterface* parent);
+
+  StatusCode initialize() override;
+  StatusCode finalize() override;
+
+  //double isPhoton(const LHCb::Particle* gamma);
+  double isNotE(const LHCb::CaloHypo* hypo,ICaloFutureHypoEstimator* e=NULL) override;
+  double isNotH(const LHCb::CaloHypo* hypo,ICaloFutureHypoEstimator* e=NULL) override;
+  void Variables(const LHCb::CaloHypo* hypo, double& clmatch,
+                         double& prse, double& e19, double& hclecl, double& prse19,double& prse49,
+                         double& sprd, double& prse4mx, double& prsm, double& spdm) override;
+
+
+  double isNotE(const double* v) override {
+    return photonDiscriminantE(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9]);
+  }
+  double isNotH(const double* v) override {
+    return photonDiscriminantH(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9]);
+  }
+
+private:
+
+  Gaudi::Property<float> m_minPt {this, "MinPt", 75.};
+
+  std::unique_ptr<IClassifierReader> m_reader0;
+  std::unique_ptr<IClassifierReader> m_reader1;
+
+
+
+  //Gaudi::XYZPoint m_vertex;
+  //Gaudi::Plane3D m_planePrs;
+
+  double photonDiscriminantE(double clmatch, double prse, double e19, double hclecl, double prse19,
+                             double prse49, double sprd, double prse4mx, double prsm, double spdm);
+
+  double photonDiscriminantH(double clmatch, double prse, double e19, double hclecl, double prse19,
+                              double prse49, double sprd, double prse4mx, double prsm, double spdm);
+
+
+  ICaloFutureHypoEstimator* m_estimator = nullptr;
+
+};
+#endif // FUTURENEUTRALIDTOOL_H
diff --git a/CaloFuture/CaloFutureTools/src/FutureXGBClassifierPhPi0.cpp b/CaloFuture/CaloFutureTools/src/FutureXGBClassifierPhPi0.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ff885ffa015462aec106c50c1773618f3960037a
--- /dev/null
+++ b/CaloFuture/CaloFutureTools/src/FutureXGBClassifierPhPi0.cpp
@@ -0,0 +1,76 @@
+#include "FutureXGBClassifierPhPi0.h"
+#include <iostream>
+#include <exception>
+
+
+FutureXGBClassifierPhPi0::FutureXGBClassifierPhPi0()
+{
+  XGDMatrixCreateFromMat(
+      &m_predictionsCache.at(0),
+      1,
+      2,
+      0.5,
+      &m_cache_matrix);
+}
+
+FutureXGBClassifierPhPi0::FutureXGBClassifierPhPi0(const std::string& path)
+{
+  xgb_path = path;
+  //std::cout<<"PATH str: "<< xgb_path << std::endl;
+  XGDMatrixCreateFromMat(
+      &m_predictionsCache.at(0),
+      1,
+      2,
+      0.5,
+      &m_cache_matrix);
+  XGBoosterCreate(&m_cache_matrix, 1, &m_booster);
+  int err_code = XGBoosterLoadModel(m_booster, xgb_path.c_str());
+  if (err_code == -1){
+    log << MSG::WARNING << "Do not load XGBModel " << endmsg;
+  }
+}
+
+void FutureXGBClassifierPhPi0::setPath(const std::string& path)
+{
+  XGBoosterCreate(&m_cache_matrix, 1, &m_booster);
+  try{
+    XGBoosterLoadModel(m_booster, path.c_str());
+  }
+  catch(const std::exception& e){
+    log << MSG::WARNING  << "Standard exception " << endmsg;
+  }
+}
+
+double FutureXGBClassifierPhPi0::getClassifierValues(const std::vector<double>& featureValues)
+{
+  // currently XGBoost only supports float
+  std::vector<float> features_f(featureValues.begin(), featureValues.end());
+
+  // fill the feature vector into a XGBoost DMatrix
+  XGDMatrixCreateFromMat(&features_f.at(0),
+                         1,
+                         features_f.size(),
+                         0,
+                         &m_feature_matrix);
+
+  // XGBoost returns the predictions into a arrayish object and return
+  // its size
+  unsigned long predictions_length;
+  const float *predictions;
+  try{
+  XGBoosterPredict(m_booster,
+                   m_feature_matrix,
+                   0,
+                   0,
+                   &predictions_length,
+                   &predictions);
+  }
+  catch(...){
+    log << MSG::WARNING << "some exeption " << endmsg;
+  }
+  std::vector<double> vec_predictions;
+  for (unsigned int i =0; i<predictions_length; i++){
+      vec_predictions.push_back(predictions[i]);
+  }
+    return vec_predictions[0];
+}
\ No newline at end of file
diff --git a/CaloFuture/CaloFutureTools/src/FutureXGBClassifierPhPi0.h b/CaloFuture/CaloFutureTools/src/FutureXGBClassifierPhPi0.h
new file mode 100644
index 0000000000000000000000000000000000000000..a5f6ce917fa5e13116b82832492b8bd2b7bdb3ca
--- /dev/null
+++ b/CaloFuture/CaloFutureTools/src/FutureXGBClassifierPhPi0.h
@@ -0,0 +1,43 @@
+#ifndef XGBCLASSIFIER_H
+#define XGBCLASSIFIER_H
+
+#include <string>
+#include <vector>
+#include "xgboost/c_api.h"
+#include "GaudiKernel/ServiceHandle.h"
+#include "GaudiKernel/IMessageSvc.h"
+#include "GaudiKernel/MsgStream.h" 
+//#include "/afs/cern.ch/user/v/vchekali/public/xgboost/include/xgboost/c_api.h"
+
+class IClassifier
+{
+public:
+
+    /**    * @brief      Main classification method    *
+           * Takes a vector of values of features and returns the corresponding MVA
+           * output.
+           *    * @param[in]  featureValues  A vector of feature values
+           *    * @return     MVA classifier value    */
+    virtual double getClassifierValues(const std::vector<double>& featureValues) = 0;
+};
+
+class FutureXGBClassifierPhPi0 : public IClassifier {
+  public:
+    FutureXGBClassifierPhPi0();
+    FutureXGBClassifierPhPi0(const std::string& path);
+    double getClassifierValues(const std::vector<double>& featureValues) override;
+    void setPath(const std::string& path);
+    ServiceHandle<IMessageSvc> msgh = ServiceHandle<IMessageSvc>("MessageSvc","XGBLog");
+    MsgStream log = MsgStream(&(*msgh), "XGBLog");
+
+  private:
+    std::string xgb_path ="def_path";
+    std::vector<float> m_predictionsCache = {0, 0};
+    DMatrixHandle m_cache_matrix,
+                  m_feature_matrix;
+    BoosterHandle m_booster;
+
+};
+
+
+#endif // XGBCLASSIFIER_H
diff --git a/CaloFuture/CaloFutureTools/src/L0CaloFuture2CaloFutureTool.cpp b/CaloFuture/CaloFutureTools/src/L0CaloFuture2CaloFutureTool.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..633ba6f7e02e8c70293fb16551e0ebe31559dcb1
--- /dev/null
+++ b/CaloFuture/CaloFutureTools/src/L0CaloFuture2CaloFutureTool.cpp
@@ -0,0 +1,344 @@
+#include "CaloFutureInterfaces/ICaloFutureClusterization.h"
+#include "L0CaloFuture2CaloFutureTool.h"
+#include "CaloKernel/CaloVector.h"
+#include "CaloDet/DeCalorimeter.h"
+#include "CaloFutureUtils/CaloFutureNeighbours.h"
+#include "Event/L0DUBase.h"
+
+#include <boost/functional/hash.hpp>
+
+/** @class L0CaloFuture2CaloFutureTool L0CaloFuture2CaloFutureTool.cpp
+ *
+ * Tool to get a list of CaloFutureClusters (owned by TES) in the vicinity of
+ * the input L0CaloFutureCandidate(s), if necessary invoking decoding and clusterization.
+ *
+ *  @author Dmitry Goloubkov
+ *  @date   2009-07-29
+ */
+
+DECLARE_COMPONENT( L0CaloFuture2CaloFutureTool )
+
+/// Standard constructor
+L0CaloFuture2CaloFutureTool::L0CaloFuture2CaloFutureTool(const std::string& type,
+                                 const std::string& name,
+                                 const IInterface* parent)
+   : base_class ( type, name , parent )
+{
+  declareInterface<IL0CaloFuture2CaloFuture>(this);
+  m_ecalCaloFutureNum = CaloCellCode::CaloNumFromName("Ecal");
+}
+// ==========================================================================
+StatusCode L0CaloFuture2CaloFutureTool::initialize()
+{
+  StatusCode sc = base_class::initialize();
+  if (sc.isFailure()) return Error("Failed to initialize", sc);
+
+  m_calo               = getDet<DeCalorimeter>( DeCalorimeterLocation::Ecal );
+  m_clusterizationTool = tool< ICaloFutureClusterization >(m_clusterizationToolName);
+  m_dataProviderTool   = tool< ICaloFutureDataProvider >(m_dataProviderToolName, "EcalDataProvider", this, true);
+
+  info() << "Clusterizing Calo around L0 candidates : NeighbourLevel  set to " << m_neighbourLevel << endmsg;
+
+  return StatusCode::SUCCESS;
+}
+// ==========================================================================
+StatusCode L0CaloFuture2CaloFutureTool::clusterize
+  ( std::vector<LHCb::CaloCluster*>&      clusters ,
+    const LHCb::CaloCellID&               cellID,
+    const unsigned int                    level     ) const
+{
+  if ( ! isUsable( cellID ) ) return StatusCode::FAILURE;
+
+  // Invoke the CaloFutureDataProvider tool
+  const LHCb::CaloDigits* digits = makeDigits( cellID, level );
+  if ( 0 == digits ) return Error(" Failure to (re)make CaloDigits!", StatusCode::FAILURE );
+
+  // Select the right seed :
+  LHCb::CaloCellID seedID = cellID;
+  unsigned int area = cellID.area();
+  unsigned int row  = cellID.row();
+  unsigned int col  = cellID.col();
+  double dig = m_dataProviderTool->digit( cellID );
+  LHCb::CaloCellID ul(m_ecalCaloFutureNum, area, row+1, col  );
+  if( m_dataProviderTool->digit( ul ) > dig ){ dig = m_dataProviderTool->digit( ul ); seedID = ul;}
+  LHCb::CaloCellID ur(m_ecalCaloFutureNum, area, row+1, col+1);
+  if( m_dataProviderTool->digit( ur ) > dig ){ dig = m_dataProviderTool->digit( ur ); seedID = ur;}
+  LHCb::CaloCellID dr(m_ecalCaloFutureNum, area, row  , col+1);
+  if( m_dataProviderTool->digit( dr ) > dig ){ dig = m_dataProviderTool->digit( dr ); seedID = dr;}
+
+  // Invoke the CaloFutureClusterizationTool
+  StatusCode sc = makeClusters( clusters, digits, seedID, level );
+  if ( sc.isFailure() ) return Error(" Failure from the CaloFutureClusterizationTool!", sc );
+
+  return putClustersOnTES( clusters );
+}
+// ==========================================================================
+StatusCode L0CaloFuture2CaloFutureTool::clusterize
+  ( std::vector<LHCb::CaloCluster*>&      clusters,
+    const LHCb::CaloCellID&               cellID   ) const
+{
+  return clusterize( clusters, cellID, m_neighbourLevel );
+}
+
+// ==========================================================================
+StatusCode L0CaloFuture2CaloFutureTool::clusterize
+( std::vector<LHCb::CaloCluster*>&      clusters,
+  const LHCb::L0CaloCandidate*          candidate,
+  const unsigned int                    level     ) const
+{
+  if ( ! isUsable( candidate ) ) return StatusCode::FAILURE;
+
+  const LHCb::CaloCellID& cellID = candidate->id();
+  return clusterize(clusters, cellID, level);
+}
+// ==========================================================================
+StatusCode L0CaloFuture2CaloFutureTool::clusterize
+( std::vector<LHCb::CaloCluster*>&      clusters,
+  const LHCb::L0CaloCandidate*          candidates ) const
+{
+  return clusterize( clusters, candidates, m_neighbourLevel );
+}
+// ==========================================================================
+StatusCode L0CaloFuture2CaloFutureTool::makeClusters
+( std::vector<LHCb::CaloCluster*>&      clusters,
+  const LHCb::CaloDigits*               digits,
+  const LHCb::CaloCellID&               cellID,
+  const unsigned int                    level    ) const
+{
+  if ( NULL == digits ) return Error("CaloDigits == NULL (should never happen here)", StatusCode::FAILURE);
+  clusters.clear();
+
+  std::vector<LHCb::CaloCellID> seeds = { cellID };
+  m_clusterizationTool->clusterize(clusters, *digits, m_calo, seeds, level);
+
+   /** sort the sequence to simplify the comparison
+   *  with other clusterisation techniques
+   */
+  if ( m_sort ){
+    error() << " FEATURE NOT implemented! (neither Sort nor SortET)" << endmsg;
+/*
+    if ( !m_sortET )
+    {
+      // sorting criteria: Energy
+      LHCb::CaloDataFunctor::Less_by_Energy<const LHCb::CaloCluster*> Cmp;
+      // perform the sorting
+      std::stable_sort    ( clusters.begin()            ,
+                            clusters.end  ()            ,
+                            LHCb::CaloDataFunctor::inverse( Cmp ) ) ;
+    }
+    else
+    {
+      // sorting criteria : Transverse Energy
+      LHCb::CaloDataFunctor::Less_by_TransverseEnergy<const LHCb::CaloCluster*,
+        const DeCalorimeter*> Cmp ( m_detector ) ;
+      // perform the sorting
+      std::stable_sort   ( clusters.begin()            ,
+                           clusters.end  ()            ,
+                           LHCb::CaloDataFunctor::inverse( Cmp ) ) ;
+    }
+*/
+  }
+
+  return StatusCode::SUCCESS;
+}
+// ==========================================================================
+StatusCode L0CaloFuture2CaloFutureTool::putClustersOnTES( std::vector<LHCb::CaloCluster*>& clusters ) const
+{
+
+
+  if( !m_clusOnTES )return StatusCode::SUCCESS;
+
+
+  LHCb::CaloClusters* output = getOrCreate<LHCb::CaloClusters, LHCb::CaloClusters>( m_clusterLocation );
+  output -> setVersion( 2 ); // update the version number (needed for serialization)
+  if ( msgLevel(MSG::DEBUG) )
+    debug() << "0: LHCb::CaloClusters at " << m_clusterLocation << " size = " << (long) output->size()
+            << " v=" << (int) output->version() << " newly found clusters.size() = " << clusters.size() << endmsg; ///////
+
+  // populate the CaloClusters TS container
+  for ( std::vector<LHCb::CaloCluster*>::iterator icluster = clusters.begin();
+        clusters.end() != icluster; ++icluster){
+    LHCb::CaloCluster* cl  = *icluster;
+    if ( 0 == cl ) continue;
+
+    // check that cluster is not yet owned by some container
+    if ( 0 != cl->parent() ) continue;
+
+    // store everything on TES (allow duplications in case of multiple calls)
+    output -> insert ( cl ) ;
+  }
+
+  if ( msgLevel(MSG::DEBUG) ) debug() << "1: LHCb::CaloClusters at " << m_clusterLocation << " size = " << long( output->size() ) << endmsg;
+
+  return StatusCode::SUCCESS;
+}
+// ==========================================================================
+bool L0CaloFuture2CaloFutureTool::isUsable( const LHCb::CaloCellID& cellID ) const
+{
+  if ( cellID.calo() != m_ecalCaloFutureNum ){
+    if ( msgLevel(MSG::DEBUG) ) debug() << "skip non-Ecal cellID = " << cellID << endmsg;
+    return false;
+  }
+
+  if ( !m_calo->valid( cellID ) ){
+    if ( msgLevel(MSG::DEBUG) ) debug() << "skip ivnalid cellID = " << cellID << endmsg;
+    return false;
+  }
+
+  return true;
+}
+// ==========================================================================
+bool L0CaloFuture2CaloFutureTool::isUsable( const LHCb::L0CaloCandidate* candidate ) const
+{
+  if ( ! candidate ) return false;
+
+  int type = candidate->type();
+  if (   type == L0DUBase::CaloType::Electron
+      || type == L0DUBase::CaloType::Photon  ) return true;
+
+  return false;
+}
+// ==========================================================================
+const LHCb::CaloDigits* L0CaloFuture2CaloFutureTool::makeDigits
+( const LHCb::CaloCellID&  cellID,
+  const unsigned int       level  ) const
+{
+  bool read = exist<LHCb::CaloDigits>( m_digitLocation );
+  if ( msgLevel(MSG::VERBOSE) ) verbose() << "0: data at " << m_digitLocation
+                                          << " does" << ( read ? "" : " NOT") << " exist" << endmsg;
+  if ( !read ){
+    //m_dataProviderTool->getBanks();
+    m_decodedSources.clear();
+  }
+
+  LHCb::CaloDigits* digits = getOrCreate<LHCb::CaloDigits, LHCb::CaloDigits>( m_digitLocation ) ;
+  if ( msgLevel(MSG::DEBUG) )
+     debug() << "1: data at " << m_digitLocation << " does" << ( exist<LHCb::CaloDigits>( m_digitLocation ) ? "" : " NOT") << " exist"
+             << " digits->size() = " << long( digits->size() ) << endmsg;
+
+  if ( m_decodedSources.find( -1 ) != m_decodedSources.end() ){
+    if ( msgLevel(MSG::DEBUG) ) debug() << " full Ecal (source =-1) has been already decoded" << endmsg;
+    return digits;
+  }
+
+
+  std::set<int> tell1s;
+  if ( m_decodeFullEcal )
+     tell1s.insert( -1 ); // single source = -1: decode everything
+  else
+     collectTell1s( tell1s, cellID, level ); // loop over neighbour cells, collect corresponding tell1s
+
+
+  std::vector<int> sources;
+  for (std::set<int>::const_iterator it = tell1s.begin(); it != tell1s.end(); ++ it){
+    int source = *it;
+    if ( m_decodedSources.find( source ) == m_decodedSources.end() ){
+      sources.push_back( source );
+      m_decodedSources.insert( source );
+    }else
+      if ( msgLevel(MSG::DEBUG) ) debug() << " source " << *it << " has been already decoded" << endmsg;
+  }
+
+  if ( sources.empty() ){
+    if ( msgLevel(MSG::DEBUG) ) debug() << " all sources have been already decoded" << endmsg;
+    return digits;
+  }
+
+
+  const CaloVector<LHCb::CaloDigit>& dgs = m_dataProviderTool->digits( sources );
+
+
+  // populate the CaloDigits TS container
+  for (CaloVector<LHCb::CaloDigit>::const_iterator it = dgs.begin(); it != dgs.end(); ++ it){
+    const LHCb::CaloDigit* found = digits->object ( it->cellID() ) ;
+    if ( 0 != found ) { continue ; }
+    digits->insert( new LHCb::CaloDigit(*it) );
+  }
+  if ( msgLevel(MSG::VERBOSE) ) verbose() << "2: digits->size() = " << ( digits ? (long) digits->size() : -1 ) << endmsg;
+
+  return digits;
+}
+// ============================================================================
+void L0CaloFuture2CaloFutureTool::collectTell1s
+( std::set<int>&                    tell1s,
+  const LHCb::CaloCellID&           cellID,
+  const unsigned int                level  ) const
+{
+  LHCb::CaloCellID::Set out_cells;
+  std::set<int> cards;
+
+  if ( !m_calo->valid(cellID) ) return;
+
+  // incert the cells corresponding to the L0CaloCandidate
+  out_cells.insert( cellID );
+
+  if ( level > 0 ){
+    unsigned int area = cellID.area();
+    unsigned int row  = cellID.row();
+    unsigned int col  = cellID.col();
+    // LHCb::CaloCellID(unsigned int Calo, unsigned int Area, unsigned int Row, unsigned int Column)
+    LHCb::CaloCellID ul(m_ecalCaloFutureNum, area, row+1, col  );
+    LHCb::CaloCellID ur(m_ecalCaloFutureNum, area, row+1, col+1);
+    LHCb::CaloCellID dr(m_ecalCaloFutureNum, area, row  , col+1);
+
+    if ( msgLevel(MSG::VERBOSE) )
+      verbose() << "seed=" << cellID << ":" << m_calo->cellCenter( cellID )
+                << " ul =" << ul << ":" << m_calo->cellCenter( ul )
+                << " ur =" << ur << ":" << m_calo->cellCenter( ur )
+                << " dr =" << dr << ":" << m_calo->cellCenter( dr ) << endmsg;
+
+    if ( m_calo->valid(ul) ) out_cells.insert( ul );
+    else
+      if( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+        debug() << "ul cell " << ul << " invalid" << endmsg;
+
+    if ( m_calo->valid(ur) ) out_cells.insert( ur );
+    else
+      if( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+        debug() << "ur cell " << ur << " invalid" << endmsg;
+
+    if ( m_calo->valid(dr) ) out_cells.insert( dr );
+    else
+      if( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+        debug() << "dr cell " << dr << " invalid" << endmsg;
+
+
+    /** find all neighbours for the given set of cells for the givel level
+     *  @param cells    (UPDATE) list of cells
+     *  @param level    (INPUT)  level
+     *  @param detector (INPUT) the detector
+     *  @return true if neighbours are added
+     */
+    LHCb::CaloFutureFunctors::neighbours(out_cells, level, m_calo);
+  }
+
+
+  for (LHCb::CaloCellID::Set::const_iterator it = out_cells.begin();
+       it != out_cells.end(); ++ it){
+    if ( ! m_calo->valid( *it ) ){
+      warning() << "one of the neighbour cells, " << *it << " turned out to be invalid" << endmsg;
+      continue;
+    }
+
+    int card = m_calo->cardNumber( *it );
+    if ( card < 0 ){
+      warning() << "valid cell " << *it << " corresponds to no FE card" << endmsg;
+      continue;
+    }
+    if ( msgLevel(MSG::DEBUG) ) debug() << "  cell " << (*it) << " card = " << card << endmsg;
+    cards.insert( card );
+  }
+
+  for (std::set<int>::const_iterator it = cards.begin(); it != cards.end(); ++ it){
+    int source = m_calo->cardToTell1( *it );
+    if ( msgLevel(MSG::DEBUG) ) debug() << " card = " << *it << " tell1 ID = " << source << endmsg;
+    if ( source < 0 ){
+      if ( msgLevel(MSG::ERROR) ) warning() <<  "FE card = " << *it << " corresponds to no Tell1" << endmsg;
+      continue;
+    }
+    tell1s.insert( source );
+  }
+
+  return;
+}
+// ============================================================================
diff --git a/CaloFuture/CaloFutureTools/src/L0CaloFuture2CaloFutureTool.h b/CaloFuture/CaloFutureTools/src/L0CaloFuture2CaloFutureTool.h
new file mode 100644
index 0000000000000000000000000000000000000000..6c33570a4aaff8f0df3e0f6f4f1f04f43d6ffe1f
--- /dev/null
+++ b/CaloFuture/CaloFutureTools/src/L0CaloFuture2CaloFutureTool.h
@@ -0,0 +1,258 @@
+#ifndef L0CALOFUTURE2CALOFUTURETOOL_H
+#define L0CALOFUTURE2CALOFUTURETOOL_H 1
+// ============================================================================
+#include <string>
+#include <iostream>
+#include <string>
+#include <iostream>
+#include "GaudiAlg/GaudiTool.h"
+#include "CaloKernel/CaloVector.h"
+#include "CaloDet/DeCalorimeter.h"
+
+#include "CaloFutureInterfaces/IL0CaloFuture2CaloFuture.h"
+#include "CaloFutureInterfaces/ICaloFutureClusterization.h"
+
+#include "CaloFutureDAQ/ICaloFutureDataProvider.h"
+
+// forward declarations
+class DeCalorimeter;
+
+/** @class L0CaloFuture2CaloFutureTool L0CaloFuture2CaloFutureTool.h
+ * Tool to get a list of CaloFutureClusters (owned by TES) in the vicinity of the input L0CaloFutureCandidate(s),
+ * if necessary invoking decoding and clusterization.
+ *
+ * Remarks:
+ * - the returned clusters are owned by TES and should not be deleted by the user;
+ * - in case of multiple calls of the tool on intersecting zones of Ecal
+ *   - there might appear duplicated clusters on TES,
+ *   - unless the input/output   std::vector<LHCb::CaloCluster*> clusters
+ *     is clear()'ed by the user before calling L0CaloFuture2CaloFutureTool::clusterize(),
+ *     this vector also might contain duplicates
+ *
+ *  @author Dmitry Golubkov
+ *  @date   2009-07-29
+ */
+class L0CaloFuture2CaloFutureTool : public extends<GaudiTool,IL0CaloFuture2CaloFuture>
+{
+
+public:
+  /// Standard constructor
+  L0CaloFuture2CaloFutureTool( const std::string& type,
+                   const std::string& name,
+                   const IInterface* parent);
+  // ==========================================================================
+  /** obtain CaloFutureClusters corresponding to L0CaloFutureCandidates
+   *
+   * Get a list of CaloFutureClusters in the vicinity of the L0CaloFutureCandidate,
+   * invoke decoding and clusterization if necessary.
+   * The output clusters are stored in TES location CaloDigitLocation, the
+   * created CaloDigits are stored on TES in CaloDigitLocation.
+   *
+   * @param clusters  (OUTPUT) vector of pointers of CaloFuture clusters (output)
+   * @param candidate (INPUT) pointer to L0CaloFutureCandidate
+   * @param level     (INPUT) number of neigbour levels around the candidate->id() cell
+   *                  for the CaloFutureClusterization tool
+   * @return FAILURE when anything goes wrong, otherwise the return StatusCode of the ICaloFutureClusterization tool used
+   */
+  StatusCode clusterize
+  ( std::vector<LHCb::CaloCluster*>&      clusters ,
+    const LHCb::L0CaloCandidate*          candidate,
+    const unsigned int                    level     ) const override;
+  // ==========================================================================
+  /** obtain CaloClusters corresponding to L0CaloCandidate
+   *
+   * Get a list of CaloClusters in the vicinity of an L0CaloCandidate,
+   * if necessary invoke decoding and clusterization.
+   *
+   * @param clusters (OUTPUT) vector of pointers of Calo clusters
+   * @param candidate (INPUT) pointer to L0CaloCandidate
+   */
+  StatusCode clusterize
+  ( std::vector<LHCb::CaloCluster*>&      clusters,
+    const LHCb::L0CaloCandidate*          candidate ) const override;
+  // ==========================================================================
+  /** obtain CaloClusters corresponding to L0CaloCandidates
+   *
+   * Get a list of CaloClusters in the vicinity of an ObjectVector of L0CaloCandidates,
+   * invoke decoding and clusterization if necessary.
+   * @param clusters (OUTPUT) vector of pointers of Calo clusters
+   * @param candidates (INPUT) pointer to L0CaloCandidates
+   * @param level (INPUT) number of neigbour levels around cell for the CaloClusterization tool
+   */
+  StatusCode clusterize
+  ( std::vector<LHCb::CaloCluster*>&      clusters,
+    const LHCb::L0CaloCandidates*         candidates,
+    const unsigned int                    level       ) const override
+  {
+    (void) clusters, (void) candidates, (void) level; // avoid compiler warning
+    fatal() << "L0CaloFuture2CaloFutureTool::clusterize(..., const LHCb::L0CaloCandidates*, ...) NOT IMPLEMENTED" << endmsg;
+    return StatusCode::FAILURE;
+  }
+  // ==========================================================================
+  /** obtain CaloClusters corresponding to L0CaloCandidates
+   *
+   * Get a list of CaloClusters in the vicinity of an ObjectVector of L0CaloCandidates,
+   * invoke decoding and clusterization if necessary.
+   * @param clusters (OUTPUT) vector of pointers of Calo clusters
+   * @param candidates (INPUT) pointer to L0CaloCandidates
+   */
+  StatusCode clusterize
+  ( std::vector<LHCb::CaloCluster*>&      clusters,
+    const LHCb::L0CaloCandidates*         candidates  ) const override { return clusterize(clusters, candidates, m_neighbourLevel); }
+  // ==========================================================================
+  /** obtain CaloClusters around a CaloCellID
+   *
+   * Get a list of CaloClusters in the vicinity of the CaloCellID,
+   * if necessary invoke decoding and clusterization.
+   *
+   * @param clusters (OUTPUT) vector of pointers of Calo clusters
+   * @param cellID   (INPUT)  pointer to CaloCellID
+   * @param level    (INPUT)  number of neigbour levels around the cell for the ICaloClusterization tool
+   */
+  StatusCode clusterize
+  ( std::vector<LHCb::CaloCluster*>&      clusters ,
+    const LHCb::CaloCellID&               cellID,
+    const unsigned int                    level     ) const override;
+  // ==========================================================================
+  /** obtain CaloClusters around a CaloCellID
+   *
+   * Get a list of CaloClusters in the vicinity of the CaloCellID,
+   * if necessary invoke decoding and clusterization.
+   *
+   * @param clusters (OUTPUT) vector of pointers of Calo clusters
+   * @param cellID   (INPUT)  pointer to CaloCellID
+   */
+  StatusCode clusterize
+  ( std::vector<LHCb::CaloCluster*>&      clusters,
+    const LHCb::CaloCellID&               cellID   ) const override;
+  // ==========================================================================
+  StatusCode initialize() override;
+  // ==========================================================================
+protected:
+  // ==========================================================================
+  /** obtain CaloClusters corresponding to the digits using cellID as a seed
+   *
+   * Get a list of CaloClusters in the vicinity of cellID, see makeDigits()
+   * for explanation of the region used for cluster search.
+   *
+   * @param clusters (OUTPUT) vector of pointers to Calo clusters
+   * @param digits (INPUT) pointer to the CaloDigits
+   * @param cellID (INPUT) of the L0CaloCandidate seed cell
+   * @param level (INPUT) the radius of the area to be clusterized
+   */
+  StatusCode makeClusters
+  ( std::vector<LHCb::CaloCluster*>&      clusters,
+    const LHCb::CaloDigits*               digits,
+    const LHCb::CaloCellID&               cellID,
+    const unsigned int                    level   ) const ;
+  // ==========================================================================
+  /** put the vector CaloClutsters on TES
+   *
+   * @param clusters (INPUT/OUTPUT) vector of pointers to Calo clusters
+   *
+   * NB: in case of multiple calls of the L0Calo2CaloTool on intersecting
+   * zones of Ecal, there might appear duplicates!
+   */
+  StatusCode putClustersOnTES
+  ( std::vector<LHCb::CaloCluster*>&      clusters ) const ;
+  // ==========================================================================
+  /** prepare CaloDigits around the given cellID and store them on TES
+   *
+   * @param cellID of the seed cell
+   * @param level defines the size of the digitized area (see below)
+   * @return container of CaloDigits corresponding to the TES
+   *
+   *  The decoding is done for the Tell1's which correspond to the cells
+   *  in the region centered around the seed cellID and having the area of the
+   *  the size ~ 2*(1+Level)x2*(1+Level) as steered by the level parameter.
+   *  The same region of cells is used by the CaloFutureClusterization tool
+   *  invoked by makeClusters(). The area is constructed by recurrent addition of
+   *  DeCalorimeter::neighborCell(...) to the the area starting from the L0CaloFutureCandidate.
+   *  Typical value which should be OK for the NeighbourLevel is ~2.
+   *
+   *  Below is an illustration for NeighbourLevel = 3:
+   * -+-+-+-+-+-+-+-+-+-+-+-+-
+   * .|.|.|.|.|.|.|.|.|.|.|.|.
+   * -+-+-+-+-+-+-+-+-+-+-+-+-
+   * .|.|.|*|*|*|*|*|*|*|*|.|.<--
+   * -+-+-+-+-+-+-+-+-+-+-+-+- |
+   * .|.|.|*|*|*|*|*|*|*|*|.|. d
+   * -+-+-+-+-+-+-+-+-+-+-+-+- |
+   * .|.|.|*|*|*|*|*|*|*|*|.|.<--   d     = level (defaults to the NighbourLevel property)
+   * -+-+-+-+-+-+-+-+-+-+-+-+-      .     = Ecal cells
+   * .|.|.|*|*|*|#|#|*|*|*|.|.      *     = cells included in the digitization
+   * -+-+-+-+-+-+-+-+-+-+-+-+-      {@,#} = 2x2 cell region of the L0CaloFutureCandidate
+   * .|.|.|*|*|*|@|#|*|*|*|.|.      @     = seed cell
+   * -+-+-+-+-+-+-+-+-+-+-+-+-
+   * .|.|.|*|*|*|*|*|*|*|*|.|. <--
+   * -+-+-+-+-+-+-+-+-+-+-+-+-  |
+   * .|.|.|*|*|*|*|*|*|*|*|.|.  d
+   * -+-+-+-+-+-+-+-+-+-+-+-+-  |
+   * .|.|.|*|*|*|*|*|*|*|*|.|. <--
+   * -+-+-+-+-+-+-+-+-+-+-+-+-
+   * .|.|.|.|.|.|.|.|.|.|.|.|.
+   *      ^     ^   ^     ^
+   *      |<-d->|   |<-d->|
+   */
+  const LHCb::CaloDigits* makeDigits( const LHCb::CaloCellID &cellID, const unsigned int level ) const ;
+  // ==========================================================================
+  /** check if cell ID is usable
+   *
+   * A cell is accepted if it corresponds to Ecal
+   * and if DeCalorimeter::valid( cellID ) is true
+   * @param cellID of the cell in question
+   * @return true if the cell is accepted / false otherwise
+   */
+  bool isUsable( const LHCb::CaloCellID &cellID ) const ;
+  // ==========================================================================
+  /** check if the L0CaloFutureCandidate is usable
+   *
+   * An L0CaloFutureCandidate is accepted if its type() is Electron or Photon (see L0DUBase::CaloFutureType )
+   * @param  candidate pointer to the tested L0CaloFutureCandidate
+   * @return true if the candidate is accepted / false otherwise
+   */
+  bool isUsable( const LHCb::L0CaloCandidate *candidate ) const ;
+  // ==========================================================================
+
+  /** collect the Tell1 numbers corresponding to the given L0CaloFutureCandidate seed cellID
+   *
+   * @param tell1s (OUTPUT) set of tell1 IDs
+   * @param cellID (INPUT) the seed cell of a 2x2 cell L0CaloFutureCandidate
+   * @param level (INPUT) the neighbour level which defines the size of the area, see makeDigits(...)
+   */
+  void collectTell1s
+  ( std::set<int>&          tell1s,
+    const LHCb::CaloCellID& cellID,
+    const unsigned int      level  ) const ;
+  // ==========================================================================
+private:
+  Gaudi::Property<std::string> m_clusterizationToolName {this, "CaloFutureClusterizationTool", "CaloFutureClusterizationTool"};
+  Gaudi::Property<std::string> m_dataProviderToolName   {this, "CaloFutureDataProviderTool"  , "CaloFutureDataProvider"};
+
+  ICaloFutureClusterization* m_clusterizationTool = nullptr;
+  ICaloFutureDataProvider*   m_dataProviderTool = nullptr;
+  DeCalorimeter*       m_calo = nullptr;
+
+  unsigned int         m_ecalCaloFutureNum;
+
+  Gaudi::Property<std::string>  m_digitLocation  {this, "CaloDigitLocation"  , LHCb::CaloDigitLocation::Hlt1Ecal};
+  Gaudi::Property<std::string>  m_clusterLocation{this, "CaloFutureClusterLocation", LHCb::CaloClusterLocation::EcalHlt1};
+
+  Gaudi::Property<unsigned int> m_neighbourLevel
+    {this, "NeighbourLevel", 2, "Level parameter for the CaloFutureClusterizationTool, search clusters in (1+2*Level)x(1+2*Level) region around the seed cell"};
+
+  Gaudi::Property<bool> m_sort
+    {this, "Sort", false, "sort the clusters due to energy"};
+
+  Gaudi::Property<bool> m_sortET
+    {this, "SortET", false, "if Sort: sort the clusters due to transverse energy"};
+
+  Gaudi::Property<bool> m_decodeFullEcal
+    {this, "DecodeFullEcal", false, "false = decode only the Tell1s around the L0CaloFutureCandidate cellID"};
+
+  Gaudi::Property<bool> m_clusOnTES
+    {this, "ClusterOnTES", false};
+
+  mutable std::set<int>  m_decodedSources;
+};
+#endif // L0CALOFUTURE2CALOFUTURETOOL_H
diff --git a/CaloFuture/CaloFutureTools/src/Part2CaloFuture.cpp b/CaloFuture/CaloFutureTools/src/Part2CaloFuture.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0caef437f63863ed1faea1011b7edba3a84bb3cb
--- /dev/null
+++ b/CaloFuture/CaloFutureTools/src/Part2CaloFuture.cpp
@@ -0,0 +1,65 @@
+// $Id: Part2CaloFuture.cpp,v 1.2 2009-05-19 13:48:22 cattanem Exp $
+// Include files 
+
+// from LHCb
+#include "Event/Particle.h"
+#include "Kernel/TrackDefaultParticles.h"
+// local
+#include "Part2CaloFuture.h"
+
+//-----------------------------------------------------------------------------
+// Implementation file for class : Part2CaloFuture
+//
+// 2006-11-30 : Olivier Deschamps
+//-----------------------------------------------------------------------------
+
+// Declaration of the Tool Factory
+DECLARE_COMPONENT( Part2CaloFuture )
+
+
+//=============================================================================
+// Standard constructor, initializes variables
+//=============================================================================
+Part2CaloFuture::Part2CaloFuture( const std::string& type,
+                        const std::string& name,
+                        const IInterface* parent )
+  : Track2CaloFuture ( type, name , parent )
+    , m_particle       ( NULL )
+    , m_proto          ( NULL ){
+  declareInterface<IPart2CaloFuture>(this);
+}
+
+//=============================================================================
+StatusCode Part2CaloFuture::initialize(){
+  StatusCode sc = Track2CaloFuture::initialize();
+  if (sc.isFailure()) return Error("Failed to initialize", sc);
+  return StatusCode::SUCCESS;  
+}
+//=============================================================================
+bool Part2CaloFuture::match(const LHCb::Particle* part, std::string det,CaloPlane::Plane plane , double delta){
+  m_status = setting( part );
+  if ( m_status )
+    return Track2CaloFuture::match( m_track, det, plane, delta, LHCb::Tr::PID( m_particle->particleID().abspid() ) );
+  return m_status;
+}
+//=============================================================================
+bool Part2CaloFuture::match(const LHCb::ProtoParticle* proto, std::string det,CaloPlane::Plane plane , double delta){
+  m_status = setting( proto );
+  if( m_status )return Track2CaloFuture::match(m_track, det, plane, delta);
+  return m_status;
+}
+//=============================================================================
+bool Part2CaloFuture::setting(const LHCb::Particle* particle){
+  m_particle = particle;
+  if( NULL == m_particle)return false;
+  const LHCb::ProtoParticle* proto = m_particle -> proto();
+  return setting(proto);
+}
+//=============================================================================
+bool Part2CaloFuture::setting(const LHCb::ProtoParticle* proto){
+  m_proto   = proto;
+  if( NULL == m_proto)return false;
+  return Track2CaloFuture::setting( m_proto->track() );
+}
+//=============================================================================
+
diff --git a/CaloFuture/CaloFutureTools/src/Part2CaloFuture.h b/CaloFuture/CaloFutureTools/src/Part2CaloFuture.h
new file mode 100644
index 0000000000000000000000000000000000000000..37f69b6d804febf77e9c93463ebe556c31d17137
--- /dev/null
+++ b/CaloFuture/CaloFutureTools/src/Part2CaloFuture.h
@@ -0,0 +1,57 @@
+// $Id: Part2CaloFuture.h,v 1.2 2010-06-10 12:46:38 cattanem Exp $
+#ifndef PART2CALOFUTURE_H
+#define PART2CALOFUTURE_H 1
+
+// Include files
+#include "Track2CaloFuture.h"
+#include "Event/ProtoParticle.h"
+// from Gaudi
+#include "CaloFutureInterfaces/IPart2CaloFuture.h"
+
+
+
+/** @class Part2CaloFuture Part2CaloFuture.h
+ *
+ *
+ *  @author Olivier Deschamps
+ *  @date   2006-11-30
+ */
+class Part2CaloFuture : public Track2CaloFuture, virtual public IPart2CaloFuture {
+public:
+  /// Standard constructor
+  Part2CaloFuture( const std::string& type,
+               const std::string& name,
+               const IInterface* parent);
+
+  StatusCode initialize() override;
+
+  using Track2CaloFuture::match;
+  bool match(const  LHCb::ProtoParticle* proto,
+                     std::string det = DeCalorimeterLocation::Ecal,
+                     CaloPlane::Plane plane = CaloPlane::ShowerMax,
+                     double delta = 0.
+                     ) override;
+  bool match(const  LHCb::Particle* part,
+                     std::string det = DeCalorimeterLocation::Ecal,
+                     CaloPlane::Plane plane = CaloPlane::ShowerMax,
+                     double delta = 0.
+                     ) override;
+  inline bool inAcceptance() override;
+
+
+protected:
+  bool setting (const  LHCb::Particle* part);
+  bool setting (const  LHCb::ProtoParticle* proto);
+  const LHCb::Particle*      m_particle;
+  const LHCb::ProtoParticle* m_proto;
+private:
+};
+#endif // PART2CALOFUTURE_H
+
+inline bool Part2CaloFuture::inAcceptance(){
+  if(m_det == DeCalorimeterLocation::Spd)  return m_proto->info(LHCb::ProtoParticle::additionalInfo::InAccSpd,  0.)!=0;
+  if(m_det == DeCalorimeterLocation::Prs)  return m_proto->info(LHCb::ProtoParticle::additionalInfo::InAccPrs,  0.)!=0;
+  if(m_det == DeCalorimeterLocation::Ecal) return m_proto->info(LHCb::ProtoParticle::additionalInfo::InAccEcal, 0.)!=0;
+  if(m_det == DeCalorimeterLocation::Hcal) return m_proto->info(LHCb::ProtoParticle::additionalInfo::InAccHcal, 0.)!=0;
+  return false;
+}
diff --git a/CaloFuture/CaloFutureTools/src/TMV_MLP_E.C b/CaloFuture/CaloFutureTools/src/TMV_MLP_E.C
new file mode 100644
index 0000000000000000000000000000000000000000..3411a09e24b4e386d2769c4091598020f9db0c7e
--- /dev/null
+++ b/CaloFuture/CaloFutureTools/src/TMV_MLP_E.C
@@ -0,0 +1,645 @@
+// Class: ReadMLPE
+// Automatically generated by MethodBase::MakeClass
+//
+
+/* configuration options =====================================================
+
+#GEN -*-*-*-*-*-*-*-*-*-*-*- general info -*-*-*-*-*-*-*-*-*-*-*-
+
+Method         : MLP::MLP
+TMVA Release   : 4.1.4         [262404]
+ROOT Release   : 5.34/05       [336389]
+Creator        : hoballah
+Date           : Wed Jul  3 22:48:23 2013
+Host           : Linux lxbuild175.cern.ch 2.6.18-308.4.1.el5 #1 SMP Wed Apr 18 16:26:27 CEST 2012 x86_64 x86_64 x86_64 GNU/Linux
+Dir            : /users/divers/lhcb/hoballah/December2012/B2KstG_ana/TMVA-v4.1.2/test/BDTs_PhotonID_new_var/train_test_E
+Training events: 1426367
+Analysis type  : [Classification]
+
+
+#OPT -*-*-*-*-*-*-*-*-*-*-*-*- options -*-*-*-*-*-*-*-*-*-*-*-*-
+
+# Set by User:
+NCycles: "750" [Number of training cycles]
+HiddenLayers: "N+5" [Specification of hidden layer architecture]
+NeuronType: "tanh" [Neuron activation function type]
+EstimatorType: "CE" [MSE (Mean Square Estimator) for Gaussian Likelihood or CE(Cross-Entropy) for Bernoulli Likelihood]
+V: "False" [Verbose output (short form of "VerbosityLevel" below - overrides the latter one)]
+VarTransform: "N" [List of variable transformations performed before training, e.g., "D_Background,P_Signal,G,N_AllClasses" for: "Decorrelation, PCA-transformation, Gaussianisation, Normalisation, each for the given class of events ('AllClasses' denotes all events of all classes, if no class indication is given, 'All' is assumed)"]
+H: "True" [Print method-specific help message]
+TrainingMethod: "BP" [Train with Back-Propagation (BP), BFGS Algorithm (BFGS), or Genetic Algorithm (GA - slower and worse)]
+TestRate: "5" [Test for overtraining performed at each #th epochs]
+UseRegulator: "False" [Use regulator to avoid over-training]
+# Default:
+RandomSeed: "1" [Random seed for initial synapse weights (0 means unique seed for each run; default value '1')]
+NeuronInputType: "sum" [Neuron input function type]
+VerbosityLevel: "Default" [Verbosity level]
+CreateMVAPdfs: "False" [Create PDFs for classifier outputs (signal and background)]
+IgnoreNegWeightsInTraining: "False" [Events with negative weights are ignored in the training (but are included for testing and performance evaluation)]
+LearningRate: "2.000000e-02" [ANN learning rate parameter]
+DecayRate: "1.000000e-02" [Decay rate for learning parameter]
+EpochMonitoring: "False" [Provide epoch-wise monitoring plots according to TestRate (caution: causes big ROOT output file!)]
+Sampling: "1.000000e+00" [Only 'Sampling' (randomly selected) events are trained each epoch]
+SamplingEpoch: "1.000000e+00" [Sampling is used for the first 'SamplingEpoch' epochs, afterwards, all events are taken for training]
+SamplingImportance: "1.000000e+00" [ The sampling weights of events in epochs which successful (worse estimator than before) are multiplied with SamplingImportance, else they are divided.]
+SamplingTraining: "True" [The training sample is sampled]
+SamplingTesting: "False" [The testing sample is sampled]
+ResetStep: "50" [How often BFGS should reset history]
+Tau: "3.000000e+00" [LineSearch "size step"]
+BPMode: "sequential" [Back-propagation learning mode: sequential or batch]
+BatchSize: "-1" [Batch size: number of events/batch, only set if in Batch Mode, -1 for BatchSize=number_of_events]
+ConvergenceImprove: "1.000000e-30" [Minimum improvement which counts as improvement (<0 means automatic convergence check is turned off)]
+ConvergenceTests: "-1" [Number of steps (without improvement) required for convergence (<0 means automatic convergence check is turned off)]
+UpdateLimit: "10000" [Maximum times of regulator update]
+CalculateErrors: "False" [Calculates inverse Hessian matrix at the end of the training to be able to calculate the uncertainties of an MVA value]
+WeightRange: "1.000000e+00" [Take the events for the estimator calculations from small deviations from the desired value to large deviations only over the weight range]
+##
+
+
+#VAR -*-*-*-*-*-*-*-*-*-*-*-* variables *-*-*-*-*-*-*-*-*-*-*-*-
+
+NVar 10
+CaloHypo_ClusterMatch   CaloHypo_ClusterMatch   CaloHypo_ClusterMatch   CaloHypo_ClusterMatch   units                             'F'    [0,9999]
+CaloHypo_ToPrsE         CaloHypo_ToPrsE         CaloHypo_ToPrsE         CaloHypo_ToPrsE         units                             'F'    [0,280.579986572]
+CaloHypo_E19            CaloHypo_E19            CaloHypo_E19            CaloHypo_E19            units                             'F'    [0,1.73788714409]
+CaloHypo_Hcal2Ecal      CaloHypo_Hcal2Ecal      CaloHypo_Hcal2Ecal      CaloHypo_Hcal2Ecal      units                             'F'    [0,94.6786651611]
+CaloHypo_PrsE19         CaloHypo_PrsE19         CaloHypo_PrsE19         CaloHypo_PrsE19         units                             'F'    [0,1]
+CaloHypo_PrsE49         CaloHypo_PrsE49         CaloHypo_PrsE49         CaloHypo_PrsE49         units                             'F'    [0,1]
+CaloHypo_Spread         CaloHypo_Spread         CaloHypo_Spread         CaloHypo_Spread         units                             'F'    [0,64433.078125]
+CaloHypo_PrsE4Max       CaloHypo_PrsE4Max       CaloHypo_PrsE4Max       CaloHypo_PrsE4Max       units                             'F'    [0,955.837036133]
+CaloHypo_HypoPrsM       CaloHypo_HypoPrsM       CaloHypo_HypoPrsM       CaloHypo_HypoPrsM       units                             'F'    [0,10]
+CaloHypo_HypoSpdM       CaloHypo_HypoSpdM       CaloHypo_HypoSpdM       CaloHypo_HypoSpdM       units                             'F'    [0,9]
+NSpec 0
+
+
+============================================================================ */
+
+#include <vector>
+#include <cmath>
+#include <string>
+#include <iostream>
+
+#ifndef IClassifierReader__def
+#define IClassifierReader__def
+
+class IClassifierReader {
+
+ public:
+
+   // constructor
+   IClassifierReader() : fStatusIsClean( true ) {}
+   virtual ~IClassifierReader() {}
+
+   // return classifier response
+   virtual double GetMvaValue( const std::vector<double>& inputValues ) const = 0;
+
+   // returns classifier status
+   bool IsStatusClean() const { return fStatusIsClean; }
+
+ protected:
+
+   bool fStatusIsClean;
+};
+
+#endif
+
+class ReadMLPE : public IClassifierReader {
+
+ public:
+
+   // constructor
+   ReadMLPE( const std::vector<std::string>& theInputVars )
+      : IClassifierReader(),
+        fClassName( "ReadMLPE" ),
+        fNvars( 10 ),
+        fIsNormalised( false )
+   {
+      // the training input variables
+      const char* inputVars[] = { "CaloHypo_ClusterMatch", "CaloHypo_ToPrsE", "CaloHypo_E19", "CaloHypo_Hcal2Ecal", "CaloHypo_PrsE19", "CaloHypo_PrsE49", "CaloHypo_Spread", "CaloHypo_PrsE4Max", "CaloHypo_HypoPrsM", "CaloHypo_HypoSpdM" };
+
+      // sanity checks
+      if (theInputVars.size() <= 0) {
+         std::cout << "Problem in class \"" << fClassName << "\": empty input vector" << std::endl;
+         fStatusIsClean = false;
+      }
+
+      if (theInputVars.size() != fNvars) {
+         std::cout << "Problem in class \"" << fClassName << "\": mismatch in number of input values: "
+                   << theInputVars.size() << " != " << fNvars << std::endl;
+         fStatusIsClean = false;
+      }
+
+      // validate input variables
+      for (size_t ivar = 0; ivar < theInputVars.size(); ivar++) {
+         if (theInputVars[ivar] != inputVars[ivar]) {
+            std::cout << "Problem in class \"" << fClassName << "\": mismatch in input variable names" << std::endl
+                      << " for variable [" << ivar << "]: " << theInputVars[ivar].c_str() << " != " << inputVars[ivar] << std::endl;
+            fStatusIsClean = false;
+         }
+      }
+
+      // initialize min and max vectors (for normalisation)
+      fVmin[0] = -1;
+      fVmax[0] = 1;
+      fVmin[1] = -1;
+      fVmax[1] = 1;
+      fVmin[2] = -1;
+      fVmax[2] = 1;
+      fVmin[3] = -1;
+      fVmax[3] = 1;
+      fVmin[4] = -1;
+      fVmax[4] = 1;
+      fVmin[5] = -1;
+      fVmax[5] = 1;
+      fVmin[6] = -1;
+      fVmax[6] = 1;
+      fVmin[7] = -1;
+      fVmax[7] = 1;
+      fVmin[8] = -1;
+      fVmax[8] = 1;
+      fVmin[9] = -1;
+      fVmax[9] = 1;
+
+      // initialize input variable types
+      fType[0] = 'F';
+      fType[1] = 'F';
+      fType[2] = 'F';
+      fType[3] = 'F';
+      fType[4] = 'F';
+      fType[5] = 'F';
+      fType[6] = 'F';
+      fType[7] = 'F';
+      fType[8] = 'F';
+      fType[9] = 'F';
+
+      // initialize constants
+      Initialize();
+
+      // initialize transformation
+      InitTransform();
+   }
+
+   // destructor
+   virtual ~ReadMLPE() {
+      Clear(); // method-specific
+   }
+
+   // the classifier response
+   // "inputValues" is a vector of input values in the same order as the
+   // variables given to the constructor
+   double GetMvaValue( const std::vector<double>& inputValues ) const override;
+
+ private:
+
+   // method-specific destructor
+   void Clear();
+
+   // input variable transformation
+
+   double fMin_1[3][10];
+   double fMax_1[3][10];
+   void InitTransform_1();
+   void Transform_1( std::vector<double> & iv, int sigOrBgd ) const;
+   void InitTransform();
+   void Transform( std::vector<double> & iv, int sigOrBgd ) const;
+
+   // common member variables
+   const char* fClassName;
+
+   const size_t fNvars;
+   size_t GetNvar()           const { return fNvars; }
+   char   GetType( int ivar ) const { return fType[ivar]; }
+
+   // normalisation of input variables
+   const bool fIsNormalised;
+   bool IsNormalised() const { return fIsNormalised; }
+   double fVmin[10];
+   double fVmax[10];
+   double NormVariable( double x, double xmin, double xmax ) const {
+      // normalise to output range: [-1, 1]
+      return 2*(x - xmin)/(xmax - xmin) - 1.0;
+   }
+
+   // type of input variable: 'F' or 'I'
+   char   fType[10];
+
+   // initialize internal variables
+   void Initialize();
+   double GetMvaValue__( const std::vector<double>& inputValues ) const;
+
+   // private members (method specific)
+
+   double ActivationFnc(double x) const;
+   double OutputActivationFnc(double x) const;
+
+   int fLayers;
+   int fLayerSize[3];
+   double fWeightMatrix0to1[16][11];   // weight matrix from layer 0 to 1
+   double fWeightMatrix1to2[1][16];   // weight matrix from layer 1 to 2
+
+   double * fWeights[3];
+};
+
+inline void ReadMLPE::Initialize()
+{
+   // build network structure
+   fLayers = 3;
+   fLayerSize[0] = 11; fWeights[0] = new double[11];
+   fLayerSize[1] = 16; fWeights[1] = new double[16];
+   fLayerSize[2] = 1; fWeights[2] = new double[1];
+   // weight matrix from layer 0 to 1
+   fWeightMatrix0to1[0][0] = -1.45648454058841;
+   fWeightMatrix0to1[1][0] = 13.5275343120003;
+   fWeightMatrix0to1[2][0] = 4.50157418654813;
+   fWeightMatrix0to1[3][0] = 0.248117194505925;
+   fWeightMatrix0to1[4][0] = -30.1607689733541;
+   fWeightMatrix0to1[5][0] = 0.207887274771161;
+   fWeightMatrix0to1[6][0] = -0.0270888143896361;
+   fWeightMatrix0to1[7][0] = 3.28884565633882;
+   fWeightMatrix0to1[8][0] = 0.341967140968008;
+   fWeightMatrix0to1[9][0] = -0.142593815083237;
+   fWeightMatrix0to1[10][0] = -0.0398619549131968;
+   fWeightMatrix0to1[11][0] = -0.0750336597813799;
+   fWeightMatrix0to1[12][0] = 0.0766911890953704;
+   fWeightMatrix0to1[13][0] = 0.0672474082833836;
+   fWeightMatrix0to1[14][0] = 0.867241067793692;
+   fWeightMatrix0to1[0][1] = -2.83950347374737;
+   fWeightMatrix0to1[1][1] = -2.15380729271302;
+   fWeightMatrix0to1[2][1] = 2.04678520389349;
+   fWeightMatrix0to1[3][1] = -4.12111391036507;
+   fWeightMatrix0to1[4][1] = 0.0150863236492678;
+   fWeightMatrix0to1[5][1] = 0.428345073987202;
+   fWeightMatrix0to1[6][1] = 0.0463806424833402;
+   fWeightMatrix0to1[7][1] = 3.07927476648953;
+   fWeightMatrix0to1[8][1] = 1.84528694146504;
+   fWeightMatrix0to1[9][1] = 4.21001060729693;
+   fWeightMatrix0to1[10][1] = 0.125225768206075;
+   fWeightMatrix0to1[11][1] = -2.76188946518049;
+   fWeightMatrix0to1[12][1] = -0.0535014315276362;
+   fWeightMatrix0to1[13][1] = 0.516400284788415;
+   fWeightMatrix0to1[14][1] = -0.641365324376028;
+   fWeightMatrix0to1[0][2] = 3.59930023956898;
+   fWeightMatrix0to1[1][2] = 0.828955519329612;
+   fWeightMatrix0to1[2][2] = -2.47879580185701;
+   fWeightMatrix0to1[3][2] = -0.236590795083167;
+   fWeightMatrix0to1[4][2] = -1.50982763020608;
+   fWeightMatrix0to1[5][2] = 4.15818760208164;
+   fWeightMatrix0to1[6][2] = -8.64091589704802;
+   fWeightMatrix0to1[7][2] = -2.03854941931439;
+   fWeightMatrix0to1[8][2] = -3.80216517204669;
+   fWeightMatrix0to1[9][2] = 2.07074419257209;
+   fWeightMatrix0to1[10][2] = -0.112980128346248;
+   fWeightMatrix0to1[11][2] = -2.27781140020139;
+   fWeightMatrix0to1[12][2] = -2.20742895752195;
+   fWeightMatrix0to1[13][2] = 1.17918944322642;
+   fWeightMatrix0to1[14][2] = -0.34063209631861;
+   fWeightMatrix0to1[0][3] = -0.456676590112288;
+   fWeightMatrix0to1[1][3] = 9.23995430720942;
+   fWeightMatrix0to1[2][3] = 7.78707526858773;
+   fWeightMatrix0to1[3][3] = 3.10666992076248;
+   fWeightMatrix0to1[4][3] = 25.400657795185;
+   fWeightMatrix0to1[5][3] = 1.19475914402133;
+   fWeightMatrix0to1[6][3] = -10.259338117333;
+   fWeightMatrix0to1[7][3] = -2.8289776603478;
+   fWeightMatrix0to1[8][3] = -0.276544824251693;
+   fWeightMatrix0to1[9][3] = 0.636533773081394;
+   fWeightMatrix0to1[10][3] = 8.36317018745479;
+   fWeightMatrix0to1[11][3] = 0.0033823112840708;
+   fWeightMatrix0to1[12][3] = -6.47144575647071;
+   fWeightMatrix0to1[13][3] = -6.40138974070392;
+   fWeightMatrix0to1[14][3] = 0.303751818575856;
+   fWeightMatrix0to1[0][4] = -0.457668810659899;
+   fWeightMatrix0to1[1][4] = 0.0227435339391494;
+   fWeightMatrix0to1[2][4] = 0.211414374850054;
+   fWeightMatrix0to1[3][4] = 0.733620726547089;
+   fWeightMatrix0to1[4][4] = 0.261596419101059;
+   fWeightMatrix0to1[5][4] = -0.717768402421295;
+   fWeightMatrix0to1[6][4] = 0.266747237202821;
+   fWeightMatrix0to1[7][4] = -0.415143840087982;
+   fWeightMatrix0to1[8][4] = 4.02900893008418;
+   fWeightMatrix0to1[9][4] = -0.314682275367909;
+   fWeightMatrix0to1[10][4] = -0.0307347748362473;
+   fWeightMatrix0to1[11][4] = 0.613657242423933;
+   fWeightMatrix0to1[12][4] = 1.54201548560833;
+   fWeightMatrix0to1[13][4] = -0.362297119846357;
+   fWeightMatrix0to1[14][4] = 0.892655907466491;
+   fWeightMatrix0to1[0][5] = 0.386851226624331;
+   fWeightMatrix0to1[1][5] = -0.393755454843198;
+   fWeightMatrix0to1[2][5] = -3.65324036626828;
+   fWeightMatrix0to1[3][5] = -2.19060232755643;
+   fWeightMatrix0to1[4][5] = -0.22524696359375;
+   fWeightMatrix0to1[5][5] = 1.36257093161029;
+   fWeightMatrix0to1[6][5] = 0.363400888976796;
+   fWeightMatrix0to1[7][5] = -0.327091014001851;
+   fWeightMatrix0to1[8][5] = -5.82025096621046;
+   fWeightMatrix0to1[9][5] = -0.0316361303312077;
+   fWeightMatrix0to1[10][5] = -0.11716442899143;
+   fWeightMatrix0to1[11][5] = 1.33146796426964;
+   fWeightMatrix0to1[12][5] = -0.529955608822344;
+   fWeightMatrix0to1[13][5] = 0.123392969661865;
+   fWeightMatrix0to1[14][5] = -0.688495531727211;
+   fWeightMatrix0to1[0][6] = 2.37511639017605;
+   fWeightMatrix0to1[1][6] = 13.8495115369364;
+   fWeightMatrix0to1[2][6] = -7.11038514530497;
+   fWeightMatrix0to1[3][6] = 1.57600408446741;
+   fWeightMatrix0to1[4][6] = -0.305469633566612;
+   fWeightMatrix0to1[5][6] = -0.802970329702063;
+   fWeightMatrix0to1[6][6] = 7.80532583827627;
+   fWeightMatrix0to1[7][6] = -27.3313128479119;
+   fWeightMatrix0to1[8][6] = -4.11021126234451;
+   fWeightMatrix0to1[9][6] = -18.9906582510047;
+   fWeightMatrix0to1[10][6] = 0.0752865468142167;
+   fWeightMatrix0to1[11][6] = -1.00673535273197;
+   fWeightMatrix0to1[12][6] = 5.70715403491534;
+   fWeightMatrix0to1[13][6] = 0.0661267698956959;
+   fWeightMatrix0to1[14][6] = 0.117595918123508;
+   fWeightMatrix0to1[0][7] = 7.18849787403715;
+   fWeightMatrix0to1[1][7] = 3.01783645520403;
+   fWeightMatrix0to1[2][7] = -8.01492216503647;
+   fWeightMatrix0to1[3][7] = -3.52555327456571;
+   fWeightMatrix0to1[4][7] = -2.13682500505441;
+   fWeightMatrix0to1[5][7] = -1.3873824489972;
+   fWeightMatrix0to1[6][7] = -1.32329585761102;
+   fWeightMatrix0to1[7][7] = 8.33522721197895;
+   fWeightMatrix0to1[8][7] = -2.95536416620716;
+   fWeightMatrix0to1[9][7] = -17.8822135849987;
+   fWeightMatrix0to1[10][7] = 1.01359329792805;
+   fWeightMatrix0to1[11][7] = -1.23283825442966;
+   fWeightMatrix0to1[12][7] = -0.24986091785677;
+   fWeightMatrix0to1[13][7] = -25.2043259727962;
+   fWeightMatrix0to1[14][7] = 0.971731397100306;
+   fWeightMatrix0to1[0][8] = -1.15525751237527;
+   fWeightMatrix0to1[1][8] = -0.446772573082124;
+   fWeightMatrix0to1[2][8] = 1.43962517859237;
+   fWeightMatrix0to1[3][8] = 0.163589949982915;
+   fWeightMatrix0to1[4][8] = -0.284672904616579;
+   fWeightMatrix0to1[5][8] = 0.157955132004244;
+   fWeightMatrix0to1[6][8] = 0.249634201604772;
+   fWeightMatrix0to1[7][8] = -1.25578487906979;
+   fWeightMatrix0to1[8][8] = -0.193703455708801;
+   fWeightMatrix0to1[9][8] = 0.398145692537802;
+   fWeightMatrix0to1[10][8] = 0.358898792890607;
+   fWeightMatrix0to1[11][8] = 2.94684386609079;
+   fWeightMatrix0to1[12][8] = -1.45650642135418;
+   fWeightMatrix0to1[13][8] = -1.0747199316049;
+   fWeightMatrix0to1[14][8] = -1.23091320072982;
+   fWeightMatrix0to1[0][9] = 5.52742374052167;
+   fWeightMatrix0to1[1][9] = 0.331953730686133;
+   fWeightMatrix0to1[2][9] = -19.5847265608038;
+   fWeightMatrix0to1[3][9] = -1.53913124664622;
+   fWeightMatrix0to1[4][9] = 0.215609305342047;
+   fWeightMatrix0to1[5][9] = -0.608411498454232;
+   fWeightMatrix0to1[6][9] = -0.430741226777065;
+   fWeightMatrix0to1[7][9] = 2.14822277825618;
+   fWeightMatrix0to1[8][9] = -0.0258283278933676;
+   fWeightMatrix0to1[9][9] = 0.146374631346389;
+   fWeightMatrix0to1[10][9] = 15.6754813951346;
+   fWeightMatrix0to1[11][9] = -0.135240317838916;
+   fWeightMatrix0to1[12][9] = -0.0996438883507816;
+   fWeightMatrix0to1[13][9] = 0.420040389884772;
+   fWeightMatrix0to1[14][9] = -0.0954172987569679;
+   fWeightMatrix0to1[0][10] = 7.57622222724628;
+   fWeightMatrix0to1[1][10] = 10.3762954958289;
+   fWeightMatrix0to1[2][10] = -11.5886090386582;
+   fWeightMatrix0to1[3][10] = -1.68832794007581;
+   fWeightMatrix0to1[4][10] = -7.04481172830748;
+   fWeightMatrix0to1[5][10] = 0.277012281276143;
+   fWeightMatrix0to1[6][10] = -4.61480527480798;
+   fWeightMatrix0to1[7][10] = -14.6265242510637;
+   fWeightMatrix0to1[8][10] = 3.20790832876608;
+   fWeightMatrix0to1[9][10] = -29.867543619819;
+   fWeightMatrix0to1[10][10] = 25.5515399649744;
+   fWeightMatrix0to1[11][10] = -3.56288755880943;
+   fWeightMatrix0to1[12][10] = -2.59069026666014;
+   fWeightMatrix0to1[13][10] = -31.7144780979234;
+   fWeightMatrix0to1[14][10] = 2.02367723120475;
+   // weight matrix from layer 1 to 2
+   fWeightMatrix1to2[0][0] = -0.212000262813969;
+   fWeightMatrix1to2[0][1] = -0.927630312796793;
+   fWeightMatrix1to2[0][2] = 0.224665001966;
+   fWeightMatrix1to2[0][3] = 0.464526112961554;
+   fWeightMatrix1to2[0][4] = -0.401309586628313;
+   fWeightMatrix1to2[0][5] = 0.647264786628303;
+   fWeightMatrix1to2[0][6] = 0.720374144356743;
+   fWeightMatrix1to2[0][7] = 0.529024374814799;
+   fWeightMatrix1to2[0][8] = 0.448318829129643;
+   fWeightMatrix1to2[0][9] = 0.593470222390118;
+   fWeightMatrix1to2[0][10] = -3.30389673548254;
+   fWeightMatrix1to2[0][11] = 0.514169636701892;
+   fWeightMatrix1to2[0][12] = 0.424253407230348;
+   fWeightMatrix1to2[0][13] = 2.90636527932807;
+   fWeightMatrix1to2[0][14] = -0.300066009969093;
+   fWeightMatrix1to2[0][15] = 3.9644881274639;
+}
+
+inline double ReadMLPE::GetMvaValue__( const std::vector<double>& inputValues ) const
+{
+   if (inputValues.size() != (unsigned int)fLayerSize[0]-1) {
+      std::cout << "Input vector needs to be of size " << fLayerSize[0]-1 << std::endl;
+      return 0;
+   }
+
+   for (int l=0; l<fLayers; l++)
+      for (int i=0; i<fLayerSize[l]; i++) fWeights[l][i]=0;
+
+   for (int l=0; l<fLayers-1; l++)
+      fWeights[l][fLayerSize[l]-1]=1;
+
+   for (int i=0; i<fLayerSize[0]-1; i++)
+      fWeights[0][i]=inputValues[i];
+
+   // layer 0 to 1
+   for (int o=0; o<fLayerSize[1]-1; o++) {
+      for (int i=0; i<fLayerSize[0]; i++) {
+         double inputVal = fWeightMatrix0to1[o][i] * fWeights[0][i];
+         fWeights[1][o] += inputVal;
+      }
+      fWeights[1][o] = ActivationFnc(fWeights[1][o]);
+   }
+   // layer 1 to 2
+   for (int o=0; o<fLayerSize[2]; o++) {
+      for (int i=0; i<fLayerSize[1]; i++) {
+         double inputVal = fWeightMatrix1to2[o][i] * fWeights[1][i];
+         fWeights[2][o] += inputVal;
+      }
+      fWeights[2][o] = OutputActivationFnc(fWeights[2][o]);
+   }
+
+   return fWeights[2][0];
+}
+
+double ReadMLPE::ActivationFnc(double x) const {
+   // hyperbolic tan
+   return tanh(x);
+}
+double ReadMLPE::OutputActivationFnc(double x) const {
+   // sigmoid
+   return 1.0/(1.0+exp(-x));
+}
+
+// Clean up
+inline void ReadMLPE::Clear()
+{
+   // nothing to clear
+}
+   inline double ReadMLPE::GetMvaValue( const std::vector<double>& inputValues ) const
+   {
+      // classifier response value
+      double retval = 0;
+
+      // classifier response, sanity check first
+      if (!IsStatusClean()) {
+         std::cout << "Problem in class \"" << fClassName << "\": cannot return classifier response"
+                   << " because status is dirty" << std::endl;
+         retval = 0;
+      }
+      else {
+         if (IsNormalised()) {
+            // normalise variables
+            std::vector<double> iV;
+            int ivar = 0;
+            for (std::vector<double>::const_iterator varIt = inputValues.begin();
+                 varIt != inputValues.end(); varIt++, ivar++) {
+               iV.push_back(NormVariable( *varIt, fVmin[ivar], fVmax[ivar] ));
+            }
+            Transform( iV, -1 );
+            retval = GetMvaValue__( iV );
+         }
+         else {
+            std::vector<double> iV;
+            int ivar = 0;
+            for (std::vector<double>::const_iterator varIt = inputValues.begin();
+                 varIt != inputValues.end(); varIt++, ivar++) {
+               iV.push_back(*varIt);
+            }
+            Transform( iV, -1 );
+            retval = GetMvaValue__( iV );
+         }
+      }
+
+      return retval;
+   }
+
+//_______________________________________________________________________
+inline void ReadMLPE::InitTransform_1()
+{
+   // Normalization transformation, initialisation
+   fMin_1[0][0] = 0;
+   fMax_1[0][0] = 9999;
+   fMin_1[1][0] = 5.03054889123e-06;
+   fMax_1[1][0] = 9999;
+   fMin_1[2][0] = 0;
+   fMax_1[2][0] = 9999;
+   fMin_1[0][1] = 0;
+   fMax_1[0][1] = 280.579986572;
+   fMin_1[1][1] = 0;
+   fMax_1[1][1] = 280.579986572;
+   fMin_1[2][1] = 0;
+   fMax_1[2][1] = 280.579986572;
+   fMin_1[0][2] = 0;
+   fMax_1[0][2] = 1.73788714409;
+   fMin_1[1][2] = 0.140638813376;
+   fMax_1[1][2] = 1.41030442715;
+   fMin_1[2][2] = 0;
+   fMax_1[2][2] = 1.73788714409;
+   fMin_1[0][3] = 0;
+   fMax_1[0][3] = 41.9832572937;
+   fMin_1[1][3] = 0;
+   fMax_1[1][3] = 94.6786651611;
+   fMin_1[2][3] = 0;
+   fMax_1[2][3] = 94.6786651611;
+   fMin_1[0][4] = 0;
+   fMax_1[0][4] = 1;
+   fMin_1[1][4] = 0;
+   fMax_1[1][4] = 1;
+   fMin_1[2][4] = 0;
+   fMax_1[2][4] = 1;
+   fMin_1[0][5] = 0;
+   fMax_1[0][5] = 1;
+   fMin_1[1][5] = 0;
+   fMax_1[1][5] = 1;
+   fMin_1[2][5] = 0;
+   fMax_1[2][5] = 1;
+   fMin_1[0][6] = 0;
+   fMax_1[0][6] = 64433.078125;
+   fMin_1[1][6] = 165.730712891;
+   fMax_1[1][6] = 52884.8945312;
+   fMin_1[2][6] = 0;
+   fMax_1[2][6] = 64433.078125;
+   fMin_1[0][7] = 0;
+   fMax_1[0][7] = 853.807983398;
+   fMin_1[1][7] = 0;
+   fMax_1[1][7] = 955.837036133;
+   fMin_1[2][7] = 0;
+   fMax_1[2][7] = 955.837036133;
+   fMin_1[0][8] = 0;
+   fMax_1[0][8] = 10;
+   fMin_1[1][8] = 0;
+   fMax_1[1][8] = 9;
+   fMin_1[2][8] = 0;
+   fMax_1[2][8] = 10;
+   fMin_1[0][9] = 0;
+   fMax_1[0][9] = 9;
+   fMin_1[1][9] = 0;
+   fMax_1[1][9] = 9;
+   fMin_1[2][9] = 0;
+   fMax_1[2][9] = 9;
+}
+
+//_______________________________________________________________________
+inline void ReadMLPE::Transform_1( std::vector<double>& iv, int cls) const
+{
+   // Normalization transformation
+   if (cls < 0 || cls > 2) {
+   if (2 > 1 ) cls = 2;
+      else cls = 2;
+   }
+   const int nVar = 10;
+
+   // get indices of used variables
+
+   // define the indices of the variables which are transformed by this transformation
+   std::vector<int> indicesGet;
+   std::vector<int> indicesPut;
+
+   indicesGet.push_back( 0);
+   indicesGet.push_back( 1);
+   indicesGet.push_back( 2);
+   indicesGet.push_back( 3);
+   indicesGet.push_back( 4);
+   indicesGet.push_back( 5);
+   indicesGet.push_back( 6);
+   indicesGet.push_back( 7);
+   indicesGet.push_back( 8);
+   indicesGet.push_back( 9);
+   indicesPut.push_back( 0);
+   indicesPut.push_back( 1);
+   indicesPut.push_back( 2);
+   indicesPut.push_back( 3);
+   indicesPut.push_back( 4);
+   indicesPut.push_back( 5);
+   indicesPut.push_back( 6);
+   indicesPut.push_back( 7);
+   indicesPut.push_back( 8);
+   indicesPut.push_back( 9);
+
+   std::vector<double> dv(nVar);
+   for (int ivar=0; ivar<nVar; ivar++) dv[ivar] = iv[indicesGet.at(ivar)];
+   for (int ivar=0;ivar<10;ivar++) {
+      double offset = fMin_1[cls][ivar];
+      double scale  = 1.0/(fMax_1[cls][ivar]-fMin_1[cls][ivar]);
+      iv[indicesPut.at(ivar)] = (dv[ivar]-offset)*scale * 2 - 1;
+   }
+}
+
+//_______________________________________________________________________
+inline void ReadMLPE::InitTransform()
+{
+   InitTransform_1();
+}
+
+//_______________________________________________________________________
+inline void ReadMLPE::Transform( std::vector<double>& iv, int sigOrBgd ) const
+{
+   Transform_1( iv, sigOrBgd );
+}
diff --git a/CaloFuture/CaloFutureTools/src/TMV_MLP_H.C b/CaloFuture/CaloFutureTools/src/TMV_MLP_H.C
new file mode 100644
index 0000000000000000000000000000000000000000..ccbff1f4e8380c7c9a94f01d30a27b69321e2e8e
--- /dev/null
+++ b/CaloFuture/CaloFutureTools/src/TMV_MLP_H.C
@@ -0,0 +1,645 @@
+// Class: ReadMLPH
+// Automatically generated by MethodBase::MakeClass
+//
+
+/* configuration options =====================================================
+
+#GEN -*-*-*-*-*-*-*-*-*-*-*- general info -*-*-*-*-*-*-*-*-*-*-*-
+
+Method         : MLP::MLP
+TMVA Release   : 4.1.4         [262404]
+ROOT Release   : 5.34/05       [336389]
+Creator        : hoballah
+Date           : Thu Jul  4 13:08:41 2013
+Host           : Linux lxbuild175.cern.ch 2.6.18-308.4.1.el5 #1 SMP Wed Apr 18 16:26:27 CEST 2012 x86_64 x86_64 x86_64 GNU/Linux
+Dir            : /users/divers/lhcb/hoballah/December2012/B2KstG_ana/TMVA-v4.1.2/test/BDTs_PhotonID_new_var/train_test_noGnoPnoE
+Training events: 3902103
+Analysis type  : [Classification]
+
+
+#OPT -*-*-*-*-*-*-*-*-*-*-*-*- options -*-*-*-*-*-*-*-*-*-*-*-*-
+
+# Set by User:
+NCycles: "750" [Number of training cycles]
+HiddenLayers: "N+5" [Specification of hidden layer architecture]
+NeuronType: "tanh" [Neuron activation function type]
+EstimatorType: "CE" [MSE (Mean Square Estimator) for Gaussian Likelihood or CE(Cross-Entropy) for Bernoulli Likelihood]
+V: "False" [Verbose output (short form of "VerbosityLevel" below - overrides the latter one)]
+VarTransform: "N" [List of variable transformations performed before training, e.g., "D_Background,P_Signal,G,N_AllClasses" for: "Decorrelation, PCA-transformation, Gaussianisation, Normalisation, each for the given class of events ('AllClasses' denotes all events of all classes, if no class indication is given, 'All' is assumed)"]
+H: "True" [Print method-specific help message]
+TrainingMethod: "BP" [Train with Back-Propagation (BP), BFGS Algorithm (BFGS), or Genetic Algorithm (GA - slower and worse)]
+TestRate: "5" [Test for overtraining performed at each #th epochs]
+UseRegulator: "False" [Use regulator to avoid over-training]
+# Default:
+RandomSeed: "1" [Random seed for initial synapse weights (0 means unique seed for each run; default value '1')]
+NeuronInputType: "sum" [Neuron input function type]
+VerbosityLevel: "Default" [Verbosity level]
+CreateMVAPdfs: "False" [Create PDFs for classifier outputs (signal and background)]
+IgnoreNegWeightsInTraining: "False" [Events with negative weights are ignored in the training (but are included for testing and performance evaluation)]
+LearningRate: "2.000000e-02" [ANN learning rate parameter]
+DecayRate: "1.000000e-02" [Decay rate for learning parameter]
+EpochMonitoring: "False" [Provide epoch-wise monitoring plots according to TestRate (caution: causes big ROOT output file!)]
+Sampling: "1.000000e+00" [Only 'Sampling' (randomly selected) events are trained each epoch]
+SamplingEpoch: "1.000000e+00" [Sampling is used for the first 'SamplingEpoch' epochs, afterwards, all events are taken for training]
+SamplingImportance: "1.000000e+00" [ The sampling weights of events in epochs which successful (worse estimator than before) are multiplied with SamplingImportance, else they are divided.]
+SamplingTraining: "True" [The training sample is sampled]
+SamplingTesting: "False" [The testing sample is sampled]
+ResetStep: "50" [How often BFGS should reset history]
+Tau: "3.000000e+00" [LineSearch "size step"]
+BPMode: "sequential" [Back-propagation learning mode: sequential or batch]
+BatchSize: "-1" [Batch size: number of events/batch, only set if in Batch Mode, -1 for BatchSize=number_of_events]
+ConvergenceImprove: "1.000000e-30" [Minimum improvement which counts as improvement (<0 means automatic convergence check is turned off)]
+ConvergenceTests: "-1" [Number of steps (without improvement) required for convergence (<0 means automatic convergence check is turned off)]
+UpdateLimit: "10000" [Maximum times of regulator update]
+CalculateErrors: "False" [Calculates inverse Hessian matrix at the end of the training to be able to calculate the uncertainties of an MVA value]
+WeightRange: "1.000000e+00" [Take the events for the estimator calculations from small deviations from the desired value to large deviations only over the weight range]
+##
+
+
+#VAR -*-*-*-*-*-*-*-*-*-*-*-* variables *-*-*-*-*-*-*-*-*-*-*-*-
+
+NVar 10
+TMath::TanH(CaloHypo_ClusterMatch/2000)  TMath_TanH_CaloHypo_ClusterMatch_D_2000_ TMath::TanH(CaloHypo_ClusterMatch/2000)  CaloHypo_ClusterMatch                          units                                              'F'    [0,0.999909102917]
+CaloHypo_ToPrsE         CaloHypo_ToPrsE         CaloHypo_ToPrsE         CaloHypo_ToPrsE               units                             'F'    [0,280.579986572]
+CaloHypo_E19            CaloHypo_E19            CaloHypo_E19            CaloHypo_E19                  units                             'F'    [0,2.09823441505]
+CaloHypo_Hcal2Ecal      CaloHypo_Hcal2Ecal      CaloHypo_Hcal2Ecal      CaloHypo_Hcal2Ecal            units                             'F'    [0,65.5371170044]
+CaloHypo_PrsE19         CaloHypo_PrsE19         CaloHypo_PrsE19         CaloHypo_PrsE19         units                             'F'    [0,1]
+CaloHypo_PrsE49         CaloHypo_PrsE49         CaloHypo_PrsE49         CaloHypo_PrsE49         units                             'F'    [0,1]
+CaloHypo_Spread         CaloHypo_Spread         CaloHypo_Spread         CaloHypo_Spread         units                             'F'    [0,72525.4921875]
+CaloHypo_PrsE4Max       CaloHypo_PrsE4Max       CaloHypo_PrsE4Max       CaloHypo_PrsE4Max       units                             'F'    [0,865.601623535]
+CaloHypo_HypoPrsM       CaloHypo_HypoPrsM       CaloHypo_HypoPrsM       CaloHypo_HypoPrsM       units                             'F'    [0,10]
+CaloHypo_HypoSpdM       CaloHypo_HypoSpdM       CaloHypo_HypoSpdM       CaloHypo_HypoSpdM       units                             'F'    [0,9]
+NSpec 0
+
+
+============================================================================ */
+
+#include <vector>
+#include <cmath>
+#include <string>
+#include <iostream>
+
+#ifndef IClassifierReader__def
+#define IClassifierReader__def
+
+class IClassifierReader {
+
+ public:
+
+   // constructor
+   IClassifierReader() : fStatusIsClean( true ) {}
+   virtual ~IClassifierReader() {}
+
+   // return classifier response
+   virtual double GetMvaValue( const std::vector<double>& inputValues ) const = 0;
+
+   // returns classifier status
+   bool IsStatusClean() const { return fStatusIsClean; }
+
+ protected:
+
+   bool fStatusIsClean;
+};
+
+#endif
+
+class ReadMLPH : public IClassifierReader {
+
+ public:
+
+   // constructor
+   ReadMLPH( std::vector<std::string>& theInputVars )
+      : IClassifierReader(),
+        fClassName( "ReadMLPH" ),
+        fNvars( 10 ),
+        fIsNormalised( false )
+   {
+      // the training input variables
+      const char* inputVars[] = { "TMath::TanH(CaloHypo_ClusterMatch/2000)", "CaloHypo_ToPrsE", "CaloHypo_E19", "CaloHypo_Hcal2Ecal", "CaloHypo_PrsE19", "CaloHypo_PrsE49", "CaloHypo_Spread", "CaloHypo_PrsE4Max", "CaloHypo_HypoPrsM", "CaloHypo_HypoSpdM" };
+
+      // sanity checks
+      if (theInputVars.size() <= 0) {
+         std::cout << "Problem in class \"" << fClassName << "\": empty input vector" << std::endl;
+         fStatusIsClean = false;
+      }
+
+      if (theInputVars.size() != fNvars) {
+         std::cout << "Problem in class \"" << fClassName << "\": mismatch in number of input values: "
+                   << theInputVars.size() << " != " << fNvars << std::endl;
+         fStatusIsClean = false;
+      }
+
+      // validate input variables
+      for (size_t ivar = 0; ivar < theInputVars.size(); ivar++) {
+         if (theInputVars[ivar] != inputVars[ivar]) {
+            std::cout << "Problem in class \"" << fClassName << "\": mismatch in input variable names" << std::endl
+                      << " for variable [" << ivar << "]: " << theInputVars[ivar].c_str() << " != " << inputVars[ivar] << std::endl;
+            fStatusIsClean = false;
+         }
+      }
+
+      // initialize min and max vectors (for normalisation)
+      fVmin[0] = -1;
+      fVmax[0] = 1;
+      fVmin[1] = -1;
+      fVmax[1] = 1;
+      fVmin[2] = -1;
+      fVmax[2] = 1;
+      fVmin[3] = -1;
+      fVmax[3] = 1;
+      fVmin[4] = -1;
+      fVmax[4] = 1;
+      fVmin[5] = -1;
+      fVmax[5] = 1;
+      fVmin[6] = -1;
+      fVmax[6] = 1;
+      fVmin[7] = -1;
+      fVmax[7] = 1;
+      fVmin[8] = -1;
+      fVmax[8] = 1;
+      fVmin[9] = -1;
+      fVmax[9] = 1;
+
+      // initialize input variable types
+      fType[0] = 'F';
+      fType[1] = 'F';
+      fType[2] = 'F';
+      fType[3] = 'F';
+      fType[4] = 'F';
+      fType[5] = 'F';
+      fType[6] = 'F';
+      fType[7] = 'F';
+      fType[8] = 'F';
+      fType[9] = 'F';
+
+      // initialize constants
+      Initialize();
+
+      // initialize transformation
+      InitTransform();
+   }
+
+   // destructor
+   virtual ~ReadMLPH() {
+      Clear(); // method-specific
+   }
+
+   // the classifier response
+   // "inputValues" is a vector of input values in the same order as the
+   // variables given to the constructor
+   double GetMvaValue( const std::vector<double>& inputValues ) const override;
+
+ private:
+
+   // method-specific destructor
+   void Clear();
+
+   // input variable transformation
+
+   double fMin_1[3][10];
+   double fMax_1[3][10];
+   void InitTransform_1();
+   void Transform_1( std::vector<double> & iv, int sigOrBgd ) const;
+   void InitTransform();
+   void Transform( std::vector<double> & iv, int sigOrBgd ) const;
+
+   // common member variables
+   const char* fClassName;
+
+   const size_t fNvars;
+   size_t GetNvar()           const { return fNvars; }
+   char   GetType( int ivar ) const { return fType[ivar]; }
+
+   // normalisation of input variables
+   const bool fIsNormalised;
+   bool IsNormalised() const { return fIsNormalised; }
+   double fVmin[10];
+   double fVmax[10];
+   double NormVariable( double x, double xmin, double xmax ) const {
+      // normalise to output range: [-1, 1]
+      return 2*(x - xmin)/(xmax - xmin) - 1.0;
+   }
+
+   // type of input variable: 'F' or 'I'
+   char   fType[10];
+
+   // initialize internal variables
+   void Initialize();
+   double GetMvaValue__( const std::vector<double>& inputValues ) const;
+
+   // private members (method specific)
+
+   double ActivationFnc(double x) const;
+   double OutputActivationFnc(double x) const;
+
+   int fLayers;
+   int fLayerSize[3];
+   double fWeightMatrix0to1[16][11];   // weight matrix from layer 0 to 1
+   double fWeightMatrix1to2[1][16];   // weight matrix from layer 1 to 2
+
+   double * fWeights[3];
+};
+
+inline void ReadMLPH::Initialize()
+{
+   // build network structure
+   fLayers = 3;
+   fLayerSize[0] = 11; fWeights[0] = new double[11];
+   fLayerSize[1] = 16; fWeights[1] = new double[16];
+   fLayerSize[2] = 1; fWeights[2] = new double[1];
+   // weight matrix from layer 0 to 1
+   fWeightMatrix0to1[0][0] = 0.499791697169584;
+   fWeightMatrix0to1[1][0] = 0.0156937346966104;
+   fWeightMatrix0to1[2][0] = -0.369738840814315;
+   fWeightMatrix0to1[3][0] = 0.0484564925536612;
+   fWeightMatrix0to1[4][0] = -54.8356074198757;
+   fWeightMatrix0to1[5][0] = -0.0517232909505474;
+   fWeightMatrix0to1[6][0] = 0.269922710629987;
+   fWeightMatrix0to1[7][0] = 0.310507069564427;
+   fWeightMatrix0to1[8][0] = -0.31650124056531;
+   fWeightMatrix0to1[9][0] = -0.0452735528566461;
+   fWeightMatrix0to1[10][0] = -0.120523769099234;
+   fWeightMatrix0to1[11][0] = 0.046729826572728;
+   fWeightMatrix0to1[12][0] = -0.425197776585007;
+   fWeightMatrix0to1[13][0] = 0.139322438251145;
+   fWeightMatrix0to1[14][0] = 0.418958254799384;
+   fWeightMatrix0to1[0][1] = 4.07414005138199;
+   fWeightMatrix0to1[1][1] = -0.963589475727424;
+   fWeightMatrix0to1[2][1] = 20.1439661887903;
+   fWeightMatrix0to1[3][1] = 47.2015659342842;
+   fWeightMatrix0to1[4][1] = -0.496248377016052;
+   fWeightMatrix0to1[5][1] = -10.0462143213249;
+   fWeightMatrix0to1[6][1] = -3.07091129501229;
+   fWeightMatrix0to1[7][1] = -4.69426919570706;
+   fWeightMatrix0to1[8][1] = 0.70997164035673;
+   fWeightMatrix0to1[9][1] = 0.207635460256797;
+   fWeightMatrix0to1[10][1] = -1.3393513051332;
+   fWeightMatrix0to1[11][1] = 17.6758445921793;
+   fWeightMatrix0to1[12][1] = -10.138950676665;
+   fWeightMatrix0to1[13][1] = 0.431077189278333;
+   fWeightMatrix0to1[14][1] = 7.86583179460318;
+   fWeightMatrix0to1[0][2] = -0.145339067450411;
+   fWeightMatrix0to1[1][2] = 9.14181522823495;
+   fWeightMatrix0to1[2][2] = 0.203611887473639;
+   fWeightMatrix0to1[3][2] = -0.984192833381782;
+   fWeightMatrix0to1[4][2] = 1.15902596596526;
+   fWeightMatrix0to1[5][2] = 0.256278952248491;
+   fWeightMatrix0to1[6][2] = -2.46517971938777;
+   fWeightMatrix0to1[7][2] = 1.73605933033758;
+   fWeightMatrix0to1[8][2] = -8.02145443971624;
+   fWeightMatrix0to1[9][2] = 5.88010305867704;
+   fWeightMatrix0to1[10][2] = -0.713758870173103;
+   fWeightMatrix0to1[11][2] = 3.01072943804073;
+   fWeightMatrix0to1[12][2] = 0.0533090280598065;
+   fWeightMatrix0to1[13][2] = 0.475632001289167;
+   fWeightMatrix0to1[14][2] = -0.691552860221979;
+   fWeightMatrix0to1[0][3] = -3.25378744785488;
+   fWeightMatrix0to1[1][3] = -3.82910122715278;
+   fWeightMatrix0to1[2][3] = -25.0393347618618;
+   fWeightMatrix0to1[3][3] = -21.3553290079127;
+   fWeightMatrix0to1[4][3] = -37.9042574373599;
+   fWeightMatrix0to1[5][3] = 26.8912335875977;
+   fWeightMatrix0to1[6][3] = -5.84669874070948;
+   fWeightMatrix0to1[7][3] = 5.80638668429173;
+   fWeightMatrix0to1[8][3] = -1.98926386954341;
+   fWeightMatrix0to1[9][3] = 0.346537600846161;
+   fWeightMatrix0to1[10][3] = -1.15664693253549;
+   fWeightMatrix0to1[11][3] = -50.2125820478813;
+   fWeightMatrix0to1[12][3] = 6.5161456101295;
+   fWeightMatrix0to1[13][3] = -87.4184704653966;
+   fWeightMatrix0to1[14][3] = 2.26483551195462;
+   fWeightMatrix0to1[0][4] = -43.9690955900493;
+   fWeightMatrix0to1[1][4] = -0.00225311038605974;
+   fWeightMatrix0to1[2][4] = -0.304541297298231;
+   fWeightMatrix0to1[3][4] = 0.436386077708362;
+   fWeightMatrix0to1[4][4] = -0.0400773986570103;
+   fWeightMatrix0to1[5][4] = 0.262851086255125;
+   fWeightMatrix0to1[6][4] = 0.0494690293025466;
+   fWeightMatrix0to1[7][4] = -0.417767855824149;
+   fWeightMatrix0to1[8][4] = 0.0719745683747573;
+   fWeightMatrix0to1[9][4] = -0.557349960187241;
+   fWeightMatrix0to1[10][4] = -0.0697771327167742;
+   fWeightMatrix0to1[11][4] = -0.458996772175548;
+   fWeightMatrix0to1[12][4] = 2.54490124785549;
+   fWeightMatrix0to1[13][4] = 0.0160307456364636;
+   fWeightMatrix0to1[14][4] = -4.52218092140512;
+   fWeightMatrix0to1[0][5] = 0.0932681130451425;
+   fWeightMatrix0to1[1][5] = 0.175053708713905;
+   fWeightMatrix0to1[2][5] = -0.516198186699607;
+   fWeightMatrix0to1[3][5] = 0.180969941357541;
+   fWeightMatrix0to1[4][5] = 0.0609761788795187;
+   fWeightMatrix0to1[5][5] = 1.19584038070839;
+   fWeightMatrix0to1[6][5] = -0.759516914525722;
+   fWeightMatrix0to1[7][5] = 0.259604893242667;
+   fWeightMatrix0to1[8][5] = -0.552814273242625;
+   fWeightMatrix0to1[9][5] = -0.801307378689026;
+   fWeightMatrix0to1[10][5] = -0.512274728868527;
+   fWeightMatrix0to1[11][5] = 0.0391452676436715;
+   fWeightMatrix0to1[12][5] = -2.61761232216897;
+   fWeightMatrix0to1[13][5] = -0.030282187902499;
+   fWeightMatrix0to1[14][5] = -12.0787509544782;
+   fWeightMatrix0to1[0][6] = 32.7142611290786;
+   fWeightMatrix0to1[1][6] = 24.4537365543701;
+   fWeightMatrix0to1[2][6] = -0.852556540766488;
+   fWeightMatrix0to1[3][6] = 1.94432767673914;
+   fWeightMatrix0to1[4][6] = -1.10789872051392;
+   fWeightMatrix0to1[5][6] = -9.11148002855678;
+   fWeightMatrix0to1[6][6] = -3.60134573550497;
+   fWeightMatrix0to1[7][6] = 1.3476123210162;
+   fWeightMatrix0to1[8][6] = 5.76955728794814;
+   fWeightMatrix0to1[9][6] = -1.75770941068646;
+   fWeightMatrix0to1[10][6] = -0.258737946670854;
+   fWeightMatrix0to1[11][6] = -0.516104689067491;
+   fWeightMatrix0to1[12][6] = 0.867922930289291;
+   fWeightMatrix0to1[13][6] = -9.68509335114876;
+   fWeightMatrix0to1[14][6] = 0.162915322984271;
+   fWeightMatrix0to1[0][7] = 6.21848032482677;
+   fWeightMatrix0to1[1][7] = 2.43681171109174;
+   fWeightMatrix0to1[2][7] = 88.9538966037031;
+   fWeightMatrix0to1[3][7] = 2.2812617164849;
+   fWeightMatrix0to1[4][7] = 0.770377225014678;
+   fWeightMatrix0to1[5][7] = -1.37936902365579;
+   fWeightMatrix0to1[6][7] = 15.4919755959471;
+   fWeightMatrix0to1[7][7] = 27.2798331216326;
+   fWeightMatrix0to1[8][7] = -3.66140454553024;
+   fWeightMatrix0to1[9][7] = -4.94761965200881;
+   fWeightMatrix0to1[10][7] = 10.5910544025928;
+   fWeightMatrix0to1[11][7] = 26.6998445644734;
+   fWeightMatrix0to1[12][7] = 5.07993714680639;
+   fWeightMatrix0to1[13][7] = 0.568443695348981;
+   fWeightMatrix0to1[14][7] = -15.551498252802;
+   fWeightMatrix0to1[0][8] = -2.772411193299;
+   fWeightMatrix0to1[1][8] = -1.21555924450806;
+   fWeightMatrix0to1[2][8] = 0.36314443999594;
+   fWeightMatrix0to1[3][8] = 1.86934585858521;
+   fWeightMatrix0to1[4][8] = -0.33870914534062;
+   fWeightMatrix0to1[5][8] = 1.63913510921973;
+   fWeightMatrix0to1[6][8] = -0.940327258142375;
+   fWeightMatrix0to1[7][8] = -0.451351657789086;
+   fWeightMatrix0to1[8][8] = -0.802023741933935;
+   fWeightMatrix0to1[9][8] = 0.142686199701208;
+   fWeightMatrix0to1[10][8] = -0.0367383893101886;
+   fWeightMatrix0to1[11][8] = -1.47027790584272;
+   fWeightMatrix0to1[12][8] = -0.201137434248754;
+   fWeightMatrix0to1[13][8] = -0.0663662609421771;
+   fWeightMatrix0to1[14][8] = -9.2876284037384;
+   fWeightMatrix0to1[0][9] = -0.864965735173749;
+   fWeightMatrix0to1[1][9] = -0.0528064176926219;
+   fWeightMatrix0to1[2][9] = 0.470761720052231;
+   fWeightMatrix0to1[3][9] = -4.15161668908394;
+   fWeightMatrix0to1[4][9] = -0.313730029263097;
+   fWeightMatrix0to1[5][9] = 1.20854286758679;
+   fWeightMatrix0to1[6][9] = 0.959470209803684;
+   fWeightMatrix0to1[7][9] = -0.098415051066843;
+   fWeightMatrix0to1[8][9] = -0.338435591709211;
+   fWeightMatrix0to1[9][9] = 0.417338282361433;
+   fWeightMatrix0to1[10][9] = 21.5291749107274;
+   fWeightMatrix0to1[11][9] = 0.0625450793356017;
+   fWeightMatrix0to1[12][9] = -0.329884751871271;
+   fWeightMatrix0to1[13][9] = -0.269901631767981;
+   fWeightMatrix0to1[14][9] = 3.69925918255513;
+   fWeightMatrix0to1[0][10] = -8.36898295190574;
+   fWeightMatrix0to1[1][10] = 19.881856870813;
+   fWeightMatrix0to1[2][10] = 83.3644105603813;
+   fWeightMatrix0to1[3][10] = 25.7312740108938;
+   fWeightMatrix0to1[4][10] = -93.7775079760724;
+   fWeightMatrix0to1[5][10] = 8.9818733871343;
+   fWeightMatrix0to1[6][10] = 2.02986019149266;
+   fWeightMatrix0to1[7][10] = 29.7198945745259;
+   fWeightMatrix0to1[8][10] = -0.102145738286132;
+   fWeightMatrix0to1[9][10] = 0.43180772162006;
+   fWeightMatrix0to1[10][10] = 29.782079447293;
+   fWeightMatrix0to1[11][10] = -7.56631264091967;
+   fWeightMatrix0to1[12][10] = 4.01881367733937;
+   fWeightMatrix0to1[13][10] = -96.4690887810243;
+   fWeightMatrix0to1[14][10] = 7.4227530669183;
+   // weight matrix from layer 1 to 2
+   fWeightMatrix1to2[0][0] = -0.477770126699446;
+   fWeightMatrix1to2[0][1] = -0.715648296234819;
+   fWeightMatrix1to2[0][2] = 1.42004899380744;
+   fWeightMatrix1to2[0][3] = 0.632464097448029;
+   fWeightMatrix1to2[0][4] = -3.61744120798587;
+   fWeightMatrix1to2[0][5] = -0.614858988134529;
+   fWeightMatrix1to2[0][6] = -0.718414740687336;
+   fWeightMatrix1to2[0][7] = 1.54245599661198;
+   fWeightMatrix1to2[0][8] = 1.7146854728026;
+   fWeightMatrix1to2[0][9] = 1.74904842763901;
+   fWeightMatrix1to2[0][10] = -2.86792997268243;
+   fWeightMatrix1to2[0][11] = 0.527811346593655;
+   fWeightMatrix1to2[0][12] = 0.715192997629513;
+   fWeightMatrix1to2[0][13] = 4.24688162871256;
+   fWeightMatrix1to2[0][14] = -0.360776619570363;
+   fWeightMatrix1to2[0][15] = -3.90430570227444;
+}
+
+inline double ReadMLPH::GetMvaValue__( const std::vector<double>& inputValues ) const
+{
+   if (inputValues.size() != (unsigned int)fLayerSize[0]-1) {
+      std::cout << "Input vector needs to be of size " << fLayerSize[0]-1 << std::endl;
+      return 0;
+   }
+
+   for (int l=0; l<fLayers; l++)
+      for (int i=0; i<fLayerSize[l]; i++) fWeights[l][i]=0;
+
+   for (int l=0; l<fLayers-1; l++)
+      fWeights[l][fLayerSize[l]-1]=1;
+
+   for (int i=0; i<fLayerSize[0]-1; i++)
+      fWeights[0][i]=inputValues[i];
+
+   // layer 0 to 1
+   for (int o=0; o<fLayerSize[1]-1; o++) {
+      for (int i=0; i<fLayerSize[0]; i++) {
+         double inputVal = fWeightMatrix0to1[o][i] * fWeights[0][i];
+         fWeights[1][o] += inputVal;
+      }
+      fWeights[1][o] = ActivationFnc(fWeights[1][o]);
+   }
+   // layer 1 to 2
+   for (int o=0; o<fLayerSize[2]; o++) {
+      for (int i=0; i<fLayerSize[1]; i++) {
+         double inputVal = fWeightMatrix1to2[o][i] * fWeights[1][i];
+         fWeights[2][o] += inputVal;
+      }
+      fWeights[2][o] = OutputActivationFnc(fWeights[2][o]);
+   }
+
+   return fWeights[2][0];
+}
+
+double ReadMLPH::ActivationFnc(double x) const {
+   // hyperbolic tan
+   return tanh(x);
+}
+double ReadMLPH::OutputActivationFnc(double x) const {
+   // sigmoid
+   return 1.0/(1.0+exp(-x));
+}
+
+// Clean up
+inline void ReadMLPH::Clear()
+{
+   // nothing to clear
+}
+   inline double ReadMLPH::GetMvaValue( const std::vector<double>& inputValues ) const
+   {
+      // classifier response value
+      double retval = 0;
+
+      // classifier response, sanity check first
+      if (!IsStatusClean()) {
+         std::cout << "Problem in class \"" << fClassName << "\": cannot return classifier response"
+                   << " because status is dirty" << std::endl;
+         retval = 0;
+      }
+      else {
+         if (IsNormalised()) {
+            // normalise variables
+            std::vector<double> iV;
+            int ivar = 0;
+            for (std::vector<double>::const_iterator varIt = inputValues.begin();
+                 varIt != inputValues.end(); varIt++, ivar++) {
+               iV.push_back(NormVariable( *varIt, fVmin[ivar], fVmax[ivar] ));
+            }
+            Transform( iV, -1 );
+            retval = GetMvaValue__( iV );
+         }
+         else {
+            std::vector<double> iV;
+            int ivar = 0;
+            for (std::vector<double>::const_iterator varIt = inputValues.begin();
+                 varIt != inputValues.end(); varIt++, ivar++) {
+               iV.push_back(*varIt);
+            }
+            Transform( iV, -1 );
+            retval = GetMvaValue__( iV );
+         }
+      }
+
+      return retval;
+   }
+
+//_______________________________________________________________________
+inline void ReadMLPH::InitTransform_1()
+{
+   // Normalization transformation, initialisation
+   fMin_1[0][0] = 0;
+   fMax_1[0][0] = 0.999909102917;
+   fMin_1[1][0] = 2.9958599157e-08;
+   fMax_1[1][0] = 0.999909102917;
+   fMin_1[2][0] = 0;
+   fMax_1[2][0] = 0.999909102917;
+   fMin_1[0][1] = 0;
+   fMax_1[0][1] = 280.579986572;
+   fMin_1[1][1] = 0;
+   fMax_1[1][1] = 280.579986572;
+   fMin_1[2][1] = 0;
+   fMax_1[2][1] = 280.579986572;
+   fMin_1[0][2] = 0;
+   fMax_1[0][2] = 1.73788714409;
+   fMin_1[1][2] = 0.115419611335;
+   fMax_1[1][2] = 2.09823441505;
+   fMin_1[2][2] = 0;
+   fMax_1[2][2] = 2.09823441505;
+   fMin_1[0][3] = 0;
+   fMax_1[0][3] = 41.9832572937;
+   fMin_1[1][3] = 0;
+   fMax_1[1][3] = 65.5371170044;
+   fMin_1[2][3] = 0;
+   fMax_1[2][3] = 65.5371170044;
+   fMin_1[0][4] = 0;
+   fMax_1[0][4] = 1;
+   fMin_1[1][4] = 0;
+   fMax_1[1][4] = 1;
+   fMin_1[2][4] = 0;
+   fMax_1[2][4] = 1;
+   fMin_1[0][5] = 0;
+   fMax_1[0][5] = 1;
+   fMin_1[1][5] = 0;
+   fMax_1[1][5] = 1;
+   fMin_1[2][5] = 0;
+   fMax_1[2][5] = 1;
+   fMin_1[0][6] = 0;
+   fMax_1[0][6] = 64433.078125;
+   fMin_1[1][6] = 155.35319519;
+   fMax_1[1][6] = 72525.4921875;
+   fMin_1[2][6] = 0;
+   fMax_1[2][6] = 72525.4921875;
+   fMin_1[0][7] = 0;
+   fMax_1[0][7] = 853.807983398;
+   fMin_1[1][7] = 0;
+   fMax_1[1][7] = 865.601623535;
+   fMin_1[2][7] = 0;
+   fMax_1[2][7] = 865.601623535;
+   fMin_1[0][8] = 0;
+   fMax_1[0][8] = 10;
+   fMin_1[1][8] = 0;
+   fMax_1[1][8] = 9;
+   fMin_1[2][8] = 0;
+   fMax_1[2][8] = 10;
+   fMin_1[0][9] = 0;
+   fMax_1[0][9] = 9;
+   fMin_1[1][9] = 0;
+   fMax_1[1][9] = 9;
+   fMin_1[2][9] = 0;
+   fMax_1[2][9] = 9;
+}
+
+//_______________________________________________________________________
+inline void ReadMLPH::Transform_1( std::vector<double>& iv, int cls) const
+{
+   // Normalization transformation
+   if (cls < 0 || cls > 2) {
+   if (2 > 1 ) cls = 2;
+      else cls = 2;
+   }
+   const int nVar = 10;
+
+   // get indices of used variables
+
+   // define the indices of the variables which are transformed by this transformation
+   std::vector<int> indicesGet;
+   std::vector<int> indicesPut;
+
+   indicesGet.push_back( 0);
+   indicesGet.push_back( 1);
+   indicesGet.push_back( 2);
+   indicesGet.push_back( 3);
+   indicesGet.push_back( 4);
+   indicesGet.push_back( 5);
+   indicesGet.push_back( 6);
+   indicesGet.push_back( 7);
+   indicesGet.push_back( 8);
+   indicesGet.push_back( 9);
+   indicesPut.push_back( 0);
+   indicesPut.push_back( 1);
+   indicesPut.push_back( 2);
+   indicesPut.push_back( 3);
+   indicesPut.push_back( 4);
+   indicesPut.push_back( 5);
+   indicesPut.push_back( 6);
+   indicesPut.push_back( 7);
+   indicesPut.push_back( 8);
+   indicesPut.push_back( 9);
+
+   std::vector<double> dv(nVar);
+   for (int ivar=0; ivar<nVar; ivar++) dv[ivar] = iv[indicesGet.at(ivar)];
+   for (int ivar=0;ivar<10;ivar++) {
+      double offset = fMin_1[cls][ivar];
+      double scale  = 1.0/(fMax_1[cls][ivar]-fMin_1[cls][ivar]);
+      iv[indicesPut.at(ivar)] = (dv[ivar]-offset)*scale * 2 - 1;
+   }
+}
+
+//_______________________________________________________________________
+inline void ReadMLPH::InitTransform()
+{
+   InitTransform_1();
+}
+
+//_______________________________________________________________________
+inline void ReadMLPH::Transform( std::vector<double>& iv, int sigOrBgd ) const
+{
+   Transform_1( iv, sigOrBgd );
+}
diff --git a/CaloFuture/CaloFutureTools/src/TMV_MLP_inner.C b/CaloFuture/CaloFutureTools/src/TMV_MLP_inner.C
new file mode 100644
index 0000000000000000000000000000000000000000..6447cd6db58c3f5bfdd9ef329bdd68efd1cd7682
--- /dev/null
+++ b/CaloFuture/CaloFutureTools/src/TMV_MLP_inner.C
@@ -0,0 +1,817 @@
+// Class: ReadMLPInner
+// Automatically generated by MethodBase::MakeClass
+//
+
+/* configuration options =====================================================
+
+#GEN -*-*-*-*-*-*-*-*-*-*-*- general info -*-*-*-*-*-*-*-*-*-*-*-
+
+Method         : MLP::MLP
+TMVA Release   : 4.1.2         [262402]
+ROOT Release   : 5.30/00       [335360]
+Creator        : calvom
+Date           : Tue Nov  8 16:41:52 2011
+Host           : Linux lxbuild148.cern.ch 2.6.18-194.26.1.el5 #1 SMP Wed Nov 10 09:45:46 CET 2010 x86_64 x86_64 x86_64 GNU/Linux
+Dir            : /afs/cern.ch/user/c/calvom/w0/GammaPi0/tmva_calib
+Training events: 27236
+Analysis type  : [Classification]
+
+
+#OPT -*-*-*-*-*-*-*-*-*-*-*-*- options -*-*-*-*-*-*-*-*-*-*-*-*-
+
+# Set by User:
+NCycles: "600" [Number of training cycles]
+HiddenLayers: "N+5" [Specification of hidden layer architecture]
+NeuronType: "tanh" [Neuron activation function type]
+V: "False" [Verbose output (short form of "VerbosityLevel" below - overrides the latter one)]
+VarTransform: "N" [List of variable transformations performed before training, e.g., "D_Background,P_Signal,G,N_AllClasses" for: "Decorrelation, PCA-transformation, Gaussianisation, Normalisation, each for the given class of events ('AllClasses' denotes all events of all classes, if no class indication is given, 'All' is assumed)"]
+H: "True" [Print method-specific help message]
+TestRate: "5" [Test for overtraining performed at each #th epochs]
+# Default:
+RandomSeed: "1" [Random seed for initial synapse weights (0 means unique seed for each run; default value '1')]
+EstimatorType: "MSE" [MSE (Mean Square Estimator) for Gaussian Likelihood or CE(Cross-Entropy) for Bernoulli Likelihood]
+NeuronInputType: "sum" [Neuron input function type]
+VerbosityLevel: "Default" [Verbosity level]
+CreateMVAPdfs: "False" [Create PDFs for classifier outputs (signal and background)]
+IgnoreNegWeightsInTraining: "False" [Events with negative weights are ignored in the training (but are included for testing and performance evaluation)]
+TrainingMethod: "BP" [Train with Back-Propagation (BP), BFGS Algorithm (BFGS), or Genetic Algorithm (GA - slower and worse)]
+LearningRate: "2.000000e-02" [ANN learning rate parameter]
+DecayRate: "1.000000e-02" [Decay rate for learning parameter]
+EpochMonitoring: "False" [Provide epoch-wise monitoring plots according to TestRate (caution: causes big ROOT output file!)]
+Sampling: "1.000000e+00" [Only 'Sampling' (randomly selected) events are trained each epoch]
+SamplingEpoch: "1.000000e+00" [Sampling is used for the first 'SamplingEpoch' epochs, afterwards, all events are taken for training]
+SamplingImportance: "1.000000e+00" [ The sampling weights of events in epochs which successful (worse estimator than before) are multiplied with SamplingImportance, else they are divided.]
+SamplingTraining: "True" [The training sample is sampled]
+SamplingTesting: "False" [The testing sample is sampled]
+ResetStep: "50" [How often BFGS should reset history]
+Tau: "3.000000e+00" [LineSearch "size step"]
+BPMode: "sequential" [Back-propagation learning mode: sequential or batch]
+BatchSize: "-1" [Batch size: number of events/batch, only set if in Batch Mode, -1 for BatchSize=number_of_events]
+ConvergenceImprove: "1.000000e-30" [Minimum improvement which counts as improvement (<0 means automatic convergence check is turned off)]
+ConvergenceTests: "-1" [Number of steps (without improvement) required for convergence (<0 means automatic convergence check is turned off)]
+UseRegulator: "False" [Use regulator to avoid over-training]
+UpdateLimit: "10000" [Maximum times of regulator update]
+CalculateErrors: "False" [Calculates inverse Hessian matrix at the end of the training to be able to calculate the uncertainties of an MVA value]
+WeightRange: "1.000000e+00" [Take the events for the estimator calculations from small deviations from the desired value to large deviations only over the weight range]
+##
+
+
+#VAR -*-*-*-*-*-*-*-*-*-*-*-* variables *-*-*-*-*-*-*-*-*-*-*-*-
+
+NVar 14
+fr2                           fr2                           fr2                           fr2                                                             'F'    [256.407440186,5158.10546875]
+fr2r4                         fr2r4                         fr2r4                         fr2r4                                                           'F'    [0.340296119452,0.940254509449]
+abs(asym)                     abs_asym_                     abs(asym)                     abs(asym)                                                       'F'    [1.20151833016e-06,0.7383441329]
+kappa                         kappa                         kappa                         kappa                                                           'F'    [0.00133013306186,0.77249121666]
+Eseed/Ecl                     Eseed_D_Ecl                   Eseed/Ecl                     Eseed/Ecl                                                       'F'    [0.209150001407,0.919608473778]
+(E2+Eseed)/Ecl                _E2_P_Eseed__D_Ecl            (E2+Eseed)/Ecl                (E2+Eseed)/Ecl                                                  'F'    [0.399627387524,0.9744130373]
+eSumPS>0?eMaxPS/eSumPS:0      eSumPS_0_eMaxPS_D_eSumPS:0    eSumPS>0?eMaxPS/eSumPS:0      eSumPS>0?eMaxPS/eSumPS:0                                        'F'    [0,1]
+eSumPS>0?e2ndPS/eSumPS:0      eSumPS_0_e2ndPS_D_eSumPS:0    eSumPS>0?e2ndPS/eSumPS:0      eSumPS>0?e2ndPS/eSumPS:0                                        'F'    [0,0.496332526207]
+r2PS                          r2PS                          r2PS                          r2PS                                                            'F'    [0,1.99933886528]
+abs(asymPS)                   abs_asymPS_                   abs(asymPS)                   abs(asymPS)                                                     'F'    [0,1]
+multiPS                       multiPS                       multiPS                       multiPS                                                         'F'    [0,9]
+multiPS15                     multiPS15                     multiPS15                     multiPS15                                                       'F'    [0,6]
+multiPS30                     multiPS30                     multiPS30                     multiPS30                                                       'F'    [0,6]
+multiPS45                     multiPS45                     multiPS45                     multiPS45                                                       'F'    [0,5]
+NSpec 0
+
+
+============================================================================ */
+
+#include <vector>
+#include <cmath>
+#include <string>
+#include <iostream>
+
+#ifndef IClassifierReader__def
+#define IClassifierReader__def
+
+class IClassifierReader {
+
+ public:
+
+   // constructor
+   IClassifierReader() : fStatusIsClean( true ) {}
+   virtual ~IClassifierReader() {}
+
+   // return classifier response
+   virtual double GetMvaValue( const std::vector<double>& inputValues ) const = 0;
+
+   // returns classifier status
+   bool IsStatusClean() const { return fStatusIsClean; }
+
+ protected:
+
+   bool fStatusIsClean;
+};
+
+#endif
+
+class ReadMLPInner : public IClassifierReader {
+
+ public:
+
+   // constructor
+   ReadMLPInner( const std::vector<std::string>& theInputVars )
+      : IClassifierReader(),
+        fClassName( "ReadMLPInner" ),
+        fNvars( 14 ),
+        fIsNormalised( false )
+   {
+      // the training input variables
+      const char* inputVars[] = { "fr2", "fr2r4", "abs(asym)", "kappa", "Eseed/Ecl", "(E2+Eseed)/Ecl", "eSumPS>0?eMaxPS/eSumPS:0", "eSumPS>0?e2ndPS/eSumPS:0", "r2PS", "abs(asymPS)", "multiPS", "multiPS15", "multiPS30", "multiPS45" };
+
+      // sanity checks
+      if (theInputVars.size() <= 0) {
+         std::cout << "Problem in class \"" << fClassName << "\": empty input vector" << std::endl;
+         fStatusIsClean = false;
+      }
+
+      if (theInputVars.size() != fNvars) {
+         std::cout << "Problem in class \"" << fClassName << "\": mismatch in number of input values: "
+                   << theInputVars.size() << " != " << fNvars << std::endl;
+         fStatusIsClean = false;
+      }
+
+      // validate input variables
+      for (size_t ivar = 0; ivar < theInputVars.size(); ivar++) {
+         if (theInputVars[ivar] != inputVars[ivar]) {
+            std::cout << "Problem in class \"" << fClassName << "\": mismatch in input variable names" << std::endl
+                      << " for variable [" << ivar << "]: " << theInputVars[ivar].c_str() << " != " << inputVars[ivar] << std::endl;
+            fStatusIsClean = false;
+         }
+      }
+
+      // initialize min and max vectors (for normalisation)
+      fVmin[0] = -1;
+      fVmax[0] = 1;
+      fVmin[1] = -1;
+      fVmax[1] = 1;
+      fVmin[2] = -1;
+      fVmax[2] = 1;
+      fVmin[3] = -1;
+      fVmax[3] = 0.99999988079071;
+      fVmin[4] = -1;
+      fVmax[4] = 1;
+      fVmin[5] = -1;
+      fVmax[5] = 1;
+      fVmin[6] = -1;
+      fVmax[6] = 1;
+      fVmin[7] = -1;
+      fVmax[7] = 1;
+      fVmin[8] = -1;
+      fVmax[8] = 1;
+      fVmin[9] = -1;
+      fVmax[9] = 1;
+      fVmin[10] = -1;
+      fVmax[10] = 1;
+      fVmin[11] = -1;
+      fVmax[11] = 1;
+      fVmin[12] = -1;
+      fVmax[12] = 1;
+      fVmin[13] = -1;
+      fVmax[13] = 1;
+
+      // initialize input variable types
+      fType[0] = 'F';
+      fType[1] = 'F';
+      fType[2] = 'F';
+      fType[3] = 'F';
+      fType[4] = 'F';
+      fType[5] = 'F';
+      fType[6] = 'F';
+      fType[7] = 'F';
+      fType[8] = 'F';
+      fType[9] = 'F';
+      fType[10] = 'F';
+      fType[11] = 'F';
+      fType[12] = 'F';
+      fType[13] = 'F';
+
+      // initialize constants
+      Initialize();
+
+      // initialize transformation
+      InitTransform();
+   }
+
+   // destructor
+   virtual ~ReadMLPInner() {
+      Clear(); // method-specific
+   }
+
+   // the classifier response
+   // "inputValues" is a vector of input values in the same order as the
+   // variables given to the constructor
+   double GetMvaValue( const std::vector<double>& inputValues ) const override;
+
+ private:
+
+   // method-specific destructor
+   void Clear();
+
+   // input variable transformation
+
+   double fMin_1[3][14];
+   double fMax_1[3][14];
+   void InitTransform_1();
+   void Transform_1( std::vector<double> & iv, int sigOrBgd ) const;
+   void InitTransform();
+   void Transform( std::vector<double> & iv, int sigOrBgd ) const;
+
+   // common member variables
+   const char* fClassName;
+
+   const size_t fNvars;
+   size_t GetNvar()           const { return fNvars; }
+   char   GetType( int ivar ) const { return fType[ivar]; }
+
+   // normalisation of input variables
+   const bool fIsNormalised;
+   bool IsNormalised() const { return fIsNormalised; }
+   double fVmin[14];
+   double fVmax[14];
+   double NormVariable( double x, double xmin, double xmax ) const {
+      // normalise to output range: [-1, 1]
+      return 2*(x - xmin)/(xmax - xmin) - 1.0;
+   }
+
+   // type of input variable: 'F' or 'I'
+   char   fType[14];
+
+   // initialize internal variables
+   void Initialize();
+   double GetMvaValue__( const std::vector<double>& inputValues ) const;
+
+   // private members (method specific)
+
+   double ActivationFnc(double x) const;
+   double OutputActivationFnc(double x) const;
+
+   int fLayers;
+   int fLayerSize[3];
+   double fWeightMatrix0to1[20][15];   // weight matrix from layer 0 to 1
+   double fWeightMatrix1to2[1][20];   // weight matrix from layer 1 to 2
+
+   double * fWeights[3];
+};
+
+inline void ReadMLPInner::Initialize()
+{
+   // build network structure
+   fLayers = 3;
+   fLayerSize[0] = 15; fWeights[0] = new double[15];
+   fLayerSize[1] = 20; fWeights[1] = new double[20];
+   fLayerSize[2] = 1; fWeights[2] = new double[1];
+   // weight matrix from layer 0 to 1
+   fWeightMatrix0to1[0][0] = -1.04290737527736;
+   fWeightMatrix0to1[1][0] = 2.70473526006312;
+   fWeightMatrix0to1[2][0] = 0.842724629892599;
+   fWeightMatrix0to1[3][0] = 2.26361521268781;
+   fWeightMatrix0to1[4][0] = -2.50890641104074;
+   fWeightMatrix0to1[5][0] = -0.846059312068215;
+   fWeightMatrix0to1[6][0] = -0.495414196093438;
+   fWeightMatrix0to1[7][0] = 2.64669025173505;
+   fWeightMatrix0to1[8][0] = -2.08512389745182;
+   fWeightMatrix0to1[9][0] = -1.32731998771946;
+   fWeightMatrix0to1[10][0] = -1.76369356867673;
+   fWeightMatrix0to1[11][0] = 0.0715211314613232;
+   fWeightMatrix0to1[12][0] = -0.369323557681417;
+   fWeightMatrix0to1[13][0] = -0.308104834419547;
+   fWeightMatrix0to1[14][0] = -1.46194920849862;
+   fWeightMatrix0to1[15][0] = 1.01388083906704;
+   fWeightMatrix0to1[16][0] = -0.688359487549371;
+   fWeightMatrix0to1[17][0] = 2.10005606938448;
+   fWeightMatrix0to1[18][0] = 0.21059023322323;
+   fWeightMatrix0to1[0][1] = 0.837073531436717;
+   fWeightMatrix0to1[1][1] = 0.0976385447684772;
+   fWeightMatrix0to1[2][1] = -1.64258403122012;
+   fWeightMatrix0to1[3][1] = 0.525861831096759;
+   fWeightMatrix0to1[4][1] = 0.687652967600606;
+   fWeightMatrix0to1[5][1] = -0.826070743174519;
+   fWeightMatrix0to1[6][1] = -0.232208661875282;
+   fWeightMatrix0to1[7][1] = 0.659261751404932;
+   fWeightMatrix0to1[8][1] = -1.57228734837995;
+   fWeightMatrix0to1[9][1] = -1.82014057521236;
+   fWeightMatrix0to1[10][1] = 0.384976761578452;
+   fWeightMatrix0to1[11][1] = 0.459553043196147;
+   fWeightMatrix0to1[12][1] = 1.27425198975868;
+   fWeightMatrix0to1[13][1] = -1.13086944167455;
+   fWeightMatrix0to1[14][1] = -2.96296349862317;
+   fWeightMatrix0to1[15][1] = -0.112078673860112;
+   fWeightMatrix0to1[16][1] = -0.364895039620327;
+   fWeightMatrix0to1[17][1] = -2.0433661174012;
+   fWeightMatrix0to1[18][1] = 1.54624548320321;
+   fWeightMatrix0to1[0][2] = -0.637671435862953;
+   fWeightMatrix0to1[1][2] = 0.397278940196906;
+   fWeightMatrix0to1[2][2] = 0.277972173520998;
+   fWeightMatrix0to1[3][2] = 1.31034307637501;
+   fWeightMatrix0to1[4][2] = 1.08237245822997;
+   fWeightMatrix0to1[5][2] = 1.92430164089826;
+   fWeightMatrix0to1[6][2] = -0.615430183398319;
+   fWeightMatrix0to1[7][2] = -0.575223577050631;
+   fWeightMatrix0to1[8][2] = 0.158409883281879;
+   fWeightMatrix0to1[9][2] = -0.178322855564784;
+   fWeightMatrix0to1[10][2] = 0.953159662758702;
+   fWeightMatrix0to1[11][2] = 1.58766160896782;
+   fWeightMatrix0to1[12][2] = 2.25712788264313;
+   fWeightMatrix0to1[13][2] = 2.38047728401168;
+   fWeightMatrix0to1[14][2] = -0.549580407122151;
+   fWeightMatrix0to1[15][2] = 1.05640851708416;
+   fWeightMatrix0to1[16][2] = -2.0559354676541;
+   fWeightMatrix0to1[17][2] = 0.0323101610937663;
+   fWeightMatrix0to1[18][2] = -0.892003791450972;
+   fWeightMatrix0to1[0][3] = -2.89424971334362;
+   fWeightMatrix0to1[1][3] = 1.26746721164734;
+   fWeightMatrix0to1[2][3] = -0.0762248316342091;
+   fWeightMatrix0to1[3][3] = -1.21441731817952;
+   fWeightMatrix0to1[4][3] = -0.250090311316658;
+   fWeightMatrix0to1[5][3] = -0.353695590021927;
+   fWeightMatrix0to1[6][3] = 0.566897065530219;
+   fWeightMatrix0to1[7][3] = 0.367598832532309;
+   fWeightMatrix0to1[8][3] = -0.97998644736544;
+   fWeightMatrix0to1[9][3] = -0.839734090224558;
+   fWeightMatrix0to1[10][3] = -1.13443817816697;
+   fWeightMatrix0to1[11][3] = 0.795613322993873;
+   fWeightMatrix0to1[12][3] = -0.36128332798357;
+   fWeightMatrix0to1[13][3] = 0.791435019948385;
+   fWeightMatrix0to1[14][3] = -0.972677060580533;
+   fWeightMatrix0to1[15][3] = 0.765038950589299;
+   fWeightMatrix0to1[16][3] = 0.78268350889215;
+   fWeightMatrix0to1[17][3] = 1.12945205131092;
+   fWeightMatrix0to1[18][3] = -0.445399279135853;
+   fWeightMatrix0to1[0][4] = -1.77770807762748;
+   fWeightMatrix0to1[1][4] = -0.632357676106347;
+   fWeightMatrix0to1[2][4] = 0.36317389912568;
+   fWeightMatrix0to1[3][4] = 0.894415041886562;
+   fWeightMatrix0to1[4][4] = 2.36637904519226;
+   fWeightMatrix0to1[5][4] = 1.16813909044691;
+   fWeightMatrix0to1[6][4] = 0.957092840127218;
+   fWeightMatrix0to1[7][4] = -1.30836798446254;
+   fWeightMatrix0to1[8][4] = -0.595420753901453;
+   fWeightMatrix0to1[9][4] = -0.614732883419485;
+   fWeightMatrix0to1[10][4] = 0.942790131176385;
+   fWeightMatrix0to1[11][4] = -1.02368950468983;
+   fWeightMatrix0to1[12][4] = -1.68076385296451;
+   fWeightMatrix0to1[13][4] = -1.23324912228085;
+   fWeightMatrix0to1[14][4] = 0.415592104701746;
+   fWeightMatrix0to1[15][4] = -0.17872879341687;
+   fWeightMatrix0to1[16][4] = 1.13361004021582;
+   fWeightMatrix0to1[17][4] = -1.20050470223068;
+   fWeightMatrix0to1[18][4] = -1.1104728542419;
+   fWeightMatrix0to1[0][5] = 2.05797225374773;
+   fWeightMatrix0to1[1][5] = -0.696162390135965;
+   fWeightMatrix0to1[2][5] = -2.21770021810581;
+   fWeightMatrix0to1[3][5] = -1.04718674389046;
+   fWeightMatrix0to1[4][5] = 0.862452877331307;
+   fWeightMatrix0to1[5][5] = -1.06419801692172;
+   fWeightMatrix0to1[6][5] = -1.76968728079571;
+   fWeightMatrix0to1[7][5] = -0.555996843115734;
+   fWeightMatrix0to1[8][5] = 1.18249132828029;
+   fWeightMatrix0to1[9][5] = -1.53431472191485;
+   fWeightMatrix0to1[10][5] = 1.57909174709495;
+   fWeightMatrix0to1[11][5] = -1.19669832089179;
+   fWeightMatrix0to1[12][5] = -1.29760121275024;
+   fWeightMatrix0to1[13][5] = 0.19270020308523;
+   fWeightMatrix0to1[14][5] = 1.24880029341451;
+   fWeightMatrix0to1[15][5] = -1.88188502955362;
+   fWeightMatrix0to1[16][5] = -0.159437524078109;
+   fWeightMatrix0to1[17][5] = 0.0348243191319361;
+   fWeightMatrix0to1[18][5] = 0.20743091300093;
+   fWeightMatrix0to1[0][6] = -0.764981614221069;
+   fWeightMatrix0to1[1][6] = -0.0788912101468469;
+   fWeightMatrix0to1[2][6] = 0.0831227210927517;
+   fWeightMatrix0to1[3][6] = -0.775775264233783;
+   fWeightMatrix0to1[4][6] = 0.39768218578583;
+   fWeightMatrix0to1[5][6] = -0.193922755794659;
+   fWeightMatrix0to1[6][6] = -1.58925719839167;
+   fWeightMatrix0to1[7][6] = -0.889817928434628;
+   fWeightMatrix0to1[8][6] = 0.649938955471886;
+   fWeightMatrix0to1[9][6] = 0.867709763850432;
+   fWeightMatrix0to1[10][6] = 0.740468306185537;
+   fWeightMatrix0to1[11][6] = -0.590596027104339;
+   fWeightMatrix0to1[12][6] = -0.533604230893194;
+   fWeightMatrix0to1[13][6] = 0.671730556997688;
+   fWeightMatrix0to1[14][6] = -0.449052784218705;
+   fWeightMatrix0to1[15][6] = 0.71912421638838;
+   fWeightMatrix0to1[16][6] = 0.423547719616505;
+   fWeightMatrix0to1[17][6] = -1.23294651339297;
+   fWeightMatrix0to1[18][6] = 0.722728624277078;
+   fWeightMatrix0to1[0][7] = -0.658192334225956;
+   fWeightMatrix0to1[1][7] = 0.196528618013865;
+   fWeightMatrix0to1[2][7] = 1.13680440873838;
+   fWeightMatrix0to1[3][7] = 1.20693801607716;
+   fWeightMatrix0to1[4][7] = -1.3096837025049;
+   fWeightMatrix0to1[5][7] = -0.37136771300458;
+   fWeightMatrix0to1[6][7] = 1.435180853539;
+   fWeightMatrix0to1[7][7] = 0.901601754691063;
+   fWeightMatrix0to1[8][7] = -0.25174077192635;
+   fWeightMatrix0to1[9][7] = -0.604725647208693;
+   fWeightMatrix0to1[10][7] = -0.16884086080176;
+   fWeightMatrix0to1[11][7] = -0.906755800255;
+   fWeightMatrix0to1[12][7] = 1.35317789869573;
+   fWeightMatrix0to1[13][7] = 0.174270227756606;
+   fWeightMatrix0to1[14][7] = -0.280830891638428;
+   fWeightMatrix0to1[15][7] = -0.362098577847321;
+   fWeightMatrix0to1[16][7] = 0.335214223040219;
+   fWeightMatrix0to1[17][7] = -0.702921687211048;
+   fWeightMatrix0to1[18][7] = 0.166031955217452;
+   fWeightMatrix0to1[0][8] = 0.91939746258453;
+   fWeightMatrix0to1[1][8] = -0.13387556855178;
+   fWeightMatrix0to1[2][8] = 0.43066585397933;
+   fWeightMatrix0to1[3][8] = 0.0811478903004244;
+   fWeightMatrix0to1[4][8] = 0.90799694626677;
+   fWeightMatrix0to1[5][8] = 0.384352609340622;
+   fWeightMatrix0to1[6][8] = 1.05363849430897;
+   fWeightMatrix0to1[7][8] = -1.45217522191468;
+   fWeightMatrix0to1[8][8] = 0.865684583886025;
+   fWeightMatrix0to1[9][8] = 1.00932821334351;
+   fWeightMatrix0to1[10][8] = 0.155860197767314;
+   fWeightMatrix0to1[11][8] = 1.10414192697408;
+   fWeightMatrix0to1[12][8] = 1.64353618478304;
+   fWeightMatrix0to1[13][8] = 0.388125070845243;
+   fWeightMatrix0to1[14][8] = 0.0693610841952537;
+   fWeightMatrix0to1[15][8] = 1.28650684566217;
+   fWeightMatrix0to1[16][8] = -1.32106134412902;
+   fWeightMatrix0to1[17][8] = 0.104715889241616;
+   fWeightMatrix0to1[18][8] = 1.34803140000267;
+   fWeightMatrix0to1[0][9] = 0.320934088411829;
+   fWeightMatrix0to1[1][9] = 0.0834251158725143;
+   fWeightMatrix0to1[2][9] = 1.07271749799617;
+   fWeightMatrix0to1[3][9] = 0.964961284465372;
+   fWeightMatrix0to1[4][9] = -1.14160729387509;
+   fWeightMatrix0to1[5][9] = 0.612322237162634;
+   fWeightMatrix0to1[6][9] = 0.376295371866361;
+   fWeightMatrix0to1[7][9] = 0.778169478111247;
+   fWeightMatrix0to1[8][9] = -0.10591272925161;
+   fWeightMatrix0to1[9][9] = -0.233317739206228;
+   fWeightMatrix0to1[10][9] = 0.533176446007596;
+   fWeightMatrix0to1[11][9] = 1.38047512736593;
+   fWeightMatrix0to1[12][9] = -0.792662013406803;
+   fWeightMatrix0to1[13][9] = -0.0448794496386986;
+   fWeightMatrix0to1[14][9] = -0.16388482687671;
+   fWeightMatrix0to1[15][9] = 0.13076205026299;
+   fWeightMatrix0to1[16][9] = 1.25466844492722;
+   fWeightMatrix0to1[17][9] = 0.398292697037867;
+   fWeightMatrix0to1[18][9] = -0.23951655977468;
+   fWeightMatrix0to1[0][10] = -0.614254353793099;
+   fWeightMatrix0to1[1][10] = 0.0992869101139523;
+   fWeightMatrix0to1[2][10] = 1.61730569546926;
+   fWeightMatrix0to1[3][10] = 1.26425380427585;
+   fWeightMatrix0to1[4][10] = -0.321855013094085;
+   fWeightMatrix0to1[5][10] = -0.304541636476265;
+   fWeightMatrix0to1[6][10] = -1.93469077724026;
+   fWeightMatrix0to1[7][10] = 0.694282106776582;
+   fWeightMatrix0to1[8][10] = -0.293506864969838;
+   fWeightMatrix0to1[9][10] = -0.747045982083812;
+   fWeightMatrix0to1[10][10] = -0.403618510687764;
+   fWeightMatrix0to1[11][10] = 0.465629196247161;
+   fWeightMatrix0to1[12][10] = 0.125535542687423;
+   fWeightMatrix0to1[13][10] = -0.696282568972736;
+   fWeightMatrix0to1[14][10] = -0.372381961976462;
+   fWeightMatrix0to1[15][10] = 0.489641588971278;
+   fWeightMatrix0to1[16][10] = -0.520374148494733;
+   fWeightMatrix0to1[17][10] = -0.156690025365887;
+   fWeightMatrix0to1[18][10] = 0.416977419039458;
+   fWeightMatrix0to1[0][11] = 0.531942145530533;
+   fWeightMatrix0to1[1][11] = 0.409193317682443;
+   fWeightMatrix0to1[2][11] = 0.609554237515943;
+   fWeightMatrix0to1[3][11] = -1.1461979146281;
+   fWeightMatrix0to1[4][11] = -0.929191100547892;
+   fWeightMatrix0to1[5][11] = 1.39878797426212;
+   fWeightMatrix0to1[6][11] = 1.29271120429798;
+   fWeightMatrix0to1[7][11] = 0.650842576125176;
+   fWeightMatrix0to1[8][11] = 0.490789613294808;
+   fWeightMatrix0to1[9][11] = 1.66405994659327;
+   fWeightMatrix0to1[10][11] = -1.56433357937701;
+   fWeightMatrix0to1[11][11] = -0.677257565580712;
+   fWeightMatrix0to1[12][11] = 0.356943018030898;
+   fWeightMatrix0to1[13][11] = -0.221601144251902;
+   fWeightMatrix0to1[14][11] = -0.441791343669387;
+   fWeightMatrix0to1[15][11] = 1.68219766495838;
+   fWeightMatrix0to1[16][11] = -0.911141573775065;
+   fWeightMatrix0to1[17][11] = 0.770791025979587;
+   fWeightMatrix0to1[18][11] = -0.608790648593897;
+   fWeightMatrix0to1[0][12] = -1.74063301540399;
+   fWeightMatrix0to1[1][12] = 0.52280179904318;
+   fWeightMatrix0to1[2][12] = 1.45741000134962;
+   fWeightMatrix0to1[3][12] = 0.811717591914303;
+   fWeightMatrix0to1[4][12] = 0.423631349618857;
+   fWeightMatrix0to1[5][12] = 0.442233458535246;
+   fWeightMatrix0to1[6][12] = 1.72245022080012;
+   fWeightMatrix0to1[7][12] = -0.155482463527143;
+   fWeightMatrix0to1[8][12] = 0.169078815586972;
+   fWeightMatrix0to1[9][12] = 0.0957820641921989;
+   fWeightMatrix0to1[10][12] = -1.51404378847068;
+   fWeightMatrix0to1[11][12] = -0.636428157748913;
+   fWeightMatrix0to1[12][12] = -1.06689847495217;
+   fWeightMatrix0to1[13][12] = 0.378085649705563;
+   fWeightMatrix0to1[14][12] = -0.363961181698494;
+   fWeightMatrix0to1[15][12] = -0.894073578739959;
+   fWeightMatrix0to1[16][12] = -1.99562899137367;
+   fWeightMatrix0to1[17][12] = 0.230784059961214;
+   fWeightMatrix0to1[18][12] = -0.910978195783922;
+   fWeightMatrix0to1[0][13] = -0.581029428272472;
+   fWeightMatrix0to1[1][13] = 0.396648153766494;
+   fWeightMatrix0to1[2][13] = 0.33856189243156;
+   fWeightMatrix0to1[3][13] = 0.694846470145189;
+   fWeightMatrix0to1[4][13] = -1.84211918628018;
+   fWeightMatrix0to1[5][13] = 0.395698508557705;
+   fWeightMatrix0to1[6][13] = 1.90696371770364;
+   fWeightMatrix0to1[7][13] = 0.858858159782207;
+   fWeightMatrix0to1[8][13] = -0.508233975106343;
+   fWeightMatrix0to1[9][13] = -1.525458318142;
+   fWeightMatrix0to1[10][13] = -1.32290040002494;
+   fWeightMatrix0to1[11][13] = -0.184942051859762;
+   fWeightMatrix0to1[12][13] = -0.820528765038721;
+   fWeightMatrix0to1[13][13] = 0.306878829145374;
+   fWeightMatrix0to1[14][13] = -0.0502141851753634;
+   fWeightMatrix0to1[15][13] = 2.09942361551934;
+   fWeightMatrix0to1[16][13] = -0.430310029954266;
+   fWeightMatrix0to1[17][13] = 0.76726047475096;
+   fWeightMatrix0to1[18][13] = -0.664806348367783;
+   fWeightMatrix0to1[0][14] = -2.3675555746175;
+   fWeightMatrix0to1[1][14] = 2.71805249000109;
+   fWeightMatrix0to1[2][14] = 0.167833726041457;
+   fWeightMatrix0to1[3][14] = -2.00895180390179;
+   fWeightMatrix0to1[4][14] = -0.236589279078717;
+   fWeightMatrix0to1[5][14] = 1.48854633506328;
+   fWeightMatrix0to1[6][14] = 0.925436530280765;
+   fWeightMatrix0to1[7][14] = -0.0484617956023451;
+   fWeightMatrix0to1[8][14] = -1.28694490057139;
+   fWeightMatrix0to1[9][14] = 0.455263024018376;
+   fWeightMatrix0to1[10][14] = 2.21527202105756;
+   fWeightMatrix0to1[11][14] = 0.179882944329227;
+   fWeightMatrix0to1[12][14] = -0.158021644420472;
+   fWeightMatrix0to1[13][14] = -0.412791984233319;
+   fWeightMatrix0to1[14][14] = 0.0848395939820601;
+   fWeightMatrix0to1[15][14] = -1.17233717764294;
+   fWeightMatrix0to1[16][14] = -0.995490564204621;
+   fWeightMatrix0to1[17][14] = -1.84487083160762;
+   fWeightMatrix0to1[18][14] = -1.39733709135126;
+   // weight matrix from layer 1 to 2
+   fWeightMatrix1to2[0][0] = 0.12776681158065;
+   fWeightMatrix1to2[0][1] = -0.343909009882047;
+   fWeightMatrix1to2[0][2] = 0.169120833034602;
+   fWeightMatrix1to2[0][3] = -0.662219696453423;
+   fWeightMatrix1to2[0][4] = -0.287408263365878;
+   fWeightMatrix1to2[0][5] = -0.161420501035208;
+   fWeightMatrix1to2[0][6] = -0.0169827742543512;
+   fWeightMatrix1to2[0][7] = -0.496489571516043;
+   fWeightMatrix1to2[0][8] = 0.183344828615848;
+   fWeightMatrix1to2[0][9] = -0.091373308557532;
+   fWeightMatrix1to2[0][10] = -0.0497970968197627;
+   fWeightMatrix1to2[0][11] = 0.00744973924889008;
+   fWeightMatrix1to2[0][12] = 0.0216840381575276;
+   fWeightMatrix1to2[0][13] = -0.117687189532725;
+   fWeightMatrix1to2[0][14] = -0.510808312092356;
+   fWeightMatrix1to2[0][15] = -0.320428567141753;
+   fWeightMatrix1to2[0][16] = 0.00849073423000328;
+   fWeightMatrix1to2[0][17] = 0.416128149278602;
+   fWeightMatrix1to2[0][18] = -0.0863910437997606;
+   fWeightMatrix1to2[0][19] = 0.210750861731697;
+}
+
+inline double ReadMLPInner::GetMvaValue__( const std::vector<double>& inputValues ) const
+{
+   if (inputValues.size() != (unsigned int)fLayerSize[0]-1) {
+      std::cout << "Input vector needs to be of size " << fLayerSize[0]-1 << std::endl;
+      return 0;
+   }
+
+   for (int l=0; l<fLayers; l++)
+      for (int i=0; i<fLayerSize[l]; i++) fWeights[l][i]=0;
+
+   for (int l=0; l<fLayers-1; l++)
+      fWeights[l][fLayerSize[l]-1]=1;
+
+   for (int i=0; i<fLayerSize[0]-1; i++)
+      fWeights[0][i]=inputValues[i];
+
+   // layer 0 to 1
+   for (int o=0; o<fLayerSize[1]-1; o++) {
+      for (int i=0; i<fLayerSize[0]; i++) {
+         double inputVal = fWeightMatrix0to1[o][i] * fWeights[0][i];
+         fWeights[1][o] += inputVal;
+      }
+      fWeights[1][o] = ActivationFnc(fWeights[1][o]);
+   }
+   // layer 1 to 2
+   for (int o=0; o<fLayerSize[2]; o++) {
+      for (int i=0; i<fLayerSize[1]; i++) {
+         double inputVal = fWeightMatrix1to2[o][i] * fWeights[1][i];
+         fWeights[2][o] += inputVal;
+      }
+      fWeights[2][o] = OutputActivationFnc(fWeights[2][o]);
+   }
+
+   return fWeights[2][0];
+}
+
+double ReadMLPInner::ActivationFnc(double x) const {
+   // hyperbolic tan
+   return tanh(x);
+}
+double ReadMLPInner::OutputActivationFnc(double x) const {
+   // identity
+   return x;
+}
+
+// Clean up
+inline void ReadMLPInner::Clear()
+{
+   // nothing to clear
+}
+   inline double ReadMLPInner::GetMvaValue( const std::vector<double>& inputValues ) const
+   {
+      // classifier response value
+      double retval = 0;
+
+      // classifier response, sanity check first
+      if (!IsStatusClean()) {
+         std::cout << "Problem in class \"" << fClassName << "\": cannot return classifier response"
+                   << " because status is dirty" << std::endl;
+         retval = 0;
+      }
+      else {
+         if (IsNormalised()) {
+            // normalise variables
+            std::vector<double> iV;
+            int ivar = 0;
+            for (std::vector<double>::const_iterator varIt = inputValues.begin();
+                 varIt != inputValues.end(); varIt++, ivar++) {
+               iV.push_back(NormVariable( *varIt, fVmin[ivar], fVmax[ivar] ));
+            }
+            Transform( iV, -1 );
+            retval = GetMvaValue__( iV );
+         }
+         else {
+            std::vector<double> iV;
+            int ivar = 0;
+            for (std::vector<double>::const_iterator varIt = inputValues.begin();
+                 varIt != inputValues.end(); varIt++, ivar++) {
+               iV.push_back(*varIt);
+            }
+            Transform( iV, -1 );
+            retval = GetMvaValue__( iV );
+         }
+      }
+
+      return retval;
+   }
+
+//_______________________________________________________________________
+inline void ReadMLPInner::InitTransform_1()
+{
+   // Normalization transformation, initialisation
+   fMin_1[0][0] = 256.407440186;
+   fMax_1[0][0] = 5158.10546875;
+   fMin_1[1][0] = 266.212738037;
+   fMax_1[1][0] = 3459.59375;
+   fMin_1[2][0] = 256.407440186;
+   fMax_1[2][0] = 5158.10546875;
+   fMin_1[0][1] = 0.340296119452;
+   fMax_1[0][1] = 0.940254509449;
+   fMin_1[1][1] = 0.423948228359;
+   fMax_1[1][1] = 0.930988788605;
+   fMin_1[2][1] = 0.340296119452;
+   fMax_1[2][1] = 0.940254509449;
+   fMin_1[0][2] = 1.20151833016e-06;
+   fMax_1[0][2] = 0.7383441329;
+   fMin_1[1][2] = 0.000120857454021;
+   fMax_1[1][2] = 0.687674760818;
+   fMin_1[2][2] = 1.20151833016e-06;
+   fMax_1[2][2] = 0.7383441329;
+   fMin_1[0][3] = 0.00158494454809;
+   fMax_1[0][3] = 0.77249121666;
+   fMin_1[1][3] = 0.00133013306186;
+   fMax_1[1][3] = 0.745648443699;
+   fMin_1[2][3] = 0.00133013306186;
+   fMax_1[2][3] = 0.77249121666;
+   fMin_1[0][4] = 0.261401534081;
+   fMax_1[0][4] = 0.919608473778;
+   fMin_1[1][4] = 0.209150001407;
+   fMax_1[1][4] = 0.898594379425;
+   fMin_1[2][4] = 0.209150001407;
+   fMax_1[2][4] = 0.919608473778;
+   fMin_1[0][5] = 0.514432489872;
+   fMax_1[0][5] = 0.9744130373;
+   fMin_1[1][5] = 0.399627387524;
+   fMax_1[1][5] = 0.962903857231;
+   fMin_1[2][5] = 0.399627387524;
+   fMax_1[2][5] = 0.9744130373;
+   fMin_1[0][6] = 0;
+   fMax_1[0][6] = 1;
+   fMin_1[1][6] = 0;
+   fMax_1[1][6] = 1;
+   fMin_1[2][6] = 0;
+   fMax_1[2][6] = 1;
+   fMin_1[0][7] = 0;
+   fMax_1[0][7] = 0.496332526207;
+   fMin_1[1][7] = 0;
+   fMax_1[1][7] = 0.491525411606;
+   fMin_1[2][7] = 0;
+   fMax_1[2][7] = 0.496332526207;
+   fMin_1[0][8] = 0;
+   fMax_1[0][8] = 1.99933886528;
+   fMin_1[1][8] = 0;
+   fMax_1[1][8] = 1.52447521687;
+   fMin_1[2][8] = 0;
+   fMax_1[2][8] = 1.99933886528;
+   fMin_1[0][9] = 0;
+   fMax_1[0][9] = 1;
+   fMin_1[1][9] = 0;
+   fMax_1[1][9] = 1;
+   fMin_1[2][9] = 0;
+   fMax_1[2][9] = 1;
+   fMin_1[0][10] = 0;
+   fMax_1[0][10] = 9;
+   fMin_1[1][10] = 0;
+   fMax_1[1][10] = 9;
+   fMin_1[2][10] = 0;
+   fMax_1[2][10] = 9;
+   fMin_1[0][11] = 0;
+   fMax_1[0][11] = 6;
+   fMin_1[1][11] = 0;
+   fMax_1[1][11] = 6;
+   fMin_1[2][11] = 0;
+   fMax_1[2][11] = 6;
+   fMin_1[0][12] = 0;
+   fMax_1[0][12] = 5;
+   fMin_1[1][12] = 0;
+   fMax_1[1][12] = 6;
+   fMin_1[2][12] = 0;
+   fMax_1[2][12] = 6;
+   fMin_1[0][13] = 0;
+   fMax_1[0][13] = 5;
+   fMin_1[1][13] = 0;
+   fMax_1[1][13] = 4;
+   fMin_1[2][13] = 0;
+   fMax_1[2][13] = 5;
+}
+
+//_______________________________________________________________________
+inline void ReadMLPInner::Transform_1( std::vector<double>& iv, int cls) const
+{
+   // Normalization transformation
+   if (cls < 0 || cls > 2) {
+   if (2 > 1 ) cls = 2;
+      else cls = 2;
+   }
+   const int nVar = 14;
+
+   // get indices of used variables
+
+   // define the indices of the variables which are transformed by this transformation
+   std::vector<int> indicesGet;
+   std::vector<int> indicesPut;
+
+   indicesGet.push_back( 0);
+   indicesGet.push_back( 1);
+   indicesGet.push_back( 2);
+   indicesGet.push_back( 3);
+   indicesGet.push_back( 4);
+   indicesGet.push_back( 5);
+   indicesGet.push_back( 6);
+   indicesGet.push_back( 7);
+   indicesGet.push_back( 8);
+   indicesGet.push_back( 9);
+   indicesGet.push_back( 10);
+   indicesGet.push_back( 11);
+   indicesGet.push_back( 12);
+   indicesGet.push_back( 13);
+   indicesPut.push_back( 0);
+   indicesPut.push_back( 1);
+   indicesPut.push_back( 2);
+   indicesPut.push_back( 3);
+   indicesPut.push_back( 4);
+   indicesPut.push_back( 5);
+   indicesPut.push_back( 6);
+   indicesPut.push_back( 7);
+   indicesPut.push_back( 8);
+   indicesPut.push_back( 9);
+   indicesPut.push_back( 10);
+   indicesPut.push_back( 11);
+   indicesPut.push_back( 12);
+   indicesPut.push_back( 13);
+
+   std::vector<double> dv(nVar);
+   for (int ivar=0; ivar<nVar; ivar++) dv[ivar] = iv[indicesGet.at(ivar)];
+   for (int ivar=0;ivar<14;ivar++) {
+      double offset = fMin_1[cls][ivar];
+      double scale  = 1.0/(fMax_1[cls][ivar]-fMin_1[cls][ivar]);
+      iv[indicesPut.at(ivar)] = (dv[ivar]-offset)*scale * 2 - 1;
+   }
+}
+
+//_______________________________________________________________________
+inline void ReadMLPInner::InitTransform()
+{
+   InitTransform_1();
+}
+
+//_______________________________________________________________________
+inline void ReadMLPInner::Transform( std::vector<double>& iv, int sigOrBgd ) const
+{
+   Transform_1( iv, sigOrBgd );
+}
diff --git a/CaloFuture/CaloFutureTools/src/TMV_MLP_middle.C b/CaloFuture/CaloFutureTools/src/TMV_MLP_middle.C
new file mode 100644
index 0000000000000000000000000000000000000000..814fe5b0e070566a2b3d230a878b234e65d8efcb
--- /dev/null
+++ b/CaloFuture/CaloFutureTools/src/TMV_MLP_middle.C
@@ -0,0 +1,817 @@
+// Class: ReadMLPMiddle
+// Automatically generated by MethodBase::MakeClass
+//
+
+/* configuration options =====================================================
+
+#GEN -*-*-*-*-*-*-*-*-*-*-*- general info -*-*-*-*-*-*-*-*-*-*-*-
+
+Method         : MLP::MLP
+TMVA Release   : 4.1.2         [262402]
+ROOT Release   : 5.30/00       [335360]
+Creator        : calvom
+Date           : Tue Nov  8 16:53:17 2011
+Host           : Linux lxbuild148.cern.ch 2.6.18-194.26.1.el5 #1 SMP Wed Nov 10 09:45:46 CET 2010 x86_64 x86_64 x86_64 GNU/Linux
+Dir            : /afs/cern.ch/user/c/calvom/w0/GammaPi0/tmva_calib
+Training events: 24786
+Analysis type  : [Classification]
+
+
+#OPT -*-*-*-*-*-*-*-*-*-*-*-*- options -*-*-*-*-*-*-*-*-*-*-*-*-
+
+# Set by User:
+NCycles: "600" [Number of training cycles]
+HiddenLayers: "N+5" [Specification of hidden layer architecture]
+NeuronType: "tanh" [Neuron activation function type]
+V: "False" [Verbose output (short form of "VerbosityLevel" below - overrides the latter one)]
+VarTransform: "N" [List of variable transformations performed before training, e.g., "D_Background,P_Signal,G,N_AllClasses" for: "Decorrelation, PCA-transformation, Gaussianisation, Normalisation, each for the given class of events ('AllClasses' denotes all events of all classes, if no class indication is given, 'All' is assumed)"]
+H: "True" [Print method-specific help message]
+TestRate: "5" [Test for overtraining performed at each #th epochs]
+# Default:
+RandomSeed: "1" [Random seed for initial synapse weights (0 means unique seed for each run; default value '1')]
+EstimatorType: "MSE" [MSE (Mean Square Estimator) for Gaussian Likelihood or CE(Cross-Entropy) for Bernoulli Likelihood]
+NeuronInputType: "sum" [Neuron input function type]
+VerbosityLevel: "Default" [Verbosity level]
+CreateMVAPdfs: "False" [Create PDFs for classifier outputs (signal and background)]
+IgnoreNegWeightsInTraining: "False" [Events with negative weights are ignored in the training (but are included for testing and performance evaluation)]
+TrainingMethod: "BP" [Train with Back-Propagation (BP), BFGS Algorithm (BFGS), or Genetic Algorithm (GA - slower and worse)]
+LearningRate: "2.000000e-02" [ANN learning rate parameter]
+DecayRate: "1.000000e-02" [Decay rate for learning parameter]
+EpochMonitoring: "False" [Provide epoch-wise monitoring plots according to TestRate (caution: causes big ROOT output file!)]
+Sampling: "1.000000e+00" [Only 'Sampling' (randomly selected) events are trained each epoch]
+SamplingEpoch: "1.000000e+00" [Sampling is used for the first 'SamplingEpoch' epochs, afterwards, all events are taken for training]
+SamplingImportance: "1.000000e+00" [ The sampling weights of events in epochs which successful (worse estimator than before) are multiplied with SamplingImportance, else they are divided.]
+SamplingTraining: "True" [The training sample is sampled]
+SamplingTesting: "False" [The testing sample is sampled]
+ResetStep: "50" [How often BFGS should reset history]
+Tau: "3.000000e+00" [LineSearch "size step"]
+BPMode: "sequential" [Back-propagation learning mode: sequential or batch]
+BatchSize: "-1" [Batch size: number of events/batch, only set if in Batch Mode, -1 for BatchSize=number_of_events]
+ConvergenceImprove: "1.000000e-30" [Minimum improvement which counts as improvement (<0 means automatic convergence check is turned off)]
+ConvergenceTests: "-1" [Number of steps (without improvement) required for convergence (<0 means automatic convergence check is turned off)]
+UseRegulator: "False" [Use regulator to avoid over-training]
+UpdateLimit: "10000" [Maximum times of regulator update]
+CalculateErrors: "False" [Calculates inverse Hessian matrix at the end of the training to be able to calculate the uncertainties of an MVA value]
+WeightRange: "1.000000e+00" [Take the events for the estimator calculations from small deviations from the desired value to large deviations only over the weight range]
+##
+
+
+#VAR -*-*-*-*-*-*-*-*-*-*-*-* variables *-*-*-*-*-*-*-*-*-*-*-*-
+
+NVar 14
+fr2                           fr2                           fr2                           fr2                                                             'F'    [396.177398682,13764.8271484]
+fr2r4                         fr2r4                         fr2r4                         fr2r4                                                           'F'    [0.301807701588,0.965358257294]
+abs(asym)                     abs_asym_                     abs(asym)                     abs(asym)                                                       'F'    [-0,0.782861948013]
+kappa                         kappa                         kappa                         kappa                                                           'F'    [0,0.843120634556]
+Eseed/Ecl                     Eseed_D_Ecl                   Eseed/Ecl                     Eseed/Ecl                                                       'F'    [0.244072809815,0.92901545763]
+(E2+Eseed)/Ecl                _E2_P_Eseed__D_Ecl            (E2+Eseed)/Ecl                (E2+Eseed)/Ecl                                                  'F'    [0.460556000471,0.964079260826]
+eSumPS>0?eMaxPS/eSumPS:0      eSumPS_0_eMaxPS_D_eSumPS:0    eSumPS>0?eMaxPS/eSumPS:0      eSumPS>0?eMaxPS/eSumPS:0                                        'F'    [0,1]
+eSumPS>0?e2ndPS/eSumPS:0      eSumPS_0_e2ndPS_D_eSumPS:0    eSumPS>0?e2ndPS/eSumPS:0      eSumPS>0?e2ndPS/eSumPS:0                                        'F'    [0,0.498583585024]
+r2PS                          r2PS                          r2PS                          r2PS                                                            'F'    [0,1.97231829166]
+abs(asymPS)                   abs_asymPS_                   abs(asymPS)                   abs(asymPS)                                                     'F'    [0,1]
+multiPS                       multiPS                       multiPS                       multiPS                                                         'F'    [0,9]
+multiPS15                     multiPS15                     multiPS15                     multiPS15                                                       'F'    [0,6]
+multiPS30                     multiPS30                     multiPS30                     multiPS30                                                       'F'    [0,6]
+multiPS45                     multiPS45                     multiPS45                     multiPS45                                                       'F'    [0,4]
+NSpec 0
+
+
+============================================================================ */
+
+#include <vector>
+#include <cmath>
+#include <string>
+#include <iostream>
+
+#ifndef IClassifierReader__def
+#define IClassifierReader__def
+
+class IClassifierReader {
+
+ public:
+
+   // constructor
+   IClassifierReader() : fStatusIsClean( true ) {}
+   virtual ~IClassifierReader() {}
+
+   // return classifier response
+   virtual double GetMvaValue( const std::vector<double>& inputValues ) const = 0;
+
+   // returns classifier status
+   bool IsStatusClean() const { return fStatusIsClean; }
+
+ protected:
+
+   bool fStatusIsClean;
+};
+
+#endif
+
+class ReadMLPMiddle : public IClassifierReader {
+
+ public:
+
+   // constructor
+   ReadMLPMiddle( const std::vector<std::string>& theInputVars )
+      : IClassifierReader(),
+        fClassName( "ReadMLPMiddle" ),
+        fNvars( 14 ),
+        fIsNormalised( false )
+   {
+      // the training input variables
+      const char* inputVars[] = { "fr2", "fr2r4", "abs(asym)", "kappa", "Eseed/Ecl", "(E2+Eseed)/Ecl", "eSumPS>0?eMaxPS/eSumPS:0", "eSumPS>0?e2ndPS/eSumPS:0", "r2PS", "abs(asymPS)", "multiPS", "multiPS15", "multiPS30", "multiPS45" };
+
+      // sanity checks
+      if (theInputVars.size() <= 0) {
+         std::cout << "Problem in class \"" << fClassName << "\": empty input vector" << std::endl;
+         fStatusIsClean = false;
+      }
+
+      if (theInputVars.size() != fNvars) {
+         std::cout << "Problem in class \"" << fClassName << "\": mismatch in number of input values: "
+                   << theInputVars.size() << " != " << fNvars << std::endl;
+         fStatusIsClean = false;
+      }
+
+      // validate input variables
+      for (size_t ivar = 0; ivar < theInputVars.size(); ivar++) {
+         if (theInputVars[ivar] != inputVars[ivar]) {
+            std::cout << "Problem in class \"" << fClassName << "\": mismatch in input variable names" << std::endl
+                      << " for variable [" << ivar << "]: " << theInputVars[ivar].c_str() << " != " << inputVars[ivar] << std::endl;
+            fStatusIsClean = false;
+         }
+      }
+
+      // initialize min and max vectors (for normalisation)
+      fVmin[0] = -1;
+      fVmax[0] = 1;
+      fVmin[1] = -1;
+      fVmax[1] = 1;
+      fVmin[2] = -1;
+      fVmax[2] = 0.99999988079071;
+      fVmin[3] = -1;
+      fVmax[3] = 0.99999988079071;
+      fVmin[4] = -1;
+      fVmax[4] = 1;
+      fVmin[5] = -1;
+      fVmax[5] = 1;
+      fVmin[6] = -1;
+      fVmax[6] = 1;
+      fVmin[7] = -1;
+      fVmax[7] = 1;
+      fVmin[8] = -1;
+      fVmax[8] = 1;
+      fVmin[9] = -1;
+      fVmax[9] = 1;
+      fVmin[10] = -1;
+      fVmax[10] = 1;
+      fVmin[11] = -1;
+      fVmax[11] = 1;
+      fVmin[12] = -1;
+      fVmax[12] = 1;
+      fVmin[13] = -1;
+      fVmax[13] = 1;
+
+      // initialize input variable types
+      fType[0] = 'F';
+      fType[1] = 'F';
+      fType[2] = 'F';
+      fType[3] = 'F';
+      fType[4] = 'F';
+      fType[5] = 'F';
+      fType[6] = 'F';
+      fType[7] = 'F';
+      fType[8] = 'F';
+      fType[9] = 'F';
+      fType[10] = 'F';
+      fType[11] = 'F';
+      fType[12] = 'F';
+      fType[13] = 'F';
+
+      // initialize constants
+      Initialize();
+
+      // initialize transformation
+      InitTransform();
+   }
+
+   // destructor
+   virtual ~ReadMLPMiddle() {
+      Clear(); // method-specific
+   }
+
+   // the classifier response
+   // "inputValues" is a vector of input values in the same order as the
+   // variables given to the constructor
+   double GetMvaValue( const std::vector<double>& inputValues ) const override;
+
+ private:
+
+   // method-specific destructor
+   void Clear();
+
+   // input variable transformation
+
+   double fMin_1[3][14];
+   double fMax_1[3][14];
+   void InitTransform_1();
+   void Transform_1( std::vector<double> & iv, int sigOrBgd ) const;
+   void InitTransform();
+   void Transform( std::vector<double> & iv, int sigOrBgd ) const;
+
+   // common member variables
+   const char* fClassName;
+
+   const size_t fNvars;
+   size_t GetNvar()           const { return fNvars; }
+   char   GetType( int ivar ) const { return fType[ivar]; }
+
+   // normalisation of input variables
+   const bool fIsNormalised;
+   bool IsNormalised() const { return fIsNormalised; }
+   double fVmin[14];
+   double fVmax[14];
+   double NormVariable( double x, double xmin, double xmax ) const {
+      // normalise to output range: [-1, 1]
+      return 2*(x - xmin)/(xmax - xmin) - 1.0;
+   }
+
+   // type of input variable: 'F' or 'I'
+   char   fType[14];
+
+   // initialize internal variables
+   void Initialize();
+   double GetMvaValue__( const std::vector<double>& inputValues ) const;
+
+   // private members (method specific)
+
+   double ActivationFnc(double x) const;
+   double OutputActivationFnc(double x) const;
+
+   int fLayers;
+   int fLayerSize[3];
+   double fWeightMatrix0to1[20][15];   // weight matrix from layer 0 to 1
+   double fWeightMatrix1to2[1][20];   // weight matrix from layer 1 to 2
+
+   double * fWeights[3];
+};
+
+inline void ReadMLPMiddle::Initialize()
+{
+   // build network structure
+   fLayers = 3;
+   fLayerSize[0] = 15; fWeights[0] = new double[15];
+   fLayerSize[1] = 20; fWeights[1] = new double[20];
+   fLayerSize[2] = 1; fWeights[2] = new double[1];
+   // weight matrix from layer 0 to 1
+   fWeightMatrix0to1[0][0] = -0.867416606481198;
+   fWeightMatrix0to1[1][0] = 1.52892005921573;
+   fWeightMatrix0to1[2][0] = 0.928852393643837;
+   fWeightMatrix0to1[3][0] = 2.7044598593846;
+   fWeightMatrix0to1[4][0] = -2.61144685740294;
+   fWeightMatrix0to1[5][0] = -1.54822294568981;
+   fWeightMatrix0to1[6][0] = -0.69991092080064;
+   fWeightMatrix0to1[7][0] = 2.49183388807665;
+   fWeightMatrix0to1[8][0] = -1.82778992022997;
+   fWeightMatrix0to1[9][0] = -1.23480074738712;
+   fWeightMatrix0to1[10][0] = -2.32999130862363;
+   fWeightMatrix0to1[11][0] = -0.0619355352938491;
+   fWeightMatrix0to1[12][0] = -0.648084451209581;
+   fWeightMatrix0to1[13][0] = -1.29854810659858;
+   fWeightMatrix0to1[14][0] = -0.964059869212921;
+   fWeightMatrix0to1[15][0] = 1.14709660666656;
+   fWeightMatrix0to1[16][0] = -0.659108613746082;
+   fWeightMatrix0to1[17][0] = 1.29220704129439;
+   fWeightMatrix0to1[18][0] = 0.219218314861889;
+   fWeightMatrix0to1[0][1] = -0.313579360837127;
+   fWeightMatrix0to1[1][1] = 1.4024752642764;
+   fWeightMatrix0to1[2][1] = -1.19851673123826;
+   fWeightMatrix0to1[3][1] = 0.58037365026283;
+   fWeightMatrix0to1[4][1] = -0.482629449494083;
+   fWeightMatrix0to1[5][1] = -0.31680037372708;
+   fWeightMatrix0to1[6][1] = -1.19146380571644;
+   fWeightMatrix0to1[7][1] = 1.92978194401728;
+   fWeightMatrix0to1[8][1] = -1.09175173970591;
+   fWeightMatrix0to1[9][1] = -1.35914101764875;
+   fWeightMatrix0to1[10][1] = 0.200995577667252;
+   fWeightMatrix0to1[11][1] = 0.571906415712693;
+   fWeightMatrix0to1[12][1] = 1.62065462400511;
+   fWeightMatrix0to1[13][1] = -0.0341372481003341;
+   fWeightMatrix0to1[14][1] = -3.45658380189554;
+   fWeightMatrix0to1[15][1] = -0.0126196639343866;
+   fWeightMatrix0to1[16][1] = -0.0844980421550597;
+   fWeightMatrix0to1[17][1] = -1.24243112895568;
+   fWeightMatrix0to1[18][1] = 1.45033544424252;
+   fWeightMatrix0to1[0][2] = -1.17333744144131;
+   fWeightMatrix0to1[1][2] = 0.537958601883077;
+   fWeightMatrix0to1[2][2] = 0.759383983445813;
+   fWeightMatrix0to1[3][2] = 1.17226490140808;
+   fWeightMatrix0to1[4][2] = 0.669805141472939;
+   fWeightMatrix0to1[5][2] = 2.1449085813314;
+   fWeightMatrix0to1[6][2] = -0.631284550782466;
+   fWeightMatrix0to1[7][2] = -1.33446196411931;
+   fWeightMatrix0to1[8][2] = 0.410131181532878;
+   fWeightMatrix0to1[9][2] = -0.301361359526247;
+   fWeightMatrix0to1[10][2] = 0.303260629430208;
+   fWeightMatrix0to1[11][2] = 1.16387977664382;
+   fWeightMatrix0to1[12][2] = 1.6108322347009;
+   fWeightMatrix0to1[13][2] = 0.601082221553922;
+   fWeightMatrix0to1[14][2] = -0.547264267034139;
+   fWeightMatrix0to1[15][2] = 1.06078483419717;
+   fWeightMatrix0to1[16][2] = -1.77078835600063;
+   fWeightMatrix0to1[17][2] = -1.11210936585844;
+   fWeightMatrix0to1[18][2] = -0.867334884904254;
+   fWeightMatrix0to1[0][3] = -2.02853398910341;
+   fWeightMatrix0to1[1][3] = 1.69808147897346;
+   fWeightMatrix0to1[2][3] = -0.113305678415982;
+   fWeightMatrix0to1[3][3] = -1.36826385097943;
+   fWeightMatrix0to1[4][3] = -0.00989162999579154;
+   fWeightMatrix0to1[5][3] = 1.2472433318308;
+   fWeightMatrix0to1[6][3] = 0.941667976489114;
+   fWeightMatrix0to1[7][3] = 1.60666277674855;
+   fWeightMatrix0to1[8][3] = -0.915602832375179;
+   fWeightMatrix0to1[9][3] = -0.855690366526691;
+   fWeightMatrix0to1[10][3] = -1.13509871477241;
+   fWeightMatrix0to1[11][3] = 0.568553603554666;
+   fWeightMatrix0to1[12][3] = -0.851252539277957;
+   fWeightMatrix0to1[13][3] = -1.14686594593269;
+   fWeightMatrix0to1[14][3] = -1.014280536591;
+   fWeightMatrix0to1[15][3] = 0.712750937101043;
+   fWeightMatrix0to1[16][3] = 1.31830506114039;
+   fWeightMatrix0to1[17][3] = 0.97980829511593;
+   fWeightMatrix0to1[18][3] = -0.418515378973496;
+   fWeightMatrix0to1[0][4] = -1.97483930490001;
+   fWeightMatrix0to1[1][4] = -0.687793978174217;
+   fWeightMatrix0to1[2][4] = 0.89010583052141;
+   fWeightMatrix0to1[3][4] = 0.421725240737996;
+   fWeightMatrix0to1[4][4] = 1.57425684241013;
+   fWeightMatrix0to1[5][4] = -1.02485739171261;
+   fWeightMatrix0to1[6][4] = 0.352037043029585;
+   fWeightMatrix0to1[7][4] = -0.989990502973038;
+   fWeightMatrix0to1[8][4] = -0.918626623275508;
+   fWeightMatrix0to1[9][4] = -0.00627843764882833;
+   fWeightMatrix0to1[10][4] = 0.650127824423305;
+   fWeightMatrix0to1[11][4] = -0.889425021440891;
+   fWeightMatrix0to1[12][4] = -1.54026365988138;
+   fWeightMatrix0to1[13][4] = -1.63539216705696;
+   fWeightMatrix0to1[14][4] = 0.290389593393486;
+   fWeightMatrix0to1[15][4] = 0.205094248586933;
+   fWeightMatrix0to1[16][4] = 1.91268676453227;
+   fWeightMatrix0to1[17][4] = -1.502890234018;
+   fWeightMatrix0to1[18][4] = -0.963493203028935;
+   fWeightMatrix0to1[0][5] = 2.18036935570376;
+   fWeightMatrix0to1[1][5] = -1.92424311845546;
+   fWeightMatrix0to1[2][5] = -2.26674800851725;
+   fWeightMatrix0to1[3][5] = -1.71287792152807;
+   fWeightMatrix0to1[4][5] = 0.480932583928402;
+   fWeightMatrix0to1[5][5] = -1.20230577451749;
+   fWeightMatrix0to1[6][5] = -1.84842005108065;
+   fWeightMatrix0to1[7][5] = -0.718821462004105;
+   fWeightMatrix0to1[8][5] = 1.1974718960183;
+   fWeightMatrix0to1[9][5] = -1.50619374498669;
+   fWeightMatrix0to1[10][5] = 1.66134007975805;
+   fWeightMatrix0to1[11][5] = -1.08016642459962;
+   fWeightMatrix0to1[12][5] = -1.42182870299292;
+   fWeightMatrix0to1[13][5] = 0.34073109703492;
+   fWeightMatrix0to1[14][5] = 1.40217161194194;
+   fWeightMatrix0to1[15][5] = -1.71243250173402;
+   fWeightMatrix0to1[16][5] = 2.22715053357944;
+   fWeightMatrix0to1[17][5] = 0.527332352536044;
+   fWeightMatrix0to1[18][5] = 0.0648949570041376;
+   fWeightMatrix0to1[0][6] = -0.738841533745263;
+   fWeightMatrix0to1[1][6] = 0.346812228849947;
+   fWeightMatrix0to1[2][6] = 0.121009510965812;
+   fWeightMatrix0to1[3][6] = -0.849131082595975;
+   fWeightMatrix0to1[4][6] = 1.09740015742468;
+   fWeightMatrix0to1[5][6] = -0.544087730510457;
+   fWeightMatrix0to1[6][6] = -1.45742111418507;
+   fWeightMatrix0to1[7][6] = -0.323638445325328;
+   fWeightMatrix0to1[8][6] = 0.215008383977184;
+   fWeightMatrix0to1[9][6] = 0.757553950948554;
+   fWeightMatrix0to1[10][6] = 0.502897133789601;
+   fWeightMatrix0to1[11][6] = -0.356301970061779;
+   fWeightMatrix0to1[12][6] = -0.404294467047688;
+   fWeightMatrix0to1[13][6] = 0.340934465825974;
+   fWeightMatrix0to1[14][6] = -0.115059503627307;
+   fWeightMatrix0to1[15][6] = 0.860186328731439;
+   fWeightMatrix0to1[16][6] = -0.233774549376029;
+   fWeightMatrix0to1[17][6] = -1.26886700798678;
+   fWeightMatrix0to1[18][6] = 0.83852481025036;
+   fWeightMatrix0to1[0][7] = -1.26627056537021;
+   fWeightMatrix0to1[1][7] = 0.470753417418729;
+   fWeightMatrix0to1[2][7] = 1.63852583469858;
+   fWeightMatrix0to1[3][7] = 0.911455600002474;
+   fWeightMatrix0to1[4][7] = -1.30875327753522;
+   fWeightMatrix0to1[5][7] = 0.00970511213226444;
+   fWeightMatrix0to1[6][7] = 1.41834501270918;
+   fWeightMatrix0to1[7][7] = 1.6763955185333;
+   fWeightMatrix0to1[8][7] = -0.234904810568052;
+   fWeightMatrix0to1[9][7] = -0.675588633320613;
+   fWeightMatrix0to1[10][7] = -0.0262219284880216;
+   fWeightMatrix0to1[11][7] = -1.1719793450669;
+   fWeightMatrix0to1[12][7] = 0.755016319470702;
+   fWeightMatrix0to1[13][7] = 0.608192764034871;
+   fWeightMatrix0to1[14][7] = -0.188706738103988;
+   fWeightMatrix0to1[15][7] = -0.406885447080173;
+   fWeightMatrix0to1[16][7] = 0.148507511443218;
+   fWeightMatrix0to1[17][7] = -1.13443049209833;
+   fWeightMatrix0to1[18][7] = -0.190033405151551;
+   fWeightMatrix0to1[0][8] = 1.16653770171993;
+   fWeightMatrix0to1[1][8] = 0.104060672308803;
+   fWeightMatrix0to1[2][8] = 0.0011134129235443;
+   fWeightMatrix0to1[3][8] = 0.312063793194653;
+   fWeightMatrix0to1[4][8] = 0.704245030963736;
+   fWeightMatrix0to1[5][8] = 0.531708176868196;
+   fWeightMatrix0to1[6][8] = 1.03663834583442;
+   fWeightMatrix0to1[7][8] = -0.953420977046398;
+   fWeightMatrix0to1[8][8] = 0.961357552027267;
+   fWeightMatrix0to1[9][8] = 0.973059383499368;
+   fWeightMatrix0to1[10][8] = 0.0861079214520543;
+   fWeightMatrix0to1[11][8] = 1.12377079068739;
+   fWeightMatrix0to1[12][8] = 1.31340672815188;
+   fWeightMatrix0to1[13][8] = -1.15902944629629;
+   fWeightMatrix0to1[14][8] = -0.110697574871031;
+   fWeightMatrix0to1[15][8] = 1.3734188670324;
+   fWeightMatrix0to1[16][8] = -0.772975126256126;
+   fWeightMatrix0to1[17][8] = -0.949931599449223;
+   fWeightMatrix0to1[18][8] = 1.25003799183296;
+   fWeightMatrix0to1[0][9] = 0.00967602377087132;
+   fWeightMatrix0to1[1][9] = 0.0182382384949106;
+   fWeightMatrix0to1[2][9] = 1.23469219755964;
+   fWeightMatrix0to1[3][9] = 0.674635594054856;
+   fWeightMatrix0to1[4][9] = -1.78482755411435;
+   fWeightMatrix0to1[5][9] = -0.0217177118607022;
+   fWeightMatrix0to1[6][9] = 0.498060817982423;
+   fWeightMatrix0to1[7][9] = 0.432790908814506;
+   fWeightMatrix0to1[8][9] = -0.373167835048286;
+   fWeightMatrix0to1[9][9] = -0.832502791655382;
+   fWeightMatrix0to1[10][9] = 0.456667494152143;
+   fWeightMatrix0to1[11][9] = 1.02336751171567;
+   fWeightMatrix0to1[12][9] = -1.35163437936133;
+   fWeightMatrix0to1[13][9] = -1.17684235069197;
+   fWeightMatrix0to1[14][9] = -0.00878962094541198;
+   fWeightMatrix0to1[15][9] = -0.156529612004041;
+   fWeightMatrix0to1[16][9] = 0.88002169679633;
+   fWeightMatrix0to1[17][9] = -0.166820217641056;
+   fWeightMatrix0to1[18][9] = -0.663361630193172;
+   fWeightMatrix0to1[0][10] = -0.793098436338315;
+   fWeightMatrix0to1[1][10] = 0.100571779785801;
+   fWeightMatrix0to1[2][10] = 1.06529019318474;
+   fWeightMatrix0to1[3][10] = 0.992082837071785;
+   fWeightMatrix0to1[4][10] = -0.152973848691906;
+   fWeightMatrix0to1[5][10] = 0.0710755177270902;
+   fWeightMatrix0to1[6][10] = -1.95362769307301;
+   fWeightMatrix0to1[7][10] = 0.652377333328601;
+   fWeightMatrix0to1[8][10] = 0.0119366823426579;
+   fWeightMatrix0to1[9][10] = -0.874841265727433;
+   fWeightMatrix0to1[10][10] = -0.229977508467751;
+   fWeightMatrix0to1[11][10] = 0.44277338795919;
+   fWeightMatrix0to1[12][10] = 0.0650852375841939;
+   fWeightMatrix0to1[13][10] = -1.30132930651378;
+   fWeightMatrix0to1[14][10] = -0.369724159139221;
+   fWeightMatrix0to1[15][10] = 0.703767772268532;
+   fWeightMatrix0to1[16][10] = -0.0626130221598321;
+   fWeightMatrix0to1[17][10] = -0.100930629477247;
+   fWeightMatrix0to1[18][10] = 1.02621196952924;
+   fWeightMatrix0to1[0][11] = 0.92546693417593;
+   fWeightMatrix0to1[1][11] = 0.503938931621139;
+   fWeightMatrix0to1[2][11] = 0.0858937656196619;
+   fWeightMatrix0to1[3][11] = -1.59045525533957;
+   fWeightMatrix0to1[4][11] = -1.73489993547179;
+   fWeightMatrix0to1[5][11] = 0.564318577651265;
+   fWeightMatrix0to1[6][11] = 1.15739834523708;
+   fWeightMatrix0to1[7][11] = 1.15618489964227;
+   fWeightMatrix0to1[8][11] = 0.266592672289452;
+   fWeightMatrix0to1[9][11] = 1.81241803610749;
+   fWeightMatrix0to1[10][11] = -1.6762844956494;
+   fWeightMatrix0to1[11][11] = -0.940592315799515;
+   fWeightMatrix0to1[12][11] = -0.0142765211246494;
+   fWeightMatrix0to1[13][11] = -1.51350023770462;
+   fWeightMatrix0to1[14][11] = 0.274862103942864;
+   fWeightMatrix0to1[15][11] = 1.63413020292962;
+   fWeightMatrix0to1[16][11] = -0.874633583035442;
+   fWeightMatrix0to1[17][11] = 0.661407739822478;
+   fWeightMatrix0to1[18][11] = -0.434044171339045;
+   fWeightMatrix0to1[0][12] = -2.16304509617558;
+   fWeightMatrix0to1[1][12] = 0.725610167020035;
+   fWeightMatrix0to1[2][12] = 0.696598971951744;
+   fWeightMatrix0to1[3][12] = 0.471111955041938;
+   fWeightMatrix0to1[4][12] = 0.0859924682021416;
+   fWeightMatrix0to1[5][12] = 0.450480677018801;
+   fWeightMatrix0to1[6][12] = 1.31243380720041;
+   fWeightMatrix0to1[7][12] = -0.393309031056374;
+   fWeightMatrix0to1[8][12] = -0.335482753900041;
+   fWeightMatrix0to1[9][12] = 0.184436808445052;
+   fWeightMatrix0to1[10][12] = -1.36214641840382;
+   fWeightMatrix0to1[11][12] = -0.792105372631398;
+   fWeightMatrix0to1[12][12] = -1.20997377555831;
+   fWeightMatrix0to1[13][12] = -0.441865451770537;
+   fWeightMatrix0to1[14][12] = -0.455845441390649;
+   fWeightMatrix0to1[15][12] = -1.00734698553553;
+   fWeightMatrix0to1[16][12] = -1.32117772087793;
+   fWeightMatrix0to1[17][12] = -0.310478331944271;
+   fWeightMatrix0to1[18][12] = -0.840833259846518;
+   fWeightMatrix0to1[0][13] = -0.337122150022944;
+   fWeightMatrix0to1[1][13] = 0.218655506674274;
+   fWeightMatrix0to1[2][13] = -0.154368567075649;
+   fWeightMatrix0to1[3][13] = 0.237691471305213;
+   fWeightMatrix0to1[4][13] = -1.32734322819975;
+   fWeightMatrix0to1[5][13] = 0.898254759266311;
+   fWeightMatrix0to1[6][13] = 1.96349493188879;
+   fWeightMatrix0to1[7][13] = 1.44498369546106;
+   fWeightMatrix0to1[8][13] = -0.63102230191847;
+   fWeightMatrix0to1[9][13] = -1.77504421027533;
+   fWeightMatrix0to1[10][13] = -0.853698426031734;
+   fWeightMatrix0to1[11][13] = -0.531542047187409;
+   fWeightMatrix0to1[12][13] = -1.10738840214253;
+   fWeightMatrix0to1[13][13] = -0.184267539610476;
+   fWeightMatrix0to1[14][13] = -0.317923292009617;
+   fWeightMatrix0to1[15][13] = 2.04610576511013;
+   fWeightMatrix0to1[16][13] = -0.208448079974731;
+   fWeightMatrix0to1[17][13] = 0.146612809162846;
+   fWeightMatrix0to1[18][13] = -0.483493639255675;
+   fWeightMatrix0to1[0][14] = -1.9290184065958;
+   fWeightMatrix0to1[1][14] = 2.77842901867793;
+   fWeightMatrix0to1[2][14] = 0.722315069412496;
+   fWeightMatrix0to1[3][14] = -1.99803885369666;
+   fWeightMatrix0to1[4][14] = -0.737012752883904;
+   fWeightMatrix0to1[5][14] = 0.637970306915431;
+   fWeightMatrix0to1[6][14] = 0.895943391331503;
+   fWeightMatrix0to1[7][14] = 0.276247873858507;
+   fWeightMatrix0to1[8][14] = -1.10558994405963;
+   fWeightMatrix0to1[9][14] = 0.383021074024618;
+   fWeightMatrix0to1[10][14] = 2.603676011013;
+   fWeightMatrix0to1[11][14] = 0.487155687196025;
+   fWeightMatrix0to1[12][14] = 0.349758905360271;
+   fWeightMatrix0to1[13][14] = 0.925365632231932;
+   fWeightMatrix0to1[14][14] = 0.357705150227094;
+   fWeightMatrix0to1[15][14] = -1.24031635175521;
+   fWeightMatrix0to1[16][14] = -0.690835412708456;
+   fWeightMatrix0to1[17][14] = -0.0828410602933603;
+   fWeightMatrix0to1[18][14] = -1.38640604196602;
+   // weight matrix from layer 1 to 2
+   fWeightMatrix1to2[0][0] = 0.0782498789202482;
+   fWeightMatrix1to2[0][1] = -0.250875309083546;
+   fWeightMatrix1to2[0][2] = 0.122602291610441;
+   fWeightMatrix1to2[0][3] = -1.3488789386558;
+   fWeightMatrix1to2[0][4] = 0.133379843710428;
+   fWeightMatrix1to2[0][5] = -0.311638983583305;
+   fWeightMatrix1to2[0][6] = 0.129042787301883;
+   fWeightMatrix1to2[0][7] = -0.164813815424402;
+   fWeightMatrix1to2[0][8] = 0.191821611847282;
+   fWeightMatrix1to2[0][9] = -0.0593658577582407;
+   fWeightMatrix1to2[0][10] = -0.862948789674314;
+   fWeightMatrix1to2[0][11] = -0.0470652379333911;
+   fWeightMatrix1to2[0][12] = -0.034632651943513;
+   fWeightMatrix1to2[0][13] = -0.353586449539869;
+   fWeightMatrix1to2[0][14] = -0.436294927850531;
+   fWeightMatrix1to2[0][15] = -0.30198913360629;
+   fWeightMatrix1to2[0][16] = -0.158425108422285;
+   fWeightMatrix1to2[0][17] = -0.0162157085346477;
+   fWeightMatrix1to2[0][18] = -0.0623532303058598;
+   fWeightMatrix1to2[0][19] = 0.354911694175998;
+}
+
+inline double ReadMLPMiddle::GetMvaValue__( const std::vector<double>& inputValues ) const
+{
+   if (inputValues.size() != (unsigned int)fLayerSize[0]-1) {
+      std::cout << "Input vector needs to be of size " << fLayerSize[0]-1 << std::endl;
+      return 0;
+   }
+
+   for (int l=0; l<fLayers; l++)
+      for (int i=0; i<fLayerSize[l]; i++) fWeights[l][i]=0;
+
+   for (int l=0; l<fLayers-1; l++)
+      fWeights[l][fLayerSize[l]-1]=1;
+
+   for (int i=0; i<fLayerSize[0]-1; i++)
+      fWeights[0][i]=inputValues[i];
+
+   // layer 0 to 1
+   for (int o=0; o<fLayerSize[1]-1; o++) {
+      for (int i=0; i<fLayerSize[0]; i++) {
+         double inputVal = fWeightMatrix0to1[o][i] * fWeights[0][i];
+         fWeights[1][o] += inputVal;
+      }
+      fWeights[1][o] = ActivationFnc(fWeights[1][o]);
+   }
+   // layer 1 to 2
+   for (int o=0; o<fLayerSize[2]; o++) {
+      for (int i=0; i<fLayerSize[1]; i++) {
+         double inputVal = fWeightMatrix1to2[o][i] * fWeights[1][i];
+         fWeights[2][o] += inputVal;
+      }
+      fWeights[2][o] = OutputActivationFnc(fWeights[2][o]);
+   }
+
+   return fWeights[2][0];
+}
+
+double ReadMLPMiddle::ActivationFnc(double x) const {
+   // hyperbolic tan
+   return tanh(x);
+}
+double ReadMLPMiddle::OutputActivationFnc(double x) const {
+   // identity
+   return x;
+}
+
+// Clean up
+inline void ReadMLPMiddle::Clear()
+{
+   // nothing to clear
+}
+   inline double ReadMLPMiddle::GetMvaValue( const std::vector<double>& inputValues ) const
+   {
+      // classifier response value
+      double retval = 0;
+
+      // classifier response, sanity check first
+      if (!IsStatusClean()) {
+         std::cout << "Problem in class \"" << fClassName << "\": cannot return classifier response"
+                   << " because status is dirty" << std::endl;
+         retval = 0;
+      }
+      else {
+         if (IsNormalised()) {
+            // normalise variables
+            std::vector<double> iV;
+            int ivar = 0;
+            for (std::vector<double>::const_iterator varIt = inputValues.begin();
+                 varIt != inputValues.end(); varIt++, ivar++) {
+               iV.push_back(NormVariable( *varIt, fVmin[ivar], fVmax[ivar] ));
+            }
+            Transform( iV, -1 );
+            retval = GetMvaValue__( iV );
+         }
+         else {
+            std::vector<double> iV;
+            int ivar = 0;
+            for (std::vector<double>::const_iterator varIt = inputValues.begin();
+                 varIt != inputValues.end(); varIt++, ivar++) {
+               iV.push_back(*varIt);
+            }
+            Transform( iV, -1 );
+            retval = GetMvaValue__( iV );
+         }
+      }
+
+      return retval;
+   }
+
+//_______________________________________________________________________
+inline void ReadMLPMiddle::InitTransform_1()
+{
+   // Normalization transformation, initialisation
+   fMin_1[0][0] = 396.177398682;
+   fMax_1[0][0] = 13764.8271484;
+   fMin_1[1][0] = 489.128509521;
+   fMax_1[1][0] = 12811.4384766;
+   fMin_1[2][0] = 396.177398682;
+   fMax_1[2][0] = 13764.8271484;
+   fMin_1[0][1] = 0.301807701588;
+   fMax_1[0][1] = 0.965358257294;
+   fMin_1[1][1] = 0.348349481821;
+   fMax_1[1][1] = 0.949014008045;
+   fMin_1[2][1] = 0.301807701588;
+   fMax_1[2][1] = 0.965358257294;
+   fMin_1[0][2] = -0;
+   fMax_1[0][2] = 0.740151584148;
+   fMin_1[1][2] = 3.28147143591e-05;
+   fMax_1[1][2] = 0.782861948013;
+   fMin_1[2][2] = -0;
+   fMax_1[2][2] = 0.782861948013;
+   fMin_1[0][3] = 0;
+   fMax_1[0][3] = 0.843120634556;
+   fMin_1[1][3] = 0.0138616990298;
+   fMax_1[1][3] = 0.811695218086;
+   fMin_1[2][3] = 0;
+   fMax_1[2][3] = 0.843120634556;
+   fMin_1[0][4] = 0.271574378014;
+   fMax_1[0][4] = 0.92901545763;
+   fMin_1[1][4] = 0.244072809815;
+   fMax_1[1][4] = 0.907343685627;
+   fMin_1[2][4] = 0.244072809815;
+   fMax_1[2][4] = 0.92901545763;
+   fMin_1[0][5] = 0.526907742023;
+   fMax_1[0][5] = 0.963463187218;
+   fMin_1[1][5] = 0.460556000471;
+   fMax_1[1][5] = 0.964079260826;
+   fMin_1[2][5] = 0.460556000471;
+   fMax_1[2][5] = 0.964079260826;
+   fMin_1[0][6] = 0;
+   fMax_1[0][6] = 1;
+   fMin_1[1][6] = 0;
+   fMax_1[1][6] = 1;
+   fMin_1[2][6] = 0;
+   fMax_1[2][6] = 1;
+   fMin_1[0][7] = 0;
+   fMax_1[0][7] = 0.498583585024;
+   fMin_1[1][7] = 0;
+   fMax_1[1][7] = 0.497716933489;
+   fMin_1[2][7] = 0;
+   fMax_1[2][7] = 0.498583585024;
+   fMin_1[0][8] = 0;
+   fMax_1[0][8] = 1.97231829166;
+   fMin_1[1][8] = 0;
+   fMax_1[1][8] = 1.69394040108;
+   fMin_1[2][8] = 0;
+   fMax_1[2][8] = 1.97231829166;
+   fMin_1[0][9] = 0;
+   fMax_1[0][9] = 1;
+   fMin_1[1][9] = 0;
+   fMax_1[1][9] = 1;
+   fMin_1[2][9] = 0;
+   fMax_1[2][9] = 1;
+   fMin_1[0][10] = 0;
+   fMax_1[0][10] = 9;
+   fMin_1[1][10] = 0;
+   fMax_1[1][10] = 9;
+   fMin_1[2][10] = 0;
+   fMax_1[2][10] = 9;
+   fMin_1[0][11] = 0;
+   fMax_1[0][11] = 6;
+   fMin_1[1][11] = 0;
+   fMax_1[1][11] = 5;
+   fMin_1[2][11] = 0;
+   fMax_1[2][11] = 6;
+   fMin_1[0][12] = 0;
+   fMax_1[0][12] = 6;
+   fMin_1[1][12] = 0;
+   fMax_1[1][12] = 4;
+   fMin_1[2][12] = 0;
+   fMax_1[2][12] = 6;
+   fMin_1[0][13] = 0;
+   fMax_1[0][13] = 4;
+   fMin_1[1][13] = 0;
+   fMax_1[1][13] = 4;
+   fMin_1[2][13] = 0;
+   fMax_1[2][13] = 4;
+}
+
+//_______________________________________________________________________
+inline void ReadMLPMiddle::Transform_1( std::vector<double>& iv, int cls) const
+{
+   // Normalization transformation
+   if (cls < 0 || cls > 2) {
+   if (2 > 1 ) cls = 2;
+      else cls = 2;
+   }
+   const int nVar = 14;
+
+   // get indices of used variables
+
+   // define the indices of the variables which are transformed by this transformation
+   std::vector<int> indicesGet;
+   std::vector<int> indicesPut;
+
+   indicesGet.push_back( 0);
+   indicesGet.push_back( 1);
+   indicesGet.push_back( 2);
+   indicesGet.push_back( 3);
+   indicesGet.push_back( 4);
+   indicesGet.push_back( 5);
+   indicesGet.push_back( 6);
+   indicesGet.push_back( 7);
+   indicesGet.push_back( 8);
+   indicesGet.push_back( 9);
+   indicesGet.push_back( 10);
+   indicesGet.push_back( 11);
+   indicesGet.push_back( 12);
+   indicesGet.push_back( 13);
+   indicesPut.push_back( 0);
+   indicesPut.push_back( 1);
+   indicesPut.push_back( 2);
+   indicesPut.push_back( 3);
+   indicesPut.push_back( 4);
+   indicesPut.push_back( 5);
+   indicesPut.push_back( 6);
+   indicesPut.push_back( 7);
+   indicesPut.push_back( 8);
+   indicesPut.push_back( 9);
+   indicesPut.push_back( 10);
+   indicesPut.push_back( 11);
+   indicesPut.push_back( 12);
+   indicesPut.push_back( 13);
+
+   std::vector<double> dv(nVar);
+   for (int ivar=0; ivar<nVar; ivar++) dv[ivar] = iv[indicesGet.at(ivar)];
+   for (int ivar=0;ivar<14;ivar++) {
+      double offset = fMin_1[cls][ivar];
+      double scale  = 1.0/(fMax_1[cls][ivar]-fMin_1[cls][ivar]);
+      iv[indicesPut.at(ivar)] = (dv[ivar]-offset)*scale * 2 - 1;
+   }
+}
+
+//_______________________________________________________________________
+inline void ReadMLPMiddle::InitTransform()
+{
+   InitTransform_1();
+}
+
+//_______________________________________________________________________
+inline void ReadMLPMiddle::Transform( std::vector<double>& iv, int sigOrBgd ) const
+{
+   Transform_1( iv, sigOrBgd );
+}
diff --git a/CaloFuture/CaloFutureTools/src/TMV_MLP_outer.C b/CaloFuture/CaloFutureTools/src/TMV_MLP_outer.C
new file mode 100644
index 0000000000000000000000000000000000000000..1b74144f6b869522bd22aee9260cd3f6216386da
--- /dev/null
+++ b/CaloFuture/CaloFutureTools/src/TMV_MLP_outer.C
@@ -0,0 +1,817 @@
+// Class: ReadMLPOuter
+// Automatically generated by MethodBase::MakeClass
+//
+
+/* configuration options =====================================================
+
+#GEN -*-*-*-*-*-*-*-*-*-*-*- general info -*-*-*-*-*-*-*-*-*-*-*-
+
+Method         : MLP::MLP
+TMVA Release   : 4.1.2         [262402]
+ROOT Release   : 5.30/00       [335360]
+Creator        : calvom
+Date           : Tue Nov  8 17:09:32 2011
+Host           : Linux lxbuild148.cern.ch 2.6.18-194.26.1.el5 #1 SMP Wed Nov 10 09:45:46 CET 2010 x86_64 x86_64 x86_64 GNU/Linux
+Dir            : /afs/cern.ch/user/c/calvom/w0/GammaPi0/tmva_calib
+Training events: 31890
+Analysis type  : [Classification]
+
+
+#OPT -*-*-*-*-*-*-*-*-*-*-*-*- options -*-*-*-*-*-*-*-*-*-*-*-*-
+
+# Set by User:
+NCycles: "600" [Number of training cycles]
+HiddenLayers: "N+5" [Specification of hidden layer architecture]
+NeuronType: "tanh" [Neuron activation function type]
+V: "False" [Verbose output (short form of "VerbosityLevel" below - overrides the latter one)]
+VarTransform: "N" [List of variable transformations performed before training, e.g., "D_Background,P_Signal,G,N_AllClasses" for: "Decorrelation, PCA-transformation, Gaussianisation, Normalisation, each for the given class of events ('AllClasses' denotes all events of all classes, if no class indication is given, 'All' is assumed)"]
+H: "True" [Print method-specific help message]
+TestRate: "5" [Test for overtraining performed at each #th epochs]
+# Default:
+RandomSeed: "1" [Random seed for initial synapse weights (0 means unique seed for each run; default value '1')]
+EstimatorType: "MSE" [MSE (Mean Square Estimator) for Gaussian Likelihood or CE(Cross-Entropy) for Bernoulli Likelihood]
+NeuronInputType: "sum" [Neuron input function type]
+VerbosityLevel: "Default" [Verbosity level]
+CreateMVAPdfs: "False" [Create PDFs for classifier outputs (signal and background)]
+IgnoreNegWeightsInTraining: "False" [Events with negative weights are ignored in the training (but are included for testing and performance evaluation)]
+TrainingMethod: "BP" [Train with Back-Propagation (BP), BFGS Algorithm (BFGS), or Genetic Algorithm (GA - slower and worse)]
+LearningRate: "2.000000e-02" [ANN learning rate parameter]
+DecayRate: "1.000000e-02" [Decay rate for learning parameter]
+EpochMonitoring: "False" [Provide epoch-wise monitoring plots according to TestRate (caution: causes big ROOT output file!)]
+Sampling: "1.000000e+00" [Only 'Sampling' (randomly selected) events are trained each epoch]
+SamplingEpoch: "1.000000e+00" [Sampling is used for the first 'SamplingEpoch' epochs, afterwards, all events are taken for training]
+SamplingImportance: "1.000000e+00" [ The sampling weights of events in epochs which successful (worse estimator than before) are multiplied with SamplingImportance, else they are divided.]
+SamplingTraining: "True" [The training sample is sampled]
+SamplingTesting: "False" [The testing sample is sampled]
+ResetStep: "50" [How often BFGS should reset history]
+Tau: "3.000000e+00" [LineSearch "size step"]
+BPMode: "sequential" [Back-propagation learning mode: sequential or batch]
+BatchSize: "-1" [Batch size: number of events/batch, only set if in Batch Mode, -1 for BatchSize=number_of_events]
+ConvergenceImprove: "1.000000e-30" [Minimum improvement which counts as improvement (<0 means automatic convergence check is turned off)]
+ConvergenceTests: "-1" [Number of steps (without improvement) required for convergence (<0 means automatic convergence check is turned off)]
+UseRegulator: "False" [Use regulator to avoid over-training]
+UpdateLimit: "10000" [Maximum times of regulator update]
+CalculateErrors: "False" [Calculates inverse Hessian matrix at the end of the training to be able to calculate the uncertainties of an MVA value]
+WeightRange: "1.000000e+00" [Take the events for the estimator calculations from small deviations from the desired value to large deviations only over the weight range]
+##
+
+
+#VAR -*-*-*-*-*-*-*-*-*-*-*-* variables *-*-*-*-*-*-*-*-*-*-*-*-
+
+NVar 14
+fr2                           fr2                           fr2                           fr2                                                             'F'    [1262.8170166,25870.0039062]
+fr2r4                         fr2r4                         fr2r4                         fr2r4                                                           'F'    [-4.7790851593,0.974924445152]
+abs(asym)                     abs_asym_                     abs(asym)                     abs(asym)                                                       'F'    [-0,0.870256125927]
+kappa                         kappa                         kappa                         kappa                                                           'F'    [0,0.902063071728]
+Eseed/Ecl                     Eseed_D_Ecl                   Eseed/Ecl                     Eseed/Ecl                                                       'F'    [0.228343188763,0.998945295811]
+(E2+Eseed)/Ecl                _E2_P_Eseed__D_Ecl            (E2+Eseed)/Ecl                (E2+Eseed)/Ecl                                                  'F'    [0.452791303396,1.00381207466]
+eSumPS>0?eMaxPS/eSumPS:0      eSumPS_0_eMaxPS_D_eSumPS:0    eSumPS>0?eMaxPS/eSumPS:0      eSumPS>0?eMaxPS/eSumPS:0                                        'F'    [0,1]
+eSumPS>0?e2ndPS/eSumPS:0      eSumPS_0_e2ndPS_D_eSumPS:0    eSumPS>0?e2ndPS/eSumPS:0      eSumPS>0?e2ndPS/eSumPS:0                                        'F'    [0,0.499058365822]
+r2PS                          r2PS                          r2PS                          r2PS                                                            'F'    [0,1.95918369293]
+abs(asymPS)                   abs_asymPS_                   abs(asymPS)                   abs(asymPS)                                                     'F'    [0,1]
+multiPS                       multiPS                       multiPS                       multiPS                                                         'F'    [0,8]
+multiPS15                     multiPS15                     multiPS15                     multiPS15                                                       'F'    [0,5]
+multiPS30                     multiPS30                     multiPS30                     multiPS30                                                       'F'    [0,4]
+multiPS45                     multiPS45                     multiPS45                     multiPS45                                                       'F'    [0,3]
+NSpec 0
+
+
+============================================================================ */
+
+#include <vector>
+#include <cmath>
+#include <string>
+#include <iostream>
+
+#ifndef IClassifierReader__def
+#define IClassifierReader__def
+
+class IClassifierReader {
+
+ public:
+
+   // constructor
+   IClassifierReader() : fStatusIsClean( true ) {}
+   virtual ~IClassifierReader() {}
+
+   // return classifier response
+   virtual double GetMvaValue( const std::vector<double>& inputValues ) const = 0;
+
+   // returns classifier status
+   bool IsStatusClean() const { return fStatusIsClean; }
+
+ protected:
+
+   bool fStatusIsClean;
+};
+
+#endif
+
+class ReadMLPOuter : public IClassifierReader {
+
+ public:
+
+   // constructor
+   ReadMLPOuter( const std::vector<std::string>& theInputVars )
+      : IClassifierReader(),
+        fClassName( "ReadMLPOuter" ),
+        fNvars( 14 ),
+        fIsNormalised( false )
+   {
+      // the training input variables
+      const char* inputVars[] = { "fr2", "fr2r4", "abs(asym)", "kappa", "Eseed/Ecl", "(E2+Eseed)/Ecl", "eSumPS>0?eMaxPS/eSumPS:0", "eSumPS>0?e2ndPS/eSumPS:0", "r2PS", "abs(asymPS)", "multiPS", "multiPS15", "multiPS30", "multiPS45" };
+
+      // sanity checks
+      if (theInputVars.size() <= 0) {
+         std::cout << "Problem in class \"" << fClassName << "\": empty input vector" << std::endl;
+         fStatusIsClean = false;
+      }
+
+      if (theInputVars.size() != fNvars) {
+         std::cout << "Problem in class \"" << fClassName << "\": mismatch in number of input values: "
+                   << theInputVars.size() << " != " << fNvars << std::endl;
+         fStatusIsClean = false;
+      }
+
+      // validate input variables
+      for (size_t ivar = 0; ivar < theInputVars.size(); ivar++) {
+         if (theInputVars[ivar] != inputVars[ivar]) {
+            std::cout << "Problem in class \"" << fClassName << "\": mismatch in input variable names" << std::endl
+                      << " for variable [" << ivar << "]: " << theInputVars[ivar].c_str() << " != " << inputVars[ivar] << std::endl;
+            fStatusIsClean = false;
+         }
+      }
+
+      // initialize min and max vectors (for normalisation)
+      fVmin[0] = -1;
+      fVmax[0] = 1;
+      fVmin[1] = -1;
+      fVmax[1] = 1;
+      fVmin[2] = -1;
+      fVmax[2] = 0.99999988079071;
+      fVmin[3] = -1;
+      fVmax[3] = 1;
+      fVmin[4] = -1;
+      fVmax[4] = 1;
+      fVmin[5] = -1;
+      fVmax[5] = 1;
+      fVmin[6] = -1;
+      fVmax[6] = 1;
+      fVmin[7] = -1;
+      fVmax[7] = 1;
+      fVmin[8] = -1;
+      fVmax[8] = 1;
+      fVmin[9] = -1;
+      fVmax[9] = 1;
+      fVmin[10] = -1;
+      fVmax[10] = 1;
+      fVmin[11] = -1;
+      fVmax[11] = 1;
+      fVmin[12] = -1;
+      fVmax[12] = 1;
+      fVmin[13] = -1;
+      fVmax[13] = 1;
+
+      // initialize input variable types
+      fType[0] = 'F';
+      fType[1] = 'F';
+      fType[2] = 'F';
+      fType[3] = 'F';
+      fType[4] = 'F';
+      fType[5] = 'F';
+      fType[6] = 'F';
+      fType[7] = 'F';
+      fType[8] = 'F';
+      fType[9] = 'F';
+      fType[10] = 'F';
+      fType[11] = 'F';
+      fType[12] = 'F';
+      fType[13] = 'F';
+
+      // initialize constants
+      Initialize();
+
+      // initialize transformation
+      InitTransform();
+   }
+
+   // destructor
+   virtual ~ReadMLPOuter() {
+      Clear(); // method-specific
+   }
+
+   // the classifier response
+   // "inputValues" is a vector of input values in the same order as the
+   // variables given to the constructor
+   double GetMvaValue( const std::vector<double>& inputValues ) const override;
+
+ private:
+
+   // method-specific destructor
+   void Clear();
+
+   // input variable transformation
+
+   double fMin_1[3][14];
+   double fMax_1[3][14];
+   void InitTransform_1();
+   void Transform_1( std::vector<double> & iv, int sigOrBgd ) const;
+   void InitTransform();
+   void Transform( std::vector<double> & iv, int sigOrBgd ) const;
+
+   // common member variables
+   const char* fClassName;
+
+   const size_t fNvars;
+   size_t GetNvar()           const { return fNvars; }
+   char   GetType( int ivar ) const { return fType[ivar]; }
+
+   // normalisation of input variables
+   const bool fIsNormalised;
+   bool IsNormalised() const { return fIsNormalised; }
+   double fVmin[14];
+   double fVmax[14];
+   double NormVariable( double x, double xmin, double xmax ) const {
+      // normalise to output range: [-1, 1]
+      return 2*(x - xmin)/(xmax - xmin) - 1.0;
+   }
+
+   // type of input variable: 'F' or 'I'
+   char   fType[14];
+
+   // initialize internal variables
+   void Initialize();
+   double GetMvaValue__( const std::vector<double>& inputValues ) const;
+
+   // private members (method specific)
+
+   double ActivationFnc(double x) const;
+   double OutputActivationFnc(double x) const;
+
+   int fLayers;
+   int fLayerSize[3];
+   double fWeightMatrix0to1[20][15];   // weight matrix from layer 0 to 1
+   double fWeightMatrix1to2[1][20];   // weight matrix from layer 1 to 2
+
+   double * fWeights[3];
+};
+
+inline void ReadMLPOuter::Initialize()
+{
+   // build network structure
+   fLayers = 3;
+   fLayerSize[0] = 15; fWeights[0] = new double[15];
+   fLayerSize[1] = 20; fWeights[1] = new double[20];
+   fLayerSize[2] = 1; fWeights[2] = new double[1];
+   // weight matrix from layer 0 to 1
+   fWeightMatrix0to1[0][0] = -0.803078780002077;
+   fWeightMatrix0to1[1][0] = 2.46852247389318;
+   fWeightMatrix0to1[2][0] = 1.13186843505129;
+   fWeightMatrix0to1[3][0] = 2.08289280349423;
+   fWeightMatrix0to1[4][0] = -2.02637667542277;
+   fWeightMatrix0to1[5][0] = -0.986243417218828;
+   fWeightMatrix0to1[6][0] = -0.244082833973297;
+   fWeightMatrix0to1[7][0] = 2.49486110312933;
+   fWeightMatrix0to1[8][0] = -1.53730331140634;
+   fWeightMatrix0to1[9][0] = -1.37630248429394;
+   fWeightMatrix0to1[10][0] = -1.89736835486016;
+   fWeightMatrix0to1[11][0] = 0.223034156937693;
+   fWeightMatrix0to1[12][0] = -1.0383802938468;
+   fWeightMatrix0to1[13][0] = -0.759650512986243;
+   fWeightMatrix0to1[14][0] = 1.82811900974975;
+   fWeightMatrix0to1[15][0] = 0.762919621719025;
+   fWeightMatrix0to1[16][0] = 0.157029807974629;
+   fWeightMatrix0to1[17][0] = 1.93320941809115;
+   fWeightMatrix0to1[18][0] = 0.143405923217408;
+   fWeightMatrix0to1[0][1] = 1.26209002843162;
+   fWeightMatrix0to1[1][1] = 0.800837943079452;
+   fWeightMatrix0to1[2][1] = -1.76747369204177;
+   fWeightMatrix0to1[3][1] = -0.361564528432957;
+   fWeightMatrix0to1[4][1] = 0.366761004922902;
+   fWeightMatrix0to1[5][1] = -1.96471302666455;
+   fWeightMatrix0to1[6][1] = -0.00863043940634471;
+   fWeightMatrix0to1[7][1] = 1.1002970997226;
+   fWeightMatrix0to1[8][1] = -0.897301827109627;
+   fWeightMatrix0to1[9][1] = -1.4370443331252;
+   fWeightMatrix0to1[10][1] = 0.726929486996826;
+   fWeightMatrix0to1[11][1] = 0.144972630146927;
+   fWeightMatrix0to1[12][1] = 1.01974710573241;
+   fWeightMatrix0to1[13][1] = -0.271869349873447;
+   fWeightMatrix0to1[14][1] = 1.42228166666045;
+   fWeightMatrix0to1[15][1] = 0.0104573774641417;
+   fWeightMatrix0to1[16][1] = -0.308118244670233;
+   fWeightMatrix0to1[17][1] = -2.30235230921859;
+   fWeightMatrix0to1[18][1] = 1.91747762926562;
+   fWeightMatrix0to1[0][2] = -1.40370127713885;
+   fWeightMatrix0to1[1][2] = 0.423607211765278;
+   fWeightMatrix0to1[2][2] = 0.818760843055836;
+   fWeightMatrix0to1[3][2] = 1.20387982860113;
+   fWeightMatrix0to1[4][2] = 1.35919685062478;
+   fWeightMatrix0to1[5][2] = 1.21540008848762;
+   fWeightMatrix0to1[6][2] = -0.544187659835051;
+   fWeightMatrix0to1[7][2] = -1.14357919480641;
+   fWeightMatrix0to1[8][2] = 0.297378412632497;
+   fWeightMatrix0to1[9][2] = -0.526383709761007;
+   fWeightMatrix0to1[10][2] = 0.883604311753331;
+   fWeightMatrix0to1[11][2] = 1.82479487589162;
+   fWeightMatrix0to1[12][2] = 1.99527911898016;
+   fWeightMatrix0to1[13][2] = 1.06309599550614;
+   fWeightMatrix0to1[14][2] = -2.17771385898406;
+   fWeightMatrix0to1[15][2] = 0.883578959090106;
+   fWeightMatrix0to1[16][2] = -1.10142776710941;
+   fWeightMatrix0to1[17][2] = -0.199074231499796;
+   fWeightMatrix0to1[18][2] = -0.406107007509069;
+   fWeightMatrix0to1[0][3] = -2.25938238908665;
+   fWeightMatrix0to1[1][3] = 2.10412597063301;
+   fWeightMatrix0to1[2][3] = 0.229288650958736;
+   fWeightMatrix0to1[3][3] = -1.31954297657338;
+   fWeightMatrix0to1[4][3] = -0.0592391931970953;
+   fWeightMatrix0to1[5][3] = -0.295338498057784;
+   fWeightMatrix0to1[6][3] = 0.883241506059367;
+   fWeightMatrix0to1[7][3] = 1.23103118599503;
+   fWeightMatrix0to1[8][3] = 0.609359545198016;
+   fWeightMatrix0to1[9][3] = 0.242221316928949;
+   fWeightMatrix0to1[10][3] = -1.18771134421954;
+   fWeightMatrix0to1[11][3] = 0.938633848501122;
+   fWeightMatrix0to1[12][3] = -0.451346424105564;
+   fWeightMatrix0to1[13][3] = -0.755660347351227;
+   fWeightMatrix0to1[14][3] = -1.13856736163619;
+   fWeightMatrix0to1[15][3] = 0.689854778538881;
+   fWeightMatrix0to1[16][3] = 1.15812394661006;
+   fWeightMatrix0to1[17][3] = 0.902214429609987;
+   fWeightMatrix0to1[18][3] = -0.0347518471475436;
+   fWeightMatrix0to1[0][4] = -1.84653992230033;
+   fWeightMatrix0to1[1][4] = -0.559554214433256;
+   fWeightMatrix0to1[2][4] = 1.34280927296906;
+   fWeightMatrix0to1[3][4] = 0.680455223703724;
+   fWeightMatrix0to1[4][4] = 2.27099267569362;
+   fWeightMatrix0to1[5][4] = 0.875384790055415;
+   fWeightMatrix0to1[6][4] = 1.07689800262901;
+   fWeightMatrix0to1[7][4] = -0.618591196087963;
+   fWeightMatrix0to1[8][4] = 0.00940997991751735;
+   fWeightMatrix0to1[9][4] = 0.119960051927709;
+   fWeightMatrix0to1[10][4] = 0.959392274846952;
+   fWeightMatrix0to1[11][4] = -1.16638883179262;
+   fWeightMatrix0to1[12][4] = -1.7460933444306;
+   fWeightMatrix0to1[13][4] = -0.755219386538928;
+   fWeightMatrix0to1[14][4] = 1.8648451240955;
+   fWeightMatrix0to1[15][4] = 0.382708379534019;
+   fWeightMatrix0to1[16][4] = 1.02893269952448;
+   fWeightMatrix0to1[17][4] = -1.33248833851209;
+   fWeightMatrix0to1[18][4] = -0.370452044508549;
+   fWeightMatrix0to1[0][5] = 1.80184695297776;
+   fWeightMatrix0to1[1][5] = -1.03783778224495;
+   fWeightMatrix0to1[2][5] = -1.87587461123689;
+   fWeightMatrix0to1[3][5] = -1.57428576422228;
+   fWeightMatrix0to1[4][5] = 0.346407925429289;
+   fWeightMatrix0to1[5][5] = -2.00403685431281;
+   fWeightMatrix0to1[6][5] = -1.90077807488318;
+   fWeightMatrix0to1[7][5] = -0.435805738924137;
+   fWeightMatrix0to1[8][5] = 2.22920897230816;
+   fWeightMatrix0to1[9][5] = -0.590267878593306;
+   fWeightMatrix0to1[10][5] = 1.81519843139597;
+   fWeightMatrix0to1[11][5] = -1.27185382653094;
+   fWeightMatrix0to1[12][5] = -1.47103922048247;
+   fWeightMatrix0to1[13][5] = 0.547787478237777;
+   fWeightMatrix0to1[14][5] = 0.227708755905687;
+   fWeightMatrix0to1[15][5] = -1.46813509039314;
+   fWeightMatrix0to1[16][5] = -0.0525733201505653;
+   fWeightMatrix0to1[17][5] = -0.109408204900155;
+   fWeightMatrix0to1[18][5] = 0.326916419457406;
+   fWeightMatrix0to1[0][6] = -0.897573267963214;
+   fWeightMatrix0to1[1][6] = -0.374010127046777;
+   fWeightMatrix0to1[2][6] = -0.0789346325365137;
+   fWeightMatrix0to1[3][6] = -0.998319913643738;
+   fWeightMatrix0to1[4][6] = 1.01933751235888;
+   fWeightMatrix0to1[5][6] = -0.985913803589177;
+   fWeightMatrix0to1[6][6] = -1.45439424255025;
+   fWeightMatrix0to1[7][6] = -0.278834694131582;
+   fWeightMatrix0to1[8][6] = -0.24879196817104;
+   fWeightMatrix0to1[9][6] = 2.19460624126606;
+   fWeightMatrix0to1[10][6] = 0.720530700907214;
+   fWeightMatrix0to1[11][6] = -0.541478420930393;
+   fWeightMatrix0to1[12][6] = -0.00862677189443074;
+   fWeightMatrix0to1[13][6] = 0.235434812899575;
+   fWeightMatrix0to1[14][6] = -0.946571167209579;
+   fWeightMatrix0to1[15][6] = 0.949420697844076;
+   fWeightMatrix0to1[16][6] = 0.397697406588499;
+   fWeightMatrix0to1[17][6] = -1.19287902043725;
+   fWeightMatrix0to1[18][6] = 0.367323540217887;
+   fWeightMatrix0to1[0][7] = -1.08982889728479;
+   fWeightMatrix0to1[1][7] = 0.0705548438716484;
+   fWeightMatrix0to1[2][7] = 1.21639858501589;
+   fWeightMatrix0to1[3][7] = 1.3533915188747;
+   fWeightMatrix0to1[4][7] = -1.72877194379874;
+   fWeightMatrix0to1[5][7] = -0.0954364128728001;
+   fWeightMatrix0to1[6][7] = 0.743186148113269;
+   fWeightMatrix0to1[7][7] = 1.58569293402206;
+   fWeightMatrix0to1[8][7] = -0.407976122711286;
+   fWeightMatrix0to1[9][7] = -0.757106488445243;
+   fWeightMatrix0to1[10][7] = -0.0513868284358275;
+   fWeightMatrix0to1[11][7] = -0.912763346380385;
+   fWeightMatrix0to1[12][7] = 1.28319073979458;
+   fWeightMatrix0to1[13][7] = 0.57440637742315;
+   fWeightMatrix0to1[14][7] = -0.0351951944683237;
+   fWeightMatrix0to1[15][7] = -0.334876100549796;
+   fWeightMatrix0to1[16][7] = 0.56826708139794;
+   fWeightMatrix0to1[17][7] = -1.11819662764277;
+   fWeightMatrix0to1[18][7] = -0.161625991599902;
+   fWeightMatrix0to1[0][8] = 1.41064908124236;
+   fWeightMatrix0to1[1][8] = -0.279389666861271;
+   fWeightMatrix0to1[2][8] = 0.647413274617866;
+   fWeightMatrix0to1[3][8] = 0.0329313689509846;
+   fWeightMatrix0to1[4][8] = 0.765222372267189;
+   fWeightMatrix0to1[5][8] = 0.805711391551295;
+   fWeightMatrix0to1[6][8] = 0.704971983155431;
+   fWeightMatrix0to1[7][8] = -1.15585865232024;
+   fWeightMatrix0to1[8][8] = 1.4004056798631;
+   fWeightMatrix0to1[9][8] = 0.59589686311756;
+   fWeightMatrix0to1[10][8] = 0.0506274444455068;
+   fWeightMatrix0to1[11][8] = 0.778310657929542;
+   fWeightMatrix0to1[12][8] = 1.36413859490602;
+   fWeightMatrix0to1[13][8] = -0.722376977263356;
+   fWeightMatrix0to1[14][8] = -0.651133777015196;
+   fWeightMatrix0to1[15][8] = 1.16225199814518;
+   fWeightMatrix0to1[16][8] = -0.898290853245839;
+   fWeightMatrix0to1[17][8] = 0.255981113911936;
+   fWeightMatrix0to1[18][8] = 1.15983322253769;
+   fWeightMatrix0to1[0][9] = 0.64410967707169;
+   fWeightMatrix0to1[1][9] = 0.298655015427935;
+   fWeightMatrix0to1[2][9] = 0.953288508810634;
+   fWeightMatrix0to1[3][9] = 1.17515129066659;
+   fWeightMatrix0to1[4][9] = -1.48534121747573;
+   fWeightMatrix0to1[5][9] = 0.383588681780043;
+   fWeightMatrix0to1[6][9] = -0.682117670973728;
+   fWeightMatrix0to1[7][9] = 1.0734580716766;
+   fWeightMatrix0to1[8][9] = 0.0972488394714247;
+   fWeightMatrix0to1[9][9] = -1.44575203315637;
+   fWeightMatrix0to1[10][9] = 0.689035260216028;
+   fWeightMatrix0to1[11][9] = 0.783461854623659;
+   fWeightMatrix0to1[12][9] = -0.897921034866479;
+   fWeightMatrix0to1[13][9] = -0.150132887679573;
+   fWeightMatrix0to1[14][9] = -0.227819148775529;
+   fWeightMatrix0to1[15][9] = -0.454368500870791;
+   fWeightMatrix0to1[16][9] = 0.926313537934954;
+   fWeightMatrix0to1[17][9] = 0.375592979473134;
+   fWeightMatrix0to1[18][9] = -0.212723032034983;
+   fWeightMatrix0to1[0][10] = -0.903684557324865;
+   fWeightMatrix0to1[1][10] = -0.269219667927999;
+   fWeightMatrix0to1[2][10] = 0.956329276333231;
+   fWeightMatrix0to1[3][10] = 1.14695509555494;
+   fWeightMatrix0to1[4][10] = -0.0665167038175885;
+   fWeightMatrix0to1[5][10] = -0.154134638989865;
+   fWeightMatrix0to1[6][10] = -0.937515521234543;
+   fWeightMatrix0to1[7][10] = 0.9660568680461;
+   fWeightMatrix0to1[8][10] = 0.389207068896224;
+   fWeightMatrix0to1[9][10] = -1.43667067795005;
+   fWeightMatrix0to1[10][10] = -0.545302499304715;
+   fWeightMatrix0to1[11][10] = 0.646453677304514;
+   fWeightMatrix0to1[12][10] = 0.368070906498839;
+   fWeightMatrix0to1[13][10] = -1.01860632431505;
+   fWeightMatrix0to1[14][10] = -0.00201116742788192;
+   fWeightMatrix0to1[15][10] = 0.609992814668807;
+   fWeightMatrix0to1[16][10] = -0.2995034193925;
+   fWeightMatrix0to1[17][10] = 0.165861384025389;
+   fWeightMatrix0to1[18][10] = 0.65872850910737;
+   fWeightMatrix0to1[0][11] = 0.76239282169146;
+   fWeightMatrix0to1[1][11] = 1.114355352444;
+   fWeightMatrix0to1[2][11] = 0.00632312719316779;
+   fWeightMatrix0to1[3][11] = -1.38700360257435;
+   fWeightMatrix0to1[4][11] = -1.33543093140446;
+   fWeightMatrix0to1[5][11] = 2.36450431921163;
+   fWeightMatrix0to1[6][11] = 1.63667811844591;
+   fWeightMatrix0to1[7][11] = 1.28531389688515;
+   fWeightMatrix0to1[8][11] = 0.311507523856964;
+   fWeightMatrix0to1[9][11] = 1.62382261557303;
+   fWeightMatrix0to1[10][11] = -1.53683084288582;
+   fWeightMatrix0to1[11][11] = -0.880227449202108;
+   fWeightMatrix0to1[12][11] = 0.469944237847874;
+   fWeightMatrix0to1[13][11] = -0.574782950115894;
+   fWeightMatrix0to1[14][11] = 0.0834393415934373;
+   fWeightMatrix0to1[15][11] = 1.73663042170519;
+   fWeightMatrix0to1[16][11] = -0.794958681610394;
+   fWeightMatrix0to1[17][11] = 1.03182112824119;
+   fWeightMatrix0to1[18][11] = -0.194707701648851;
+   fWeightMatrix0to1[0][12] = -1.12453351932177;
+   fWeightMatrix0to1[1][12] = 0.349214136004141;
+   fWeightMatrix0to1[2][12] = 0.648304976611225;
+   fWeightMatrix0to1[3][12] = 0.863958688425645;
+   fWeightMatrix0to1[4][12] = 0.53991657996592;
+   fWeightMatrix0to1[5][12] = -0.175441713082249;
+   fWeightMatrix0to1[6][12] = 1.86358071406195;
+   fWeightMatrix0to1[7][12] = -1.15194868707706;
+   fWeightMatrix0to1[8][12] = 0.303276761188666;
+   fWeightMatrix0to1[9][12] = -0.293569411375138;
+   fWeightMatrix0to1[10][12] = -1.13999727749549;
+   fWeightMatrix0to1[11][12] = -0.668860599026539;
+   fWeightMatrix0to1[12][12] = -0.929148759645519;
+   fWeightMatrix0to1[13][12] = 0.0354692929050461;
+   fWeightMatrix0to1[14][12] = -0.786027039415339;
+   fWeightMatrix0to1[15][12] = -1.04264078551136;
+   fWeightMatrix0to1[16][12] = -1.44812079105289;
+   fWeightMatrix0to1[17][12] = 0.0540896196172365;
+   fWeightMatrix0to1[18][12] = -0.492485393452257;
+   fWeightMatrix0to1[0][13] = -0.333167216181322;
+   fWeightMatrix0to1[1][13] = 0.123887737942558;
+   fWeightMatrix0to1[2][13] = 0.380006497159629;
+   fWeightMatrix0to1[3][13] = 0.451090958441009;
+   fWeightMatrix0to1[4][13] = -1.24985513801445;
+   fWeightMatrix0to1[5][13] = 0.146122374228418;
+   fWeightMatrix0to1[6][13] = 2.45815635758746;
+   fWeightMatrix0to1[7][13] = 1.67650332997768;
+   fWeightMatrix0to1[8][13] = 0.0261643692739909;
+   fWeightMatrix0to1[9][13] = -1.47712987834849;
+   fWeightMatrix0to1[10][13] = -1.0713005012704;
+   fWeightMatrix0to1[11][13] = 0.0656128452057918;
+   fWeightMatrix0to1[12][13] = -0.72591709364151;
+   fWeightMatrix0to1[13][13] = 0.490200081745697;
+   fWeightMatrix0to1[14][13] = 0.0825337270008085;
+   fWeightMatrix0to1[15][13] = 2.1664215923145;
+   fWeightMatrix0to1[16][13] = 0.390608640807874;
+   fWeightMatrix0to1[17][13] = 0.514931391652967;
+   fWeightMatrix0to1[18][13] = -0.0561729443152231;
+   fWeightMatrix0to1[0][14] = -2.09001832233408;
+   fWeightMatrix0to1[1][14] = 1.72881427757093;
+   fWeightMatrix0to1[2][14] = -0.0381319424927858;
+   fWeightMatrix0to1[3][14] = -2.05905352202282;
+   fWeightMatrix0to1[4][14] = -0.84529895120051;
+   fWeightMatrix0to1[5][14] = -0.325430883200274;
+   fWeightMatrix0to1[6][14] = 1.25000988278363;
+   fWeightMatrix0to1[7][14] = -0.0268772937346941;
+   fWeightMatrix0to1[8][14] = -0.651686501592155;
+   fWeightMatrix0to1[9][14] = 0.115833680890629;
+   fWeightMatrix0to1[10][14] = 2.11416880687827;
+   fWeightMatrix0to1[11][14] = 0.40560026675739;
+   fWeightMatrix0to1[12][14] = 0.319016786783736;
+   fWeightMatrix0to1[13][14] = -0.33280581243366;
+   fWeightMatrix0to1[14][14] = 0.496865152794801;
+   fWeightMatrix0to1[15][14] = -0.615512669262649;
+   fWeightMatrix0to1[16][14] = -1.46690737428128;
+   fWeightMatrix0to1[17][14] = -1.52062200595209;
+   fWeightMatrix0to1[18][14] = -1.66633039441861;
+   // weight matrix from layer 1 to 2
+   fWeightMatrix1to2[0][0] = 0.0428683723750179;
+   fWeightMatrix1to2[0][1] = -0.177501101264912;
+   fWeightMatrix1to2[0][2] = 0.641503101776094;
+   fWeightMatrix1to2[0][3] = -0.658895361751999;
+   fWeightMatrix1to2[0][4] = -0.0571464010312664;
+   fWeightMatrix1to2[0][5] = -0.704806328003322;
+   fWeightMatrix1to2[0][6] = -0.121182349512334;
+   fWeightMatrix1to2[0][7] = -0.0680342016206922;
+   fWeightMatrix1to2[0][8] = 0.132383506938821;
+   fWeightMatrix1to2[0][9] = 0.0530225967277884;
+   fWeightMatrix1to2[0][10] = 0.0968814546615638;
+   fWeightMatrix1to2[0][11] = 0.0706561052588567;
+   fWeightMatrix1to2[0][12] = -0.028978796869773;
+   fWeightMatrix1to2[0][13] = 0.0827747721359912;
+   fWeightMatrix1to2[0][14] = 0.329575883298149;
+   fWeightMatrix1to2[0][15] = 0.318011854043643;
+   fWeightMatrix1to2[0][16] = 0.0087319385918838;
+   fWeightMatrix1to2[0][17] = 0.674654265382897;
+   fWeightMatrix1to2[0][18] = 0.00140682084534325;
+   fWeightMatrix1to2[0][19] = 0.484340512284042;
+}
+
+inline double ReadMLPOuter::GetMvaValue__( const std::vector<double>& inputValues ) const
+{
+   if (inputValues.size() != (unsigned int)fLayerSize[0]-1) {
+      std::cout << "Input vector needs to be of size " << fLayerSize[0]-1 << std::endl;
+      return 0;
+   }
+
+   for (int l=0; l<fLayers; l++)
+      for (int i=0; i<fLayerSize[l]; i++) fWeights[l][i]=0;
+
+   for (int l=0; l<fLayers-1; l++)
+      fWeights[l][fLayerSize[l]-1]=1;
+
+   for (int i=0; i<fLayerSize[0]-1; i++)
+      fWeights[0][i]=inputValues[i];
+
+   // layer 0 to 1
+   for (int o=0; o<fLayerSize[1]-1; o++) {
+      for (int i=0; i<fLayerSize[0]; i++) {
+         double inputVal = fWeightMatrix0to1[o][i] * fWeights[0][i];
+         fWeights[1][o] += inputVal;
+      }
+      fWeights[1][o] = ActivationFnc(fWeights[1][o]);
+   }
+   // layer 1 to 2
+   for (int o=0; o<fLayerSize[2]; o++) {
+      for (int i=0; i<fLayerSize[1]; i++) {
+         double inputVal = fWeightMatrix1to2[o][i] * fWeights[1][i];
+         fWeights[2][o] += inputVal;
+      }
+      fWeights[2][o] = OutputActivationFnc(fWeights[2][o]);
+   }
+
+   return fWeights[2][0];
+}
+
+double ReadMLPOuter::ActivationFnc(double x) const {
+   // hyperbolic tan
+   return tanh(x);
+}
+double ReadMLPOuter::OutputActivationFnc(double x) const {
+   // identity
+   return x;
+}
+
+// Clean up
+inline void ReadMLPOuter::Clear()
+{
+   // nothing to clear
+}
+   inline double ReadMLPOuter::GetMvaValue( const std::vector<double>& inputValues ) const
+   {
+      // classifier response value
+      double retval = 0;
+
+      // classifier response, sanity check first
+      if (!IsStatusClean()) {
+         std::cout << "Problem in class \"" << fClassName << "\": cannot return classifier response"
+                   << " because status is dirty" << std::endl;
+         retval = 0;
+      }
+      else {
+         if (IsNormalised()) {
+            // normalise variables
+            std::vector<double> iV;
+            int ivar = 0;
+            for (std::vector<double>::const_iterator varIt = inputValues.begin();
+                 varIt != inputValues.end(); varIt++, ivar++) {
+               iV.push_back(NormVariable( *varIt, fVmin[ivar], fVmax[ivar] ));
+            }
+            Transform( iV, -1 );
+            retval = GetMvaValue__( iV );
+         }
+         else {
+            std::vector<double> iV;
+            int ivar = 0;
+            for (std::vector<double>::const_iterator varIt = inputValues.begin();
+                 varIt != inputValues.end(); varIt++, ivar++) {
+               iV.push_back(*varIt);
+            }
+            Transform( iV, -1 );
+            retval = GetMvaValue__( iV );
+         }
+      }
+
+      return retval;
+   }
+
+//_______________________________________________________________________
+inline void ReadMLPOuter::InitTransform_1()
+{
+   // Normalization transformation, initialisation
+   fMin_1[0][0] = 1262.8170166;
+   fMax_1[0][0] = 25870.0039062;
+   fMin_1[1][0] = 1367.57849121;
+   fMax_1[1][0] = 23745.2070312;
+   fMin_1[2][0] = 1262.8170166;
+   fMax_1[2][0] = 25870.0039062;
+   fMin_1[0][1] = -4.7790851593;
+   fMax_1[0][1] = 0.974924445152;
+   fMin_1[1][1] = -0.42424929142;
+   fMax_1[1][1] = 0.970570802689;
+   fMin_1[2][1] = -4.7790851593;
+   fMax_1[2][1] = 0.974924445152;
+   fMin_1[0][2] = -0;
+   fMax_1[0][2] = 0.869569957256;
+   fMin_1[1][2] = 0;
+   fMax_1[1][2] = 0.870256125927;
+   fMin_1[2][2] = -0;
+   fMax_1[2][2] = 0.870256125927;
+   fMin_1[0][3] = 0;
+   fMax_1[0][3] = 0.874010562897;
+   fMin_1[1][3] = 0;
+   fMax_1[1][3] = 0.902063071728;
+   fMin_1[2][3] = 0;
+   fMax_1[2][3] = 0.902063071728;
+   fMin_1[0][4] = 0.278514027596;
+   fMax_1[0][4] = 0.998945295811;
+   fMin_1[1][4] = 0.228343188763;
+   fMax_1[1][4] = 0.97812306881;
+   fMin_1[2][4] = 0.228343188763;
+   fMax_1[2][4] = 0.998945295811;
+   fMin_1[0][5] = 0.546376109123;
+   fMax_1[0][5] = 1.00381207466;
+   fMin_1[1][5] = 0.452791303396;
+   fMax_1[1][5] = 0.99529415369;
+   fMin_1[2][5] = 0.452791303396;
+   fMax_1[2][5] = 1.00381207466;
+   fMin_1[0][6] = 0;
+   fMax_1[0][6] = 1;
+   fMin_1[1][6] = 0;
+   fMax_1[1][6] = 1;
+   fMin_1[2][6] = 0;
+   fMax_1[2][6] = 1;
+   fMin_1[0][7] = 0;
+   fMax_1[0][7] = 0.499058365822;
+   fMin_1[1][7] = 0;
+   fMax_1[1][7] = 0.498812377453;
+   fMin_1[2][7] = 0;
+   fMax_1[2][7] = 0.499058365822;
+   fMin_1[0][8] = 0;
+   fMax_1[0][8] = 1.95758318901;
+   fMin_1[1][8] = 0;
+   fMax_1[1][8] = 1.95918369293;
+   fMin_1[2][8] = 0;
+   fMax_1[2][8] = 1.95918369293;
+   fMin_1[0][9] = 0;
+   fMax_1[0][9] = 1;
+   fMin_1[1][9] = 0;
+   fMax_1[1][9] = 1;
+   fMin_1[2][9] = 0;
+   fMax_1[2][9] = 1;
+   fMin_1[0][10] = 0;
+   fMax_1[0][10] = 8;
+   fMin_1[1][10] = 0;
+   fMax_1[1][10] = 8;
+   fMin_1[2][10] = 0;
+   fMax_1[2][10] = 8;
+   fMin_1[0][11] = 0;
+   fMax_1[0][11] = 4;
+   fMin_1[1][11] = 0;
+   fMax_1[1][11] = 5;
+   fMin_1[2][11] = 0;
+   fMax_1[2][11] = 5;
+   fMin_1[0][12] = 0;
+   fMax_1[0][12] = 3;
+   fMin_1[1][12] = 0;
+   fMax_1[1][12] = 4;
+   fMin_1[2][12] = 0;
+   fMax_1[2][12] = 4;
+   fMin_1[0][13] = 0;
+   fMax_1[0][13] = 3;
+   fMin_1[1][13] = 0;
+   fMax_1[1][13] = 3;
+   fMin_1[2][13] = 0;
+   fMax_1[2][13] = 3;
+}
+
+//_______________________________________________________________________
+inline void ReadMLPOuter::Transform_1( std::vector<double>& iv, int cls) const
+{
+   // Normalization transformation
+   if (cls < 0 || cls > 2) {
+   if (2 > 1 ) cls = 2;
+      else cls = 2;
+   }
+   const int nVar = 14;
+
+   // get indices of used variables
+
+   // define the indices of the variables which are transformed by this transformation
+   std::vector<int> indicesGet;
+   std::vector<int> indicesPut;
+
+   indicesGet.push_back( 0);
+   indicesGet.push_back( 1);
+   indicesGet.push_back( 2);
+   indicesGet.push_back( 3);
+   indicesGet.push_back( 4);
+   indicesGet.push_back( 5);
+   indicesGet.push_back( 6);
+   indicesGet.push_back( 7);
+   indicesGet.push_back( 8);
+   indicesGet.push_back( 9);
+   indicesGet.push_back( 10);
+   indicesGet.push_back( 11);
+   indicesGet.push_back( 12);
+   indicesGet.push_back( 13);
+   indicesPut.push_back( 0);
+   indicesPut.push_back( 1);
+   indicesPut.push_back( 2);
+   indicesPut.push_back( 3);
+   indicesPut.push_back( 4);
+   indicesPut.push_back( 5);
+   indicesPut.push_back( 6);
+   indicesPut.push_back( 7);
+   indicesPut.push_back( 8);
+   indicesPut.push_back( 9);
+   indicesPut.push_back( 10);
+   indicesPut.push_back( 11);
+   indicesPut.push_back( 12);
+   indicesPut.push_back( 13);
+
+   std::vector<double> dv(nVar);
+   for (int ivar=0; ivar<nVar; ivar++) dv[ivar] = iv[indicesGet.at(ivar)];
+   for (int ivar=0;ivar<14;ivar++) {
+      double offset = fMin_1[cls][ivar];
+      double scale  = 1.0/(fMax_1[cls][ivar]-fMin_1[cls][ivar]);
+      iv[indicesPut.at(ivar)] = (dv[ivar]-offset)*scale * 2 - 1;
+   }
+}
+
+//_______________________________________________________________________
+inline void ReadMLPOuter::InitTransform()
+{
+   InitTransform_1();
+}
+
+//_______________________________________________________________________
+inline void ReadMLPOuter::Transform( std::vector<double>& iv, int sigOrBgd ) const
+{
+   Transform_1( iv, sigOrBgd );
+}
diff --git a/CaloFuture/CaloFutureTools/src/Track2CaloFuture.cpp b/CaloFuture/CaloFutureTools/src/Track2CaloFuture.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d8437288326b0428e5815fc31a32830b17ef3146
--- /dev/null
+++ b/CaloFuture/CaloFutureTools/src/Track2CaloFuture.cpp
@@ -0,0 +1,137 @@
+// Include files 
+
+// LHCb
+#include "GaudiKernel/Point3DTypes.h"
+#include "GaudiKernel/Vector3DTypes.h"
+#include "LHCbMath/Line.h"
+#include "LHCbMath/GeomFun.h"
+#include "Event/Track.h"
+#include "Event/CaloCluster.h"
+#include "Event/CaloHypo.h"
+#include "TrackInterfaces/ITrackExtrapolator.h"
+// local
+#include "Track2CaloFuture.h"
+
+//-----------------------------------------------------------------------------
+// Implementation file for class : Track2CaloFuture
+//
+// Simple tool to propagate track to Calo reference planes
+//
+// 2007-06-25 : Olivier Deschamps
+//-----------------------------------------------------------------------------
+
+// Declaration of the Tool Factory
+DECLARE_COMPONENT( Track2CaloFuture )
+
+
+//=============================================================================
+// Standard constructor, initializes variables
+//=============================================================================
+Track2CaloFuture::Track2CaloFuture( const std::string& type,
+                            const std::string& name,
+                            const IInterface* parent )
+  : GaudiTool ( type, name , parent )
+{
+  declareInterface<ITrack2CaloFuture>(this);
+}
+
+//=============================================================================
+StatusCode Track2CaloFuture::initialize(){
+  StatusCode sc = GaudiTool::initialize();
+  if (sc.isFailure()) return Error("Failed to initialize", sc);
+  m_extrapolator = tool<ITrackExtrapolator>( m_extrapolatorType,"Extrapolator",this );
+  return StatusCode::SUCCESS;  
+}
+//=============================================================================
+bool Track2CaloFuture::match(const LHCb::Track* track, std::string det,CaloPlane::Plane plane , double delta, const LHCb::Tr::PID pid ){
+  m_status = setting(track);
+  m_det    = det;
+  m_calo   = getDet<DeCalorimeter>( det );
+  m_state  = caloState(plane, delta, pid);
+  m_cell   = m_calo->Cell( m_state.position() );
+  m_valid  = m_calo->valid( m_cell );
+  if( UNLIKELY( msgLevel(MSG::DEBUG) ) ) 
+    debug() << " Track2CaloFuture setting [" << *track <<","<< det<<"] status : " <<m_status << endmsg;
+  return m_status;
+}
+//=============================================================================
+LHCb::State Track2CaloFuture::caloState(CaloPlane::Plane plane , double delta, const LHCb::Tr::PID pid ){
+
+  LHCb::State state; // empty state
+  if( !m_status ) return state;
+  
+  // get caloPlane
+  ROOT::Math::Plane3D refPlane = m_calo->plane( plane );
+  // propagate state to refPlane
+  LHCb::State calostate( m_track->closestState( refPlane ) );
+  StatusCode sc = m_extrapolator->propagate ( calostate, refPlane , m_tolerance , pid  );
+  if(sc.isFailure())return state;  
+
+  if( 0. == delta)return calostate; 
+  
+  Gaudi::XYZVector dir (calostate.tx(), calostate.ty(), 1.);
+  Gaudi::XYZPoint  point = calostate.position() + delta * dir/dir.R();
+  // extrapolate to the new point
+  sc = m_extrapolator->propagate ( calostate, point.z(), pid );
+  if(sc.isFailure())return state;
+  return calostate;
+}
+//=============================================================================
+bool Track2CaloFuture::setting(const LHCb::Track* track){
+  m_track   = track;
+  return ( NULL == m_track) ? false : true;
+}
+
+
+
+
+LHCb::State Track2CaloFuture::closestState(LHCb::CaloCluster* cluster,const LHCb::Tr::PID pid  ){
+  return closestState( cluster->position(),pid);
+}
+
+LHCb::State Track2CaloFuture::closestState(LHCb::CaloHypo* hypo,const LHCb::Tr::PID pid ){
+  LHCb::State state ;//emtpy state
+  LHCb::CaloPosition* calopos  = hypo->position();
+  if(calopos == NULL)return state;
+  return closestState( *calopos ,pid);
+}
+LHCb::State Track2CaloFuture::closestState(LHCb::CaloPosition calopos,const LHCb::Tr::PID pid ){
+  double x = calopos.parameters()(LHCb::CaloPosition::Index::X);
+  double y = calopos.parameters()(LHCb::CaloPosition::Index::Y);
+  return closestState(x,y, pid);
+}
+LHCb::State Track2CaloFuture::closestState(LHCb::CaloCellID cellID,const LHCb::Tr::PID pid ){
+  Gaudi::XYZPoint point = m_calo->cellCenter( cellID );
+  return closestState(point.X(),point.Y(), pid);
+}
+
+//=============================================================================
+LHCb::State Track2CaloFuture::closestState(double x, double y,const LHCb::Tr::PID pid){
+  LHCb::State state; // empty state
+  if( !m_status ) return state;
+  
+  // get state on Front of Ecal
+  LHCb::State calostate = caloState( CaloPlane::Front);
+  if(calostate.z() == 0 ) return state;
+
+  // get frontPlane
+  ROOT::Math::Plane3D frontPlane = m_calo->plane( CaloPlane::Front );
+
+  // Define calo line (from transversal barycenter) and track line in Ecal
+  typedef Gaudi::Math::Line<Gaudi::XYZPoint,Gaudi::XYZVector> Line;
+  Gaudi::XYZVector normal = frontPlane.Normal();
+  double zEcal = ( -normal.X()*x -normal.Y()*y - frontPlane.HesseDistance() )/normal.Z(); // tilt
+  Gaudi::XYZPoint point( x , y , zEcal );
+  Line cLine( point ,frontPlane.Normal() );
+  Line tLine( calostate.position() , calostate.slopes() );
+
+  // Find points of closest distance between calo Line and track Line
+  Gaudi::XYZPoint cP,tP;
+  Gaudi::Math::closestPoints<Line,Line,Gaudi::XYZPoint>(cLine,tLine,cP,tP);
+
+  // propagate the state the new Z of closest distance
+  StatusCode sc = m_extrapolator->propagate ( calostate, tP.Z() , pid);
+
+  if(sc.isFailure())return state;
+  return calostate;
+}
diff --git a/CaloFuture/CaloFutureTools/src/Track2CaloFuture.h b/CaloFuture/CaloFutureTools/src/Track2CaloFuture.h
new file mode 100644
index 0000000000000000000000000000000000000000..70d8a778bc83f0347a6023336870d687fe03c623
--- /dev/null
+++ b/CaloFuture/CaloFutureTools/src/Track2CaloFuture.h
@@ -0,0 +1,71 @@
+// $Id: Track2CaloFuture.h,v 1.1.1.1 2008-05-08 09:09:02 cattanem Exp $
+#ifndef TRACK2CALOFUTURE_H
+#define TRACK2CALOFUTURE_H 1
+
+// Include files
+// from Gaudi
+#include "GaudiAlg/GaudiTool.h"
+//from LHCb
+#include "CaloFutureInterfaces/ITrack2CaloFuture.h"
+#include "Event/Track.h"
+
+// Forward declarations
+struct ITrackExtrapolator;
+namespace LHCb
+{
+}
+
+/** @class Track2CaloFuture Track2CaloFuture.h
+ *
+ *
+ *  @author Olivier Deschamps
+ *  @date   2006-11-30
+ */
+class Track2CaloFuture : public GaudiTool, virtual public ITrack2CaloFuture {
+public:
+  /// Standard constructor
+  Track2CaloFuture( const std::string& type,
+               const std::string& name,
+               const IInterface* parent);
+
+  StatusCode initialize() override;
+
+  bool match(const  LHCb::Track* track,
+                     std::string det = DeCalorimeterLocation::Ecal,
+                     CaloPlane::Plane plane = CaloPlane::ShowerMax,
+                     double delta = 0.,
+                     const LHCb::Tr::PID pid = LHCb::Tr::PID::Pion()
+                     ) override;
+
+  LHCb::State caloState() override {return m_state;};
+  LHCb::CaloCellID caloCellID() override {return m_cell;};
+  bool isValid() override {return m_valid;};
+
+  // Closest State
+  LHCb::State closestState(LHCb::CaloHypo*    hypo   ,const LHCb::Tr::PID pid = LHCb::Tr::PID::Pion()) override;
+  LHCb::State closestState(LHCb::CaloCluster* cluster,const LHCb::Tr::PID pid = LHCb::Tr::PID::Pion()) override;
+  LHCb::State closestState(LHCb::CaloPosition calopos,const LHCb::Tr::PID pid = LHCb::Tr::PID::Pion()) override;
+  LHCb::State closestState(LHCb::CaloCellID   cellID ,const LHCb::Tr::PID pid = LHCb::Tr::PID::Pion()) override;
+  const LHCb::Track* track() override {return m_track;};
+
+
+
+protected:
+  LHCb::State closestState(double x, double y,const LHCb::Tr::PID pid = LHCb::Tr::PID::Pion());
+  LHCb::State caloState(CaloPlane::Plane plane= CaloPlane::ShowerMax ,
+                        double delta =0 ,
+                        const LHCb::Tr::PID pid = LHCb::Tr::PID::Pion() );
+  bool setting (const  LHCb::Track* track);
+  bool                    m_status = false;
+  const LHCb::Track*      m_track = nullptr;
+  LHCb::State             m_state;
+  DeCalorimeter*          m_calo = nullptr;
+  std::string             m_det;
+private:
+  ITrackExtrapolator*  m_extrapolator = nullptr;
+  Gaudi::Property<std::string> m_extrapolatorType {this, "ExtrapolatorType", "TrackRungeKuttaExtrapolator"};
+  Gaudi::Property<float> m_tolerance {this, "Tolerance", 0.01};
+  LHCb::CaloCellID        m_cell;
+  bool                    m_valid = false;
+};
+#endif // TRACK2CALOFUTURE_H
diff --git a/Rec/GlobalReco/CMakeLists.txt b/Rec/GlobalReco/CMakeLists.txt
index 2c0dad2c47f5b604c747ee3b602ed30534d2f32c..b71c14edbd8eef03fde596b051c14edd3b076ddb 100644
--- a/Rec/GlobalReco/CMakeLists.txt
+++ b/Rec/GlobalReco/CMakeLists.txt
@@ -5,6 +5,8 @@ gaudi_subdir(GlobalReco v6r55)
 
 gaudi_depends_on_subdirs(Calo/CaloInterfaces
                          Calo/CaloUtils
+                         CaloFuture/CaloFutureInterfaces
+                         CaloFuture/CaloFutureUtils
                          Det/CaloDet
                          Event/RecEvent
                          GaudiAlg
@@ -19,7 +21,7 @@ include_directories(SYSTEM ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS})
 gaudi_add_module(GlobalReco
                  src/*.cpp
                  INCLUDE_DIRS Tr/TrackInterfaces
-                 LINK_LIBRARIES CaloUtils CaloDetLib RecEvent GaudiAlgLib RelationsLib)
+                 LINK_LIBRARIES CaloUtils CaloFutureUtils CaloDetLib RecEvent GaudiAlgLib RelationsLib)
 
 gaudi_install_python_modules()
 
diff --git a/Rec/GlobalReco/python/GlobalReco/Configuration.py b/Rec/GlobalReco/python/GlobalReco/Configuration.py
index 9993bda2fcacb0c668ac6233c7f250de6186417f..e930556580c80692339b4855361c79259d4d56e1 100644
--- a/Rec/GlobalReco/python/GlobalReco/Configuration.py
+++ b/Rec/GlobalReco/python/GlobalReco/Configuration.py
@@ -68,6 +68,11 @@ class GlobalRecoConf(LHCbConfigurableUser):
                                     ChargedProtoParticleAddHcalInfo,
                                     ChargedProtoParticleAddPrsInfo,
                                     ChargedProtoParticleAddSpdInfo,
+                                    FutureChargedProtoParticleAddEcalInfo,
+                                    FutureChargedProtoParticleAddBremInfo,
+                                    FutureChargedProtoParticleAddHcalInfo,
+                                    FutureChargedProtoParticleAddPrsInfo,
+                                    FutureChargedProtoParticleAddSpdInfo,
                                     ChargedProtoParticleAddVeloInfo,
                                     ChargedProtoCombineDLLsAlg,
                                     DelegatingTrackSelector )
@@ -83,9 +88,14 @@ class GlobalRecoConf(LHCbConfigurableUser):
         # Add PID information
         rich = ChargedProtoParticleAddRichInfo("ChargedProtoPAddRich")
         muon = ChargedProtoParticleAddMuonInfo("ChargedProtoPAddMuon")
-        ecal = ChargedProtoParticleAddEcalInfo("ChargedProtoPAddEcal")
-        brem = ChargedProtoParticleAddBremInfo("ChargedProtoPAddBrem")
-        hcal = ChargedProtoParticleAddHcalInfo("ChargedProtoPAddHcal")
+        if self.getProp("NoSpdPrs") :
+            ecal = FutureChargedProtoParticleAddEcalInfo("FutureChargedProtoPAddEcal")
+            brem = FutureChargedProtoParticleAddBremInfo("FutureChargedProtoPAddBrem")
+            hcal = FutureChargedProtoParticleAddHcalInfo("FutureChargedProtoPAddHcal")
+        else:
+            ecal = ChargedProtoParticleAddEcalInfo("ChargedProtoPAddEcal")
+            brem = ChargedProtoParticleAddBremInfo("ChargedProtoPAddBrem")
+            hcal = ChargedProtoParticleAddHcalInfo("ChargedProtoPAddHcal")
         velo = ChargedProtoParticleAddVeloInfo("ChargedProtoPAddVeloDEDX")
         # Fill the Combined DLL information in the charged protoparticles
         combine = ChargedProtoCombineDLLsAlg("ChargedProtoPCombDLLs")
@@ -98,11 +108,15 @@ class GlobalRecoConf(LHCbConfigurableUser):
         cseq.Members += [ velo, rich,muon,combine ]
         
         # Neutrals
-        from Configurables import NeutralProtoPAlg
+        from Configurables import NeutralProtoPAlg, FutureNeutralProtoPAlg
         nseq = GaudiSequencer("NeutralProtoParticles")
         seq.Members += [nseq]
-        neutral = NeutralProtoPAlg("NeutralProtoPMaker")
-        nseq.Members += [ neutral ]
+        if self.getProp("NoSpdPrs") :
+            neutral = FutureNeutralProtoPAlg("FutureNeutralProtoPMaker")
+            nseq.Members += [ neutral ]
+        else:
+            neutral = NeutralProtoPAlg("NeutralProtoPMaker")
+            nseq.Members += [ neutral ]
         
         # Set output levels
         if self.isPropertySet("OutputLevel"):
diff --git a/Rec/GlobalReco/src/FutureChargedProtoParticleAddBremInfo.cpp b/Rec/GlobalReco/src/FutureChargedProtoParticleAddBremInfo.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7cfff2e7895702107c84fac989e054b6ea372dbf
--- /dev/null
+++ b/Rec/GlobalReco/src/FutureChargedProtoParticleAddBremInfo.cpp
@@ -0,0 +1,166 @@
+
+//-----------------------------------------------------------------------------
+/** @file ChargedProtoParticleAddBremInfo.cpp
+ *
+ * Implementation file for algorithm ChargedProtoParticleAddBremInfo
+ *
+ * @author Chris Jones   Christopher.Rob.Jones@cern.ch
+ * @date 28/08/2009
+ */
+//-----------------------------------------------------------------------------
+
+// local
+#include "FutureChargedProtoParticleAddBremInfo.h"
+
+//-----------------------------------------------------------------------------
+
+// Declaration of the Algorithm Factory
+DECLARE_COMPONENT( FutureChargedProtoParticleAddBremInfo )
+
+//=============================================================================
+// Standard constructor, initializes variables
+//=============================================================================
+FutureChargedProtoParticleAddBremInfo::
+FutureChargedProtoParticleAddBremInfo( const std::string& name,
+                                 ISvcLocator* pSvcLocator)
+  : FutureChargedProtoParticleCALOFUTUREBaseAlg ( name , pSvcLocator )
+{
+  // default locations from context()
+
+  using namespace LHCb::CaloFuture2Track;
+  using namespace LHCb::CaloFutureIdLocation;
+  using namespace LHCb::CaloFutureAlgUtils;
+
+  m_inBremPath      = PathFromContext( context() , InBrem      );
+  m_bremMatchPath   = PathFromContext( context() , BremMatch   );
+  m_bremChi2Path    = PathFromContext( context() , BremChi2    );
+  m_bremPIDePath    = PathFromContext( context() , BremPIDe    );
+  m_protoPath       = LHCb::ProtoParticleLocation::Charged ;
+
+  declareProperty("InputInBremLocation"        , m_inBremPath       );
+  declareProperty("InputBremMatchLocation"     , m_bremMatchPath    );
+  declareProperty("InputBremChi2Location"      , m_bremChi2Path     );
+  declareProperty("InputBremPIDeLocation"      , m_bremPIDePath     );
+  declareProperty("ProtoParticleLocation"      , m_protoPath        );
+
+}
+
+//=============================================================================
+// Main execution
+//=============================================================================
+StatusCode FutureChargedProtoParticleAddBremInfo::execute()
+{
+  // Load the Brem data
+  const auto sc = getBremData();
+  if ( !sc )
+  {
+    return Warning( "No BREM data -> ProtoParticles will not be changed.", StatusCode::SUCCESS );
+  }
+
+  // ProtoParticle container
+  auto * protos = getIfExists<LHCb::ProtoParticles>(m_protoPath);
+  if ( !protos )
+  {
+    if( msgLevel(MSG::DEBUG) ) debug() << "No existing ProtoParticle container at "
+                                       <<  m_protoPath<<" thus do nothing."<<endmsg;
+    return StatusCode::SUCCESS;
+  }
+
+  // Loop over proto particles and fill brem info
+  for ( auto * proto : *protos ) { addBrem(proto); }
+
+  if ( counterStat->isQuiet() )
+    counter("BremPIDs("+context()+") ==> " + m_protoPath )+= protos->size();
+
+  return StatusCode::SUCCESS;
+}
+
+//=============================================================================
+
+//=============================================================================
+// Loads the Calo Brem data
+//=============================================================================
+bool FutureChargedProtoParticleAddBremInfo::getBremData()
+{
+  const bool sc1 = loadCaloTable(m_InBremTable  , m_inBremPath);
+  const bool sc2 = loadCaloTable(m_bremTrTable  , m_bremMatchPath);
+  const bool sc3 = loadCaloTable(m_BremChi2Table, m_bremChi2Path);
+  const bool sc4 = loadCaloTable(m_dlleBremTable, m_bremPIDePath);
+
+  const bool sc  = sc1 && sc2 && sc3 && sc4;
+  if ( sc && msgLevel(MSG::DEBUG) ) debug() << "BREM PID SUCCESSFULLY LOADED" << endmsg;
+
+  return sc;
+}
+
+//=============================================================================
+// Add Calo Brem info to the protoparticle
+//=============================================================================
+bool FutureChargedProtoParticleAddBremInfo::addBrem( LHCb::ProtoParticle * proto ) const
+{
+  // First remove existing BREM info
+  proto->removeCaloBremInfo();
+
+  // Add new info
+
+  bool hasBremPID = false;
+
+  const auto aRange = m_InBremTable -> relations ( proto->track() ) ;
+  if ( !aRange.empty() )
+  {
+    hasBremPID = aRange.front().to();
+    if ( hasBremPID )
+    {
+      if ( msgLevel(MSG::VERBOSE) ) verbose() << " -> The Brem. extrapolated line is in Ecal acceptance"  << endmsg;
+      proto->addInfo(LHCb::ProtoParticle::additionalInfo::InAccBrem , true );
+
+      // Get the highest weight associated brem. CaloHypo (3D matching)
+      const auto hRange = m_bremTrTable->inverse()->relations ( proto->track() ) ;
+      if ( !hRange.empty() )
+      {
+        const auto * hypo = hRange.front().to();
+        proto->addToCalo ( hypo );
+        using namespace CaloFutureDataType;
+        proto->addInfo(LHCb::ProtoParticle::additionalInfo::CaloNeutralSpd, m_estimator->data(hypo, HypoSpdM ) > 0 );
+        proto->addInfo(LHCb::ProtoParticle::additionalInfo::CaloNeutralPrs, m_estimator->data(hypo, HypoPrsE )  );
+        proto->addInfo(LHCb::ProtoParticle::additionalInfo::CaloNeutralEcal, m_estimator->data(hypo, ClusterE )  );
+        proto->addInfo(LHCb::ProtoParticle::additionalInfo::CaloBremMatch , m_estimator->data(hypo, BremMatch ) );
+        proto->addInfo(LHCb::ProtoParticle::additionalInfo::CaloNeutralID ,  m_estimator->data(hypo, CellID )  );
+        proto->addInfo(LHCb::ProtoParticle::additionalInfo::CaloNeutralHcal2Ecal  ,  m_estimator->data(hypo, Hcal2Ecal )  );
+        proto->addInfo(LHCb::ProtoParticle::additionalInfo::CaloNeutralE49        ,  m_estimator->data(hypo, E49 )  );
+      }
+
+      // Get the BremChi2 (intermediate) estimator
+      {
+        const auto vRange = m_BremChi2Table -> relations ( proto->track() ) ;
+        if ( !vRange.empty() ) { proto->addInfo(LHCb::ProtoParticle::additionalInfo::CaloBremChi2,  vRange.front().to() ); }
+      }
+
+      // Get the Brem DLL(e)
+      {
+        const auto vRange = m_dlleBremTable -> relations ( proto->track() ) ;
+        if ( !vRange.empty() ) { proto->addInfo(LHCb::ProtoParticle::additionalInfo::BremPIDe , vRange.front().to() ); }
+      }
+
+      if ( msgLevel(MSG::VERBOSE) )
+        verbose() << " -> BremStrahlung PID : "
+                  << " Chi2-Brem  =" <<  proto->info(LHCb::ProtoParticle::additionalInfo::CaloBremMatch, -999.)
+                  << " BremChi2   =" <<  proto->info(LHCb::ProtoParticle::additionalInfo::CaloBremChi2, -999.)
+                  << " Dlle (Brem) =" <<  proto->info(LHCb::ProtoParticle::additionalInfo::BremPIDe, -999.)
+                  << " Spd Digits " <<  proto->info(LHCb::ProtoParticle::additionalInfo::CaloNeutralSpd, 0.)
+                  << " Prs Digits " <<  proto->info(LHCb::ProtoParticle::additionalInfo::CaloNeutralPrs, 0.)
+                  << " Ecal Cluster " <<  proto->info(LHCb::ProtoParticle::additionalInfo::CaloNeutralEcal, 0.)
+                  << endmsg;
+    }
+    else
+    {
+      if ( msgLevel(MSG::VERBOSE) ) verbose() << " -> The Brem. extrapolated line is NOT in Ecal acceptance"  << endmsg;
+    }
+  }
+  else
+  {
+    if ( msgLevel(MSG::VERBOSE) ) verbose() << " ->  No entry for that track in the Brem acceptance table"  << endmsg;
+  }
+
+  return hasBremPID;
+}
diff --git a/Rec/GlobalReco/src/FutureChargedProtoParticleAddBremInfo.h b/Rec/GlobalReco/src/FutureChargedProtoParticleAddBremInfo.h
new file mode 100644
index 0000000000000000000000000000000000000000..f42b9e31ee6bcaace460e460759e3f4bc6332338
--- /dev/null
+++ b/Rec/GlobalReco/src/FutureChargedProtoParticleAddBremInfo.h
@@ -0,0 +1,60 @@
+
+//-----------------------------------------------------------------------------
+/** @file ChargedProtoParticleAddBremInfo.h
+ *
+ * Header file for algorithm ChargedProtoParticleAddBremInfo
+ *
+ * @author Chris Jones   Christopher.Rob.Jones@cern.ch
+ * @date 29/03/2006
+ */
+//-----------------------------------------------------------------------------
+
+#ifndef GLOBALRECO_FutureChargedProtoParticleAddBremInfo_H
+#define GLOBALRECO_FutureChargedProtoParticleAddBremInfo_H 1
+
+// from Gaudi
+#include "FutureChargedProtoParticleCALOFUTUREBaseAlg.h"
+
+/** @class FutureChargedProtoParticleAddBremInfo FutureChargedProtoParticleAddBremInfo.h
+ *
+ *  Updates the CALO 'BREM' information stored in the ProtoParticles
+ *
+ *  @author Chris Jones   Christopher.Rob.Jones@cern.ch
+ *  @date 28/08/2009
+ */
+
+class FutureChargedProtoParticleAddBremInfo final : public FutureChargedProtoParticleCALOFUTUREBaseAlg
+{
+
+public:
+
+  /// Standard constructor
+  FutureChargedProtoParticleAddBremInfo( const std::string& name, ISvcLocator* pSvcLocator );
+
+  StatusCode execute() override; ///< Algorithm execution
+
+private:
+
+  /// Load the Calo Brem tables
+  bool getBremData();
+
+  /// Add Calo Brem information to the given ProtoParticle
+  bool addBrem( LHCb::ProtoParticle * proto ) const;
+
+private:
+
+  std::string m_protoPath; ///< Location of the ProtoParticles in the TES
+
+  std::string m_inBremPath ;
+  std::string m_bremMatchPath ;
+  std::string m_bremChi2Path ;
+  std::string m_bremPIDePath ;
+
+  const LHCb::CaloFuture2Track::ITrAccTable*  m_InBremTable = nullptr;
+  const LHCb::CaloFuture2Track::IHypoTrTable2D* m_bremTrTable = nullptr;
+  const LHCb::CaloFuture2Track::ITrEvalTable*  m_BremChi2Table = nullptr;
+  const LHCb::CaloFuture2Track::ITrEvalTable* m_dlleBremTable = nullptr;
+
+};
+
+#endif // GLOBALRECO_FutureChargedProtoParticleAddBremInfo_H
diff --git a/Rec/GlobalReco/src/FutureChargedProtoParticleAddEcalInfo.cpp b/Rec/GlobalReco/src/FutureChargedProtoParticleAddEcalInfo.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1ffe4ccc7bcc09e9816bd5d49eb05da298c0b0c0
--- /dev/null
+++ b/Rec/GlobalReco/src/FutureChargedProtoParticleAddEcalInfo.cpp
@@ -0,0 +1,225 @@
+
+//-----------------------------------------------------------------------------
+/** @file FutureChargedProtoParticleAddEcalInfo.cpp
+ *
+ * Implementation file for algorithm FutureChargedProtoParticleAddEcalInfo
+ *
+ * @author Chris Jones   Christopher.Rob.Jones@cern.ch
+ * @date 28/08/2009
+ */
+//-----------------------------------------------------------------------------
+
+// local
+#include "FutureChargedProtoParticleAddEcalInfo.h"
+
+//-----------------------------------------------------------------------------
+
+// Declaration of the Algorithm Factory
+DECLARE_COMPONENT( FutureChargedProtoParticleAddEcalInfo )
+
+//=============================================================================
+// Standard constructor, initializes variables
+//=============================================================================
+FutureChargedProtoParticleAddEcalInfo::
+FutureChargedProtoParticleAddEcalInfo( const std::string& name,
+                                 ISvcLocator* pSvcLocator)
+: FutureChargedProtoParticleCALOFUTUREBaseAlg ( name , pSvcLocator )
+{
+  // default locations from context()
+
+  using namespace LHCb::CaloFuture2Track;
+  using namespace LHCb::CaloFutureIdLocation;
+  m_protoPath         =  LHCb::ProtoParticleLocation::Charged ;
+  m_inEcalPath        =  LHCb::CaloFutureAlgUtils::PathFromContext( context() , InEcal        );
+  m_electronMatchPath =  LHCb::CaloFutureAlgUtils::PathFromContext( context() , ElectronMatch );
+  m_clusterMatchPath  =  LHCb::CaloFutureAlgUtils::PathFromContext( context() , ClusterMatch  );
+  m_ecalChi2Path      =  LHCb::CaloFutureAlgUtils::PathFromContext( context() , EcalChi2      );
+  m_ecalEPath         =  LHCb::CaloFutureAlgUtils::PathFromContext( context() , EcalE         );
+  m_clusterChi2Path   =  LHCb::CaloFutureAlgUtils::PathFromContext( context() , ClusChi2      );
+  m_ecalPIDePath      =  LHCb::CaloFutureAlgUtils::PathFromContext( context() , EcalPIDe      );
+  m_ecalPIDmuPath     =  LHCb::CaloFutureAlgUtils::PathFromContext( context() , EcalPIDmu     );
+  declareProperty("InputInEcalLocation"        , m_inEcalPath         );
+  declareProperty("InputElectronMatchLocation" , m_electronMatchPath  );
+  declareProperty("InputClusterMatchLocation"  , m_clusterMatchPath   );
+  declareProperty("InputEcalChi2Location"      , m_ecalChi2Path       );
+  declareProperty("InputEcalELocation"         , m_ecalEPath          );
+  declareProperty("InputClusterChi2Location"   , m_clusterChi2Path    );
+  declareProperty("InputEcalPIDeLocation"      , m_ecalPIDePath       );
+  declareProperty("InputEcalPIDmuLocation"     , m_ecalPIDmuPath      );
+
+  // ProtoParticles
+  declareProperty( "ProtoParticleLocation", m_protoPath );
+}
+
+//=============================================================================
+// Initialization
+//=============================================================================
+StatusCode FutureChargedProtoParticleAddEcalInfo::initialize()
+{
+  const StatusCode sc = FutureChargedProtoParticleCALOFUTUREBaseAlg::initialize();
+  if ( sc.isFailure() ) return sc;
+
+  // CaloElectron tool
+  //m_electron = tool<ICaloElectron>("CaloElectron","CaloElectron",this);
+  m_electron = tool<ICaloFutureElectron>("CaloFutureElectron","CaloFutureElectron",this);
+
+  return sc;
+}
+
+//=============================================================================
+// Main execution
+//=============================================================================
+StatusCode FutureChargedProtoParticleAddEcalInfo::execute()
+{
+  // Load the ECAL data
+  const bool sc = getEcalData();
+  if ( !sc )
+  {
+    return Warning( "No ECAL data -> ProtoParticles will not be changed.", StatusCode::SUCCESS );
+  }
+
+  // ProtoParticle container
+  auto * protos = getIfExists<LHCb::ProtoParticles>(m_protoPath);
+  if ( !protos )
+  {
+    if( msgLevel(MSG::DEBUG) ) debug() << "No existing ProtoParticle container at "
+                                       <<  m_protoPath<<" thus do nothing."<<endmsg;
+    return StatusCode::SUCCESS;
+  }
+
+  // Loop over proto particles and update ECAL info
+  for ( auto * proto : *protos ) { addEcal(proto); }
+
+  if ( counterStat->isQuiet() )
+    counter("EcalPIDs("+context()+") ==> " + m_protoPath )+= protos->size();
+
+  return StatusCode::SUCCESS;
+}
+
+//=============================================================================
+
+//=============================================================================
+// Loads the Calo Ecal data
+//=============================================================================
+bool FutureChargedProtoParticleAddEcalInfo::getEcalData()
+{
+  const bool sc1 = loadCaloTable(m_InEcalTable  , m_inEcalPath       );
+  const bool sc2 = loadCaloTable(m_elecTrTable  , m_electronMatchPath);
+  const bool sc3 = loadCaloTable(m_clusTrTable  , m_clusterMatchPath );
+  const bool sc4 = loadCaloTable(m_EcalChi2Table, m_ecalChi2Path);
+  const bool sc5 = loadCaloTable(m_EcalETable   , m_ecalEPath);
+  const bool sc6 = loadCaloTable(m_ClusChi2Table, m_clusterChi2Path);
+  const bool sc7 = loadCaloTable(m_dlleEcalTable, m_ecalPIDePath);
+  const bool sc8 = loadCaloTable(m_dllmuEcalTable,m_ecalPIDmuPath);
+
+  const bool sc  = sc1 && sc2 && sc3 && sc4 && sc5 && sc6 && sc7 && sc8;
+  if ( sc && msgLevel(MSG::DEBUG) ) debug() << "Ecal PID SUCCESSFULLY LOADED" << endmsg;
+
+  return sc;
+}
+
+//=============================================================================
+// Add Calo Ecal info to the protoparticle
+//=============================================================================
+bool FutureChargedProtoParticleAddEcalInfo::addEcal( LHCb::ProtoParticle * proto ) const
+{
+  // First remove existing ECAL info
+  proto->removeCaloEcalInfo();
+
+  // Now add new ECAL info
+
+  bool hasEcalPID = false;
+
+  const auto aRange = m_InEcalTable -> relations ( proto->track() ) ;
+  if ( !aRange.empty() )
+  {
+    hasEcalPID = aRange.front().to();
+
+    if( hasEcalPID )
+    {
+      if ( msgLevel(MSG::VERBOSE) ) verbose() << " -> The track is in Ecal acceptance"  << endmsg;
+      proto->addInfo(LHCb::ProtoParticle::additionalInfo::InAccEcal, true );
+
+      // Get the highest weight associated electron CaloHypo (3D matching)
+      const auto hRange = m_elecTrTable->inverse()->relations ( proto->track() ) ;
+      if ( !hRange.empty() ){
+
+        const auto * hypo = hRange.front().to();
+        proto->addToCalo ( hypo );
+        // CaloElectron->caloTrajectory must be after addToCalo
+        if ( electronTool()->set(proto) ){
+          proto->addInfo( LHCb::ProtoParticle::additionalInfo::CaloTrajectoryL, electronTool()->caloTrajectoryL(CaloPlane::ShowerMax,"hypo") );
+          proto->addInfo( LHCb::ProtoParticle::additionalInfo::CaloEoverP, electronTool()->eOverP() );
+        }
+
+        using namespace CaloFutureDataType;
+        proto->addInfo(LHCb::ProtoParticle::additionalInfo::CaloChargedSpd,  m_estimator->data(hypo, HypoSpdM ) > 0 );
+        proto->addInfo(LHCb::ProtoParticle::additionalInfo::CaloChargedPrs,  m_estimator->data(hypo, HypoPrsE )   );
+        proto->addInfo(LHCb::ProtoParticle::additionalInfo::CaloChargedEcal, m_estimator->data(hypo, ClusterE )  );
+        proto->addInfo(LHCb::ProtoParticle::additionalInfo::CaloChargedID       ,  m_estimator->data(hypo, CellID )  );
+        proto->addInfo(LHCb::ProtoParticle::additionalInfo::CaloElectronMatch , hRange.front().weight() );
+      }
+
+      // Get the highest weight associated CaloCluster (2D matching)
+      const auto cRange = m_clusTrTable -> inverse() ->relations ( proto->track() ) ;
+      if ( !cRange.empty() ) { proto->addInfo(LHCb::ProtoParticle::additionalInfo::CaloTrMatch , cRange.front().weight() ); }
+
+      // Get EcalE (intermediate) estimator
+      {
+        const auto vRange = m_EcalETable -> relations ( proto->track() ) ;
+        if ( !vRange.empty() ) { proto->addInfo(LHCb::ProtoParticle::additionalInfo::CaloEcalE ,  vRange.front().to() ); }
+      }
+
+      // Get EcalChi2 (intermediate) estimator
+      {
+        const auto vRange = m_EcalChi2Table -> relations ( proto->track() ) ;
+        if ( !vRange.empty() ) { proto->addInfo(LHCb::ProtoParticle::additionalInfo::CaloEcalChi2,  vRange.front().to() ); }
+      }
+
+      // Get ClusChi2 (intermediate) estimator
+      {
+        const auto vRange = m_ClusChi2Table -> relations ( proto->track() ) ;
+        if ( !vRange.empty() ) { proto->addInfo(LHCb::ProtoParticle::additionalInfo::CaloClusChi2,  vRange.front().to() ); }
+      }
+
+      // Get Ecal DLL(e)
+      {
+        const auto vRange = m_dlleEcalTable -> relations ( proto->track() ) ;
+        if ( !vRange.empty() ) { proto->addInfo(LHCb::ProtoParticle::additionalInfo::EcalPIDe , vRange.front().to() ); }
+      }
+
+      // Get Ecal DLL(mu)
+      {
+        const auto vRange = m_dllmuEcalTable -> relations ( proto->track() ) ;
+        if ( !vRange.empty() ) { proto->addInfo(LHCb::ProtoParticle::additionalInfo::EcalPIDmu , vRange.front().to() ); }
+      }
+
+      if ( msgLevel(MSG::VERBOSE) )
+        verbose() << " -> Ecal PID : "
+                  << " Chi2-3D    =" <<  proto->info(LHCb::ProtoParticle::additionalInfo::CaloElectronMatch, -999.)
+                  << " Chi2-2D    =" <<  proto->info(LHCb::ProtoParticle::additionalInfo::CaloTrMatch, -999.)
+                  << " EcalE      =" <<  proto->info(LHCb::ProtoParticle::additionalInfo::CaloEcalE , -999.)
+                  << " ClusChi2   =" <<  proto->info(LHCb::ProtoParticle::additionalInfo::CaloClusChi2, -999.)
+                  << " EcalChi2   =" <<  proto->info(LHCb::ProtoParticle::additionalInfo::CaloEcalChi2, -999.)
+                  << " Dlle (Ecal) =" <<  proto->info(LHCb::ProtoParticle::additionalInfo::EcalPIDe, -999.)
+                  << " Dllmu (Ecal) =" <<  proto->info(LHCb::ProtoParticle::additionalInfo::EcalPIDmu, -999.)
+                  << " Spd Digits " <<  proto->info(LHCb::ProtoParticle::additionalInfo::CaloChargedSpd, 0.)
+                  << " Prs Digits " <<  proto->info(LHCb::ProtoParticle::additionalInfo::CaloChargedPrs, 0.)
+                  << " Spd Digits " <<  proto->info(LHCb::ProtoParticle::additionalInfo::CaloChargedSpd, 0.)
+                  << " Ecal Cluster " <<  proto->info(LHCb::ProtoParticle::additionalInfo::CaloChargedEcal, 0.)
+                  << " TrajectoryL " <<  proto->info(LHCb::ProtoParticle::additionalInfo::CaloTrajectoryL, 0.)
+                  << endmsg;
+
+    }
+    else
+    {
+      if ( msgLevel(MSG::VERBOSE) )verbose() << " -> The track is NOT in Ecal acceptance"  << endmsg;
+    }
+  }
+  else
+  {
+    if ( msgLevel(MSG::VERBOSE) )verbose() << " -> No entry for that track in the Ecal acceptance table "  << endmsg;
+  }
+
+  return hasEcalPID;
+}
diff --git a/Rec/GlobalReco/src/FutureChargedProtoParticleAddEcalInfo.h b/Rec/GlobalReco/src/FutureChargedProtoParticleAddEcalInfo.h
new file mode 100644
index 0000000000000000000000000000000000000000..3ac9e984c47851da822023b62d7332d8d7dd99ec
--- /dev/null
+++ b/Rec/GlobalReco/src/FutureChargedProtoParticleAddEcalInfo.h
@@ -0,0 +1,74 @@
+//-----------------------------------------------------------------------------
+/** @file FutureChargedProtoParticleAddEcalInfo.h
+ *
+ * Header file for algorithm FutureChargedProtoParticleAddEcalInfo
+ *
+ * @author Chris Jones   Christopher.Rob.Jones@cern.ch
+ * @date 29/03/2006
+ */
+//-----------------------------------------------------------------------------
+
+#ifndef GLOBALRECO_FutureChargedProtoParticleAddEcalInfo_H
+#define GLOBALRECO_FutureChargedProtoParticleAddEcalInfo_H 1
+
+#include "FutureChargedProtoParticleCALOFUTUREBaseAlg.h"
+#include "CaloFutureUtils/ICaloFutureElectron.h"
+
+/** @class FutureChargedProtoParticleAddEcalInfo FutureChargedProtoParticleAddEcalInfo.h
+ *
+ *  Updates the ECAL information stored in the ProtoParticles
+ *
+ *  @author Chris Jones   Christopher.Rob.Jones@cern.ch
+ *  @date 28/08/2009
+ */
+
+class FutureChargedProtoParticleAddEcalInfo final : public FutureChargedProtoParticleCALOFUTUREBaseAlg
+{
+
+public:
+
+  /// Standard constructor
+  FutureChargedProtoParticleAddEcalInfo( const std::string& name, ISvcLocator* pSvcLocator );
+
+  StatusCode initialize() override;    ///< Algorithm initialization
+  StatusCode execute() override;       ///< Algorithm execution
+
+private:
+
+  /// Load the Calo Ecal tables
+  bool getEcalData();
+
+  /// Add Calo Ecal information to the given ProtoParticle
+  bool addEcal( LHCb::ProtoParticle * proto ) const;
+
+  /// Access the electron tool
+  inline ICaloFutureElectron * electronTool() const noexcept { return m_electron; }
+
+private:
+
+  std::string m_protoPath; ///< Location of the ProtoParticles in the TES
+
+  std::string m_inEcalPath ;
+  std::string m_electronMatchPath ;
+  std::string m_clusterMatchPath ;
+  std::string m_ecalChi2Path ;
+  std::string m_ecalEPath ;
+  std::string m_clusterChi2Path ;
+  std::string m_ecalPIDePath ;
+  std::string m_ecalPIDmuPath ;
+
+  const LHCb::CaloFuture2Track::ITrAccTable*  m_InEcalTable     = nullptr;
+  const LHCb::CaloFuture2Track::IHypoTrTable2D* m_elecTrTable   = nullptr;
+  const LHCb::CaloFuture2Track::IClusTrTable2D* m_clusTrTable   = nullptr;
+  const LHCb::CaloFuture2Track::ITrEvalTable*  m_EcalChi2Table  = nullptr;
+  const LHCb::CaloFuture2Track::ITrEvalTable*  m_EcalETable     = nullptr;
+  const LHCb::CaloFuture2Track::ITrEvalTable*  m_ClusChi2Table  = nullptr;
+  const LHCb::CaloFuture2Track::ITrEvalTable* m_dlleEcalTable   = nullptr;
+  const LHCb::CaloFuture2Track::ITrEvalTable* m_dllmuEcalTable  = nullptr;
+
+  /// CaloElectron tool
+  ICaloFutureElectron * m_electron = nullptr;
+
+};
+
+#endif // GLOBALRECO_FutureChargedProtoParticleAddEcalInfo_H
diff --git a/Rec/GlobalReco/src/FutureChargedProtoParticleAddHcalInfo.cpp b/Rec/GlobalReco/src/FutureChargedProtoParticleAddHcalInfo.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2bfb3f2b34423ed61a3e5d8aade746926c49a3d0
--- /dev/null
+++ b/Rec/GlobalReco/src/FutureChargedProtoParticleAddHcalInfo.cpp
@@ -0,0 +1,149 @@
+
+//-----------------------------------------------------------------------------
+/** @file FutureChargedProtoParticleAddHcalInfo.cpp
+ *
+ * Implementation file for algorithm FutureChargedProtoParticleAddHcalInfo
+ *
+ * @author Chris Jones   Christopher.Rob.Jones@cern.ch
+ * @date 28/08/2009
+ */
+//-----------------------------------------------------------------------------
+
+// local
+#include "FutureChargedProtoParticleAddHcalInfo.h"
+
+//-----------------------------------------------------------------------------
+
+// Declaration of the Algorithm Factory
+DECLARE_COMPONENT( FutureChargedProtoParticleAddHcalInfo )
+
+//=============================================================================
+// Standard constructor, initializes variables
+//=============================================================================
+FutureChargedProtoParticleAddHcalInfo::
+FutureChargedProtoParticleAddHcalInfo( const std::string& name,
+                                 ISvcLocator* pSvcLocator)
+  : FutureChargedProtoParticleCALOFUTUREBaseAlg ( name , pSvcLocator )
+{
+  // default locations from context()
+
+  using namespace LHCb::CaloFuture2Track;
+  using namespace LHCb::CaloFutureIdLocation;
+  using namespace LHCb::CaloFutureAlgUtils;
+
+  m_protoPath         = LHCb::ProtoParticleLocation::Charged ;
+  m_inHcalPath        = PathFromContext( context() , InHcal              );
+  m_hcalEPath         = PathFromContext( context() , HcalE               );
+  m_hcalPIDePath      = PathFromContext( context() , HcalPIDe            );
+  m_hcalPIDmuPath     = PathFromContext( context() , HcalPIDmu           );
+
+  declareProperty("ProtoParticleLocation"      , m_protoPath      );
+  declareProperty("InputInHcalLocation"        , m_inHcalPath     );
+  declareProperty("InputHcalELocation"         , m_hcalEPath      );
+  declareProperty("InputHcalPIDeLocation"      , m_hcalPIDePath   );
+  declareProperty("InputHcalPIDmuLocation"     , m_hcalPIDmuPath  );
+}
+
+//=============================================================================
+// Main execution
+//=============================================================================
+StatusCode FutureChargedProtoParticleAddHcalInfo::execute()
+{
+  // Load the HCAL data
+  const bool sc = getHcalData();
+  if ( !sc )
+  {
+    return Warning( "No HCAL data -> ProtoParticles will not be changed.", StatusCode::SUCCESS );
+  }
+
+  // ProtoParticle container
+  auto * protos = getIfExists<LHCb::ProtoParticles>(m_protoPath);
+  if ( !protos )
+  {
+    if( msgLevel(MSG::DEBUG) ) debug() << "No existing ProtoParticle container at "
+                                       <<  m_protoPath<<" thus do nothing."<<endmsg;
+    return StatusCode::SUCCESS;
+  }
+
+  // Loop over proto particles and update HCAL info
+  for ( auto * proto : *protos ) { addHcal(proto); }
+
+  if ( counterStat->isQuiet() )
+    counter("HcalPIDs("+context()+") ==> " + m_protoPath )+= protos->size();
+
+  return StatusCode::SUCCESS;
+}
+
+//=============================================================================
+
+//=============================================================================
+// Loads the Calo Hcal data
+//=============================================================================
+bool FutureChargedProtoParticleAddHcalInfo::getHcalData()
+{
+  const bool sc1 = loadCaloTable(m_InHcalTable   , m_inHcalPath);
+  const bool sc2 = loadCaloTable(m_HcalETable    , m_hcalEPath);
+  const bool sc3 = loadCaloTable(m_dlleHcalTable , m_hcalPIDePath);
+  const bool sc4 = loadCaloTable(m_dllmuHcalTable, m_hcalPIDmuPath);
+  const bool sc  = sc1 && sc2 && sc3 && sc4;
+  if ( sc && msgLevel(MSG::DEBUG) ) debug() << "HCAL PID SUCCESSFULLY LOADED" << endmsg;
+  return sc;
+}
+
+//=============================================================================
+// Add Calo Hcal info to the protoparticle
+//=============================================================================
+bool FutureChargedProtoParticleAddHcalInfo::addHcal( LHCb::ProtoParticle * proto ) const
+{
+  // clear HCAL info
+  proto->removeCaloHcalInfo();
+
+  bool hasHcalPID = false;
+
+  const auto aRange = m_InHcalTable -> relations ( proto->track() ) ;
+  if ( !aRange.empty() )
+  {
+    hasHcalPID = aRange.front().to();
+    if( hasHcalPID )
+    {
+      if ( msgLevel(MSG::VERBOSE) )verbose() << " -> The track is in Hcal acceptance"  << endmsg;
+      proto->addInfo(LHCb::ProtoParticle::additionalInfo::InAccHcal, true );
+
+      // Get the HcalE (intermediate) estimator
+      {
+      const auto vRange = m_HcalETable -> relations ( proto->track() ) ;
+      if ( !vRange.empty() ) { proto->addInfo(LHCb::ProtoParticle::additionalInfo::CaloHcalE,  vRange.front().to() ); }
+      }
+
+      // Get the Hcal DLL(e)
+      {
+        const auto vRange = m_dlleHcalTable -> relations ( proto->track() ) ;
+        if ( !vRange.empty() ) { proto->addInfo(LHCb::ProtoParticle::additionalInfo::HcalPIDe , vRange.front().to() ); }
+      }
+
+      // Get the Hcal DLL(mu)
+      {
+        const auto vRange = m_dllmuHcalTable -> relations ( proto->track() ) ;
+        if ( !vRange.empty() ) { proto->addInfo(LHCb::ProtoParticle::additionalInfo::HcalPIDmu , vRange.front().to() ); }
+      }
+
+      if ( msgLevel(MSG::VERBOSE) )
+        verbose() << " -> Hcal PID  : "
+                  << " HcalE      =" <<  proto->info(LHCb::ProtoParticle::additionalInfo::CaloHcalE, -999.)
+                  << " Dlle (Hcal) =" <<  proto->info(LHCb::ProtoParticle::additionalInfo::HcalPIDe, -999.)
+                  << " Dllmu (Hcal) =" <<  proto->info(LHCb::ProtoParticle::additionalInfo::HcalPIDmu, -999.)
+                  << endmsg;
+
+    }
+    else
+    {
+      if ( msgLevel(MSG::VERBOSE) )verbose() << " -> The track is NOT in Hcal acceptance"  << endmsg;
+    }
+  }
+  else
+  {
+    if ( msgLevel(MSG::VERBOSE) )verbose() << " -> No entry for that track in the Hcal acceptance table"  << endmsg;
+  }
+
+  return hasHcalPID;
+}
diff --git a/Rec/GlobalReco/src/FutureChargedProtoParticleAddHcalInfo.h b/Rec/GlobalReco/src/FutureChargedProtoParticleAddHcalInfo.h
new file mode 100644
index 0000000000000000000000000000000000000000..2693afb36ddcf8091bc53aff8c7d017010343d04
--- /dev/null
+++ b/Rec/GlobalReco/src/FutureChargedProtoParticleAddHcalInfo.h
@@ -0,0 +1,60 @@
+
+//-----------------------------------------------------------------------------
+/** @file FutureChargedProtoParticleAddHcalInfo.h
+ *
+ * Header file for algorithm FutureChargedProtoParticleAddHcalInfo
+ *
+ * @author Chris Jones   Christopher.Rob.Jones@cern.ch
+ * @date 29/03/2006
+ */
+//-----------------------------------------------------------------------------
+
+#ifndef GLOBALRECO_FutureChargedProtoParticleAddHcalInfo_H
+#define GLOBALRECO_FutureChargedProtoParticleAddHcalInfo_H 1
+
+// from Gaudi
+#include "FutureChargedProtoParticleCALOFUTUREBaseAlg.h"
+
+/** @class FutureChargedProtoParticleAddHcalInfo FutureChargedProtoParticleAddHcalInfo.h
+ *
+ *  Updates the CALO HCAL information stored in the ProtoParticles
+ *
+ *  @author Chris Jones   Christopher.Rob.Jones@cern.ch
+ *  @date 28/08/2009
+ */
+
+class FutureChargedProtoParticleAddHcalInfo final : public FutureChargedProtoParticleCALOFUTUREBaseAlg
+{
+
+public:
+
+  /// Standard constructor
+  FutureChargedProtoParticleAddHcalInfo( const std::string& name, ISvcLocator* pSvcLocator );
+
+  StatusCode execute() override;       ///< Algorithm execution
+
+private:
+
+  /// Load the Calo Hcal tables
+  bool getHcalData();
+
+  /// Add Calo Hcal information to the given ProtoParticle
+  bool addHcal( LHCb::ProtoParticle * proto ) const;
+
+private:
+
+  std::string m_protoPath; ///< Location of the ProtoParticles in the TES
+
+  std::string m_inHcalPath ;
+  std::string m_hcalEPath ;
+  std::string m_hcalPIDePath ;
+  std::string m_hcalPIDmuPath ;
+
+  const LHCb::CaloFuture2Track::ITrAccTable*  m_InHcalTable    = nullptr;
+  const LHCb::CaloFuture2Track::ITrEvalTable*  m_HcalETable    = nullptr;
+  const LHCb::CaloFuture2Track::ITrEvalTable* m_dlleHcalTable  = nullptr;
+  const LHCb::CaloFuture2Track::ITrEvalTable* m_dllmuHcalTable = nullptr;
+
+};
+
+#endif // GLOBALRECO_FutureChargedProtoParticleAddHcalInfo_H
diff --git a/Rec/GlobalReco/src/FutureChargedProtoParticleAddPrsInfo.cpp b/Rec/GlobalReco/src/FutureChargedProtoParticleAddPrsInfo.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1c867aa62f19aa3bcf79e3eb219530ccea621853
--- /dev/null
+++ b/Rec/GlobalReco/src/FutureChargedProtoParticleAddPrsInfo.cpp
@@ -0,0 +1,141 @@
+
+//-----------------------------------------------------------------------------
+/** @file FutureChargedProtoParticleAddPrsInfo.cpp
+ *
+ * Implementation file for algorithm FutureChargedProtoParticleAddPrsInfo
+ *
+ * @author Chris Jones   Christopher.Rob.Jones@cern.ch
+ * @date 28/08/2009
+ */
+//-----------------------------------------------------------------------------
+
+// local
+#include "FutureChargedProtoParticleAddPrsInfo.h"
+
+//-----------------------------------------------------------------------------
+
+// Declaration of the Algorithm Factory
+DECLARE_COMPONENT( FutureChargedProtoParticleAddPrsInfo )
+
+//=============================================================================
+// Standard constructor, initializes variables
+//=============================================================================
+FutureChargedProtoParticleAddPrsInfo::
+FutureChargedProtoParticleAddPrsInfo( const std::string& name,
+                                ISvcLocator* pSvcLocator)
+  : FutureChargedProtoParticleCALOFUTUREBaseAlg ( name , pSvcLocator )
+{
+  // default locations from context()
+
+  using namespace LHCb::CaloFuture2Track;
+  using namespace LHCb::CaloFutureIdLocation;
+  using namespace LHCb::CaloFutureAlgUtils;
+
+  m_protoPath         = LHCb::ProtoParticleLocation::Charged ;
+  m_inPrsPath         = PathFromContext( context() , InPrs   );
+  m_prsEPath          = PathFromContext( context() , PrsE    );
+  m_prsPIDePath       = PathFromContext( context() , PrsPIDe );
+
+  declareProperty("ProtoParticleLocation"      , m_protoPath        );
+  declareProperty("InputInPrsLocation"         , m_inPrsPath        );
+  declareProperty("InputPrsELocation"          , m_prsEPath         );
+  declareProperty("InputPrsPIDeLocation"       , m_prsPIDePath      );
+
+}
+
+//=============================================================================
+// Main execution
+//=============================================================================
+StatusCode FutureChargedProtoParticleAddPrsInfo::execute()
+{
+  // Load the Brem data
+  const bool sc = getPrsData();
+  if ( !sc )
+  {
+    return Warning( "No BREM data -> ProtoParticles will not be changed.", StatusCode::SUCCESS );
+  }
+
+  // ProtoParticle container
+  auto * protos = getIfExists<LHCb::ProtoParticles>(m_protoPath);
+  if ( !protos )
+  {
+    if ( msgLevel(MSG::DEBUG) ) debug() << "No existing ProtoParticle container at "
+                                        <<  m_protoPath<<" thus do nothing."<<endmsg;
+    return StatusCode::SUCCESS;
+  }
+
+  // Loop over proto particles and update PRS info
+  for ( auto * proto : *protos ) { addPrs(proto); }
+
+  if ( counterStat->isQuiet() ) counter("PrsPIDs("+context()+") ==> " + m_protoPath )+= protos->size();
+
+  return StatusCode::SUCCESS;
+}
+
+//=============================================================================
+
+//=============================================================================
+// Loads the Calo Prs data
+//=============================================================================
+bool FutureChargedProtoParticleAddPrsInfo::getPrsData()
+{
+  const bool sc1 = loadCaloTable(m_InPrsTable  , m_inPrsPath);
+  const bool sc2 = loadCaloTable(m_PrsETable   , m_prsEPath);
+  const bool sc3 = loadCaloTable(m_dllePrsTable, m_prsPIDePath);
+  const bool sc  = sc1 && sc2 && sc3;
+  if ( sc && msgLevel(MSG::DEBUG) ) debug() << "PRS PID SUCCESSFULLY LOADED" << endmsg;
+  return sc;
+}
+
+//=============================================================================
+// Add Calo Prs info to the protoparticle
+//=============================================================================
+bool FutureChargedProtoParticleAddPrsInfo::addPrs( LHCb::ProtoParticle * proto ) const
+{
+  // clear PRS info
+  proto->removeCaloPrsInfo();
+
+  // Add new info
+
+  bool hasPrsPID = false;
+
+  const auto aRange = m_InPrsTable -> relations ( proto->track() ) ;
+  if( !aRange.empty() )
+  {
+    hasPrsPID = aRange.front().to();
+    if( hasPrsPID )
+    {
+      if ( msgLevel(MSG::VERBOSE) )verbose() << " -> The track is in Prs acceptance"  << endmsg;
+      proto->addInfo(LHCb::ProtoParticle::additionalInfo::InAccPrs , true );
+
+      // Get the PrsE (intermediate) estimator
+      {
+        const auto vRange = m_PrsETable -> relations ( proto->track() ) ;
+        if ( !vRange.empty() ) { proto->addInfo(LHCb::ProtoParticle::additionalInfo::CaloPrsE,  vRange.front().to() ); }
+      }
+
+      // Get the Prs DLL(e)
+      {
+        const auto vRange = m_dllePrsTable -> relations ( proto->track() ) ;
+        if ( !vRange.empty() ) { proto->addInfo(LHCb::ProtoParticle::additionalInfo::PrsPIDe , vRange.front().to() ); }
+      }
+
+      if ( msgLevel(MSG::VERBOSE) )
+        verbose() << " -> Prs PID : "
+                  << " PrsE       =" <<  proto->info(LHCb::ProtoParticle::additionalInfo::CaloPrsE, -999.)
+                  << " Dlle (Prs)  =" <<  proto->info(LHCb::ProtoParticle::additionalInfo::PrsPIDe , -999.)
+                  << endmsg;
+
+    }
+    else
+    {
+      if ( msgLevel(MSG::VERBOSE) )verbose() << " -> The track is NOT in Prs acceptance"  << endmsg;
+    }
+  }
+  else
+  {
+    if ( msgLevel(MSG::VERBOSE) )verbose() << " -> No entry for that track in the Prs acceptance table"  << endmsg;
+  }
+
+  return hasPrsPID;
+}
diff --git a/Rec/GlobalReco/src/FutureChargedProtoParticleAddPrsInfo.h b/Rec/GlobalReco/src/FutureChargedProtoParticleAddPrsInfo.h
new file mode 100644
index 0000000000000000000000000000000000000000..5119f576c10504ae31feb45c48197bc6d3e304b3
--- /dev/null
+++ b/Rec/GlobalReco/src/FutureChargedProtoParticleAddPrsInfo.h
@@ -0,0 +1,58 @@
+
+//-----------------------------------------------------------------------------
+/** @file FutureChargedProtoParticleAddPrsInfo.h
+ *
+ * Header file for algorithm FutureChargedProtoParticleAddPrsInfo
+ *
+ * @author Chris Jones   Christopher.Rob.Jones@cern.ch
+ * @date 29/03/2006
+ */
+//-----------------------------------------------------------------------------
+
+#ifndef GLOBALRECO_FutureChargedProtoParticleAddPrsInfo_H
+#define GLOBALRECO_FutureChargedProtoParticleAddPrsInfo_H 1
+
+// from Gaudi
+#include "FutureChargedProtoParticleCALOFUTUREBaseAlg.h"
+
+/** @class FutureChargedProtoParticleAddPrsInfo FutureChargedProtoParticleAddPrsInfo.h
+ *
+ *  Updates the CALO 'BREM' information stored in the ProtoParticles
+ *
+ *  @author Chris Jones   Christopher.Rob.Jones@cern.ch
+ *  @date 28/08/2009
+ */
+
+class FutureChargedProtoParticleAddPrsInfo final : public FutureChargedProtoParticleCALOFUTUREBaseAlg
+{
+
+public:
+
+  /// Standard constructor
+  FutureChargedProtoParticleAddPrsInfo( const std::string& name, ISvcLocator* pSvcLocator );
+
+  StatusCode execute() override;       ///< Algorithm execution
+
+private:
+
+  /// Load the Calo Prs tables
+  bool getPrsData();
+
+  /// Add Calo Prs information to the given ProtoParticle
+  bool addPrs( LHCb::ProtoParticle * proto ) const;
+
+private:
+
+  std::string m_protoPath; ///< Location of the ProtoParticles in the TES
+
+  std::string m_inPrsPath ;
+  std::string m_prsEPath ;
+  std::string m_prsPIDePath ;
+
+  const LHCb::CaloFuture2Track::ITrAccTable*  m_InPrsTable = nullptr;
+  const LHCb::CaloFuture2Track::ITrEvalTable*  m_PrsETable = nullptr;
+  const LHCb::CaloFuture2Track::ITrEvalTable* m_dllePrsTable = nullptr;
+
+};
+
+#endif // GLOBALRECO_FutureChargedProtoParticleAddPrsInfo_H
diff --git a/Rec/GlobalReco/src/FutureChargedProtoParticleAddSpdInfo.cpp b/Rec/GlobalReco/src/FutureChargedProtoParticleAddSpdInfo.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..95cdb941f3c70719ed46dad6ffacbff9f736d5b4
--- /dev/null
+++ b/Rec/GlobalReco/src/FutureChargedProtoParticleAddSpdInfo.cpp
@@ -0,0 +1,128 @@
+
+//-----------------------------------------------------------------------------
+/** @file FutureChargedProtoParticleAddSpdInfo.cpp
+ *
+ * Implementation file for algorithm FutureChargedProtoParticleAddSpdInfo
+ *
+ * @author Chris Jones   Christopher.Rob.Jones@cern.ch
+ * @date 28/08/2009
+ */
+//-----------------------------------------------------------------------------
+
+// local
+#include "FutureChargedProtoParticleAddSpdInfo.h"
+
+//-----------------------------------------------------------------------------
+
+// Declaration of the Algorithm Factory
+DECLARE_COMPONENT( FutureChargedProtoParticleAddSpdInfo )
+
+//=============================================================================
+// Standard constructor, initializes variables
+//=============================================================================
+FutureChargedProtoParticleAddSpdInfo::
+FutureChargedProtoParticleAddSpdInfo( const std::string& name,
+                                ISvcLocator* pSvcLocator)
+  : FutureChargedProtoParticleCALOFUTUREBaseAlg ( name , pSvcLocator )
+{
+  // default locations from context()
+
+  using namespace LHCb::CaloFuture2Track;
+  using namespace LHCb::CaloFutureIdLocation;
+  using namespace LHCb::CaloFutureAlgUtils;
+
+  m_protoPath   = LHCb::ProtoParticleLocation::Charged ;
+  m_inSpdPath   = PathFromContext( context() , InSpd  );
+  m_spdEPath    = PathFromContext( context() , SpdE   );
+
+  declareProperty("ProtoParticleLocation"      , m_protoPath       );
+  declareProperty("InputInSpdLocation"         , m_inSpdPath       );
+  declareProperty("InputSpdELocation"          , m_spdEPath        );
+}
+
+//=============================================================================
+// Main execution
+//=============================================================================
+StatusCode FutureChargedProtoParticleAddSpdInfo::execute()
+{
+  // Load the Brem data
+  const bool sc = getSpdData();
+  if ( !sc )
+  {
+    return Warning( "No CALO SPD data -> ProtoParticles will not be changed.",
+                    StatusCode::SUCCESS );
+  }
+
+  // ProtoParticle container
+  auto * protos = getIfExists<LHCb::ProtoParticles>(m_protoPath);
+  if ( !protos )
+  {
+    if ( msgLevel(MSG::DEBUG) ) debug() << "No existing ProtoParticle container at "
+                                        <<  m_protoPath<<" thus do nothing."<<endmsg;
+    return StatusCode::SUCCESS;
+  }
+
+  // Loop over proto particles and update SPD info
+  for ( auto * proto : *protos ) { addSpd(proto); }
+
+  if ( counterStat->isQuiet() )
+    counter("SpdPIDs("+context()+") ==> " + m_protoPath )+= protos->size();
+
+  return StatusCode::SUCCESS;
+}
+
+//=============================================================================
+
+//=============================================================================
+// Loads the Calo Spd data
+//=============================================================================
+bool FutureChargedProtoParticleAddSpdInfo::getSpdData()
+{
+  const bool sc1 = loadCaloTable(m_InSpdTable , m_inSpdPath);
+  const bool sc2 = loadCaloTable(m_SpdETable  , m_spdEPath );
+  const bool sc  = sc1 && sc2;
+  if ( sc && msgLevel(MSG::DEBUG) ) debug() << "SPD PID SUCCESSFULLY LOADED" << endmsg;
+  return sc;
+}
+
+//=============================================================================
+// Add Calo Spd info to the protoparticle
+//=============================================================================
+bool FutureChargedProtoParticleAddSpdInfo::addSpd( LHCb::ProtoParticle * proto ) const
+{
+  // clear SPD info
+  proto->removeCaloSpdInfo();
+
+  bool hasSpdPID = false;
+
+  const auto aRange = m_InSpdTable -> relations ( proto->track() ) ;
+  if ( !aRange.empty() )
+  {
+    hasSpdPID = aRange.front().to();
+    if ( hasSpdPID )
+    {
+      if ( msgLevel(MSG::VERBOSE) )verbose() << " -> The track is in Spd acceptance"  << endmsg;
+      proto->addInfo(LHCb::ProtoParticle::additionalInfo::InAccSpd , true );
+
+      // Get the PrsE (intermediate) estimator
+      const auto vRange = m_SpdETable -> relations ( proto->track() ) ;
+      if ( !vRange.empty() ) { proto->addInfo(LHCb::ProtoParticle::additionalInfo::CaloSpdE,  vRange.front().to() ); }
+
+      if ( msgLevel(MSG::VERBOSE) )
+        verbose() << " -> Spd PID : "
+                  << " SpdE       =" <<  proto->info(LHCb::ProtoParticle::additionalInfo::CaloSpdE, -999.)
+                  << endmsg;
+
+    }
+    else
+    {
+      if ( msgLevel(MSG::VERBOSE) ) verbose() << " -> The track is NOT in Spd acceptance"  << endmsg;
+    }
+  }
+  else
+  {
+    if ( msgLevel(MSG::VERBOSE) ) verbose() << " -> No entry for that track in the Spd acceptance table"  << endmsg;
+  }
+
+  return hasSpdPID;
+}
diff --git a/Rec/GlobalReco/src/FutureChargedProtoParticleAddSpdInfo.h b/Rec/GlobalReco/src/FutureChargedProtoParticleAddSpdInfo.h
new file mode 100644
index 0000000000000000000000000000000000000000..01de1e1e1fb004da060604eb7aaa3250118cd3fe
--- /dev/null
+++ b/Rec/GlobalReco/src/FutureChargedProtoParticleAddSpdInfo.h
@@ -0,0 +1,56 @@
+
+//-----------------------------------------------------------------------------
+/** @file FutureChargedProtoParticleAddSpdInfo.h
+ *
+ * Header file for algorithm FutureChargedProtoParticleAddSpdInfo
+ *
+ * @author Chris Jones   Christopher.Rob.Jones@cern.ch
+ * @date 29/03/2006
+ */
+//-----------------------------------------------------------------------------
+
+#ifndef GLOBALRECO_FutureChargedProtoParticleAddSpdInfo_H
+#define GLOBALRECO_FutureChargedProtoParticleAddSpdInfo_H 1
+
+// from Gaudi
+#include "FutureChargedProtoParticleCALOFUTUREBaseAlg.h"
+
+/** @class FutureChargedProtoParticleAddSpdInfo FutureChargedProtoParticleAddSpdInfo.h
+ *
+ *  Updates the CALO SPD information stored in the ProtoParticles
+ *
+ *  @author Chris Jones   Christopher.Rob.Jones@cern.ch
+ *  @date 28/08/2009
+ */
+
+class FutureChargedProtoParticleAddSpdInfo final : public FutureChargedProtoParticleCALOFUTUREBaseAlg
+{
+
+public:
+
+  /// Standard constructor
+  FutureChargedProtoParticleAddSpdInfo( const std::string& name, ISvcLocator* pSvcLocator );
+
+  StatusCode execute() override;       ///< Algorithm execution
+
+private:
+
+  /// Load the Calo Spd tables
+  bool getSpdData();
+
+  /// Add Calo Spd information to the given ProtoParticle
+  bool addSpd( LHCb::ProtoParticle * proto ) const;
+
+private:
+
+  std::string m_protoPath; ///< Location of the ProtoParticles in the TES
+
+  std::string m_inSpdPath ;
+  std::string m_spdEPath ;
+
+  const LHCb::CaloFuture2Track::ITrAccTable*  m_InSpdTable = nullptr;
+  const LHCb::CaloFuture2Track::ITrEvalTable*  m_SpdETable = nullptr;
+
+};
+
+#endif // GLOBALRECO_FutureChargedProtoParticleAddSpdInfo_H
diff --git a/Rec/GlobalReco/src/FutureChargedProtoParticleCALOFUTUREBaseAlg.cpp b/Rec/GlobalReco/src/FutureChargedProtoParticleCALOFUTUREBaseAlg.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1fb7f88c2e0dfc480dc80a3cad6b1fe50882193f
--- /dev/null
+++ b/Rec/GlobalReco/src/FutureChargedProtoParticleCALOFUTUREBaseAlg.cpp
@@ -0,0 +1,28 @@
+//-----------------------------------------------------------------------------
+/** @file FutureChargedProtoParticleCALOFUTUREBaseAlg.cpp
+ *
+ * Implementation file for algorithm FutureChargedProtoParticleCALOFUTUREBaseAlg
+ *
+ * @author Chris Jones   Christopher.Rob.Jones@cern.ch
+ * @date 28/08/2009
+ */
+//-----------------------------------------------------------------------------
+
+// local
+#include "FutureChargedProtoParticleCALOFUTUREBaseAlg.h"
+
+//-----------------------------------------------------------------------------
+
+//=============================================================================
+// Initialization
+//=============================================================================
+StatusCode FutureChargedProtoParticleCALOFUTUREBaseAlg::initialize()
+{
+  const StatusCode sc = GaudiAlgorithm::initialize();
+  if ( sc.isFailure() ) return sc;
+
+  counterStat = tool<IFutureCounterLevel>("FutureCounterLevel");
+  m_estimator = tool<ICaloFutureHypoEstimator>("CaloFutureHypoEstimator","CaloFutureHypoEstimator",this);
+
+  return sc;
+}
diff --git a/Rec/GlobalReco/src/FutureChargedProtoParticleCALOFUTUREBaseAlg.h b/Rec/GlobalReco/src/FutureChargedProtoParticleCALOFUTUREBaseAlg.h
new file mode 100644
index 0000000000000000000000000000000000000000..abb781a29a16302cfc0c662db65c3a54d9c4090d
--- /dev/null
+++ b/Rec/GlobalReco/src/FutureChargedProtoParticleCALOFUTUREBaseAlg.h
@@ -0,0 +1,72 @@
+//-----------------------------------------------------------------------------
+/** @file FutureChargedProtoParticleCALOFUTUREBaseAlg.h
+ *
+ * Header file for algorithm FutureChargedProtoParticleCALOFUTUREBaseAlg
+ *
+ * @author Chris Jones   Christopher.Rob.Jones@cern.ch
+ * @date 29/03/2006
+ */
+//-----------------------------------------------------------------------------
+
+#ifndef GLOBALRECO_FutureChargedProtoParticleCALOFUTUREBaseAlg_H
+#define GLOBALRECO_FutureChargedProtoParticleCALOFUTUREBaseAlg_H 1
+
+// from Gaudi
+#include "GaudiAlg/GaudiAlgorithm.h"
+
+// Event
+#include "Event/ProtoParticle.h"
+
+// from CaloUtils
+#include "CaloFutureUtils/CaloFuture2Track.h"
+#include "Event/CaloDataFunctor.h"
+#include "CaloFutureUtils/CaloFutureAlgUtils.h"
+
+// Relations
+#include "Relations/IRelation.h"
+#include "Relations/IRelationWeighted2D.h"
+#include "CaloFutureInterfaces/ICaloFutureHypoEstimator.h"
+#include "CaloFutureInterfaces/IFutureCounterLevel.h"
+
+/** @class FutureChargedProtoParticleCALOFUTUREBaseAlg FutureChargedProtoParticleCALOFUTUREBaseAlg.h
+ *
+ *  Base class for ProtoParticle algorithms that add CALOFUTURE information
+ *
+ *  @author Chris Jones   Christopher.Rob.Jones@cern.ch
+ *  @date 28/08/2009
+ */
+
+class FutureChargedProtoParticleCALOFUTUREBaseAlg : public GaudiAlgorithm
+{
+
+public:
+
+  /// Standard constructor
+  using GaudiAlgorithm::GaudiAlgorithm;
+
+  StatusCode initialize() override; ///< Algorithm initialization
+
+protected:
+  IFutureCounterLevel* counterStat;
+
+  /// Loads a CALOFUTURE relations table
+  template < typename TYPE >
+  inline bool loadCaloTable( TYPE *& table, const std::string & location ) const
+  {
+    table = getIfExists<TYPE>( location );
+    if ( !table )
+    {
+      Warning("No CALOFUTURE "+System::typeinfoName(typeid(TYPE))+
+              " table at '"+location+"'", StatusCode::SUCCESS ).ignore();
+    }
+    return ( nullptr != table );
+  }
+
+protected:
+
+  // Add extra info from CaloDigits (Spd+Prs)
+  ICaloFutureHypoEstimator * m_estimator = nullptr;
+
+};
+
+#endif // GLOBALRECO_FutureChargedProtoParticleCALOFUTUREBaseAlg_H
diff --git a/Rec/GlobalReco/src/FutureNeutralProtoPAlg.cpp b/Rec/GlobalReco/src/FutureNeutralProtoPAlg.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..41e9bfb05b4fb8b905520237018f0795fbc722bc
--- /dev/null
+++ b/Rec/GlobalReco/src/FutureNeutralProtoPAlg.cpp
@@ -0,0 +1,248 @@
+// ============================================================================
+// Include files
+// ============================================================================
+#include "FutureNeutralProtoPAlg.h"
+// ============================================================================
+/** @file
+ *  Implementation file for class FutureNeutralProtoPAlg
+ *  @date 2006-06-09
+ *  @author Olivier Deschamps
+ */
+// Declaration of the Algorithm Factory
+DECLARE_COMPONENT( FutureNeutralProtoPAlg )
+// ============================================================================
+// Standard constructor, initializes variables
+// ============================================================================
+FutureNeutralProtoPAlg::FutureNeutralProtoPAlg( const std::string& name,
+                                    ISvcLocator* pSvcLocator)
+: GaudiAlgorithm ( name , pSvcLocator )
+{
+  // declare the properties
+  declareProperty ( "HyposLocations"        , m_hyposLocations   ) ;
+  declareProperty ( "ProtoParticleLocation" ,  m_protoLocation   ) ;
+  declareProperty ( "LightMode"      , m_light_mode = false,
+                    "Use 'light' mode and do not collect all information. Useful for Calibration." ) ;
+
+  // default location from context()
+  using namespace LHCb::CaloHypoLocation;
+  m_hyposLocations.push_back( LHCb::CaloFutureAlgUtils::PathFromContext( context() , MergedPi0s   ) ) ; // put it 1st to speed-up photon mass retrieval
+  m_hyposLocations.push_back( LHCb::CaloFutureAlgUtils::PathFromContext( context() , Photons      ) ) ;
+  m_hyposLocations.push_back( LHCb::CaloFutureAlgUtils::PathFromContext( context() , SplitPhotons ) ) ;
+  //  m_protoLocation = LHCb::CaloFutureAlgUtils::PathFromContext( flag , LHCb::ProtoParticleLocation::Neutrals );
+  m_protoLocation = LHCb::ProtoParticleLocation::Neutrals ;
+}
+// ============================================================================
+// Initialization
+// ============================================================================
+StatusCode FutureNeutralProtoPAlg::initialize()
+{
+  const StatusCode sc = GaudiAlgorithm::initialize(); // must be executed first
+  if ( sc.isFailure() ) return sc;  // error printed already by GaudiAlgorithm
+  if( msgLevel(MSG::DEBUG) ) debug() << "==> Initialize" << endmsg;
+
+  for ( const auto & loc : m_hyposLocations )
+  { info() << " Hypothesis loaded from " << loc << endmsg; }
+
+  counterStat = tool<IFutureCounterLevel>("FutureCounterLevel");
+
+  if ( lightMode() )
+    info() << "FutureNeutral protoparticles will be created in 'Light' Mode" << endmsg ;
+
+  m_estimator = tool<ICaloFutureHypoEstimator>("CaloFutureHypoEstimator","CaloFutureHypoEstimator",this);
+  m_estimator->hypo2CaloFuture()->_setProperty("Seed", "false").ignore();
+  m_estimator->hypo2CaloFuture()->_setProperty("PhotonLine", "true").ignore();
+  m_estimator->hypo2CaloFuture()->_setProperty("AddNeighbors", "false").ignore();
+
+  m_mass.clear();
+  m_setMass = false;
+
+  return sc;
+}
+
+double FutureNeutralProtoPAlg::getMass( const int cellCode ) const
+{
+  if( !m_setMass )
+  {
+    Warning("You should process MergedPi0 protoparticles first to speed up retrieval of photon 'mass'",StatusCode::SUCCESS,1).ignore();
+    // === storing masses
+    m_setMass = true;
+    using namespace LHCb::CaloHypoLocation;
+    const auto loc =  LHCb::CaloFutureAlgUtils::PathFromContext( context() , MergedPi0s   );
+    const auto * hypos = getIfExists<LHCb::CaloHypos>( loc );
+    if ( !hypos )return 0.;
+    for ( const auto& hypo : *hypos )
+    {
+      if ( !hypo ) continue;
+      using namespace CaloFutureDataType;
+      const auto cellCode = int(m_estimator->data(hypo, CellID ));
+      m_mass[cellCode]=m_estimator->data(hypo, HypoM );
+    }
+  }
+  const auto it = m_mass.find(cellCode);
+  return ( it == m_mass.end() ? 0.0 : it->second );
+}
+
+// ============================================================================
+// Main execution
+// ============================================================================
+StatusCode FutureNeutralProtoPAlg::execute()
+{
+
+  // create and register the output container
+  LHCb::ProtoParticles* protos = nullptr;
+  if ( !lightMode() && exist<LHCb::ProtoParticles>(m_protoLocation) )
+  {
+    Warning( "Existing ProtoParticle container at " +m_protoLocation+ " found -> Will replace", StatusCode::SUCCESS, 1).ignore();
+    if(counterStat->isQuiet())counter("Replaced Proto")+=1;
+    protos = get<LHCb::ProtoParticles>(m_protoLocation);
+    protos->clear();
+  }
+  else
+  {
+    protos = new LHCb::ProtoParticles();
+    put( protos , m_protoLocation ) ;
+  }
+
+  if ( !protos )return Warning("FutureNeutralProto container points to NULL ",StatusCode::SUCCESS);
+
+  // -- reset mass storage
+  m_mass.clear();
+  m_setMass=false;
+  //------ loop over all caloHypo containers
+  for ( const auto & loc : m_hyposLocations )
+  {
+
+    //==  Load the CaloHypo container
+    const auto * hypos = getIfExists<LHCb::CaloHypos>( loc );
+    if ( ! hypos )
+    {
+      if( msgLevel(MSG::DEBUG) ) debug()<< "No CaloHypo at '" << loc << "'" << endmsg ;
+      if ( counterStat->isQuiet() ) counter("No " + loc + " container") += 1;
+      continue;
+    }
+
+    // no cluster mass storage when no MergedPi0
+    if ( LHCb::CaloFutureAlgUtils::toUpper(loc).find("MERGED") != std::string::npos &&
+         hypos->empty() ) { m_setMass = true; }
+
+    if ( msgLevel(MSG::DEBUG) )
+      debug() << "CaloHypo loaded at " << loc << " (# " << hypos->size()<<")"<< endmsg;
+    int count = 0 ;
+
+    // == Loop over CaloHypos
+    for ( const auto * hypo : *hypos )
+    {
+      if ( ! hypo ) { continue ; }
+      count++;
+
+      // == create and store the corresponding ProtoParticle
+      auto * proto = new LHCb::ProtoParticle() ;
+      protos->insert( proto ) ;
+
+      // == link CaloHypo to ProtoP
+      using namespace CaloFutureDataType;
+      proto-> addToCalo( hypo ) ;
+
+      // ===== add data to protoparticle
+      if ( !lightMode() )
+      {
+        std::ostringstream type("");
+        type << hypo->hypothesis();
+        const auto hypothesis = type.str();
+        // extra data :
+        pushData(proto, LHCb::ProtoParticle::additionalInfo::CaloNeutralID  ,hypo, CellID   );   // seed cellID
+        // retrieve HypoM for photon
+        const auto cellCode = int(m_estimator->data(hypo, CellID ));
+        if( hypo -> hypothesis() == LHCb::CaloHypo::Hypothesis::Photon )
+        {
+          const auto mass  = getMass( cellCode );
+          if( mass > 0. )
+          {
+            proto->addInfo( LHCb::ProtoParticle::additionalInfo::ClusterMass, mass );
+            if(counterStat->isVerbose())counter("ClusterMass for Photon") += mass;
+          }
+        }
+        else if ( hypo -> hypothesis() == LHCb::CaloHypo::Hypothesis::Pi0Merged )
+        {
+          pushData(proto, LHCb::ProtoParticle::additionalInfo::ClusterMass, hypo, HypoM);
+          m_setMass=true;
+          m_mass[cellCode] = m_estimator->data(hypo, HypoM );
+        }
+        if( hypo -> hypothesis() != LHCb::CaloHypo::Hypothesis::Pi0Merged ){
+          pushData(proto, LHCb::ProtoParticle::additionalInfo::ClusterAsX, hypo, ClusterAsX, 0);
+          pushData(proto, LHCb::ProtoParticle::additionalInfo::ClusterAsY, hypo, ClusterAsY, 0);
+        }
+
+        pushData(proto, LHCb::ProtoParticle::additionalInfo::CaloNeutralPrs, hypo, HypoPrsE );
+        pushData(proto, LHCb::ProtoParticle::additionalInfo::CaloNeutralEcal,hypo, ClusterE );
+
+        pushData(proto, LHCb::ProtoParticle::additionalInfo::CaloTrMatch, hypo, ClusterMatch , +1.e+06 );  // ** input to neutralID
+        pushData(proto, LHCb::ProtoParticle::additionalInfo::ShowerShape, hypo, Spread);         // ** input to neutralID  && isPhoton (as Fr2)
+        pushData(proto, LHCb::ProtoParticle::additionalInfo::CaloNeutralSpd, hypo, HypoSpdM );   // ** input to neutralID
+        pushData(proto, LHCb::ProtoParticle::additionalInfo::CaloNeutralHcal2Ecal, hypo, Hcal2Ecal); // ** input to neutralID
+        pushData(proto, LHCb::ProtoParticle::additionalInfo::CaloClusterCode, hypo , ClusterCode);
+        pushData(proto, LHCb::ProtoParticle::additionalInfo::CaloClusterFrac, hypo , ClusterFrac,1);
+        pushData(proto, LHCb::ProtoParticle::additionalInfo::Saturation, hypo, Saturation, 0);
+
+
+
+        auto dep = (m_estimator->data(hypo,  ToSpdM ) > 0) ? -1. : +1.;
+        dep *= m_estimator->data(hypo,  ToPrsE );
+        proto -> addInfo ( LHCb::ProtoParticle::additionalInfo::CaloDepositID   , dep ) ;     // ** input to neutralID toPrsE=|caloDepositID|
+
+        // DLL-based neutralID (to be obsolete)  :
+        pushData(proto, LHCb::ProtoParticle::additionalInfo::PhotonID , hypo, NeutralID , -1. ,true    ); // old DLL-based neutral-ID // FORCE
+
+        // isNotX  inputs :
+        pushData(proto, LHCb::ProtoParticle::additionalInfo::CaloNeutralE49   , hypo, E49 );
+        pushData(proto, LHCb::ProtoParticle::additionalInfo::CaloNeutralE19   , hypo, E19 );      // ** input to neutralID
+        pushData(proto, LHCb::ProtoParticle::additionalInfo::CaloPrsNeutralE49, hypo, PrsE49  );  // ** input to neutralID
+        pushData(proto, LHCb::ProtoParticle::additionalInfo::CaloPrsNeutralE19, hypo, PrsE19  );  // ** input to neutralID
+        pushData(proto, LHCb::ProtoParticle::additionalInfo::CaloPrsNeutralE4max,hypo, PrsE4Max); // ** input to neutralID
+        pushData(proto, LHCb::ProtoParticle::additionalInfo::CaloNeutralPrsM  , hypo, HypoPrsM);  // ** input to neutralID
+        // isNotX output :
+        pushData(proto, LHCb::ProtoParticle::additionalInfo::IsNotH   , hypo, isNotH  , -1. , true     ); // new NN-based neutral-ID (anti-H) // FORCE
+        pushData(proto, LHCb::ProtoParticle::additionalInfo::IsNotE   , hypo, isNotE  , -1. , true     ); // new NN-based neutral-ID (anti-E) // FORCE
+
+        // isPhoton inputs (photon & mergedPi0 only)
+        if( hypo -> hypothesis() != LHCb::CaloHypo::Hypothesis::PhotonFromMergedPi0 )
+        {
+          pushData(proto, LHCb::ProtoParticle::additionalInfo::CaloShapeFr2r4     ,hypo, isPhotonFr2r4);  // -- input to isPhoton
+          pushData(proto, LHCb::ProtoParticle::additionalInfo::CaloShapeAsym      ,hypo, isPhotonAsym);   // -- input to isPhoton
+          pushData(proto, LHCb::ProtoParticle::additionalInfo::CaloShapeKappa     ,hypo, isPhotonKappa);  // -- input to isPhoton
+          pushData(proto, LHCb::ProtoParticle::additionalInfo::CaloShapeE1        ,hypo, isPhotonEseed);     // -- input to isPhoton
+          pushData(proto, LHCb::ProtoParticle::additionalInfo::CaloShapeE2        ,hypo, isPhotonE2);     // -- input to isPhoton
+          pushData(proto, LHCb::ProtoParticle::additionalInfo::CaloPrsShapeE2     ,hypo, isPhotonPrsE2);     // -- input to isPhoton
+          pushData(proto, LHCb::ProtoParticle::additionalInfo::CaloPrsShapeEmax   ,hypo, isPhotonPrsEmax);   // -- input to isPhoton
+          pushData(proto, LHCb::ProtoParticle::additionalInfo::CaloPrsShapeFr2    ,hypo, isPhotonPrsFr2);    // -- input to isPhoton
+          pushData(proto, LHCb::ProtoParticle::additionalInfo::CaloPrsShapeAsym   ,hypo, isPhotonPrsAsym);   // -- input to isPhoton
+          pushData(proto, LHCb::ProtoParticle::additionalInfo::CaloPrsM           ,hypo, isPhotonPrsM);      // -- input to isPhoton
+          pushData(proto, LHCb::ProtoParticle::additionalInfo::CaloPrsM15         ,hypo, isPhotonPrsM15);    // -- input to isPhoton
+          pushData(proto, LHCb::ProtoParticle::additionalInfo::CaloPrsM30         ,hypo, isPhotonPrsM30);    // -- input to isPhoton
+          pushData(proto, LHCb::ProtoParticle::additionalInfo::CaloPrsM45         ,hypo, isPhotonPrsM45);    // -- input to isPhoton
+          // isPhoton output :
+          pushData(proto, LHCb::ProtoParticle::additionalInfo::IsPhoton , hypo, isPhoton , +1. , true    ); // NN-based neutral-ID (anti-pi0) // FORCE to +1 when missing (i.e. PT < 2 GeV)
+          pushData(proto, LHCb::ProtoParticle::additionalInfo::IsPhotonXGB , hypo, isPhotonXGB , +1. , true    ); // XGBoost-based neutral-ID (anti-pi0) // FORCE to +1 when missing (i.e. PT < 2 GeV)
+
+        }
+      }// lightmode
+    } // loop over CaloHypos
+    if ( counterStat->isQuiet() ) counter( loc + "=>" + m_protoLocation) += count;
+  } // loop over HyposLocations
+
+
+  if ( msgLevel(MSG::DEBUG) )debug() << "# Future Neutral ProtoParticles created : " << protos -> size() << endmsg;
+  if(counterStat->isQuiet())counter ("#protos in " + m_protoLocation) += protos->size() ;
+  return StatusCode::SUCCESS;
+}
+// ============================================================================
+//  Finalize
+// ============================================================================
+
+StatusCode FutureNeutralProtoPAlg::finalize(){
+  //
+  if ( lightMode() )
+  { info() << "Future Neutral protoparticles have been created in 'Light' Mode" << endmsg ; }
+
+  return GaudiAlgorithm::finalize();  // must be called after all other actions
+}
diff --git a/Rec/GlobalReco/src/FutureNeutralProtoPAlg.h b/Rec/GlobalReco/src/FutureNeutralProtoPAlg.h
new file mode 100644
index 0000000000000000000000000000000000000000..99675b2a154a95c93ebe754aaa212f8631a34dcc
--- /dev/null
+++ b/Rec/GlobalReco/src/FutureNeutralProtoPAlg.h
@@ -0,0 +1,106 @@
+// ============================================================================
+#ifndef GLOBALRECO_FUTURENEUTRALPROTOPALG_H
+#define GLOBALRECO_FUTURENEUTRALPROTOPALG_H 1
+// ============================================================================
+// Include files
+// ============================================================================
+// Event
+#include "Event/CaloHypo.h"
+#include "Event/ProtoParticle.h"
+// Calo
+#include "CaloFutureUtils/CaloFutureAlgUtils.h"
+#include "CaloFutureInterfaces/ICaloFutureHypoEstimator.h"
+#include "CaloFutureInterfaces/IFutureCounterLevel.h"
+// from Gaudi
+#include "GaudiAlg/GaudiAlgorithm.h"
+/** @class FutureNeutralProtoPAlg FutureNeutralProtoPAlg.h
+ *
+ *  Creator of the neutral ProtoParticles from CaloHypos
+ *
+ *  The current version fills the following estimators for ProtoParticle
+ *
+ *  <ul>
+ *  <li>  <i>CaloTrMatch</i>     as <b>minimal</b> of this estimator for all
+ *        linked <i>CaloHypo</i> objects. The value is extracted from
+ *        the relation table/associator as a relation weigth between
+ *        <i>CaloCluster</i> and <i>TrStoredTrack</i> objects </li>
+ *  <li>  <i>CaloDepositID</i>   as <b>maximal</b> of this estimator for all
+ *        linked <i>CaloHypo</i> objects using Spd/Prs estimator tool
+ *        written by Frederic Machefert </li>
+ *  <li>  <i>CaloShowerShape</i> as <b>maximal</b> of the estimator for
+ *        all linked <i>CaloHypo</i> objects. Estimator is equal to the
+ *        sum of diagonal elements of cluster spread matrix (2nd order
+ *        moments of the cluster) </li>
+ *  <li>  <i>ClusterMass</i>     as <b>maximal</b> of the estimator of
+ *        cluster mass using smart algorithm by Olivier Deschamp </li>
+ *  <li>  <i>PhotonID</i>        as the estimator of PhotonID
+ *        using nice identifiaction tool
+ *        CaloPhotonEstimatorTool by Frederic Machefert *
+ *  </ul>
+ *
+ *
+ *  @author Olivier Deschamps
+ *  @date   2006-06-09
+ *  Adapted from NeutralPPsFromCPsAlg class (Vanya Belyaev Ivan.Belyaev@itep.ru)
+ */
+class FutureNeutralProtoPAlg final : public GaudiAlgorithm
+{
+  // ==========================================================================
+ public:
+  // ==========================================================================
+  /// Standard constructor
+  FutureNeutralProtoPAlg ( const std::string& name, ISvcLocator* pSvcLocator );
+
+  StatusCode initialize() override;    ///< Algorithm initialization
+  StatusCode execute() override;    ///< Algorithm execution
+  StatusCode finalize() override;    ///< Algorithm finalization
+
+ private:
+
+  /// use"light" mode? ( suitable fo recalibration purposes)
+  inline bool lightMode() const noexcept { return m_light_mode ; }
+
+  void pushData( LHCb::ProtoParticle*,
+                 LHCb::ProtoParticle::additionalInfo,
+                 const LHCb::CaloHypo*,
+                 const CaloFutureDataType::DataType,
+                 const double def=CaloFutureDataType::Default,
+                 const bool force=false) const;
+
+  double getMass( const int cellCode ) const;
+
+private:// data
+
+  IFutureCounterLevel* counterStat = nullptr;
+
+  std::string               m_protoLocation     ;
+  std::vector<std::string>  m_hyposLocations    ;
+  /// flag to indicate "light/calibration" mode
+  bool  m_light_mode{false} ;
+  ICaloFutureHypoEstimator * m_estimator = nullptr;
+  mutable std::map<const int,double> m_mass = {{}};
+  mutable bool m_setMass{false};
+
+};
+
+inline void FutureNeutralProtoPAlg::pushData(LHCb::ProtoParticle* proto ,
+                                       LHCb::ProtoParticle::additionalInfo pflag ,
+                                       const LHCb::CaloHypo* hypo,
+                                       const CaloFutureDataType::DataType hflag,
+                                       const double def,
+                                       const bool force ) const
+{
+  const auto data =  m_estimator->data(hypo, hflag , def );
+  if ( data != def || force )
+  {
+    proto->addInfo( pflag,data ); // only store when different from default
+    std::ostringstream mess;
+    mess << pflag << " for " << hypo->hypothesis();
+    counter( mess.str() ) += data;
+  }
+}
+
+
+
+
+#endif // GLOBALRECO_FUTURENEUTRALPROTOPALG_H
diff --git a/Rec/GlobalReco/src/FutureNeutralProtoParticleAddNeutralID.cpp b/Rec/GlobalReco/src/FutureNeutralProtoParticleAddNeutralID.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e7af779dc195af065d886d0b765201f5a5a028a1
--- /dev/null
+++ b/Rec/GlobalReco/src/FutureNeutralProtoParticleAddNeutralID.cpp
@@ -0,0 +1,131 @@
+// Include files
+
+// local
+#include "FutureNeutralProtoParticleAddNeutralID.h"
+#include "CaloFutureUtils/CaloMomentum.h"
+
+//-----------------------------------------------------------------------------
+// Implementation file for class : FutureNeutralProtoParticleAddNeutralID
+//
+// 2014-05-27 : Olivier Deschamps
+//-----------------------------------------------------------------------------
+
+namespace {
+
+enum class func_type { none, abs, area };
+
+bool addInput( double& data,
+               const LHCb::ProtoParticle* proto,
+               const LHCb::ProtoParticle::additionalInfo flag,
+               const func_type func = func_type::none )
+{
+  auto v = proto->info( flag,-1e+06 );
+  if      ( func == func_type::abs  ) { v = fabs(v); }
+  else if ( func == func_type::area ) { v = double( (int( v ) >> 12) & 0x3 ); }
+  data = v;
+  return proto->hasInfo( flag );
+}
+}
+
+//=============================================================================
+// Main execution
+//=============================================================================
+StatusCode FutureNeutralProtoParticleAddNeutralID::execute()
+{
+  // locate input data
+  for ( auto * proto : * get<LHCb::ProtoParticles>(evtSvc(),m_input) )
+  {
+
+    const auto & hypos  = proto->calo() ;
+    if ( hypos.empty() ) { continue ; }
+
+    const auto hypo = hypos.front();
+    const auto pt = LHCb::CaloMomentum(hypo).pt();
+
+    if( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+      debug() << "---------- " << hypo->hypothesis() << " ---------- " <<endmsg;
+
+    //======== re-build neutralID
+    if ( m_isNotE.value() || m_isNotH.value())
+    {
+      double nV[10] = {};
+      bool nOk = true;
+      nOk &= addInput(nV[0],proto,LHCb::ProtoParticle::additionalInfo::CaloTrMatch);
+      nOk &= addInput(nV[1],proto,LHCb::ProtoParticle::additionalInfo::CaloDepositID,func_type::abs);
+      nOk &= addInput(nV[2],proto,LHCb::ProtoParticle::additionalInfo::CaloNeutralE19);
+      nOk &= addInput(nV[3],proto,LHCb::ProtoParticle::additionalInfo::CaloNeutralHcal2Ecal);
+      nOk &= addInput(nV[4],proto,LHCb::ProtoParticle::additionalInfo::CaloPrsNeutralE19);
+      nOk &= addInput(nV[5],proto,LHCb::ProtoParticle::additionalInfo::CaloPrsNeutralE49);
+      nOk &= addInput(nV[6],proto,LHCb::ProtoParticle::additionalInfo::ShowerShape);
+      nOk &= addInput(nV[7],proto,LHCb::ProtoParticle::additionalInfo::CaloPrsNeutralE4max);
+      nOk &= addInput(nV[8],proto,LHCb::ProtoParticle::additionalInfo::CaloNeutralPrsM);
+      nOk &= addInput(nV[9],proto,LHCb::ProtoParticle::additionalInfo::CaloNeutralSpd);
+      const double* nnV = nV;
+      if ( m_isNotE.value() && nOk )
+      {
+        const auto temp = proto->info(LHCb::ProtoParticle::additionalInfo::IsNotE,-1.);
+        proto->eraseInfo(LHCb::ProtoParticle::additionalInfo::IsNotE);
+        const auto val = ( pt > m_isNotE_Pt.value() ) ? m_neutralID->isNotE(nnV) : -1. ;
+        proto->addInfo(LHCb::ProtoParticle::additionalInfo::IsNotE,val );
+        if( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+          debug()  << "UPDATING IsNotE : "
+                   << temp << " ---> " << proto->info(LHCb::ProtoParticle::additionalInfo::IsNotE,-1.)
+                   << " (" << proto->hasInfo(LHCb::ProtoParticle::additionalInfo::IsNotE ) << ")" << endmsg;
+      }
+      if ( m_isNotH.value() && nOk )
+      {
+        const auto temp = proto->info(LHCb::ProtoParticle::additionalInfo::IsNotH,-1.);
+        proto->eraseInfo(LHCb::ProtoParticle::additionalInfo::IsNotH);
+        const auto val = (  pt > m_isNotH_Pt) ?  m_neutralID->isNotH(nnV) : -1.;
+        proto->addInfo(LHCb::ProtoParticle::additionalInfo::IsNotH, val );
+        if( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+          debug() << "UPDATING IsNotH : "
+                  << temp << " ---> " << proto->info(LHCb::ProtoParticle::additionalInfo::IsNotH,-1.)
+                  << " (" << proto->hasInfo(LHCb::ProtoParticle::additionalInfo::IsNotH ) << ")" << endmsg;
+      }
+    }
+
+    // re-build gamma/pi0 separation
+    if ( m_isPhoton.value() &&  hypo -> hypothesis() != LHCb::CaloHypo::Hypothesis::PhotonFromMergedPi0 )
+    {
+      double pV[15] = {};
+      bool pOk = true;
+      pOk &= addInput(pV[0],proto,LHCb::ProtoParticle::additionalInfo::CaloNeutralID,func_type::area);
+      pOk &= addInput(pV[1],proto,LHCb::ProtoParticle::additionalInfo::ShowerShape);
+      pOk &= addInput(pV[2],proto,LHCb::ProtoParticle::additionalInfo::CaloShapeFr2r4);
+      pOk &= addInput(pV[3],proto,LHCb::ProtoParticle::additionalInfo::CaloShapeAsym);
+      pOk &= addInput(pV[4],proto,LHCb::ProtoParticle::additionalInfo::CaloShapeKappa);
+      pOk &= addInput(pV[5],proto,LHCb::ProtoParticle::additionalInfo::CaloShapeE1);
+      pOk &= addInput(pV[6],proto,LHCb::ProtoParticle::additionalInfo::CaloShapeE2);
+      pOk &= addInput(pV[7],proto,LHCb::ProtoParticle::additionalInfo::CaloPrsShapeFr2);
+      pOk &= addInput(pV[8],proto,LHCb::ProtoParticle::additionalInfo::CaloPrsShapeAsym);
+      pOk &= addInput(pV[9],proto,LHCb::ProtoParticle::additionalInfo::CaloPrsShapeEmax);
+      pOk &= addInput(pV[10],proto,LHCb::ProtoParticle::additionalInfo::CaloPrsShapeE2);
+      pOk &= addInput(pV[11],proto,LHCb::ProtoParticle::additionalInfo::CaloPrsM);
+      pOk &= addInput(pV[12],proto,LHCb::ProtoParticle::additionalInfo::CaloPrsM15);
+      pOk &= addInput(pV[13],proto,LHCb::ProtoParticle::additionalInfo::CaloPrsM30);
+      pOk &= addInput(pV[14],proto,LHCb::ProtoParticle::additionalInfo::CaloPrsM45);
+      const double* ppV = pV;
+
+      if ( m_isPhoton.value() && pOk )
+      {
+        const auto temp=proto->info(LHCb::ProtoParticle::additionalInfo::IsPhoton,-1.);
+        proto->eraseInfo(LHCb::ProtoParticle::additionalInfo::IsPhoton);
+        const auto val = ( pt > m_isPhoton_Pt.value() ) ? m_gammaPi0->isPhoton(ppV) : -1.;
+        proto->addInfo( LHCb::ProtoParticle::additionalInfo::IsPhoton, val );
+        if( UNLIKELY( msgLevel(MSG::DEBUG) ) )
+          debug() << "UPDATING IsPhoton : "
+                  << temp << " ---> " << proto->info(LHCb::ProtoParticle::additionalInfo::IsPhoton,-1.)
+                  << " (" << proto->hasInfo(LHCb::ProtoParticle::additionalInfo::IsPhoton ) << ")" << endmsg;
+      }
+    }
+  }
+  return StatusCode::SUCCESS;
+}
+
+//=============================================================================
+
+// Declaration of the Algorithm Factory
+DECLARE_COMPONENT( FutureNeutralProtoParticleAddNeutralID )
+
+//=============================================================================
diff --git a/Rec/GlobalReco/src/FutureNeutralProtoParticleAddNeutralID.h b/Rec/GlobalReco/src/FutureNeutralProtoParticleAddNeutralID.h
new file mode 100644
index 0000000000000000000000000000000000000000..25f8ff023da3b36433347d68d480a269d162b9f5
--- /dev/null
+++ b/Rec/GlobalReco/src/FutureNeutralProtoParticleAddNeutralID.h
@@ -0,0 +1,42 @@
+#ifndef FUTURENEUTRALPROTOPARTICLEADDNEUTRALID_H
+#define FUTURENEUTRALPROTOPARTICLEADDNEUTRALID_H 1
+
+// Include files
+// from Gaudi
+#include "GaudiAlg/GaudiAlgorithm.h"
+#include "CaloFutureInterfaces/IFutureGammaPi0SeparationTool.h"
+#include "CaloFutureInterfaces/IFutureNeutralIDTool.h"
+#include "Event/ProtoParticle.h"
+
+/** @class FutureNeutralProtoParticleAddNeutralID FutureNeutralProtoParticleAddNeutralID.h
+ *
+ *
+ *  @author Olivier Deschamps
+ *  @date   2014-05-27
+ */
+
+class FutureNeutralProtoParticleAddNeutralID final : public GaudiAlgorithm
+{
+
+ public:
+
+  using GaudiAlgorithm::GaudiAlgorithm;
+
+  StatusCode execute() override;    ///< Algorithm execution
+
+ private:
+
+  Gaudi::Property<std::string> m_input  { this,   "Input"          , LHCb::ProtoParticleLocation::Neutrals };
+  Gaudi::Property<bool>   m_isNotE      { this,  "UpdateIsNotE"    , true    };
+  Gaudi::Property<bool>   m_isNotH      { this,  "UpdateIsNotH"    , true    };
+  Gaudi::Property<bool>   m_isPhoton    { this,  "UpdateIsPhoton"  , true    };
+  Gaudi::Property<double> m_isNotE_Pt   { this,  "MinPtIsNotE"     , 75.0    };
+  Gaudi::Property<double> m_isNotH_Pt   { this,  "MinPtIsNotH"     , 75.0    };
+  Gaudi::Property<double> m_isPhoton_Pt { this,  "MinPtIsPhoton"   ,  2000.0 };
+  ToolHandle<IFutureGammaPi0SeparationTool> m_gammaPi0  { this, "FutureGammaPi0SeparationTool" , "FutureGammaPi0SeparationTool" };
+  ToolHandle<IFutureNeutralIDTool>          m_neutralID { this, "FutureNeutralIDTool" , "FutureNeutralIDTool" };
+
+};
+
+
+#endif // FUTURENEUTRALPROTOPARTICLEADDNEUTRALID_H
diff --git a/Rec/RecConf/python/RecConf/Configuration.py b/Rec/RecConf/python/RecConf/Configuration.py
index 2343743677cff49d3f35d976669ef3d621d79167..200a650aeb1d81e7e6a07ab410ef40f6b8e397cb 100755
--- a/Rec/RecConf/python/RecConf/Configuration.py
+++ b/Rec/RecConf/python/RecConf/Configuration.py
@@ -9,9 +9,9 @@ __author__  = "Rob Lambert"
 from LHCbKernel.Configuration import *
 from TrackSys.Configuration   import *
 from GlobalReco.Configuration import *
-from Configurables import CaloProcessor
+from Configurables import CaloProcessor, CaloFutureProcessor
 
-from Configurables import ( ProcessPhase, CaloMoniDstConf,
+from Configurables import ( ProcessPhase, CaloMoniDstConf, CaloFutureMoniDstConf,
                             VeloRecMonitors, GlobalRecoChecks,
                             MuonTrackMonitorConf, MuonIDAlg )
 
@@ -24,7 +24,8 @@ class RecSysConf(LHCbConfigurableUser):
     ## Possible used Configurables
     __used_configurables__ = [ GlobalRecoConf ,
                                TrackSys       ,
-                               CaloProcessor  ]
+                               CaloProcessor  ,
+                               CaloFutureProcessor]
 
     ## Default tracking Sub-detector processing sequence (Run I )
     DefaultTrackingSubdets     = ["VELO","TT","IT","OT","Tr","Vertex"]
@@ -37,7 +38,7 @@ class RecSysConf(LHCbConfigurableUser):
     ## Default reconstruction sequence for field-on data (Run II)
     DefaultSubDetsFieldOnRun2     = ["Decoding"] + DefaultTrackingSubdetsRun2    + ["RICH","CALO","MUON","PROTO","SUMMARY"]
     ## Default reconstruction sequence for field-on data (Upgrade)
-    DefaultSubDetsFieldOnUpgrade  = ["Decoding"] + DefaultTrackingSubdetsUpgrade + ["RICH","CALO","MUON","PROTO","SUMMARY"]
+    DefaultSubDetsFieldOnUpgrade  = ["Decoding"] + DefaultTrackingSubdetsUpgrade + ["RICH","CALOFUTURE","MUON","PROTO","SUMMARY"]
     ## List of known special data processing options
     KnownSpecialData = [ "cosmics", "veloOpen", "fieldOff", "beamGas", "microBiasTrigger", "pA", "pGun"]
     ## List of DataTypes (years) for Run 2
@@ -83,11 +84,11 @@ class RecSysConf(LHCbConfigurableUser):
                 trackConf = TrackSys()
                 trSeq = trackConf.getProp("TrackingSequence")
                 if trSeq != []:
-                    DefaultSubDetsFieldOnUpgrade  = ["Decoding"] + trSeq + ["RICH","CALO",
+                    DefaultSubDetsFieldOnUpgrade  = ["Decoding"] + trSeq + ["RICH","CALOFUTURE",
                                                                             "MUON","PROTO","SUMMARY"]
                 else:
                     DefaultSubDetsFieldOnUpgrade  = ["Decoding","TrFast","TrBest","RICH",
-                                                     "CALO","MUON","PROTO","SUMMARY"]
+                                                     "CALOFUTURE","MUON","PROTO","SUMMARY"]
                 self.setProp("RecoSequence",DefaultSubDetsFieldOnUpgrade)
                 
         recoSeq = self.getProp("RecoSequence")
@@ -255,6 +256,20 @@ class RecSysConf(LHCbConfigurableUser):
             seq.Members = [caloConf.caloSequence()]
             GaudiKernel.ProcessJobOptions.PrintOff()
 
+        if "CALOFUTURE" in recoSeq:
+            import GaudiKernel.ProcessJobOptions            
+            seq  = GaudiSequencer ( 'RecoCALOFUTURESeq' )
+            caloConf=CaloFutureProcessor(
+                Context            = self.getProp('Context')       ,
+                OutputLevel        = self.getProp('OutputLevel')    ,
+                UseTracks          = True                           ,
+                EnableOnDemand     = False                          ,
+                DataType           = self.getProp ('DataType')      
+                )
+            GaudiKernel.ProcessJobOptions.PrintOn(force=True)
+            seq.Members = [caloConf.caloFutureSequence()]
+            GaudiKernel.ProcessJobOptions.PrintOff()
+
         # MUON
         if "MUON" in recoSeq:
             from MuonID import ConfiguredMuonIDs
@@ -297,6 +312,7 @@ class RecMoniConf(LHCbConfigurableUser):
 
     ## Possible used Configurables
     __used_configurables__ = [ CaloMoniDstConf,
+                               CaloFutureMoniDstConf,
                                VeloRecMonitors,
                                MuonTrackMonitorConf,
                                GlobalRecoChecks ]
@@ -331,7 +347,8 @@ class RecMoniConf(LHCbConfigurableUser):
        }
 
     ## Known monitoring sequences, all run by default
-    KnownMoniSubdets        = ["CALO","RICH","MUON","VELO","OT","ST"]
+
+    KnownMoniSubdets        = ["CALO","RICH","MUON","VELO","OT","ST"]        
     KnownMoniGeneral        = ["GENERAL","Tr","PROTO","Hlt"]
     KnownMoniSubdets        = KnownMoniSubdets + KnownMoniGeneral
     KnownExpertMoniSubdets  = KnownMoniSubdets+["TT","IT"]
@@ -353,7 +370,10 @@ class RecMoniConf(LHCbConfigurableUser):
         if [det for det in ['IT', 'TT'] if det in dets]:
             dets.append("ST")
         if [det for det in ['SPD', 'PRS', 'ECAL', 'HCAL'] if det in dets]:
-            dets.append("CALO")
+            if self.getProp("DataType") == "Upgrade":
+                dets.append("CALOFUTURE")
+            else:
+                dets.append("CALO")
         if [det for det in ['RICH1','RICH2','RICH1PMT','RICH2PMT'] if det in dets]:
             dets.append("RICH")
             
@@ -391,6 +411,7 @@ class RecMoniConf(LHCbConfigurableUser):
         from Configurables import ProcessPhase
         ProcessPhase("Moni").DetectorList += moniSeq
 
+
         # Histograms filled both in real and simulated data cases
         if "GENERAL" in moniSeq :
 
@@ -430,9 +451,14 @@ class RecMoniConf(LHCbConfigurableUser):
             seq.Members += [richTime]
 
             # CALO
-            caloTime = RecProcessingTimeMoni("CaloEventProcTime")
-            caloTime.Algorithms = ["RecoCALOSeq"]
-            seq.Members += [caloTime]
+            if self.getProp("DataType") == "Upgrade":
+                caloTime = RecProcessingTimeMoni("CaloFutureEventProcTime")
+                caloTime.Algorithms = ["RecoCALOFUTURESeq"]
+                seq.Members += [caloTime]
+            else:
+                caloTime = RecProcessingTimeMoni("CaloEventProcTime")
+                caloTime.Algorithms = ["RecoCALOSeq"]
+                seq.Members += [caloTime]
 
             # MUON
             muonTime = RecProcessingTimeMoni("MuonEventProcTime")
@@ -464,6 +490,22 @@ class RecMoniConf(LHCbConfigurableUser):
             self.setOtherProps(caloMoni,["Histograms"])
             GaudiKernel.ProcessJobOptions.PrintOff()
 
+        if "CALOFUTURE" in moniSeq :
+            import GaudiKernel.ProcessJobOptions
+            GaudiKernel.ProcessJobOptions.PrintOn(force=True)
+            from Configurables import GaudiSequencer
+            seq = GaudiSequencer( "MoniCALOFUTURESeq")
+            noSPDPRS = True
+            if [det for det in ['SPD','PRS'] if det in dets]:
+                noSPDPRS = False
+            caloMoni = CaloFutureMoniDstConf( MonitorSequence    = seq,
+                                              OutputLevel = self.getProp('OutputLevel'),
+                                              Context = 'Offline',
+                                              NoSpdPrs = noSPDPRS)
+            caloMoni.printConf()
+            self.setOtherProps(caloMoni,["Histograms"])
+            GaudiKernel.ProcessJobOptions.PrintOff()
+
         if "VELO" in moniSeq :
             from Configurables import GaudiSequencer
             self.setOtherProps(VeloRecMonitors(),["Histograms","OutputLevel"])