diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 4e9c688312e4180f48f5f64f0ac341345ac41f9e..9de6be441a32f781e3d62222f2c6134e0dc3bb78 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -38,7 +38,7 @@ test_unittest:
   tags:
     - k8s-cvmfs
   script:
-    - set +e && export ALRB_CONT_RUNPAYLOAD="asetup --input=asetup.faser Athena,24.0.41; source `find . -name 'setup.sh'`; cd build; ctest -j3 --output-on-failure" && set -e
+    - set +e && export ALRB_CONT_RUNPAYLOAD="asetup --input=asetup.faser Athena,24.0.41; source `find . -name 'setup.sh'`; cd build; ctest -j3" && set -e
     - echo $ALRB_CONT_RUNPAYLOAD
     - set +e && source ${ATLAS_LOCAL_ROOT_BASE}/user/atlasLocalSetup.sh -c alma9 && set -e
   dependencies:
diff --git a/Calorimeter/CaloDetDescr/CaloIdDictFiles/data/IdDictCalorimeter.xml b/Calorimeter/CaloDetDescr/CaloIdDictFiles/data/IdDictCalorimeter.xml
index 37bed2379f814331055b953646980bbd9e3b444e..8e8b3bb5fb98e203fa5da7a5eeecd67b70ea3b65 100644
--- a/Calorimeter/CaloDetDescr/CaloIdDictFiles/data/IdDictCalorimeter.xml
+++ b/Calorimeter/CaloDetDescr/CaloIdDictFiles/data/IdDictCalorimeter.xml
@@ -1,7 +1,8 @@
 <IdDictionary name="Calorimeter">
 
   <field name="part" >
-    <label name="Ecal" value="1" />
+    <label name="Ecal"   value="1" />
+    <label name="CaloNu" value="2" />
   </field>
 
   <field name="row">
@@ -23,4 +24,12 @@
     <range field="module"     values="Starboard Port" wraparound="FALSE" />
     <range field="pmt"        minvalue="0" maxvalue="1" />
   </region>
+
+  <region>
+    <range field="part"       value="CaloNu" />
+    <range field="row"        values="Bottom Top" wraparound="FALSE" />
+    <range field="module"     values="Starboard Port" wraparound="FALSE" />
+    <range field="pmt"        minvalue="0" maxvalue="0" />
+  </region>    
+
 </IdDictionary>
diff --git a/Calorimeter/CaloDetDescr/CaloIdDictFiles/data/IdDictCalorimeter_TB00.xml b/Calorimeter/CaloDetDescr/CaloIdDictFiles/data/IdDictCalorimeter_TB00.xml
index c932a0c74bfeaf9d15648d49eb6a2cfa5aeb49b8..6099442785b80501ab30124b558de98f467f8fb8 100644
--- a/Calorimeter/CaloDetDescr/CaloIdDictFiles/data/IdDictCalorimeter_TB00.xml
+++ b/Calorimeter/CaloDetDescr/CaloIdDictFiles/data/IdDictCalorimeter_TB00.xml
@@ -2,6 +2,7 @@
 
   <field name="part" >
     <label name="Ecal" value="1" />
+    <label name="CaloNu" value="2" />
   </field>
 
   <field name="row">
@@ -24,4 +25,4 @@
     <range field="module"     values="Starboard Center Port" wraparound="FALSE" />
     <range field="pmt"        minvalue="0" maxvalue="0" />
   </region>
-</IdDictionary>
\ No newline at end of file
+</IdDictionary>
diff --git a/Calorimeter/CaloDetDescr/FaserCaloIdentifier/CMakeLists.txt b/Calorimeter/CaloDetDescr/FaserCaloIdentifier/CMakeLists.txt
index 54ba749cddc246185bc3d2e161bb56663f0a925c..497b2e92d0672e8d60a4ba19c8d9e8c6740957c8 100644
--- a/Calorimeter/CaloDetDescr/FaserCaloIdentifier/CMakeLists.txt
+++ b/Calorimeter/CaloDetDescr/FaserCaloIdentifier/CMakeLists.txt
@@ -11,6 +11,7 @@ find_package( ROOT COMPONENTS Core Tree MathCore Hist RIO pthread )
 # Component(s) in the package:
 atlas_add_library( FaserCaloIdentifier
                    src/EcalID.cxx
+                   src/CaloNuID.cxx
                    PUBLIC_HEADERS FaserCaloIdentifier
                    PRIVATE_INCLUDE_DIRS ${ROOT_INCLUDE_DIRS}
                    LINK_LIBRARIES AthenaKernel FaserDetDescr IdDict Identifier
diff --git a/Calorimeter/CaloDetDescr/FaserCaloIdentifier/FaserCaloIdentifier/CaloNuID.h b/Calorimeter/CaloDetDescr/FaserCaloIdentifier/FaserCaloIdentifier/CaloNuID.h
new file mode 100644
index 0000000000000000000000000000000000000000..f3fa83d7b846b06cbd45c78805c9060ac110baa8
--- /dev/null
+++ b/Calorimeter/CaloDetDescr/FaserCaloIdentifier/FaserCaloIdentifier/CaloNuID.h
@@ -0,0 +1,540 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef CALOIDENTIFIER_CALONUID_H
+#define CALOIDENTIFIER_CALONUID_H
+/**
+ * @file CaloNuID.h
+ *
+ * @brief This is an Identifier helper class for the CaloNu
+ *  subdetector. This class is a factory for creating compact
+ *  Identifier objects and IdentifierHash or hash ids. And it also
+ *  allows decoding of these ids.
+ *
+ */
+
+//<<<<<< INCLUDES                                                       >>>>>>
+
+#include "FaserDetDescr/FaserDetectorID.h"
+#include "Identifier/Identifier.h"
+#include "Identifier/IdentifierHash.h"
+#include "Identifier/Range.h"
+#include "Identifier/IdHelper.h"
+#include "IdDict/IdDictFieldImplementation.h"
+#include "AthenaKernel/CLASS_DEF.h"
+
+#include <string>
+#include <assert.h>
+#include <algorithm>
+
+//<<<<<< PUBLIC DEFINES                                                 >>>>>>
+//<<<<<< PUBLIC CONSTANTS                                               >>>>>>
+//<<<<<< PUBLIC TYPES                                                   >>>>>>
+
+class IdDictDictionary;
+
+//<<<<<< PUBLIC VARIABLES                                               >>>>>>
+//<<<<<< PUBLIC FUNCTIONS                                               >>>>>>
+//<<<<<< CLASS DECLARATIONS                                             >>>>>>
+
+/**
+ **  @class CaloNuID
+ **  
+ **  @brief This is an Identifier helper class for the CaloNu
+ **  subdetector. This class is a factory for creating compact
+ **  Identifier objects and IdentifierHash or hash ids. And it also
+ **  allows decoding of these ids.
+ **
+ **  Definition and the range of values for the levels of the
+ **  identifier are:
+ **
+ ** @verbatim
+ **    element           range              meaning
+ **    -------           -----              -------
+ **
+ **    row              0 - 1               vertical location of module (bottom, top)
+ **    module           0 - 1               horizontal location of module in row (left, right)
+ **    pmt              0                   single pmt per module
+ **
+ ** @endverbatim
+ **
+ */
+class CaloNuID : public FaserDetectorID
+{
+public:
+        
+    /// @name public typedefs
+    //@{
+    typedef Identifier::size_type                       size_type; 
+    typedef std::vector<Identifier>::const_iterator     const_id_iterator;
+    typedef MultiRange::const_identifier_factory        const_expanded_id_iterator;
+    //@}
+
+    /// @name strutors
+    //@{
+    CaloNuID(void);
+    virtual ~CaloNuID(void) = default;
+    //@}
+        
+    /// @name Creators for module ids and pmt ids
+    //@{
+    /// For a single row
+    Identifier  row_id ( int row ) const;
+    Identifier  row_id ( int row,
+                         bool checks) const;
+
+    /// For a row from a module id
+    Identifier  row_id ( const Identifier& module_id ) const;
+
+    /// For a single module
+    Identifier  module_id ( int row, 
+                            int module ) const;
+    Identifier  module_id ( int row, 
+                            int module,
+                            bool checks) const;
+
+    /// For a single module from a pmt id
+    Identifier  module_id ( const Identifier& pmt_id ) const;
+
+    /// From hash - optimized
+    Identifier  module_id ( IdentifierHash module_hash ) const;
+
+    /// For an individual pmt
+    Identifier  pmt_id ( int row, 
+                         int module, 
+                         int pmt ) const; 
+
+    Identifier  pmt_id ( int row, 
+                         int module, 
+                         int pmt,
+                         bool check ) const; 
+
+    Identifier  pmt_id ( const Identifier& module_id, 
+                         int pmt ) const;
+
+    //@}
+
+
+    /// @name Hash table maximum sizes
+    //@{
+    size_type   module_hash_max         (void) const;
+    size_type   pmt_hash_max            (void) const;
+    //@}
+
+    /// @name Access to all ids
+    //@{
+    /// Iterators over full set of ids. Module iterator is sorted
+    const_id_iterator   module_begin                     (void) const;
+    const_id_iterator   module_end                       (void) const;
+    /// For pmt ids, only expanded id iterators are available. Use
+    /// following "pmt_id" method to obtain a compact identifier
+    const_expanded_id_iterator  pmt_begin             (void) const;  
+    const_expanded_id_iterator  pmt_end               (void) const;
+    //@}
+    
+
+    /// @name Optimized accessors  - ASSUMES id IS an CaloNu id, i.e. NOT other
+    //@{
+    /// module hash from id - optimized
+    IdentifierHash      module_hash      (Identifier module_id) const;
+
+    /// Values of different levels (failure returns 0)
+    int         row       (const Identifier& id) const;  
+    int         module    (const Identifier& id) const; 
+    int         pmt       (const Identifier& id) const; 
+
+    /// Max/Min values for each field (-999 == failure)
+    int         row_max      (const Identifier& id) const;
+    int         module_max   (const Identifier& id) const;
+    int         pmt_max      (const Identifier& id) const;
+    //@}
+
+    /// @name module navigation
+    //@{
+        // /// Previous in z
+        // int get_prev_in_z(const IdentifierHash& id, IdentifierHash& prev) const;
+        // /// Next in z
+        // int get_next_in_z(const IdentifierHash& id, IdentifierHash& next) const;
+        /// Previous module hash in phi (return == 0 for neighbor found)
+        int get_prev_in_phi (const IdentifierHash& id, IdentifierHash& prev) const;
+        /// Next module hash in phi (return == 0 for neighbor found)
+        int get_next_in_phi (const IdentifierHash& id, IdentifierHash& next) const;
+        /// Previous module hash in eta (return == 0 for neighbor found)
+        int get_prev_in_eta (const IdentifierHash& id, IdentifierHash& prev) const;
+        // /// Next module hash in eta (return == 0 for neighbor found)
+        int get_next_in_eta (const IdentifierHash& id, IdentifierHash& next) const;
+    // /// Wafer hash on other side
+    // int         get_other_side  (const IdentifierHash& id, IdentifierHash& other) const;
+    
+    // Check limits
+    bool        is_phi_module_max(const Identifier& id) const;
+    bool        is_phi_module_min(const Identifier& id) const;
+    bool        is_eta_module_min(const Identifier& id) const;
+    bool        is_eta_module_max(const Identifier& id) const;
+    //@}
+
+    /// @name contexts to distinguish module id from pmt id
+    //@{
+    IdContext   module_context          (void) const;
+    IdContext   pmt_context             (void) const;
+    //@}
+
+    /// @name methods from abstract interface - slower than opt version
+    //@{
+    /// Create compact id from hash id (return == 0 for OK)
+    virtual int         get_id          (const IdentifierHash& hash_id,
+                                         Identifier& id,
+                                         const IdContext* context = 0) const;
+    
+    /// Create hash id from compact id (return == 0 for OK)
+    virtual int         get_hash        (const Identifier& id, 
+                                         IdentifierHash& hash_id,
+                                         const IdContext* context = 0) const;
+    //@}
+
+    /// Return the lowest bit position used in the channel id
+    int                 base_bit        (void) const;
+
+    /// Calculate a channel offset between the two identifiers.
+    Identifier::diff_type calc_offset(const Identifier& base,
+                                      const Identifier& target) const;
+
+    /// Create an identifier with a given base and channel offset
+    Identifier pmt_id_offset(const Identifier& base,
+                             Identifier::diff_type offset) const;
+
+    /// @name interaction with id dictionary
+    //@{
+    /// Create strip Identifier from expanded id, which is returned by the
+    /// id_iterators
+    Identifier          pmt_id        (const ExpandedIdentifier& pmt_id) const;
+
+    /// Create expanded id from compact id (return == 0 for OK)
+    void                get_expanded_id (const Identifier& id,
+                                         ExpandedIdentifier& exp_id,
+                                         const IdContext* context = 0) const;
+
+    /// Initialization from the identifier dictionary
+    virtual int         initialize_from_dictionary(const IdDictMgr& dict_mgr);
+
+    /// Tests of packing
+    void        test_module_packing      (void) const;
+    //@}
+    
+private:
+        
+    enum {NOT_VALID_HASH        = 64000};
+
+    typedef std::vector<Identifier>     id_vec;
+    typedef id_vec::const_iterator      id_vec_it;
+    typedef std::vector<unsigned short> hash_vec;
+    typedef hash_vec::const_iterator    hash_vec_it;
+
+    void module_id_checks ( int row, 
+                            int module ) const; 
+
+    void pmt_id_checks ( int row, 
+                         int module, 
+                         int pmt ) const;
+
+
+    int         initLevelsFromDict(void);
+
+    int         init_hashes(void);
+
+    int         init_neighbors(void);
+
+    // Temporary method for adapting an identifier for the MultiRange
+    // check - MR is missing the InnerDetector level
+    // Identifier  idForCheck      (const Identifier& id) const;
+
+    size_type                   m_calonu_region_index;
+    size_type                   m_CALO_INDEX;
+    size_type                   m_CALONU_INDEX;
+    size_type                   m_ROW_INDEX;
+    size_type                   m_MODULE_INDEX;
+    size_type                   m_PMT_INDEX;
+
+    const IdDictDictionary*     m_dict;
+    MultiRange                  m_full_module_range;
+    MultiRange                  m_full_pmt_range;
+    size_type                   m_module_hash_max;
+    size_type                   m_pmt_hash_max;
+    // Range::field                m_barrel_field;
+    id_vec                      m_module_vec;
+    // hash_vec                    m_prev_z_plate_vec;
+    // hash_vec                    m_next_z_plate_vec;
+    hash_vec                    m_prev_phi_module_vec;
+    hash_vec                    m_next_phi_module_vec;
+    hash_vec                    m_prev_eta_module_vec;
+    hash_vec                    m_next_eta_module_vec;   
+    // bool 			m_hasRows	;
+
+    IdDictFieldImplementation   m_calo_impl	;
+    IdDictFieldImplementation   m_calonu_impl	;
+    IdDictFieldImplementation   m_row_impl	;
+    IdDictFieldImplementation   m_module_impl	;
+    IdDictFieldImplementation   m_pmt_impl	;
+};
+    
+
+//<<<<<< INLINE PUBLIC FUNCTIONS                                        >>>>>>
+
+/////////////////////////////////////////////////////////////////////////////
+//<<<<<< INLINE MEMBER FUNCTIONS                                        >>>>>>
+/////////////////////////////////////////////////////////////////////////////
+
+//using the macros below we can assign an identifier (and a version)
+//This is required and checked at compile time when you try to record/retrieve
+CLASS_DEF(CaloNuID, 167327975, 1)
+
+//----------------------------------------------------------------------------
+inline Identifier  
+CaloNuID::row_id ( int row, 
+                 bool checks) const
+{
+    
+    // Build identifier
+    Identifier result((Identifier::value_type)0);
+
+    // Pack fields independently
+    m_calo_impl.pack        (calo_field_value(),    result);
+    m_calonu_impl.pack      (calonu_field_value(),  result);
+    m_row_impl.pack         (row,             result);
+    // Do checks
+    if(checks) 
+    {
+        module_id_checks ( row, 0 );
+    }
+
+    return result;
+}
+
+inline Identifier  
+CaloNuID::row_id ( int row ) const 
+{
+  return row_id (row, do_checks());
+}
+
+//----------------------------------------------------------------------------
+inline Identifier  
+CaloNuID::row_id ( const Identifier& module_id ) const
+{
+    Identifier result(module_id);
+    //  Reset the module and pmt fields
+    m_module_impl.reset(result);
+    m_pmt_impl.reset(result);
+    return (result);
+}
+
+//----------------------------------------------------------------------------
+inline Identifier
+CaloNuID::module_id ( int row,  
+                   int module, 
+                   bool checks) const
+{
+    // Build identifier
+    Identifier result((Identifier::value_type)0);
+
+    // Pack fields independently
+    m_calo_impl.pack     (calo_field_value(), result);
+    m_calonu_impl.pack     (calonu_field_value(), result);
+    m_row_impl.pack      (row,                result);
+    m_module_impl.pack   (module,             result);
+
+    // Do checks
+    if(checks) 
+    {
+        module_id_checks ( row, module );
+    }
+    return result;
+}
+
+inline Identifier
+CaloNuID::module_id ( int row,  
+                    int module ) const
+{
+  return module_id (row, module, do_checks());
+}
+
+//----------------------------------------------------------------------------
+inline Identifier
+CaloNuID::module_id ( const Identifier& pmt_id ) const
+{
+    Identifier result(pmt_id);
+    // reset the pmt field
+    m_pmt_impl.reset(result);
+    return (result);
+}
+
+//----------------------------------------------------------------------------
+inline Identifier  CaloNuID::module_id ( IdentifierHash module_hash ) const
+{
+    return (m_module_vec[module_hash]);
+}
+
+//----------------------------------------------------------------------------
+inline IdentifierHash      CaloNuID::module_hash      (Identifier module_id) const 
+{
+    // MsgStream log(m_msgSvc, "CaloNuID");
+    // log << MSG::VERBOSE << "m_module_vec size: " << m_module_vec.size() << endmsg;
+    // log << MSG::VERBOSE << "input id = " << module_id << endmsg;
+    // for (size_t i = 0; i < m_module_vec.size(); i++)
+    // {
+    //     log << MSG::VERBOSE << "Hash = " <<  i << " : ID = " << m_module_vec[i] << endmsg;
+    // }
+    id_vec_it it = std::lower_bound(m_module_vec.begin(), 
+                                    m_module_vec.end(), 
+                                    module_id);
+    // Require that module_id matches the one in vector
+    if (it != m_module_vec.end() && module_id == (*it)) {
+        return (it - m_module_vec.begin());
+    }
+    IdentifierHash result;
+    return (result); // return hash in invalid state
+}
+
+//----------------------------------------------------------------------------
+inline Identifier
+CaloNuID::pmt_id ( int row,  
+                 int module, 
+                 int pmt,
+                 bool checks) const
+{
+    // Build identifier
+    Identifier result((Identifier::value_type)0);
+
+    // Pack fields independently
+    m_calo_impl.pack     (calo_field_value(),  result);
+    m_calonu_impl.pack     (calonu_field_value(),  result);
+    m_row_impl.pack      (row,                 result);
+    m_module_impl.pack   (module,              result);
+    m_pmt_impl.pack      (pmt,                 result);
+
+    // Do checks
+    if(checks) {
+        pmt_id_checks ( row, module, pmt );
+    }
+    return result;
+}
+
+inline Identifier
+CaloNuID::pmt_id ( int row,  
+                 int module, 
+                 int pmt ) const
+{
+  return pmt_id (row, module, pmt, do_checks());
+}
+
+//----------------------------------------------------------------------------
+inline Identifier               
+CaloNuID::pmt_id        (const ExpandedIdentifier& id) const
+{
+    // Build identifier
+    Identifier result((Identifier::value_type)0);
+
+    // Pack fields independently
+    m_calo_impl.pack     (calo_field_value(),    result);
+    m_calonu_impl.pack     (calonu_field_value(),    result);
+    m_row_impl.pack      (id[m_ROW_INDEX],       result);
+    m_module_impl.pack   (id[m_MODULE_INDEX],    result);
+    m_pmt_impl.pack      (id[m_PMT_INDEX],       result);
+
+    // Do checks
+    if(m_do_checks) 
+    {
+       	pmt_id_checks ( id[m_ROW_INDEX],  
+                        id[m_MODULE_INDEX], 
+                       	id[m_PMT_INDEX]);    
+    }
+    return result;
+}
+
+//----------------------------------------------------------------------------
+inline Identifier  
+CaloNuID::pmt_id ( const Identifier& module_id, int pmt ) const
+{
+	// Build identifier
+    Identifier result(module_id);
+  
+    // Reset pmt and then add in value
+    m_pmt_impl.reset   (result);
+ 	m_pmt_impl.pack    (pmt, result);
+  
+    if(m_do_checks)
+    {          
+	    pmt_id_checks ( row(result), 
+		           		module(result), 
+                        pmt );
+	}
+	return result;
+}
+
+//----------------------------------------------------------------------------
+inline Identifier::diff_type
+CaloNuID::calc_offset(const Identifier& base, const Identifier& target) const
+{
+  Identifier::diff_type tval = static_cast<Identifier::diff_type>(target.get_compact() >> base_bit());
+  Identifier::diff_type bval = static_cast<Identifier::diff_type>(base.get_compact() >> base_bit());
+  return (tval - bval);
+}
+
+//----------------------------------------------------------------------------
+inline Identifier
+CaloNuID::pmt_id_offset(const Identifier& base,
+                        Identifier::diff_type offset) const
+{
+  Identifier::value_type bval = base.get_compact() >> base_bit();
+  return Identifier((bval + offset) << base_bit());
+}
+
+//----------------------------------------------------------------------------
+inline int
+CaloNuID::base_bit ( void ) const
+{
+  int base = static_cast<int>(m_pmt_impl.shift()); // lowest field base
+  return (base > 32) ? 32 : base;
+  // max base is 32 so we can still read old strip id's and differences
+  // from non-SLHC releases.
+}
+
+//----------------------------------------------------------------------------
+inline IdContext        
+CaloNuID::module_context           (void) const
+{
+    ExpandedIdentifier id;
+    return (IdContext(id, 0, m_MODULE_INDEX));
+}
+
+//----------------------------------------------------------------------------
+inline IdContext        
+CaloNuID::pmt_context   (void) const
+{
+    ExpandedIdentifier id;
+    return (IdContext(id, 0, m_PMT_INDEX));
+}
+
+//----------------------------------------------------------------------------
+inline int 
+CaloNuID::row       (const Identifier& id) const
+{
+    return (m_row_impl.unpack(id));
+}
+
+//----------------------------------------------------------------------------
+inline int 
+CaloNuID::module     (const Identifier& id) const
+{
+    return (m_module_impl.unpack(id));
+}
+
+//----------------------------------------------------------------------------
+inline int 
+CaloNuID::pmt           (const Identifier& id) const
+{
+    return (m_pmt_impl.unpack(id));
+}
+
+
+#endif // CALOIDENTIFIER_CALONUID_H
diff --git a/Calorimeter/CaloDetDescr/FaserCaloIdentifier/FaserCaloIdentifier/FaserCaloIdentifierDict.h b/Calorimeter/CaloDetDescr/FaserCaloIdentifier/FaserCaloIdentifier/FaserCaloIdentifierDict.h
index 2d8825f50fa3aec58ad56e3a4bd161774a429714..42b8c1655692e8d116c7acf46e840695d026e506 100644
--- a/Calorimeter/CaloDetDescr/FaserCaloIdentifier/FaserCaloIdentifier/FaserCaloIdentifierDict.h
+++ b/Calorimeter/CaloDetDescr/FaserCaloIdentifier/FaserCaloIdentifier/FaserCaloIdentifierDict.h
@@ -13,5 +13,6 @@
 #define FASERCALOIDENTIFIER_CALOIDENTIFIERDICT_H 
 
 #include "FaserCaloIdentifier/EcalID.h"
+#include "FaserCaloIdentifier/CaloNuID.h"
 
 #endif // FASERCALOIDENTIFIER_CALOIDENTIFIERDICT_H 
diff --git a/Calorimeter/CaloDetDescr/FaserCaloIdentifier/FaserCaloIdentifier/selection.xml b/Calorimeter/CaloDetDescr/FaserCaloIdentifier/FaserCaloIdentifier/selection.xml
index d66c6ce0e07e175229e53c2dd8e4554e1f5d55cd..6b475bbc17b1be6fd0e8f7084a0d887dfe20e4f4 100644
--- a/Calorimeter/CaloDetDescr/FaserCaloIdentifier/FaserCaloIdentifier/selection.xml
+++ b/Calorimeter/CaloDetDescr/FaserCaloIdentifier/FaserCaloIdentifier/selection.xml
@@ -1,3 +1,4 @@
 <lcgdict>
   <class name="EcalID" />
+  <class name="CaloNuID" />
 </lcgdict>
diff --git a/Calorimeter/CaloDetDescr/FaserCaloIdentifier/src/CaloNuID.cxx b/Calorimeter/CaloDetDescr/FaserCaloIdentifier/src/CaloNuID.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..586c006d98a7f292f1dabef96de5dbcc06e233c8
--- /dev/null
+++ b/Calorimeter/CaloDetDescr/FaserCaloIdentifier/src/CaloNuID.cxx
@@ -0,0 +1,865 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+/***************************************************************************
+ Calorimeter identifier package
+ -------------------------------------------
+***************************************************************************/
+
+//<<<<<< INCLUDES                                                       >>>>>>
+#include "GaudiKernel/MsgStream.h"
+
+#include "FaserCaloIdentifier/CaloNuID.h"
+#include "Identifier/IdentifierHash.h"
+#include "IdDict/IdDictDefs.h"  
+#include <set>
+#include <algorithm>
+#include <iostream>
+
+//<<<<<< PRIVATE DEFINES                                                >>>>>>
+//<<<<<< PRIVATE CONSTANTS                                              >>>>>>
+//<<<<<< PRIVATE TYPES                                                  >>>>>>
+//<<<<<< PRIVATE VARIABLE DEFINITIONS                                   >>>>>>
+//<<<<<< PUBLIC VARIABLE DEFINITIONS                                    >>>>>>
+//<<<<<< CLASS STRUCTURE INITIALIZATION                                 >>>>>>
+//<<<<<< PRIVATE FUNCTION DEFINITIONS                                   >>>>>>
+//<<<<<< PUBLIC FUNCTION DEFINITIONS                                    >>>>>>
+//<<<<<< MEMBER FUNCTION DEFINITIONS                                    >>>>>>
+
+
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+
+
+CaloNuID::CaloNuID(void)
+        :
+        m_calonu_region_index(0),
+        m_CALO_INDEX(0),
+        m_CALONU_INDEX(1),
+        m_ROW_INDEX(2),
+        m_MODULE_INDEX(3),
+        m_PMT_INDEX(4),
+        m_dict(0),
+        m_module_hash_max(0),
+        m_pmt_hash_max(0)
+{
+}
+
+void
+CaloNuID::module_id_checks ( int row,  
+                           int module ) const
+{
+
+    // Check that id is within allowed range
+
+    // Fill expanded id
+    ExpandedIdentifier id;
+    id << calo_field_value() << calonu_field_value()
+       << row << module;
+
+    if (!m_full_module_range.match(id)) {  // module range check is sufficient
+        MsgStream log(m_msgSvc, "CaloNuID");
+        log << MSG::ERROR << " CaloNuID::module_id result is NOT ok. ID, range "
+            << (std::string)id <<  " " << (std::string)m_full_module_range << endmsg;
+    }
+}
+
+void
+CaloNuID::pmt_id_checks ( int row,  
+                        int module, 
+                        int pmt) const
+{
+
+    // Check that id is within allowed range
+
+    // Fill expanded id
+    ExpandedIdentifier id;
+    id << calo_field_value() << calonu_field_value()
+       << row << module << pmt;
+
+    if (!m_full_pmt_range.match(id)) {  
+        MsgStream log(m_msgSvc, "CaloNuID");
+        log << MSG::ERROR << " CaloNuID::pmt_id result is NOT ok. ID, range "
+            << (std::string)id << " " << (std::string)m_full_pmt_range << std::endl;
+    }
+}
+
+int 
+CaloNuID::row_max(const Identifier& id) const
+{
+    // get max from dictionary
+    ExpandedIdentifier expId;
+    IdContext module_context1 = module_context();
+    get_expanded_id(id, expId, &module_context1);
+    for (unsigned int i = 0; i < m_full_module_range.size(); ++i) {
+        const Range& range = m_full_module_range[i];
+        if (range.match(expId)) {
+            const Range::field& row_field = range[m_ROW_INDEX];
+            if (row_field.has_maximum()) {
+                return (row_field.get_maximum());
+            }
+        }
+    }
+    return (-999);  // default
+}
+
+int     
+CaloNuID::pmt_max       (const Identifier& id) const
+{
+    ExpandedIdentifier expId;
+    IdContext row_context(expId, 0, m_ROW_INDEX);
+    get_expanded_id(id, expId, &row_context);
+    int result = -999;
+    for (unsigned int i = 0; i < m_full_pmt_range.size(); ++i) {
+        const Range& range = m_full_pmt_range[i];
+        if (range.match(expId)) {
+            const Range::field& pmt_field = range[m_PMT_INDEX];
+            if (pmt_field.has_maximum()) {
+                int pmt = pmt_field.get_maximum();
+                if (result < pmt) result = pmt;
+            }
+        }
+    }
+    return (result);
+}
+
+int 
+CaloNuID::module_max(const Identifier& id) const
+{
+    // get max from dictionary
+    ExpandedIdentifier expId;
+    IdContext module_context1 = module_context();
+    get_expanded_id(id, expId, &module_context1);
+    for (unsigned int i = 0; i < m_full_module_range.size(); ++i) {
+        const Range& range = m_full_module_range[i];
+        if (range.match(expId)) {
+            const Range::field& module_field = range[m_MODULE_INDEX];
+            if (module_field.has_maximum()) {
+                return (module_field.get_maximum());
+            }
+        }
+    }
+    return -1;
+}
+
+int
+CaloNuID::initialize_from_dictionary(const IdDictMgr& dict_mgr)
+{
+    MsgStream log(m_msgSvc, "CaloNuID");
+    log << MSG::INFO << "Initialize from dictionary" << endmsg;
+  
+    // Check whether this helper should be reinitialized
+    if (!reinitialize(dict_mgr)) {
+        log << MSG::INFO << "Request to reinitialize not satisfied - tags have not changed" << endmsg;
+        return (0);
+    }
+    else {
+        if (m_msgSvc) {
+            log << MSG::DEBUG << "(Re)initialize" << endmsg;
+        }
+        else {
+            std::cout  << " DEBUG (Re)initialize" << std::endl;
+        }
+    }
+
+    // init base object
+    if(FaserDetectorID::initialize_from_dictionary(dict_mgr)) return (1);
+
+    // Register version of InnerDetector dictionary 
+    if (register_dict_tag(dict_mgr, "Calorimeter")) return(1);
+
+    m_dict = dict_mgr.find_dictionary ("Calorimeter"); 
+    if(!m_dict) {
+        log << MSG::ERROR << " CaloNuID::initialize_from_dict - cannot access Calorimeter dictionary " << endmsg;
+        return 1;
+    }
+
+    // Initialize the field indices
+    if(initLevelsFromDict()) return (1);
+
+    //
+    // Build multirange for the valid set of identifiers
+    //
+
+
+    // Find value for the field Scintillator
+    const IdDictDictionary* faserDict = dict_mgr.find_dictionary ("FASER"); 
+    int caloField   = -1;
+    if (faserDict->get_label_value("subdet", "Calorimeter", caloField)) {
+        log << MSG::ERROR << "Could not get value for label 'Calorimeter' of field 'subdet' in dictionary " 
+            << faserDict->m_name
+            << endmsg;
+        return (1);
+    }
+
+    // Find value for the field CaloNu
+    int calonuField   = -1;
+    if (m_dict->get_label_value("part", "CaloNu", calonuField)) {
+        log << MSG::ERROR << "Could not get value for label 'CaloNu' of field 'part' in dictionary " 
+            << m_dict->m_name
+            << endmsg;
+        return (1);
+    }
+    if (m_msgSvc) {
+        log << MSG::DEBUG << " CaloNuID::initialize_from_dict " 
+            << "Found field values: CaloNu "  
+            << calonuField
+            << std::endl;
+    }
+    else {
+        std::cout << " DEBUG CaloNuID::initialize_from_dict " 
+                  << "Found field values: CaloNu "  
+                  << calonuField
+                  << std::endl;
+    }
+    
+    // Set up id for region and range prefix
+    ExpandedIdentifier region_id;
+    region_id.add(caloField);
+    region_id.add(calonuField);
+    Range prefix;
+    m_full_module_range = m_dict->build_multirange(region_id, prefix, "module");
+    m_full_pmt_range = m_dict->build_multirange(region_id, prefix);
+
+    // Setup the hash tables
+    if(init_hashes()) return (1);
+
+    // Setup hash tables for finding neighbors
+    if(init_neighbors()) return (1);
+    
+    if (m_msgSvc) {
+        log << MSG::INFO << " CaloNuID::initialize_from_dict "  << endmsg;
+        log << MSG::DEBUG  
+            << "Module range -> " << (std::string)m_full_module_range
+            <<   endmsg;
+        log << MSG::DEBUG
+            << "Pmt range -> " << (std::string)m_full_pmt_range
+            << endmsg;
+    }
+    else {
+        std::cout << " INFO CaloNuID::initialize_from_dict "  << std::endl;
+        std::cout << " DEBUG  Module range -> " << (std::string)m_full_module_range
+                  <<   std::endl;
+        std::cout << " DEBUG Pmt range -> " << (std::string)m_full_pmt_range
+                  << std::endl;
+    }
+    
+    return 0;
+}
+
+int
+CaloNuID::init_hashes(void)
+{
+
+    //
+    // create a vector(s) to retrieve the hashes for compact ids. For
+    // the moment, we implement a hash for modules but NOT for pmts
+    //
+    MsgStream log(m_msgSvc, "CaloNuID");
+    // module hash
+    m_module_hash_max = m_full_module_range.cardinality();
+    m_module_vec.resize(m_module_hash_max);
+    unsigned int nids = 0;
+    std::set<Identifier> ids;
+    for (unsigned int i = 0; i < m_full_module_range.size(); ++i) {
+        const Range& range = m_full_module_range[i];
+        Range::const_identifier_factory first = range.factory_begin();
+        Range::const_identifier_factory last  = range.factory_end();
+        for (; first != last; ++first) {
+            const ExpandedIdentifier& exp_id = (*first);
+            Identifier id = module_id(exp_id[m_ROW_INDEX],
+                                      exp_id[m_MODULE_INDEX]); 
+            if(!(ids.insert(id)).second) {
+                log << MSG::ERROR << " CaloNuID::init_hashes "
+                    << " Error: duplicated id for module id. nid " << nids
+                    << " compact id " << id.getString()
+                    << " id " << (std::string)exp_id << endmsg;
+                return (1);
+            }
+            nids++;
+        }
+    }
+    if(ids.size() != m_module_hash_max) {
+        log << MSG::ERROR << " CaloNuID::init_hashes "
+            << " Error: set size NOT EQUAL to hash max. size " << ids.size()
+            << " hash max " << m_module_hash_max 
+            << endmsg;
+        return (1);
+    }
+
+    nids = 0;
+    std::set<Identifier>::const_iterator first = ids.begin();
+    std::set<Identifier>::const_iterator last  = ids.end();
+    for (; first != last && nids < m_module_vec.size(); ++first) {
+        m_module_vec[nids] = (*first);
+        nids++;
+    }
+
+    // pmt hash - we do not keep a vec for the pmts
+    m_pmt_hash_max = m_full_pmt_range.cardinality();
+
+    return (0);
+}
+
+    // int
+    // CaloNuID::get_prev_in_z(const IdentifierHash& id, IdentifierHash& prev) const
+    // {
+    //     unsigned short index = id;
+    //     if (index < m_prev_z_module_vec.size())
+    //     {
+    //         if (m_prev_z_module_vec[index] == NOT_VALID_HASH) return (1);
+    //         prev = m_prev_z_module_vec[index];
+    //         return (0);
+    //     }
+    //     return (1);
+    // }
+
+    // int
+    // CaloNuID::get_next_in_z(const IdentifierHash& id, IdentifierHash& next) const
+    // {
+    //     unsigned short index = id;
+    //     if (index < m_next_z_module_vec.size())
+    //     {
+    //         if (m_next_z_module_vec[index] == NOT_VALID_HASH) return (1);
+    //         next = m_next_z_module_vec[index];
+    //         return (0);
+    //     }
+    //     return (1);
+    // }
+
+int             
+CaloNuID::get_prev_in_phi(const IdentifierHash& id, IdentifierHash& prev) const
+{
+    unsigned short index = id;
+    if (index < m_prev_phi_module_vec.size()) {
+        if (m_prev_phi_module_vec[index] == NOT_VALID_HASH) return (1);
+        prev =  m_prev_phi_module_vec[index];
+        return (0);
+    }
+    return (1);
+}
+
+int             
+CaloNuID::get_next_in_phi(const IdentifierHash& id, IdentifierHash& next) const
+{
+    unsigned short index = id;
+    if (index < m_next_phi_module_vec.size()) {
+        if (m_next_phi_module_vec[index] == NOT_VALID_HASH) return (1);
+        next =  m_next_phi_module_vec[index];
+        return (0);
+    }
+    return (1);
+}
+
+int             
+CaloNuID::get_prev_in_eta(const IdentifierHash& id, IdentifierHash& prev) const
+{
+    unsigned short index = id;
+    if (index < m_prev_eta_module_vec.size()) {
+        if (m_prev_eta_module_vec[index] == NOT_VALID_HASH) return (1);
+        prev =  m_prev_eta_module_vec[index];
+        return (0);
+    }
+    return (1);
+}
+
+int
+CaloNuID::get_next_in_eta(const IdentifierHash& id, IdentifierHash& next) const
+{
+    unsigned short index = id;
+    if (index < m_next_eta_module_vec.size()) {
+        if (m_next_eta_module_vec[index] == NOT_VALID_HASH) return (1);
+        next =  m_next_eta_module_vec[index];
+        return (0);
+    }
+    return (1);
+}
+
+int
+CaloNuID::init_neighbors(void)
+{
+    //
+    // create a vector(s) to retrieve the hashes for compact ids for
+    // module neighbors.
+    //
+    MsgStream log(m_msgSvc, "CaloNuID");
+
+    m_prev_phi_module_vec.resize(m_module_hash_max, NOT_VALID_HASH);
+    m_next_phi_module_vec.resize(m_module_hash_max, NOT_VALID_HASH);
+    m_prev_eta_module_vec.resize(m_module_hash_max, NOT_VALID_HASH);
+    m_next_eta_module_vec.resize(m_module_hash_max, NOT_VALID_HASH);
+
+    for (unsigned int i = 0; i < m_full_module_range.size(); ++i) {
+        const Range& range = m_full_module_range[i];
+        const Range::field& phi_field = range[m_MODULE_INDEX];
+        const Range::field& eta_field = range[m_ROW_INDEX];
+        Range::const_identifier_factory first = range.factory_begin();
+        Range::const_identifier_factory last  = range.factory_end();
+        for (; first != last; ++first) {
+            const ExpandedIdentifier& exp_id = (*first);
+            ExpandedIdentifier::element_type previous_phi;
+            ExpandedIdentifier::element_type next_phi;
+            ExpandedIdentifier::element_type previous_eta;
+            ExpandedIdentifier::element_type next_eta;
+            bool pphi = phi_field.get_previous(exp_id[m_MODULE_INDEX], previous_phi);
+            bool nphi = phi_field.get_next    (exp_id[m_MODULE_INDEX], next_phi);
+            bool peta = eta_field.get_previous(exp_id[m_ROW_INDEX], previous_eta);
+            bool neta = eta_field.get_next    (exp_id[m_ROW_INDEX], next_eta);
+
+            IdContext      wcontext = module_context();
+            
+            // First get primary hash id
+            IdentifierHash hash_id;
+            Identifier id = module_id(exp_id[m_ROW_INDEX],
+                                     exp_id[m_MODULE_INDEX]); 
+            if (get_hash(id, hash_id, &wcontext)) {
+                log << MSG::ERROR << " CaloNuID::init_neighbors - unable to get hash, exp/compact "
+                    << show_to_string(id, &wcontext)
+                    << " " << (std::string)m_full_module_range << endmsg;
+                return (1);
+            }
+
+            // index for the subsequent arrays
+            unsigned short index = hash_id;
+            assert (hash_id < m_prev_phi_module_vec.size());
+            assert (hash_id < m_next_phi_module_vec.size());
+            assert (hash_id < m_prev_eta_module_vec.size());
+            assert (hash_id < m_next_eta_module_vec.size());
+            
+            if (pphi) {
+                // Get previous phi hash id
+                ExpandedIdentifier expId = exp_id;
+                expId[m_MODULE_INDEX] = previous_phi;
+                Identifier id = module_id(expId[m_ROW_INDEX],
+                                          expId[m_MODULE_INDEX]);
+                if (get_hash(id, hash_id, &wcontext)) {
+                    log << MSG::ERROR << " CaloNuID::init_neighbors - unable to get previous phi hash, exp/compact " << id.getString() << " " 
+                        << endmsg;
+                    return (1);
+                }
+                m_prev_phi_module_vec[index] = hash_id;
+            }
+            
+            if (nphi) {
+                // Get next phi hash id
+                ExpandedIdentifier expId = exp_id;
+                expId[m_MODULE_INDEX] = next_phi;
+                Identifier id = module_id(expId[m_ROW_INDEX],
+                                          expId[m_MODULE_INDEX]);
+                if (get_hash(id, hash_id, &wcontext)) {
+                    log << MSG::ERROR << " CaloNuID::init_neighbors - unable to get next phi hash, exp/compact " << id.getString() << 
+                        " " << MSG::hex << id.getString() << MSG::dec << endmsg;
+                    return (1);
+                }
+                m_next_phi_module_vec[index] = hash_id;
+            }
+            
+            if (peta) {
+                // Get previous eta hash id
+                ExpandedIdentifier expId = exp_id;
+                expId[m_ROW_INDEX] = previous_eta;
+                Identifier id = module_id(expId[m_ROW_INDEX],
+                                          expId[m_MODULE_INDEX]);
+                if (get_hash(id, hash_id, &wcontext)) {
+                    log << MSG::ERROR << " CaloNuID::init_neighbors - unable to get previous eta hash, exp/compact " << id.getString() 
+                        << " " << std::endl;
+                    return (1);
+                }
+                m_prev_eta_module_vec[index] = hash_id;
+            }
+            
+            if (neta) {
+                // Get next eta hash id
+                ExpandedIdentifier expId = exp_id;
+                expId[m_ROW_INDEX] = next_eta;
+                Identifier id = module_id(expId[m_ROW_INDEX],
+                                          expId[m_MODULE_INDEX]);
+                if (get_hash(id, hash_id, &wcontext)) {
+                    log << MSG::ERROR << " CaloNuID::init_neighbors - unable to get next eta hash, exp/compact " << id.getString() 
+                        << " " << endmsg;
+                    return (1);
+                }
+                m_next_eta_module_vec[index] = hash_id;
+            }
+            
+
+        //  std::cout << " CaloNuID::init_neighbors "
+        //            << " phi, previous, next " << id[m_MODULE_INDEX]
+        //            << " " << pphi
+        //            << " " << previous_phi
+        //            << " " << nphi
+        //            << " " << next_phi
+        //            << " eta, previous, next " << id[m_ROW_INDEX]
+        //            << " " << peta
+        //            << " " << previous_eta
+        //            << " " << neta
+        //            << " " << next_eta
+        //            << " id " << (std::string)(*first) 
+        //            << std::endl;
+        }
+    }
+    return (0);
+}
+
+
+
+int     
+CaloNuID::initLevelsFromDict()
+{
+    MsgStream log(m_msgSvc, "CaloNuID");
+    if(!m_dict) {
+        log << MSG::ERROR << " CaloNuID::initLevelsFromDict - dictionary NOT initialized " << endmsg;
+        return (1);
+    }
+    
+    // Find out which identifier field corresponds to each level. Use
+    // names to find each field/leve.
+
+    m_CALO_INDEX                = 999;
+    m_CALONU_INDEX                = 999;
+    m_ROW_INDEX                 = 999;
+    m_MODULE_INDEX              = 999;
+    m_PMT_INDEX                 = 999;    
+
+    // Save index to a CaloNu region for unpacking
+    ExpandedIdentifier id; 
+    id << calo_field_value() << calonu_field_value();
+    if (m_dict->find_region(id, m_calonu_region_index)) {
+        log << MSG::ERROR << "CaloNuID::initLevelsFromDict - unable to find calonu region index: id, reg "  
+            << (std::string)id << " " << m_calonu_region_index
+            << endmsg;
+        return (1);
+    }
+
+    // Find a CaloNu region
+    IdDictField* field = m_dict->find_field("subdet");
+    if (field) {
+        m_CALO_INDEX = field->m_index;
+    }
+    else {
+        log << MSG::ERROR << "CaloNuID::initLevelsFromDict - unable to find 'subdet' field "  << endmsg;
+        return (1);
+    }
+    field = m_dict->find_field("part");
+    if (field) {
+        m_CALONU_INDEX = field->m_index;
+    }
+    else {
+        log << MSG::ERROR << "CaloNuID::initLevelsFromDict - unable to find 'part' field "  << endmsg;
+        return (1);
+    }
+    field = m_dict->find_field("row");
+    if (field) {
+        m_ROW_INDEX = field->m_index;
+    }
+    else {
+        log << MSG::ERROR << "CaloNuID::initLevelsFromDict - unable to find 'row' field "   << endmsg;
+        return (1);
+    }
+    field = m_dict->find_field("module");
+    if (field) {
+        m_MODULE_INDEX = field->m_index;
+    }
+    else {
+        log << MSG::ERROR<< "CaloNuID::initLevelsFromDict - unable to find 'module' field "  << endmsg;
+        return (1);
+    }
+    field = m_dict->find_field("pmt");
+    if (field) {
+        m_PMT_INDEX = field->m_index;
+    }
+    else {
+        log << MSG::ERROR << "CaloNuID::initLevelsFromDict - unable to find 'pmt' field " << endmsg;    
+        return (1);
+    }
+    
+    // Set the field implementations
+
+    const IdDictRegion& region = *m_dict->m_regions[m_calonu_region_index];
+
+    m_calo_impl      = region.m_implementation[m_CALO_INDEX]; 
+    m_calonu_impl      = region.m_implementation[m_CALONU_INDEX]; 
+    m_row_impl       = region.m_implementation[m_ROW_INDEX]; 
+    m_module_impl    = region.m_implementation[m_MODULE_INDEX];
+    m_pmt_impl       = region.m_implementation[m_PMT_INDEX]; 
+
+    if (m_msgSvc) {
+        log << MSG::DEBUG << "decode index and bit fields for each level: " << endmsg;
+        log << MSG::DEBUG << "calo      "  << m_calo_impl.show_to_string() << endmsg;
+        log << MSG::DEBUG << "calonu      "  << m_calonu_impl.show_to_string() << endmsg; 
+        log << MSG::DEBUG << "row       "  << m_row_impl.show_to_string() << endmsg; 
+        log << MSG::DEBUG << "module    "  << m_module_impl.show_to_string() << endmsg; 
+        log << MSG::DEBUG << "pmt       "  << m_pmt_impl.show_to_string() << endmsg; 
+    }
+    else {
+        std::cout << " DEBUG decode index and bit fields for each level: " << std::endl;
+        std::cout << " DEBUG calo    "  << m_calo_impl.show_to_string() << std::endl;
+        std::cout << " DEBUG calonu    "  << m_calonu_impl.show_to_string() << std::endl; 
+        std::cout << " DEBUG row     "  << m_row_impl.show_to_string() << std::endl; 
+        std::cout << " DEBUG module  "  << m_module_impl.show_to_string() << std::endl;
+        std::cout << " DEBUG pmt     "  << m_pmt_impl.show_to_string() << std::endl; 
+    }
+    
+    std::cout << "calo "  << m_calo_impl.decode_index() << " " 
+              <<   (std::string)m_calo_impl.ored_field() << " " 
+              << std::hex    << m_calo_impl.mask() << " " 
+              << m_calo_impl.zeroing_mask() << " " 
+              << std::dec    << m_calo_impl.shift() << " "
+              << m_calo_impl.bits() << " "
+              << m_calo_impl.bits_offset()
+              << std::endl;
+    std::cout << "calonu "     << m_calonu_impl.decode_index() << " " 
+              <<   (std::string)m_calonu_impl.ored_field() << " " 
+              << std::hex    << m_calonu_impl.mask() << " " 
+              << m_calonu_impl.zeroing_mask() << " " 
+              << std::dec    << m_calonu_impl.shift() << " "
+              << m_calonu_impl.bits() << " "
+              << m_calonu_impl.bits_offset()
+              << std::endl;
+    std::cout << "row "<< m_row_impl.decode_index() << " " 
+              <<   (std::string)m_row_impl.ored_field() << " " 
+              << std::hex    << m_row_impl.mask() << " " 
+              << m_row_impl.zeroing_mask() << " " 
+              << std::dec    << m_row_impl.shift() << " "
+              << m_row_impl.bits() << " "
+              << m_row_impl.bits_offset()
+              << std::endl;
+    std::cout << "module "    << m_module_impl.decode_index() << " " 
+              <<   (std::string)m_module_impl.ored_field() << " " 
+              << std::hex    << m_module_impl.mask() << " " 
+              << m_module_impl.zeroing_mask() << " " 
+              << std::dec    << m_module_impl.shift() << " "
+              << m_module_impl.bits() << " "
+              << m_module_impl.bits_offset()
+              << std::endl;
+    std::cout << "pmt"   << m_pmt_impl.decode_index() << " " 
+              <<   (std::string)m_pmt_impl.ored_field() << " " 
+              << std::hex    << m_pmt_impl.mask() << " " 
+              << m_pmt_impl.zeroing_mask() << " " 
+              << std::dec    << m_pmt_impl.shift() << " "
+              << m_pmt_impl.bits() << " "
+              << m_pmt_impl.bits_offset()
+              << std::endl;
+
+    return (0);
+}
+
+CaloNuID::size_type       
+CaloNuID::module_hash_max (void) const
+{
+    return m_module_hash_max;
+}
+
+CaloNuID::size_type       
+CaloNuID::pmt_hash_max (void) const
+{
+    return m_pmt_hash_max;
+}
+
+CaloNuID::const_id_iterator       CaloNuID::module_begin             (void) const
+{
+    return (m_module_vec.begin());
+}
+
+CaloNuID::const_id_iterator       CaloNuID::module_end               (void) const
+{
+    return (m_module_vec.end());
+}
+
+CaloNuID::const_expanded_id_iterator      CaloNuID::pmt_begin     (void) const
+{
+    return (m_full_pmt_range.factory_begin());
+}
+
+CaloNuID::const_expanded_id_iterator      CaloNuID::pmt_end       (void) const
+{
+    return (m_full_pmt_range.factory_end());
+}
+
+// From hash get Identifier
+int     
+CaloNuID::get_id          (const IdentifierHash& hash_id,
+                         Identifier& id,
+                         const IdContext* context) const
+{
+
+    int result = 1;
+    id.clear();
+
+    size_t begin = (context) ? context->begin_index(): 0;
+    // cannot get hash if end is 0:
+    size_t end   = (context) ? context->end_index()  : 0; 
+    if (0 == begin) { 
+        // No hashes yet for ids with prefixes
+        if (m_MODULE_INDEX == end) {
+            if (hash_id < (unsigned int)(m_module_vec.end() - m_module_vec.begin())) {
+                id = m_module_vec[hash_id];
+                result = 0;
+            }
+        }
+        else if (m_PMT_INDEX == end) {
+            // Do not know how to calculate strip id from hash yet!!
+            std::cout << "Do not know how to calculate pmt id from hash yet!!" << std::endl;
+        }
+    }
+    return (result);
+}
+
+void
+CaloNuID::get_expanded_id (const Identifier& id,
+                         ExpandedIdentifier& exp_id,
+                         const IdContext* context) const
+{
+    exp_id.clear();
+    exp_id << calo_field_value()
+           << calonu_field_value()
+           << row(id)
+           << module(id);
+    if(!context || context->end_index() == m_PMT_INDEX) 
+    {
+       	exp_id << pmt(id);
+    }
+}
+
+int     
+CaloNuID::get_hash        (const Identifier& id, 
+                         IdentifierHash& hash_id,
+                         const IdContext* context) const
+{
+
+    // Get the hash code from either a vec (for module) or calculate
+    // it (pmts). For the former, we convert to compact and call
+    // get_hash again. For the latter, we calculate the hash from the
+    // Identifier.
+
+    int result = 1;
+    hash_id = 0;
+    size_t begin = (context) ? context->begin_index(): 0;
+    size_t end   = (context) ? context->end_index()  : 0; 
+    if (0 == begin) {
+        // No hashes yet for ids with prefixes
+        if (m_MODULE_INDEX  == end) {
+            hash_id = module_hash(id);
+            if (hash_id.is_valid()) result = 0;
+        }
+        else if (context && context->end_index() == m_PMT_INDEX) {
+            // Must calculate for pmt hash
+            ExpandedIdentifier new_id;
+            get_expanded_id(id, new_id);
+            hash_id =  m_full_pmt_range.cardinalityUpTo(new_id);
+            result = 0;
+        }
+    }
+    return (result);
+}
+
+
+void    
+CaloNuID::test_module_packing      (void) const
+{
+    MsgStream log(m_msgSvc, "CaloNuID");
+
+    if (m_dict) {
+        
+        int nids = 0;
+        int nerr = 0;
+        IdContext context = module_context();
+        const_id_iterator first = m_module_vec.begin();
+        const_id_iterator last  = m_module_vec.end();
+        for (; first != last; ++first, ++nids) {
+            Identifier id = (*first);
+            ExpandedIdentifier exp_id;
+            get_expanded_id(id, exp_id, &context);
+            Identifier new_id = module_id(exp_id[m_ROW_INDEX],
+                                          exp_id[m_MODULE_INDEX]);
+            if (id != new_id) {
+                log << MSG::ERROR << "CaloNuID::test_module_packing: new and old compacts not equal. New/old/expanded ids " 
+                    << MSG::hex << show_to_string(id) << " " << show_to_string(new_id) << " " << MSG::dec 
+                    << (std::string)exp_id << endmsg;
+                nerr++;
+                continue;
+            }
+            // check row id
+            if (!exp_id[m_MODULE_INDEX]) {
+                
+                Identifier new_id1 = row_id(exp_id[m_ROW_INDEX]);
+                if (id != new_id1) {
+                    log << MSG::ERROR << "CaloNuID::test_module_packing: new and old row ids not equal. New/old/expanded ids " 
+                        << MSG::hex << show_to_string(id) << " " << show_to_string(new_id1) << " " << MSG::dec 
+                        << (std::string)exp_id << endmsg;
+                    nerr++;
+                    continue;
+                }
+            }
+        }
+
+        if (m_msgSvc) { 
+            log << MSG::DEBUG << "CaloNuID::test_module_packing: tested module and row ids. nids, errors " 
+                << nids << " " << nerr << endmsg;
+        }
+        else {
+            std::cout << " DEBUG CaloNuID::test_module_packing: tested module and row ids. nids, errors " 
+                      << nids << " " << nerr << std::endl;
+        }
+        
+        nids = 0;
+        context = pmt_context();
+        const_expanded_id_iterator      first_calonu = pmt_begin();  
+        const_expanded_id_iterator      last_calonu  = pmt_end();
+        for (; first_calonu != last_calonu; ++first_calonu, ++nids) {
+            // if (nids%10000 != 1) continue;
+            const ExpandedIdentifier& exp_id = *first_calonu;
+            ExpandedIdentifier new_exp_id;
+
+            Identifier id = module_id(exp_id[m_ROW_INDEX],
+                                      exp_id[m_MODULE_INDEX]);
+            get_expanded_id(id, new_exp_id, &context);
+            if (exp_id[0] != new_exp_id[0] ||
+                exp_id[1] != new_exp_id[1] ||
+                exp_id[2] != new_exp_id[2] ||
+                exp_id[3] != new_exp_id[3])
+            {
+                log << MSG::ERROR << "CaloNuID::test_module_packing: new and old ids not equal. New/old/compact ids "
+                    << (std::string)new_exp_id << " " << (std::string)exp_id
+                    << " " << show_to_string(id) << endmsg;
+                continue;
+            }
+
+            Identifier pmtid	;
+	        Identifier pmtid1	;
+           	pmtid = pmt_id ( 
+                       exp_id[m_ROW_INDEX],
+					   exp_id[m_MODULE_INDEX],
+					   exp_id[m_PMT_INDEX]);
+
+    	   	pmtid1 = pmt_id (	    
+                        row(pmtid),
+                        module(pmtid),
+                        pmt(pmtid));
+
+            if (pmtid != pmtid1) {
+                log << MSG::ERROR << "CaloNuID::test_module_packing: new and old pmt ids not equal. New/old ids "
+                    << " " << show_to_string(pmtid1) << " " 
+                    << show_to_string(pmtid) << endmsg;
+            }
+        }
+
+        if (m_msgSvc) {
+            log << MSG::DEBUG << "CaloNuID::test_module_packing: Successful tested " 
+                << nids << " ids. " 
+                << endmsg;
+        }
+        else {
+            std::cout << " DEBUG CaloNuID::test_module_packing: Successful tested " 
+                      << nids << " ids. " 
+                      << std::endl;
+        }
+    }
+    else {
+        log << MSG::ERROR << "CaloNuID::test_module_packing: Unable to test module packing - no dictionary has been defined. " 
+            << endmsg;
+    }
+}
+
diff --git a/Calorimeter/CaloDetDescrCnv/CaloIdCnv/src/CaloIdCnv_entries.cxx b/Calorimeter/CaloDetDescrCnv/CaloIdCnv/src/CaloIdCnv_entries.cxx
index 46971794e0241e93a06eb6defd6c01607f3e7c3b..768522f42732cbdf0189c29adc97994ce2f220ad 100644
--- a/Calorimeter/CaloDetDescrCnv/CaloIdCnv/src/CaloIdCnv_entries.cxx
+++ b/Calorimeter/CaloDetDescrCnv/CaloIdCnv/src/CaloIdCnv_entries.cxx
@@ -1,4 +1,6 @@
 
 #include "EcalIDDetDescrCnv.h"
+#include "CaloNuIDDetDescrCnv.h"
 
 DECLARE_CONVERTER(EcalIDDetDescrCnv)
+DECLARE_CONVERTER(CaloNuIDDetDescrCnv)
diff --git a/Calorimeter/CaloDetDescrCnv/CaloIdCnv/src/CaloNuIDDetDescrCnv.cxx b/Calorimeter/CaloDetDescrCnv/CaloIdCnv/src/CaloNuIDDetDescrCnv.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..ec589bfc0f9eef9418682fe5dd5b519161a7ebf1
--- /dev/null
+++ b/Calorimeter/CaloDetDescrCnv/CaloIdCnv/src/CaloNuIDDetDescrCnv.cxx
@@ -0,0 +1,239 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+/***************************************************************************
+ Calo DetDescrCnv package
+ -----------------------------------------
+ ***************************************************************************/
+
+//<<<<<< INCLUDES                                                       >>>>>>
+
+#include "CaloNuIDDetDescrCnv.h"
+
+#include "DetDescrCnvSvc/DetDescrConverter.h"
+#include "DetDescrCnvSvc/DetDescrAddress.h"
+#include "GaudiKernel/MsgStream.h"
+#include "StoreGate/StoreGateSvc.h" 
+
+#include "IdDictDetDescr/IdDictManager.h"
+#include "FaserCaloIdentifier/CaloNuID.h"
+
+
+//<<<<<< PRIVATE DEFINES                                                >>>>>>
+//<<<<<< PRIVATE CONSTANTS                                              >>>>>>
+//<<<<<< PRIVATE TYPES                                                  >>>>>>
+//<<<<<< PRIVATE VARIABLE DEFINITIONS                                   >>>>>>
+//<<<<<< PUBLIC VARIABLE DEFINITIONS                                    >>>>>>
+//<<<<<< CLASS STRUCTURE INITIALIZATION                                 >>>>>>
+//<<<<<< PRIVATE FUNCTION DEFINITIONS                                   >>>>>>
+//<<<<<< PUBLIC FUNCTION DEFINITIONS                                    >>>>>>
+//<<<<<< MEMBER FUNCTION DEFINITIONS                                    >>>>>>
+
+//--------------------------------------------------------------------
+
+long int   
+CaloNuIDDetDescrCnv::repSvcType() const
+{
+  return (storageType());
+}
+
+//--------------------------------------------------------------------
+
+StatusCode 
+CaloNuIDDetDescrCnv::initialize()
+{
+    // First call parent init
+    StatusCode sc = DetDescrConverter::initialize();
+    MsgStream log(msgSvc(), "CaloNuIDDetDescrCnv");
+    log << MSG::DEBUG << "in initialize" << endmsg;
+
+    if (sc.isFailure()) {
+        log << MSG::ERROR << "DetDescrConverter::initialize failed" << endmsg;
+	return sc;
+    }
+    
+    // The following is an attempt to "bootstrap" the loading of a
+    // proxy for CaloNuID into the detector store. However,
+    // CaloNuIDDetDescrCnv::initialize is NOT called by the conversion
+    // service.  So for the moment, this cannot be use. Instead the
+    // DetDescrCnvSvc must do the bootstrap from a parameter list.
+
+
+//      // Add Calo_DetDescrManager proxy as entry point to the detector store
+//      // - this is ONLY needed for the manager of each system
+//      sc = addToDetStore(classID(), "CaloNuID");
+//      if (sc.isFailure()) {
+//  	log << MSG::FATAL << "Unable to add proxy for CaloNuID to the Detector Store!" << endmsg;
+//  	return StatusCode::FAILURE;
+//      } else {}
+
+    return StatusCode::SUCCESS; 
+}
+
+//--------------------------------------------------------------------
+
+StatusCode 
+CaloNuIDDetDescrCnv::finalize()
+{
+    MsgStream log(msgSvc(), "CaloNuIDDetDescrCnv");
+    log << MSG::DEBUG << "in finalize" << endmsg;
+
+    return StatusCode::SUCCESS; 
+}
+
+//--------------------------------------------------------------------
+
+StatusCode
+CaloNuIDDetDescrCnv::createObj(IOpaqueAddress* pAddr, DataObject*& pObj) 
+{
+    //StatusCode sc = StatusCode::SUCCESS;
+    MsgStream log(msgSvc(), "CaloNuIDDetDescrCnv");
+    log << MSG::INFO << "in createObj: creating an CaloNuID helper object in the detector store" << endmsg;
+
+    // Create a new CaloNuID
+
+    DetDescrAddress* ddAddr;
+    ddAddr = dynamic_cast<DetDescrAddress*> (pAddr);
+    if(!ddAddr) {
+	log << MSG::FATAL << "Could not cast to DetDescrAddress." << endmsg;
+	return StatusCode::FAILURE;
+    }
+
+    // Get the StoreGate key of this container.
+    std::string helperKey  = *( ddAddr->par() );
+    if ("" == helperKey) {
+	log << MSG::DEBUG << "No Helper key " << endmsg;
+    }
+    else {
+	log << MSG::DEBUG << "Helper key is " << helperKey << endmsg;
+    }
+    
+
+    // get DetectorStore service
+    StoreGateSvc * detStore;
+    StatusCode status = serviceLocator()->service("DetectorStore", detStore);
+    if (status.isFailure()) {
+	log << MSG::FATAL << "DetectorStore service not found !" << endmsg;
+	return StatusCode::FAILURE;
+    } else {}
+ 
+    // Get the dictionary manager from the detector store
+    const IdDictManager* idDictMgr;
+    status = detStore->retrieve(idDictMgr, "IdDict");
+    if (status.isFailure()) {
+	log << MSG::FATAL << "Could not get IdDictManager !" << endmsg;
+	return StatusCode::FAILURE;
+    } 
+    else {
+	log << MSG::DEBUG << " Found the IdDictManager. " << endmsg;
+    }
+
+    // Only create new helper if it is the first pass or if there is a
+    // change in the the file or tag
+    bool initHelper               = false;
+
+    const IdDictMgr* mgr          = idDictMgr->manager();
+
+    // Internal Calo id tag
+    std::string   caloIDTag      = mgr->tag();
+
+    // DoChecks flag
+    bool doChecks                 = mgr->do_checks();
+
+    IdDictDictionary* dict = mgr->find_dictionary("Calorimeter");  
+    if (!dict) {
+	log << MSG::ERROR 
+	    << "unable to find idDict for Calorimeter" 
+	    << endmsg;
+	return StatusCode::FAILURE;
+    }
+
+    // File to be read for Calo ids
+    std::string   caloIDFileName = dict->file_name();
+
+    // Tag of RDB record for Calo ids
+    std::string   caloIdDictTag  = dict->dict_tag();
+
+
+    if (m_calonuId) {
+
+	// CaloNu id helper already exists - second pass. Check for a
+	// change 
+	if (caloIDTag != m_caloIDTag) { 
+	    // Internal Calo id tag
+	    initHelper = true;
+	    log << MSG::DEBUG << " Changed internal Calo id tag: " 
+		<< caloIDTag << endmsg;
+	}
+	if (caloIDFileName != m_caloIDFileName) {
+	    // File to be read for Calo ids
+	    initHelper = true;
+	    log << MSG::DEBUG << " Changed CaloFileName:" 
+		<< caloIDFileName << endmsg;
+	}
+	if (caloIdDictTag != m_caloIdDictTag) {
+	    // Tag of RDB record for Calo ids
+	    initHelper = true;
+	    log << MSG::DEBUG << " Changed CaloIdDictTag: "
+		<< caloIdDictTag 
+		<< endmsg;
+	}
+	if (doChecks != m_doChecks) {
+	    // DoChecks flag
+	    initHelper = true;
+	    log << MSG::DEBUG << " Changed doChecks flag: "
+		<< doChecks
+		<< endmsg;
+        }
+    }
+    else {
+	// create the helper
+	m_calonuId = new CaloNuID;
+	initHelper = true;
+        // add in message service for printout
+        m_calonuId->setMessageSvc(msgSvc());
+    }
+    
+    if (initHelper) {
+	if (idDictMgr->initializeHelper(*m_calonuId)) {
+	    log << MSG::ERROR << "Unable to initialize CaloNuID" << endmsg;
+	    return StatusCode::FAILURE;
+	} 
+	// Save state:
+	m_caloIDTag      = caloIDTag;
+	m_caloIDFileName = caloIDFileName;
+	m_caloIdDictTag  = caloIdDictTag;
+	m_doChecks        = doChecks;
+    }
+
+    // Pass a pointer to the container to the Persistency service by reference.
+    pObj = SG::asStorable(m_calonuId);
+
+    return StatusCode::SUCCESS; 
+
+}
+
+//--------------------------------------------------------------------
+
+long
+CaloNuIDDetDescrCnv::storageType()
+{
+    return DetDescr_StorageType;
+}
+
+//--------------------------------------------------------------------
+const CLID& 
+CaloNuIDDetDescrCnv::classID() { 
+    return ClassID_traits<CaloNuID>::ID(); 
+}
+
+//--------------------------------------------------------------------
+CaloNuIDDetDescrCnv::CaloNuIDDetDescrCnv(ISvcLocator* svcloc) 
+    :
+    DetDescrConverter(ClassID_traits<CaloNuID>::ID(), svcloc),
+    m_calonuId(0),
+    m_doChecks(false)
+
+{}
+
diff --git a/Calorimeter/CaloDetDescrCnv/CaloIdCnv/src/CaloNuIDDetDescrCnv.h b/Calorimeter/CaloDetDescrCnv/CaloIdCnv/src/CaloNuIDDetDescrCnv.h
new file mode 100644
index 0000000000000000000000000000000000000000..4e0c96c838e549954b5b62e6c1203c5675e8bdb4
--- /dev/null
+++ b/Calorimeter/CaloDetDescrCnv/CaloIdCnv/src/CaloNuIDDetDescrCnv.h
@@ -0,0 +1,71 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+/***************************************************************************
+ Calo DetDescrCnv package
+ -----------------------------------------
+ ***************************************************************************/
+
+#ifndef CALOIDCNV_CALONUIDDETDESCRCNV_H
+#define CALOIDCNV_CALONUIDDETDESCRCNV_H
+
+//<<<<<< INCLUDES                                                       >>>>>>
+
+#include "DetDescrCnvSvc/DetDescrConverter.h"
+
+//<<<<<< PUBLIC DEFINES                                                 >>>>>>
+//<<<<<< PUBLIC CONSTANTS                                               >>>>>>
+//<<<<<< PUBLIC TYPES                                                   >>>>>>
+
+class CaloNuID;
+
+//<<<<<< PUBLIC VARIABLES                                               >>>>>>
+//<<<<<< PUBLIC FUNCTIONS                                               >>>>>>
+//<<<<<< CLASS DECLARATIONS                                             >>>>>>
+
+
+/**
+ **  This class is a converter for the CaloNuID an IdHelper which is
+ **  stored in the detector store. This class derives from
+ **  DetDescrConverter which is a converter of the DetDescrCnvSvc.
+ **
+ **/
+
+class CaloNuIDDetDescrCnv: public DetDescrConverter {
+
+public:
+    virtual long int   repSvcType() const;
+    virtual StatusCode initialize();
+    virtual StatusCode finalize();
+    virtual StatusCode createObj(IOpaqueAddress* pAddr, DataObject*& pObj);
+
+    // Storage type and class ID (used by CnvFactory)
+    static long storageType();
+    static const CLID& classID();
+
+    CaloNuIDDetDescrCnv(ISvcLocator* svcloc);
+
+private:
+    /// The helper - only will create it once
+    CaloNuID*       m_calonuId;
+
+    /// File to be read for Scint ids
+    std::string   m_caloIDFileName;
+
+    /// Tag of RDB record for Scint ids
+    std::string   m_caloIdDictTag;
+
+    /// Internal Scint id tag
+    std::string   m_caloIDTag;
+
+    /// Whether or not 
+    bool          m_doChecks;
+
+};
+
+
+//<<<<<< INLINE PUBLIC FUNCTIONS                                        >>>>>>
+//<<<<<< INLINE MEMBER FUNCTIONS                                        >>>>>>
+
+#endif // CALOIDCNV_CALONUIDDETDESCRCNV_H
diff --git a/Calorimeter/CaloRecAlgs/python/CaloRecAlgsConfig.py b/Calorimeter/CaloRecAlgs/python/CaloRecAlgsConfig.py
index 7204d63c7fbf6f79c6804c5c1026b7b421afc082..fde1341c389fe5ebf3093dd62a88605ef7ff30cf 100644
--- a/Calorimeter/CaloRecAlgs/python/CaloRecAlgsConfig.py
+++ b/Calorimeter/CaloRecAlgs/python/CaloRecAlgsConfig.py
@@ -19,10 +19,12 @@ def CalorimeterReconstructionCfg(flags, **kwargs):
 
     kwargs.setdefault("CaloWaveHitContainerKey", "CaloWaveformHits")
     kwargs.setdefault("Calo2WaveHitContainerKey", "Calo2WaveformHits")
+    kwargs.setdefault("CaloNuWaveHitContainerKey", "CaloNuWaveformHits")
     kwargs.setdefault("PreshowerWaveHitContainerKey", "PreshowerWaveformHits")
     
     kwargs.setdefault("CaloHitContainerKey", "CaloHits")
     kwargs.setdefault("Calo2HitContainerKey", "Calo2Hits")
+    kwargs.setdefault("CaloNuHitContainerKey", "CaloNuHits")
     kwargs.setdefault("PreshowerHitContainerKey", "PreshowerHits")
 
     acc.merge(CaloRecToolCfg(flags, **kwargs))
diff --git a/Calorimeter/CaloRecAlgs/src/CaloRecAlg.cxx b/Calorimeter/CaloRecAlgs/src/CaloRecAlg.cxx
index 4e60ea011ed392b34fff441cf9807b352d14d04d..54015ecec729bf65d30e0dbdcc8730b13c9f6a1c 100644
--- a/Calorimeter/CaloRecAlgs/src/CaloRecAlg.cxx
+++ b/Calorimeter/CaloRecAlgs/src/CaloRecAlg.cxx
@@ -13,6 +13,7 @@ StatusCode CaloRecAlg::initialize() {
   // Set key to read calo hits from
   ATH_CHECK( m_caloWaveHitContainerKey.initialize() );
   ATH_CHECK( m_calo2WaveHitContainerKey.initialize() );
+  ATH_CHECK( m_caloNuWaveHitContainerKey.initialize() );
 
   // Set key to read preshower hits from
   ATH_CHECK( m_preshowerWaveHitContainerKey.initialize() );
@@ -20,6 +21,7 @@ StatusCode CaloRecAlg::initialize() {
   // Set key to write container
   ATH_CHECK( m_caloHitContainerKey.initialize() );
   ATH_CHECK( m_calo2HitContainerKey.initialize() );
+  ATH_CHECK( m_caloNuHitContainerKey.initialize() );
   ATH_CHECK( m_preshowerHitContainerKey.initialize() );
 
   // Initalize tools
@@ -51,6 +53,8 @@ StatusCode CaloRecAlg::execute(const EventContext& ctx) const {
   }
 
   SG::ReadHandle<xAOD::WaveformHitContainer> calo2WaveHitHandle(m_calo2WaveHitContainerKey, ctx);
+
+  SG::ReadHandle<xAOD::WaveformHitContainer> caloNuWaveHitHandle(m_caloNuWaveHitContainerKey, ctx);
   
   SG::ReadHandle<xAOD::WaveformHitContainer> preshowerWaveHitHandle(m_preshowerWaveHitContainerKey, ctx);
 
@@ -95,7 +99,7 @@ StatusCode CaloRecAlg::execute(const EventContext& ctx) const {
   }  
   ATH_MSG_DEBUG("PreshowerHitContainer '" << preshowerHitContainerHandle.name() << "' filled with "<< preshowerHitContainerHandle->size() <<" items");
   
-  // High-gain calo isn't guaranteed to exist
+  // High-range calo isn't guaranteed to exist
   if ( calo2WaveHitHandle.isValid() ) {
     ATH_MSG_DEBUG("Found ReadHandle for WaveformHitContainer " << m_calo2WaveHitContainerKey);
 
@@ -103,7 +107,7 @@ StatusCode CaloRecAlg::execute(const EventContext& ctx) const {
       ATH_MSG_DEBUG("Calorimeter 2 Waveform Hit container found with zero length!");
     }
 
-    // Reconstruct high-gain calorimeter hits
+    // Reconstruct high-range calorimeter hits
     SG::WriteHandle<xAOD::CalorimeterHitContainer> calo2HitContainerHandle(m_calo2HitContainerKey, ctx);
     ATH_CHECK( calo2HitContainerHandle.record( std::make_unique<xAOD::CalorimeterHitContainer>(),
 					       std::make_unique<xAOD::CalorimeterHitAuxContainer>() ) );
@@ -122,6 +126,33 @@ StatusCode CaloRecAlg::execute(const EventContext& ctx) const {
     ATH_MSG_DEBUG("No ReadHandle for WaveformHitContainer " << m_calo2WaveHitContainerKey);
   }
 
+  // CaloNu isn't guaranteed to exist
+  if ( caloNuWaveHitHandle.isValid() ) {
+    ATH_MSG_DEBUG("Found ReadHandle for WaveformHitContainer " << m_caloNuWaveHitContainerKey);
+
+    if (caloNuWaveHitHandle->size() == 0) {
+      ATH_MSG_DEBUG("Calorimeter 2 Waveform Hit container found with zero length!");
+    }
+
+    // Reconstruct CaloNu calorimeter hits
+    SG::WriteHandle<xAOD::CalorimeterHitContainer> caloNuHitContainerHandle(m_caloNuHitContainerKey, ctx);
+    ATH_CHECK( caloNuHitContainerHandle.record( std::make_unique<xAOD::CalorimeterHitContainer>(),
+					       std::make_unique<xAOD::CalorimeterHitAuxContainer>() ) );
+    ATH_MSG_DEBUG("WaveformsHitContainer '" << caloNuHitContainerHandle.name() << "' initialized");
+
+    for( const auto& hit : *caloNuWaveHitHandle ) {
+      if (hit->status_bit(xAOD::WaveformStatus::SECONDARY)) continue;
+      xAOD::CalorimeterHit* calo_hit = new xAOD::CalorimeterHit();
+      caloNuHitContainerHandle->push_back(calo_hit);    
+      calo_hit->addHit(caloNuWaveHitHandle.get(), hit);
+      m_recoCalibTool->reconstruct(ctx, calo_hit, correct_gain=false);
+    }
+    ATH_MSG_DEBUG("CaloNuHitContainer '" << caloNuHitContainerHandle.name() << "' filled with "<< caloNuHitContainerHandle->size() <<" items");
+    
+  } else {
+    ATH_MSG_DEBUG("No ReadHandle for WaveformHitContainer " << m_caloNuWaveHitContainerKey);
+  }
+  
   return StatusCode::SUCCESS;
 }
 
diff --git a/Calorimeter/CaloRecAlgs/src/CaloRecAlg.h b/Calorimeter/CaloRecAlgs/src/CaloRecAlg.h
index b11fc05ae5cf91b8e5b4aed67074d07674a511a7..f5953ecfa25df972611ccb2e30bce5ca9b10f567 100644
--- a/Calorimeter/CaloRecAlgs/src/CaloRecAlg.h
+++ b/Calorimeter/CaloRecAlgs/src/CaloRecAlg.h
@@ -75,6 +75,10 @@ class CaloRecAlg : public AthReentrantAlgorithm {
   SG::ReadHandleKey<xAOD::WaveformHitContainer> m_calo2WaveHitContainerKey {this, "Calo2WaveHitContainerKey", "Calo2WaveformHits"};
   //@}
 
+  //@{
+  SG::ReadHandleKey<xAOD::WaveformHitContainer> m_caloNuWaveHitContainerKey {this, "CaloNuWaveHitContainerKey", "CaloNuWaveformHits"};
+  //@}
+
   //@{
   SG::ReadHandleKey<xAOD::WaveformHitContainer> m_preshowerWaveHitContainerKey {this, "PreshowerWaveHitContainerKey", "PreshowerWaveformHits"};
   //@}
@@ -85,6 +89,7 @@ class CaloRecAlg : public AthReentrantAlgorithm {
   //@{
   SG::WriteHandleKey<xAOD::CalorimeterHitContainer> m_caloHitContainerKey {this, "CaloHitContainerKey", "CaloHits"};
   SG::WriteHandleKey<xAOD::CalorimeterHitContainer> m_calo2HitContainerKey {this, "Calo2HitContainerKey", "Calo2Hits"};
+  SG::WriteHandleKey<xAOD::CalorimeterHitContainer> m_caloNuHitContainerKey {this, "CaloNuHitContainerKey", "CaloNuHits"};
   SG::WriteHandleKey<xAOD::CalorimeterHitContainer> m_preshowerHitContainerKey {this, "PreshowerHitContainerKey", "PreshowerHits"};
   //@}
 
diff --git a/Calorimeter/CaloRecTools/src/CaloRecTool.cxx b/Calorimeter/CaloRecTools/src/CaloRecTool.cxx
index 01a81e287ca312ecde8616cf22a1c23a29186767..c09c2760136a4b539a3013d380d8116e10001298 100644
--- a/Calorimeter/CaloRecTools/src/CaloRecTool.cxx
+++ b/Calorimeter/CaloRecTools/src/CaloRecTool.cxx
@@ -41,19 +41,40 @@ CaloRecTool::initialize() {
   HVgaincurves_rootFile->Close(); // close the root file
 
   // These should be in DB, but just hardcode this for now
+  // This is a bit ugly, as channel mappings hav changed with the years
+  // but for now we can still cover all options
+
+  // Paramters to convert N_mip to E_dep
+  
+  // Original ECal or CaloLo
   m_MIP_sim_Edep[0] = m_MIP_sim_Edep_calo.value();
   m_MIP_sim_Edep[1] = m_MIP_sim_Edep_calo.value();
   m_MIP_sim_Edep[2] = m_MIP_sim_Edep_calo.value();
   m_MIP_sim_Edep[3] = m_MIP_sim_Edep_calo.value();
 
-  m_MIP_sim_Edep[12] = m_MIP_sim_Edep_preshower.value();
-  m_MIP_sim_Edep[13] = m_MIP_sim_Edep_preshower.value();
-  
+  // CaloHi 
   m_MIP_sim_Edep[16] = m_MIP_sim_Edep_calo2.value();
   m_MIP_sim_Edep[17] = m_MIP_sim_Edep_calo2.value();
   m_MIP_sim_Edep[18] = m_MIP_sim_Edep_calo2.value();
   m_MIP_sim_Edep[19] = m_MIP_sim_Edep_calo2.value();
 
+  // CaloNu (2 locations)
+  m_MIP_sim_Edep[20] = m_MIP_sim_Edep_calonu.value();
+  m_MIP_sim_Edep[21] = m_MIP_sim_Edep_calonu.value();
+  m_MIP_sim_Edep[22] = m_MIP_sim_Edep_calonu.value();
+  m_MIP_sim_Edep[23] = m_MIP_sim_Edep_calonu.value();
+
+  m_MIP_sim_Edep[6] = m_MIP_sim_Edep_calonu.value();
+  m_MIP_sim_Edep[7] = m_MIP_sim_Edep_calonu.value();
+  m_MIP_sim_Edep[14] = m_MIP_sim_Edep_calonu.value();
+  m_MIP_sim_Edep[15] = m_MIP_sim_Edep_calonu.value();
+
+  // Preshower (always in same place)
+  m_MIP_sim_Edep[12] = m_MIP_sim_Edep_preshower.value();
+  m_MIP_sim_Edep[13] = m_MIP_sim_Edep_preshower.value();
+
+  // Paramters to convert N_mip to E_EM
+  // Conversion to EM energy scale (same for all calorimeters)
   m_EM_mu_Map[0] = m_calo_EM_mu.value();
   m_EM_mu_Map[1] = m_calo_EM_mu.value();
   m_EM_mu_Map[2] = m_calo_EM_mu.value();
@@ -64,6 +85,20 @@ CaloRecTool::initialize() {
   m_EM_mu_Map[18] = m_calo_EM_mu.value();
   m_EM_mu_Map[19] = m_calo_EM_mu.value();
 
+  m_EM_mu_Map[20] = m_calo_EM_mu.value();
+  m_EM_mu_Map[21] = m_calo_EM_mu.value();
+  m_EM_mu_Map[22] = m_calo_EM_mu.value();
+  m_EM_mu_Map[23] = m_calo_EM_mu.value();
+
+  m_EM_mu_Map[6] = m_calo_EM_mu.value();
+  m_EM_mu_Map[7] = m_calo_EM_mu.value();
+  m_EM_mu_Map[14] = m_calo_EM_mu.value();
+  m_EM_mu_Map[15] = m_calo_EM_mu.value();
+
+  // Missing this for preshower?
+  m_EM_mu_Map[12] = m_preshower_EM_mu.value();
+  m_EM_mu_Map[13] = m_preshower_EM_mu.value();
+  
   return StatusCode::SUCCESS;
 }
 
@@ -235,6 +270,9 @@ CaloRecTool::reconstruct(const EventContext& ctx,
   // Get the waveform hit attached to this calo hit
   const xAOD::WaveformHit* wave_hit = calo_hit->Hit(0);
   ATH_MSG_DEBUG("calo_hit in channel " << wave_hit->channel() );
+
+  // Must set channel
+  calo_hit->set_channel(wave_hit->channel());
   
   float MIPcharge_ref = getMIPcharge_ref(ctx, wave_hit->channel()); // get reference MIP charge from database
 
diff --git a/Calorimeter/CaloRecTools/src/CaloRecTool.h b/Calorimeter/CaloRecTools/src/CaloRecTool.h
index 82ba2b60740dade0e64e91273e089d2ced98780a..46c24bd73ed290101a6d02a8f85de9393faf4087 100644
--- a/Calorimeter/CaloRecTools/src/CaloRecTool.h
+++ b/Calorimeter/CaloRecTools/src/CaloRecTool.h
@@ -90,12 +90,16 @@ class CaloRecTool: public extends<AthAlgTool, ICaloRecTool> {
   SG::ReadCondHandleKey<CondAttrListCollection> m_MIP_ref_ReadKey{this, "MIP_ref_ReadKey", "/WAVE/Calibration/MIP_ref", "Key of folder for MIP charge calibration measurment, also stores PMT HV used to measure the reference MIP charge"};
 
   // Could also put these in DB, but just hardcode them for now
-  FloatProperty m_MIP_sim_Edep_calo {this, "MIP_sim_Edep_calo", 58.5}; // MIP deposits 5.85 MeV of energy in calo
-  FloatProperty m_MIP_sim_Edep_calo2 {this, "MIP_sim_Edep_calo2", 58.5}; // MIP deposits 5.85 MeV of energy in calo
+  FloatProperty m_MIP_sim_Edep_calo {this, "MIP_sim_Edep_calo", 58.5}; // MIP deposits 58.5 MeV of energy in calo
+  FloatProperty m_MIP_sim_Edep_calo2 {this, "MIP_sim_Edep_calo2", 58.5}; // MIP deposits 58.5 MeV of energy in calo
+  FloatProperty m_MIP_sim_Edep_calonu {this, "MIP_sim_Edep_calonu", 58.5}; // MIP deposits 58.5 MeV of energy in calo
   FloatProperty m_MIP_sim_Edep_preshower {this, "MIP_sim_Edep_preshower", 4.894}; // MIP deposits 4.894 MeV of energy in a preshower layer
 
   FloatProperty m_calo_EM_mu {this, "m_calo_EM_mu", 330.0}; // factor used to do rough calibration of calo to EM energy: 0.33 GeV or 330 MeV
 
+  // This isn't calibrated yet, just use CALO value for the moment
+  FloatProperty m_preshower_EM_mu {this, "m_preshower_EM_mu", 330.0}; // factor used to do rough calibration of calo to EM energy: 0.33 GeV or 330 MeV
+
   float m_MIP_sim_Edep[32]; // vector that holds Edep factors for calo and preshower
   float m_EM_mu_Map[32]; // vector that holds EM_mu calibration factors for calo channels
 
diff --git a/Control/CalypsoExample/Reconstruction/scripts/faser_reco.py b/Control/CalypsoExample/Reconstruction/scripts/faser_reco.py
index 8923c532622198918c71536fe191008f5a0b38c1..c43e75440dbfcb2a3fd0c64724db2e12149d9a86 100755
--- a/Control/CalypsoExample/Reconstruction/scripts/faser_reco.py
+++ b/Control/CalypsoExample/Reconstruction/scripts/faser_reco.py
@@ -167,7 +167,7 @@ elif runtype in ["TI12Data03", "TI12MC03"]:
 # Updated 2023 TI12 geometry
 elif runtype in ["TI12Data04", "TI12MC04"]:
     configFlags.GeoModel.FaserVersion = "FASERNU-04" 
-    configFlags.IOVDb.GlobalTag = "OFLCOND-FASER-04"
+    configFlags.IOVDb.GlobalTag = "OFLCOND-FASER-05" # Latest 2025 alignment
     useCal = True
     if not args.isMC:
         useLHC = True
diff --git a/Control/CalypsoExample/WaveformDataAccessExample/src/RawWaveformAccess.cxx b/Control/CalypsoExample/WaveformDataAccessExample/src/RawWaveformAccess.cxx
index 166d219c6fe29670843d5169ba5fea1c597c45f3..52cdd42b41e9d5746e5913c3f6fab9b169aedd31 100644
--- a/Control/CalypsoExample/WaveformDataAccessExample/src/RawWaveformAccess.cxx
+++ b/Control/CalypsoExample/WaveformDataAccessExample/src/RawWaveformAccess.cxx
@@ -28,9 +28,11 @@ RawWaveformAccess::initialize()
   // Must initialize SG handles
   ATH_CHECK( m_CaloWaveformContainer.initialize() );
   ATH_CHECK( m_Calo2WaveformContainer.initialize() );
+  ATH_CHECK( m_CaloNuWaveformContainer.initialize() );
   ATH_CHECK( m_VetoWaveformContainer.initialize() );
   ATH_CHECK( m_TriggerWaveformContainer.initialize() );
   ATH_CHECK( m_PreshowerWaveformContainer.initialize() );
+  ATH_CHECK( m_MuonWaveformContainer.initialize() );
   ATH_CHECK( m_ClockWaveformContainer.initialize() );
 
   return StatusCode::SUCCESS;
@@ -56,7 +58,11 @@ RawWaveformAccess::execute(const EventContext& ctx) const
 
   SG::ReadHandle<RawWaveformContainer> calo2Handle(m_Calo2WaveformContainer, ctx);
   ATH_MSG_INFO("Found ReadHandle for Calo2Waveforms");
-  ATH_MSG_INFO(*caloHandle);
+  ATH_MSG_INFO(*calo2Handle);
+
+  SG::ReadHandle<RawWaveformContainer> caloNuHandle(m_CaloNuWaveformContainer, ctx);
+  ATH_MSG_INFO("Found ReadHandle for CaloNuWaveforms");
+  ATH_MSG_INFO(*caloNuHandle);
 
   SG::ReadHandle<RawWaveformContainer> vetoHandle(m_VetoWaveformContainer, ctx);
   ATH_MSG_INFO("Found ReadHandle for VetoWaveforms");
@@ -70,6 +76,10 @@ RawWaveformAccess::execute(const EventContext& ctx) const
   ATH_MSG_INFO("Found ReadHandle for PreshowerWaveforms");
   ATH_MSG_INFO(*preshowerHandle);
 
+  SG::ReadHandle<RawWaveformContainer> muonHandle(m_MuonWaveformContainer, ctx);
+  ATH_MSG_INFO("Found ReadHandle for MuonWaveforms");
+  ATH_MSG_INFO(*muonHandle);
+
   SG::ReadHandle<RawWaveformContainer> clockHandle(m_ClockWaveformContainer, ctx);
   ATH_MSG_INFO("Found ReadHandle for ClockWaveforms");
   ATH_MSG_INFO(*clockHandle);
diff --git a/Control/CalypsoExample/WaveformDataAccessExample/src/RawWaveformAccess.h b/Control/CalypsoExample/WaveformDataAccessExample/src/RawWaveformAccess.h
index b07edde805c383b9b3750a10953df27b8aa28df7..f73314ffd84c0fd1d3bf889c30163382aaa80590 100644
--- a/Control/CalypsoExample/WaveformDataAccessExample/src/RawWaveformAccess.h
+++ b/Control/CalypsoExample/WaveformDataAccessExample/src/RawWaveformAccess.h
@@ -34,12 +34,16 @@ class RawWaveformAccess: public AthReentrantAlgorithm
     { this, "CaloWaveformContainerKey", "CaloWaveforms", "ReadHandleKey for CaloWaveforms Container"};
   SG::ReadHandleKey<RawWaveformContainer> m_Calo2WaveformContainer
     { this, "Calo2WaveformContainerKey", "Calo2Waveforms", "ReadHandleKey for Calo2Waveforms Container"};
+  SG::ReadHandleKey<RawWaveformContainer> m_CaloNuWaveformContainer
+    { this, "CaloNuWaveformContainerKey", "CaloNuWaveforms", "ReadHandleKey for CaloNuWaveforms Container"};
   SG::ReadHandleKey<RawWaveformContainer> m_VetoWaveformContainer
-    { this, "VetoWaveformContainerKey", "VetoWaveforms", "ReadHandleKey for CaloWaveforms Container"};
+    { this, "VetoWaveformContainerKey", "VetoWaveforms", "ReadHandleKey for VetoWaveforms Container"};
   SG::ReadHandleKey<RawWaveformContainer> m_TriggerWaveformContainer
     { this, "TriggerWaveformContainerKey", "TriggerWaveforms", "ReadHandleKey for TriggerWaveforms Container"};
   SG::ReadHandleKey<RawWaveformContainer> m_PreshowerWaveformContainer
     { this, "PreshowerWaveformContainerKey", "PreshowerWaveforms", "ReadHandleKey for PreshowerWaveforms Container"};
+  SG::ReadHandleKey<RawWaveformContainer> m_MuonWaveformContainer
+    { this, "MuonWaveformContainerKey", "MuonWaveforms", "ReadHandleKey for MuonWaveforms Container"};
   SG::ReadHandleKey<RawWaveformContainer> m_ClockWaveformContainer
     { this, "ClockWaveformContainerKey", "ClockWaveforms", "ReadHandleKey for ClockWaveforms Container"};
 };
diff --git a/DetectorDescription/DetDescrCnvSvc/src/DetDescrCnvSvc.cxx b/DetectorDescription/DetDescrCnvSvc/src/DetDescrCnvSvc.cxx
index cc2fca779acd953d177963424389477baa30c856..0fd7d530d9f45faeca8a8b0ec9c371d41dc2a28c 100644
--- a/DetectorDescription/DetDescrCnvSvc/src/DetDescrCnvSvc.cxx
+++ b/DetectorDescription/DetDescrCnvSvc/src/DetDescrCnvSvc.cxx
@@ -127,10 +127,14 @@ DetDescrCnvSvc::initialize()     {
     if (status != StatusCode::SUCCESS) return status;
     status =  addToDetStore(247779284, "VetoNuID");
     if (status != StatusCode::SUCCESS) return status;
+    status =  addToDetStore(143274416, "MuonID");
+    if (status != StatusCode::SUCCESS) return status;
     status =  addToDetStore(205618430, "FaserSCT_ID");
     if (status != StatusCode::SUCCESS) return status;
     status =  addToDetStore(113753346, "EcalID");
     if (status != StatusCode::SUCCESS) return status;
+    status =  addToDetStore(167327975, "CaloNuID");
+    if (status != StatusCode::SUCCESS) return status;
 
     return status;
 }
diff --git a/DetectorDescription/FaserDetDescr/FaserDetDescr/FaserDetTechnology.h b/DetectorDescription/FaserDetDescr/FaserDetDescr/FaserDetTechnology.h
index 0ee1ecc5d64e53a1d5cd0e04ad969421f8344c59..0bb74ba7b5c9a1e76267b71991315698ca8060ef 100644
--- a/DetectorDescription/FaserDetDescr/FaserDetDescr/FaserDetTechnology.h
+++ b/DetectorDescription/FaserDetDescr/FaserDetDescr/FaserDetTechnology.h
@@ -39,17 +39,19 @@ namespace FaserDetDescr {
             fFaserVeto                         = 3,
             fFaserTrigger                      = 4,
             fFaserPreshower                    = 5,
-            fLastFaserScintillatorTechnology   = 5,
+	    fFaserMuon                         = 6,
+            fLastFaserScintillatorTechnology   = 6,
         // Tracker
-            fFirstFaserTrackerTechnology = 6,
-            fFaserSCT                    = 6,
-            fLastFaserTrackerTechnology  = 6,
+            fFirstFaserTrackerTechnology = 7,
+            fFaserSCT                    = 7,
+            fLastFaserTrackerTechnology  = 7,
         // Calorimeter
-            fFirstFaserCalorimeterTechnology    = 7,
-            fFaserECAL                          = 7,
-            fLastFaserCalorimeterTechnology     = 7,
+            fFirstFaserCalorimeterTechnology    = 8,
+            fFaserECAL                          = 8,
+	    fFaserCaloNu                        = 9,
+            fLastFaserCalorimeterTechnology     = 9,
         // number of defined detector technologies
-            fNumFaserDetTechnologies    = 8
+            fNumFaserDetTechnologies    = 10
    };
 
 } // end of namespace
diff --git a/DetectorDescription/FaserDetDescr/FaserDetDescr/FaserDetectorID.h b/DetectorDescription/FaserDetDescr/FaserDetDescr/FaserDetectorID.h
index 3ac1160a9e0c12935f522b0750b09a74fe4d4983..e745518739f8f78f74ff76ea8a32f9bf1df1e068 100644
--- a/DetectorDescription/FaserDetDescr/FaserDetDescr/FaserDetectorID.h
+++ b/DetectorDescription/FaserDetDescr/FaserDetDescr/FaserDetectorID.h
@@ -85,6 +85,7 @@ public:
     Identifier          vetonu          (void) const;
     Identifier          trigger         (void) const;
     Identifier          preshower       (void) const;
+    Identifier          muon            (void) const;
     //@}
 
     /// @name Tracker subsystem ids
@@ -95,6 +96,7 @@ public:
     /// @name Calorimeter subsystem ids
     //@{
     Identifier          ecal            (void) const;
+    Identifier          calonu          (void) const;
     //@}
 
     /// @name Contexts to provide id length - e.g. for use in generic decoding
@@ -161,8 +163,10 @@ public:
     bool                is_vetonu       (Identifier id) const;
     bool                is_trigger      (Identifier id) const;
     bool                is_preshower    (Identifier id) const;
+    bool                is_muon         (Identifier id) const;
     bool                is_sct          (Identifier id) const;
     bool                is_ecal         (Identifier id) const;
+    bool                is_calonu       (Identifier id) const;
     //@}
 
 
@@ -177,8 +181,10 @@ public:
     bool                is_vetonu       (const ExpandedIdentifier& id) const;
     bool                is_trigger      (const ExpandedIdentifier& id) const;
     bool                is_preshower    (const ExpandedIdentifier& id) const;
+    bool                is_muon         (const ExpandedIdentifier& id) const;
     bool                is_sct          (const ExpandedIdentifier& id) const;
     bool                is_ecal         (const ExpandedIdentifier& id) const;
+    bool                is_calonu         (const ExpandedIdentifier& id) const;
     //@}
 
     /// @name  Dictionary versioning: provide access to dictionary names and versions. Note that a helper may correspond to one or more id dictionary
@@ -236,12 +242,14 @@ protected:
     ExpandedIdentifier          vetonu_exp          (void) const;
     ExpandedIdentifier          trigger_exp         (void) const;
     ExpandedIdentifier          preshower_exp       (void) const;
+    ExpandedIdentifier          muon_exp            (void) const;
 
     /// Tracker:
     ExpandedIdentifier          sct_exp             (void) const;
 
     /// Calorimeter:
     ExpandedIdentifier          ecal_exp            (void) const;
+    ExpandedIdentifier          calonu_exp          (void) const;
 
     /// Provide efficient access to individual field values, for
     /// subclass idhelpers
@@ -254,8 +262,10 @@ protected:
     int                 vetonu_field_value       () const;     
     int                 trigger_field_value      () const;       
     int                 preshower_field_value    () const;       
+    int                 muon_field_value         () const;     
     int                 sct_field_value          () const;
     int                 ecal_field_value         () const;
+    int                 calonu_field_value       () const;
 
     /// Register the file and tag names for a particular IdDict
     /// dictionary
@@ -311,12 +321,14 @@ private:
     int                 m_CALO_ID;
     int                 m_EMULSION_ID;
     int                 m_VETO_ID;     
-    int                 m_VETONU_ID;     
     int                 m_TRIGGER_ID;       
     int                 m_PRESHOWER_ID;       
+    int                 m_VETONU_ID;     
+    int                 m_MUON_ID;     
     int                 m_SCT_ID;
     int                 m_ECAL_ID;
-
+    int                 m_CALONU_ID;
+  
     /// Flag for slhc layout:
     bool                m_isSLHC;
 
@@ -409,6 +421,12 @@ FaserDetectorID::preshower_exp             (void) const
     return (result << m_PRESHOWER_ID);  
 }
 
+inline ExpandedIdentifier          
+FaserDetectorID::muon_exp           (void) const
+{
+    ExpandedIdentifier result(scint_exp());
+    return (result << m_MUON_ID);
+}
 inline ExpandedIdentifier          
 FaserDetectorID::sct_exp                   (void) const
 {
@@ -423,8 +441,15 @@ FaserDetectorID::ecal_exp                (void) const
     return (result << m_ECAL_ID);  
 }
 
+inline ExpandedIdentifier          
+FaserDetectorID::calonu_exp                (void) const
+{
+    ExpandedIdentifier result(calo_exp());
+    return (result << m_CALONU_ID);  
+}
+
 inline int                 
-FaserDetectorID::neutrino_field_value     () const {return (m_NEUTRINO_ID);}     
+FaserDetectorID::neutrino_field_value     () const {return (m_NEUTRINO_ID);}
 
 inline int                 
 FaserDetectorID::scint_field_value        () const {return (m_SCINT_ID);}     
@@ -436,7 +461,7 @@ inline int
 FaserDetectorID::calo_field_value         () const {return (m_CALO_ID);}
 
 inline int                 
-FaserDetectorID::emulsion_field_value     () const {return (m_EMULSION_ID);}     
+FaserDetectorID::emulsion_field_value     () const {return (m_EMULSION_ID);}
 
 inline int                 
 FaserDetectorID::veto_field_value         () const {return (m_VETO_ID);}     
@@ -445,10 +470,13 @@ inline int
 FaserDetectorID::vetonu_field_value       () const {return (m_VETONU_ID);}     
 
 inline int                 
-FaserDetectorID::trigger_field_value      () const {return (m_TRIGGER_ID);}       
+FaserDetectorID::trigger_field_value      () const {return (m_TRIGGER_ID);}
 
 inline int                 
-FaserDetectorID::preshower_field_value    () const {return (m_PRESHOWER_ID);}       
+FaserDetectorID::preshower_field_value    () const {return (m_PRESHOWER_ID);}
+
+inline int                 
+FaserDetectorID::muon_field_value         () const {return (m_MUON_ID);}
 
 inline int                 
 FaserDetectorID::sct_field_value          () const {return (m_SCT_ID);}       
@@ -456,6 +484,9 @@ FaserDetectorID::sct_field_value          () const {return (m_SCT_ID);}
 inline int                 
 FaserDetectorID::ecal_field_value         () const {return (m_ECAL_ID);}       
 
+inline int                 
+FaserDetectorID::calonu_field_value         () const {return (m_CALONU_ID);}  
+
 inline bool               
 FaserDetectorID::is_neutrino             (Identifier id) const
 {
@@ -530,6 +561,16 @@ FaserDetectorID::is_preshower         (Identifier id) const
     return result;
 }
 
+inline bool               
+FaserDetectorID::is_muon       (Identifier id) const
+{
+    bool result = false;
+    if(is_scint(id)) {
+        result = (m_scint_part_impl.unpack(id) == m_MUON_ID);
+    }
+    return result;
+}
+
 inline bool               
 FaserDetectorID::is_sct              (Identifier id) const
 {
@@ -550,4 +591,14 @@ FaserDetectorID::is_ecal             (Identifier id) const
     return result;
 }
 
+inline bool               
+FaserDetectorID::is_calonu           (Identifier id) const
+{
+    bool result = false;
+    if(is_calo(id)) {
+        result = (m_calo_part_impl.unpack(id) == m_CALONU_ID);
+    }
+    return result;
+}
+
 #endif // FASERDETDESCR_FASERDETECTORID_H
diff --git a/DetectorDescription/FaserDetDescr/src/FaserDetectorID.cxx b/DetectorDescription/FaserDetDescr/src/FaserDetectorID.cxx
index 59d81a8d8006bdde022b1db76092a6f97567e85e..308e1fa20f343a60909856afcff4efb527e82fce 100644
--- a/DetectorDescription/FaserDetDescr/src/FaserDetectorID.cxx
+++ b/DetectorDescription/FaserDetDescr/src/FaserDetectorID.cxx
@@ -36,17 +36,25 @@ FaserDetectorID::FaserDetectorID()
         m_is_initialized_from_dict(false),
         m_DET_INDEX(999),
         m_SUBDET_INDEX(999),
+	
         m_NEUTRINO_ID(1),
         m_SCINT_ID(2),
         m_TRACKER_ID(3),
         m_CALO_ID(4),
+	
         m_EMULSION_ID(1),
+	
         m_VETO_ID(1),
-    	m_VETONU_ID(4),
         m_TRIGGER_ID(2),
         m_PRESHOWER_ID(3),
+    	m_VETONU_ID(4),
+	m_MUON_ID(5),
+	
         m_SCT_ID(1),
+	
         m_ECAL_ID(1),
+	m_CALONU_ID(2),
+	
         m_isSLHC(false),
         m_faser_dict(0),
         m_neutrino_dict(0),
@@ -81,8 +89,10 @@ FaserDetectorID::FaserDetectorID(const FaserDetectorID& other)
         m_VETONU_ID               (other.m_VETONU_ID),
         m_TRIGGER_ID              (other.m_TRIGGER_ID),
         m_PRESHOWER_ID            (other.m_PRESHOWER_ID),
+        m_MUON_ID                 (other.m_MUON_ID),
         m_SCT_ID                  (other.m_SCT_ID),
         m_ECAL_ID                 (other.m_ECAL_ID),
+	m_CALONU_ID               (other.m_CALONU_ID),
         m_isSLHC                  (other.m_isSLHC),
         m_faser_dict              (other.m_faser_dict),
         m_neutrino_dict           (other.m_neutrino_dict),
@@ -125,8 +135,10 @@ FaserDetectorID::operator= (const FaserDetectorID& other)
         m_TRIGGER_ID            = other.m_TRIGGER_ID;
         m_PRESHOWER_ID          = other.m_PRESHOWER_ID;
         m_VETONU_ID             = other.m_VETONU_ID;
+	m_MUON_ID               = other.m_MUON_ID;
         m_SCT_ID                = other.m_SCT_ID;
         m_ECAL_ID               = other.m_ECAL_ID;
+        m_CALONU_ID             = other.m_CALONU_ID;
         m_faser_dict            = other.m_faser_dict;
         m_neutrino_dict         = other.m_neutrino_dict;
         m_scint_dict            = other.m_scint_dict;
@@ -237,6 +249,16 @@ FaserDetectorID::preshower          (void) const
     return (result);
 }
 
+Identifier
+FaserDetectorID::muon        (void) const
+{
+    Identifier result((Identifier::value_type)0);
+    // Pack field
+    m_det_impl.pack       (scint_field_value(), result);
+    m_scint_part_impl.pack(m_MUON_ID, result);
+    return (result);
+}
+
 Identifier
 FaserDetectorID::sct          (void) const
 {
@@ -257,6 +279,16 @@ FaserDetectorID::ecal          (void) const
     return (result);
 }
 
+Identifier
+FaserDetectorID::calonu        (void) const
+{
+    Identifier result((Identifier::value_type)0);
+    // Pack field
+    m_det_impl.pack       (calo_field_value(), result);
+    m_calo_part_impl.pack(m_CALONU_ID, result);
+    return (result);
+}
+
 /// IdContext (indicates id length) for detector systems
 IdContext
 FaserDetectorID::detsystem_context (void) const
@@ -487,6 +519,16 @@ FaserDetectorID::is_preshower         (const ExpandedIdentifier& id) const
     return result;
 }
 
+bool
+FaserDetectorID::is_muon       (const ExpandedIdentifier& id) const
+{
+    bool result = false;
+    if ( is_scint(id) && id.fields() > 1 ){
+        if ( id[1] == m_MUON_ID ) result = true;
+    }
+    return result;
+}
+
 bool
 FaserDetectorID::is_sct         (const ExpandedIdentifier& id) const
 {
@@ -507,6 +549,16 @@ FaserDetectorID::is_ecal         (const ExpandedIdentifier& id) const
     return result;
 }
 
+bool
+FaserDetectorID::is_calonu      (const ExpandedIdentifier& id) const
+{
+    bool result = false;
+    if ( is_calo(id) && id.fields() > 1 ){
+        if ( id[1] == m_CALONU_ID ) result = true;
+    }
+    return result;
+}
+
 // Short print out of any identifier:
 void
 FaserDetectorID::show           (Identifier id,
@@ -753,9 +805,11 @@ FaserDetectorID::initLevelsFromDict(const IdDictMgr& dict_mgr)
     m_TRIGGER_ID            = -1;
     m_PRESHOWER_ID          = -1;
     m_VETONU_ID             = -1;
+    m_MUON_ID               = -1;
     m_SCT_ID                = -1;
     m_ECAL_ID               = -1;
-
+    m_CALONU_ID             = -1;
+    
     // Save generic dict for top levels
     IdDictDictionary*   top_dict = 0;
 
@@ -990,6 +1044,36 @@ FaserDetectorID::initLevelsFromDict(const IdDictMgr& dict_mgr)
             return (1);
         }
 
+        label = field->find_label("Muon");
+        if (label) {
+            if (label->m_valued) {
+                m_MUON_ID = label->m_value;
+            }
+            else {
+                if(m_msgSvc) {
+                    MsgStream log(m_msgSvc, "FaserDetectorID" );
+                    log << MSG::ERROR << "initLevelsFromDict - label Muon does NOT have a value "
+                        << endmsg;
+                }
+                else {
+                    std::cout << "FaserDetectorID::initLevelsFromDict - label Muon does NOT have a value "
+                              << std::endl;
+                }
+                return (1);
+            }
+        }
+        else {
+            if(m_msgSvc) {
+                MsgStream log(m_msgSvc, "FaserDetectorID" );
+                log << MSG::ERROR << "initLevelsFromDict - unable to find 'Muon label "
+                    << endmsg;
+            }
+            else {
+                std::cout << "FaserDetectorID::initLevelsFromDict - unable to find 'Muon' label "
+                          << std::endl;
+            }
+            return (1);
+        }
 
     }
 
@@ -1118,6 +1202,37 @@ FaserDetectorID::initLevelsFromDict(const IdDictMgr& dict_mgr)
             }
             return (1);
         }
+
+        label = field->find_label("CaloNu");
+        if (label) {
+            if (label->m_valued) {
+                m_CALONU_ID = label->m_value;
+            }
+            else {
+                if(m_msgSvc) {
+                    MsgStream log(m_msgSvc, "FaserDetectorID" );
+                    log << MSG::ERROR << "initLevelsFromDict - label CALONU does NOT have a value "
+                        << endmsg;
+                }
+                else {
+                    std::cout << "FaserDetectorID::initLevelsFromDict - label CALONU does NOT have a value "
+                              << std::endl;
+                }
+                return (1);
+            }
+        }
+        else {
+            if(m_msgSvc) {
+                MsgStream log(m_msgSvc, "FaserDetectorID" );
+                log << MSG::ERROR << "initLevelsFromDict - unable to find 'CALONU' label "
+                    << endmsg;
+            }
+            else {
+                std::cout << "FaserDetectorID::initLevelsFromDict - unable to find 'CALONU' label "
+                          << std::endl;
+            }
+            return (1);
+        }
     }
 
     // set det/subdet indices
diff --git a/DetectorDescription/FaserDetDescr/src/FaserDetectorIDHelper.cxx b/DetectorDescription/FaserDetDescr/src/FaserDetectorIDHelper.cxx
index f192dcaff52bf68da5d9de6e815810b643963715..343be1f50fc9e8b8cff6601a8e9fd0a6a9db109a 100644
--- a/DetectorDescription/FaserDetDescr/src/FaserDetectorIDHelper.cxx
+++ b/DetectorDescription/FaserDetDescr/src/FaserDetectorIDHelper.cxx
@@ -30,12 +30,15 @@ FaserDetectorIDHelper::FaserDetectorIDHelper(void)
 	m_isSLHC(false),
 	m_emulsion_region_index(UNDEFINED),
 	m_veto_region_index(UNDEFINED),
+	m_vetonu_region_index(UNDEFINED),
 	m_trigger_region_index(UNDEFINED),
 	m_preshower_region_index(UNDEFINED),
-    m_sct_region_index(UNDEFINED),
-    m_ecal_region_index(UNDEFINED),
+	m_muon_region_index(UNDEFINED),
+        m_sct_region_index(UNDEFINED),
+        m_ecal_region_index(UNDEFINED),
+	m_calonu_region_index(UNDEFINED),
 	m_initialized(false),
-    m_msgSvc(0)
+        m_msgSvc(0)
 {}
 
 FaserDetectorIDHelper::~FaserDetectorIDHelper(void)
@@ -99,7 +102,7 @@ FaserDetectorIDHelper::initialize_from_dictionary(const IdDictMgr& dict_mgr)
     }
     else {
 	// Check if this is SLHC layout
-	m_isSLHC = (dict->m_version=="SLHC");
+	//m_isSLHC = (dict->m_version=="SLHC");
 
 	// Save index to a VETO region for unpacking
 	id = faser_id.veto_exp(); 
@@ -117,40 +120,70 @@ FaserDetectorIDHelper::initialize_from_dictionary(const IdDictMgr& dict_mgr)
             }
 	}
 
-	//if (!m_isSLHC) {
-	    
-	    // Save index to a TRIGGER region for unpacking
-	    id = faser_id.trigger_exp();
-	    if (dict->find_region(id, m_trigger_region_index)) {
-                if(m_msgSvc) {
-                    MsgStream log(m_msgSvc, "FaserDetectorIDHelper" );
-                    log << MSG::WARNING << "initialize_from_dictionary - unable to find trigger region index: id, reg "  
-                        << (std::string)id << " " << m_trigger_region_index
-                        << endmsg;
-                }
-                else {
-                    std::cout << "FaserDetectorIDHelper::initialize_from_dictionary - Warning: unable to trigger sct region index: id, reg "  
-                              << (std::string)id << " " << m_trigger_region_index
-                              << std::endl;
-                }
-	    }
+	// Save index to a VETONU region for unpacking
+	id = faser_id.vetonu_exp(); 
+	if (dict->find_region(id, m_vetonu_region_index)) {
+            if(m_msgSvc) {
+                MsgStream log(m_msgSvc, "FaserDetectorIDHelper" );
+                log << MSG::WARNING << "initialize_from_dictionary - unable to find vetonu region index: id, reg "  
+                    << (std::string)id << " " << m_vetonu_region_index
+                    << endmsg;
+            }
+            else {
+                std::cout << "FaserDetectorIDHelper::initialize_from_dictionary - Warning: unable to find vetonu region index: id, reg "  
+                          << (std::string)id << " " << m_vetonu_region_index
+                          << std::endl;
+            }
+	}
+	
+	// Save index to a TRIGGER region for unpacking
+	id = faser_id.trigger_exp();
+	if (dict->find_region(id, m_trigger_region_index)) {
+	  if(m_msgSvc) {
+	    MsgStream log(m_msgSvc, "FaserDetectorIDHelper" );
+	    log << MSG::WARNING << "initialize_from_dictionary - unable to find trigger region index: id, reg "  
+		<< (std::string)id << " " << m_trigger_region_index
+		<< endmsg;
+	  }
+	  else {
+	    std::cout << "FaserDetectorIDHelper::initialize_from_dictionary - Warning: unable to trigger sct region index: id, reg "  
+		      << (std::string)id << " " << m_trigger_region_index
+		      << std::endl;
+	  }
+	}
 
-	    // Save index to a PRESHOWER region for unpacking
-	    id = faser_id.preshower_exp(); 
-	    if (dict->find_region(id, m_preshower_region_index)) {
-                if(m_msgSvc) {
-                    MsgStream log(m_msgSvc, "FaserDetectorIDHelper" );
-                    log << MSG::WARNING << "initialize_from_dictionary - unable to find preshower region index: id, reg "  
-                        << (std::string)id << " " << m_preshower_region_index
-                        << endmsg;
-                }
-                else {
-                    std::cout << "FaserDetectorIDHelper::initialize_from_dictionary - Warning: unable to find preshower region index: id, reg "  
-                              << (std::string)id << " " << m_preshower_region_index
-                              << std::endl;
-                }
+	// Save index to a PRESHOWER region for unpacking
+	id = faser_id.preshower_exp(); 
+	if (dict->find_region(id, m_preshower_region_index)) {
+	  if(m_msgSvc) {
+	    MsgStream log(m_msgSvc, "FaserDetectorIDHelper" );
+	    log << MSG::WARNING << "initialize_from_dictionary - unable to find preshower region index: id, reg "  
+		<< (std::string)id << " " << m_preshower_region_index
+		<< endmsg;
+	  }
+	  else {
+	    std::cout << "FaserDetectorIDHelper::initialize_from_dictionary - Warning: unable to find preshower region index: id, reg "  
+		      << (std::string)id << " " << m_preshower_region_index
+		      << std::endl;
+	  }
+	}
+
+	// Save index to a MUON region for unpacking
+	id = faser_id.muon_exp(); 
+	if (dict->find_region(id, m_muon_region_index)) {
+            if(m_msgSvc) {
+                MsgStream log(m_msgSvc, "FaserDetectorIDHelper" );
+                log << MSG::WARNING << "initialize_from_dictionary - unable to find muon region index: id, reg "  
+                    << (std::string)id << " " << m_muon_region_index
+                    << endmsg;
             }
-	//}
+            else {
+                std::cout << "FaserDetectorIDHelper::initialize_from_dictionary - Warning: unable to find muon region index: id, reg "  
+                          << (std::string)id << " " << m_muon_region_index
+                          << std::endl;
+            }
+	}
+	
     }
     
     dict = dict_mgr.find_dictionary ("Tracker"); 
@@ -197,21 +230,38 @@ FaserDetectorIDHelper::initialize_from_dictionary(const IdDictMgr& dict_mgr)
         }
     }
     else {
-        // Save index to an ECAL region for unpacking
-        id = faser_id.ecal_exp(); 
-        if (dict->find_region(id, m_ecal_region_index)) {
-                if(m_msgSvc) {
-                    MsgStream log(m_msgSvc, "FaserDetectorIDHelper" );
-                    log << MSG::WARNING << "initialize_from_dictionary - unable to find ecal region index: id, reg "  
-                        << (std::string)id << " " << m_ecal_region_index
-                        << endmsg;
-                }
-                else {
-                    std::cout << "FaserDetectorIDHelper::initialize_from_dictionary - Warning: unable to find ecal region index: id, reg "  
-                            << (std::string)id << " " << m_ecal_region_index
-                            << std::endl;
-                }
-        }	
+      // Save index to an ECAL region for unpacking
+      id = faser_id.ecal_exp(); 
+      if (dict->find_region(id, m_ecal_region_index)) {
+	if(m_msgSvc) {
+	  MsgStream log(m_msgSvc, "FaserDetectorIDHelper" );
+	  log << MSG::WARNING << "initialize_from_dictionary - unable to find ecal region index: id, reg "  
+	      << (std::string)id << " " << m_ecal_region_index
+	      << endmsg;
+	}
+	else {
+	  std::cout << "FaserDetectorIDHelper::initialize_from_dictionary - Warning: unable to find ecal region index: id, reg "  
+		    << (std::string)id << " " << m_ecal_region_index
+		    << std::endl;
+	}
+      }	
+
+      // Save index to an CALONU region for unpacking
+      id = faser_id.calonu_exp(); 
+      if (dict->find_region(id, m_calonu_region_index)) {
+	if(m_msgSvc) {
+	  MsgStream log(m_msgSvc, "FaserDetectorIDHelper" );
+	  log << MSG::WARNING << "initialize_from_dictionary - unable to find calonu region index: id, reg "  
+	      << (std::string)id << " " << m_calonu_region_index
+	      << endmsg;
+	}
+	else {
+	  std::cout << "FaserDetectorIDHelper::initialize_from_dictionary - Warning: unable to find calonu region index: id, reg "  
+		    << (std::string)id << " " << m_calonu_region_index
+		    << std::endl;
+	}
+      }	
+
     }
         
     return (0);
diff --git a/DetectorDescription/FaserDetDescr/src/FaserDetectorIDHelper.h b/DetectorDescription/FaserDetDescr/src/FaserDetectorIDHelper.h
index ead07e481e66177d74b0ac9bf5f2ca71fc8de857..11d02fa9e3de91a8db14bd17c465347f2e3ff87b 100644
--- a/DetectorDescription/FaserDetDescr/src/FaserDetectorIDHelper.h
+++ b/DetectorDescription/FaserDetDescr/src/FaserDetectorIDHelper.h
@@ -47,10 +47,13 @@ public:
     
     size_type   emulsion_region_index();
     size_type   veto_region_index();
+    size_type   vetonu_region_index();
     size_type   trigger_region_index();
     size_type   preshower_region_index();
+    size_type   muon_region_index();
     size_type   sct_region_index();
     size_type   ecal_region_index();
+    size_type   calonu_region_index();
 
     void        setMsgSvc(IMessageSvc* msgSvc) { m_msgSvc = msgSvc; }
 
@@ -62,10 +65,14 @@ private:
     bool                m_isSLHC;
     size_type   m_emulsion_region_index;
     size_type		m_veto_region_index;
+    size_type		m_vetonu_region_index;
     size_type		m_trigger_region_index;
     size_type		m_preshower_region_index;
+    size_type		m_muon_region_index;
+
     size_type   m_sct_region_index;
     size_type   m_ecal_region_index;
+    size_type   m_calonu_region_index;
     bool		m_initialized;
     /// pointer to the message service
     IMessageSvc*        m_msgSvc;
@@ -82,17 +89,26 @@ inline FaserDetectorIDHelper::size_type   FaserDetectorIDHelper::emulsion_region
 inline FaserDetectorIDHelper::size_type   FaserDetectorIDHelper::veto_region_index()
 {return (m_veto_region_index);}       
 
+inline FaserDetectorIDHelper::size_type   FaserDetectorIDHelper::vetonu_region_index()
+{return (m_vetonu_region_index);}       
+
 inline FaserDetectorIDHelper::size_type   FaserDetectorIDHelper::trigger_region_index()
 {return (m_trigger_region_index);}         
 
 inline FaserDetectorIDHelper::size_type   FaserDetectorIDHelper::preshower_region_index()
 {return (m_preshower_region_index);}         
 
+inline FaserDetectorIDHelper::size_type   FaserDetectorIDHelper::muon_region_index()
+{return (m_muon_region_index);}       
+
 inline FaserDetectorIDHelper::size_type   FaserDetectorIDHelper::sct_region_index()
 {return (m_sct_region_index);}         
 
 inline FaserDetectorIDHelper::size_type   FaserDetectorIDHelper::ecal_region_index()
 {return (m_ecal_region_index);}         
 
+inline FaserDetectorIDHelper::size_type   FaserDetectorIDHelper::calonu_region_index()
+{return (m_calonu_region_index);}         
+
 
 #endif // SRC_FASERDETECTORIDHELPER_H
diff --git a/Event/FaserByteStreamCnvSvcBase/python/FaserByteStreamCnvSvcBaseConfig.py b/Event/FaserByteStreamCnvSvcBase/python/FaserByteStreamCnvSvcBaseConfig.py
index 0762f26a32509e0dd8c0f565d58d46baad9f64d8..971cbb02381db9add998e9feaa08c3efd234ff4e 100644
--- a/Event/FaserByteStreamCnvSvcBase/python/FaserByteStreamCnvSvcBaseConfig.py
+++ b/Event/FaserByteStreamCnvSvcBase/python/FaserByteStreamCnvSvcBaseConfig.py
@@ -15,10 +15,12 @@ def FaserByteStreamCnvSvcBaseCfg(flags, **kwargs):
     adxProvider.TypeNames += [
         "RawWaveformContainer/CaloWaveforms",
         "RawWaveformContainer/Calo2Waveforms",
+        "RawWaveformContainer/CaloNuWaveforms",
         "RawWaveformContainer/VetoWaveforms",
         "RawWaveformContainer/VetoNuWaveforms",
         "RawWaveformContainer/TriggerWaveforms",
         "RawWaveformContainer/PreshowerWaveforms",
+        "RawWaveformContainer/MuonWaveforms",
         "RawWaveformContainer/ClockWaveforms",
         "RawWaveformContainer/TestWaveforms"  
     ]
diff --git a/LHCData/LHCDataAlgs/src/LHCDataAlg.cxx b/LHCData/LHCDataAlgs/src/LHCDataAlg.cxx
index 1c0e49926225f2198d0ad6c8c4447a3bd966a628..0799eb393c187b4df1c9a0b0fb6522653c1d010a 100644
--- a/LHCData/LHCDataAlgs/src/LHCDataAlg.cxx
+++ b/LHCData/LHCDataAlgs/src/LHCDataAlg.cxx
@@ -82,6 +82,9 @@ LHCDataAlg::execute(const EventContext& ctx) const {
   if (m_lhcTool->getBeam1Bunches(ctx) == 0) {
     ATH_MSG_INFO("No beam 1 bunches, can't set nearest");
     nearest = -3564;
+  } else if (m_lhcTool->getBeam1Bunches(ctx) <= m_lhcTool->getCollidingBunches(ctx)) {
+    ATH_MSG_INFO("No unpaired beam 1 bunches, " << m_lhcTool->getCollidingBunches(ctx) << " colliding, can't set nearest unpaired");
+    nearest = -3564;
   } else {
     nearest = findNearest(bcid, bcid_mask, 1);  // Beam1 unpaired
   }
@@ -92,6 +95,9 @@ LHCDataAlg::execute(const EventContext& ctx) const {
   if (m_lhcTool->getBeam2Bunches(ctx) == 0) {
     ATH_MSG_INFO("No beam 2 bunches, can't set nearest");
     nearest = -3564;
+  } else if (m_lhcTool->getBeam2Bunches(ctx) <= m_lhcTool->getCollidingBunches(ctx)) {
+    ATH_MSG_INFO("No unpaired beam 2 bunches, " << m_lhcTool->getCollidingBunches(ctx) << " colliding, can't set nearest unpaired");
+    nearest = -3564;
   } else {
     nearest = findNearest(bcid, bcid_mask, 2);  // Beam2 unpaired
   }
@@ -101,8 +107,12 @@ LHCDataAlg::execute(const EventContext& ctx) const {
 
   // Add 127 to current BCID to check if inbound B1 is nearby FASER
   if (m_lhcTool->getBeam1Bunches(ctx) == 0) {
-    ATH_MSG_INFO("No beam 1 bunches, can't set nearest");
+    ATH_MSG_INFO("No beam 1 bunches, can't set nearest inbound");
     nearest = -3564;
+  } else if (m_lhcTool->getBeam1Bunches(ctx) <= m_lhcTool->getCollidingBunches(ctx)) {
+    // No unpaired B1
+    int offset_bcid = (bcid + 127) % 3564;
+    nearest = findNearest(offset_bcid, bcid_mask, 3);  // Inbound B1
   } else {
     int offset_bcid = (bcid + 127) % 3564;
     nearest = findNearest(offset_bcid, bcid_mask, 1);  // Inbound B1
@@ -115,7 +125,7 @@ LHCDataAlg::execute(const EventContext& ctx) const {
 
   unsigned int previous;
   if (m_lhcTool->getCollidingBunches(ctx) == 0) {
-    ATH_MSG_INFO("No colliding bunches, can't set nearest");
+    ATH_MSG_INFO("No colliding bunches, can't set previous colliding");
     previous = 9999;
   } else {
     previous = previousColliding(bcid, bcid_mask);
@@ -125,7 +135,7 @@ LHCDataAlg::execute(const EventContext& ctx) const {
 		<< " to the previous colliding bunch ");
 
   if (m_lhcTool->getCollidingBunches(ctx) == 0) {
-    ATH_MSG_INFO("No colliding bunches, can't set nearest");
+    ATH_MSG_INFO("No colliding bunches, can't set start of train");
     previous = 9999;
   } else {
     previous = previousTrain(bcid, bcid_mask);
diff --git a/PhysicsAnalysis/NtupleDumper/CMakeLists.txt b/PhysicsAnalysis/NtupleDumper/CMakeLists.txt
index 56d8fd54b7983d5725af044dd365b39a551920cb..359fe29b29ca0a4156289ef2f416b80ee499a407 100644
--- a/PhysicsAnalysis/NtupleDumper/CMakeLists.txt
+++ b/PhysicsAnalysis/NtupleDumper/CMakeLists.txt
@@ -8,7 +8,7 @@ atlas_add_component(
         src/NtupleDumperAlg.cxx
         src/component/NtupleDumper_entries.cxx
 
-        LINK_LIBRARIES AthenaBaseComps StoreGateLib xAODFaserWaveform xAODFaserCalorimeter xAODFaserTrigger xAODFaserLHC ScintIdentifier FaserCaloIdentifier GeneratorObjects FaserActsGeometryLib TrackerSimEvent TrackerSimData TrackerIdentifier TrackerReadoutGeometry TrkTrack GeoPrimitives TrackerRIO_OnTrack TrackerSpacePoint FaserActsKalmanFilterLib AtlasHepMCLib WaveformConditionsToolsLib FaserActsmanVertexingLib 
+        LINK_LIBRARIES AthenaBaseComps StoreGateLib xAODFaserWaveform xAODFaserCalorimeter xAODFaserTrigger xAODFaserLHC ScintIdentifier FaserCaloIdentifier GeneratorObjects FaserActsGeometryLib TrackerSimEvent TrackerSimData TrackerIdentifier ScintIdentifier TrackerReadoutGeometry TrkTrack GeoPrimitives TrackerRIO_OnTrack TrackerSpacePoint FaserActsKalmanFilterLib AtlasHepMCLib WaveformConditionsToolsLib FaserActsmanVertexingLib 
 	PRIVATE_LINK_LIBRARIES nlohmann_json::nlohmann_json )
 
 atlas_install_python_modules( python/*.py )
diff --git a/PhysicsAnalysis/NtupleDumper/scripts/faser_ntuple_maker.py b/PhysicsAnalysis/NtupleDumper/scripts/faser_ntuple_maker.py
index 3f28a5782da238b899812baad6a3dc13aa2b2853..c9e7b70454ab19afea4dd908e4c24ea180da441a 100755
--- a/PhysicsAnalysis/NtupleDumper/scripts/faser_ntuple_maker.py
+++ b/PhysicsAnalysis/NtupleDumper/scripts/faser_ntuple_maker.py
@@ -46,9 +46,11 @@ parser.add_argument("--partial", action='store_true',
                     help="Allow partial input files")
 
 parser.add_argument("-c", "--cond", default="",
-                    help="Specify global conditions tag (default: OFLCOND-FASER-04)")
+                    help="Specify global conditions tag (default: OFLCOND-FASER-05)")
 parser.add_argument("--backward", action='store_true',
                     help="Use backward CKF tracks (default: forward)")
+parser.add_argument("--useIFT", action='store_true',
+                    help="Use 4-station tracks (default: 3-station)")
 
 parser.add_argument("--trigFilt", action='store_true',
                     help="apply trigger event filter")
@@ -232,6 +234,7 @@ print(f"Blind = {not args.unblind}")
 print(f"OnlyBlinded = {args.onlyblind}")
 print(f"Stable Beams = {not args.no_stable}")
 print(f"Backward = {args.backward}")
+print(f"Use IFT = {args.useIFT}")
 print(f"GRL = {args.grl}")
 print(f"Random Filter = {args.randomTrigFilt}")
 print(f"Random Only Filter = {args.randomOnlyTrigFilt}")
@@ -262,7 +265,7 @@ else:
 
 if runtype in ["TI12Data04", "TI12MC04"]:
     configFlags.GeoModel.FaserVersion = "FASERNU-04" # FASER geometry
-    configFlags.IOVDb.GlobalTag = "OFLCOND-FASER-04"   
+    configFlags.IOVDb.GlobalTag = "OFLCOND-FASER-05"   
 
 elif runtype == "TI12Data03":
     configFlags.GeoModel.FaserVersion = "FASERNU-03" # FASER geometry
@@ -317,9 +320,16 @@ if args.fluka:
 if args.backward:
     if args.isMC:
         mc_kwargs['TrackCollectionWithoutIFT'] = "CKFTrackCollectionBackwardWithoutIFT"
+        mc_kwargs['TrackCollection'] = "CKFTrackCollectionBackward"
     else:
         grl_kwargs['TrackCollectionWithoutIFT'] = "CKFTrackCollectionBackwardWithoutIFT"
+        grl_kwargs['TrackCollection'] = "CKFTrackCollectionBackward"
 
+if args.isMC:
+    mc_kwargs['UseIFT'] = args.useIFT
+else:
+    grl_kwargs['UseIFT'] = args.useIFT
+    
 # algorithm
 from NtupleDumper.NtupleDumperConfig import NtupleDumperAlgCfg
 if args.isMC:
diff --git a/PhysicsAnalysis/NtupleDumper/scripts/submit_faser_ntuple_maker.sh b/PhysicsAnalysis/NtupleDumper/scripts/submit_faser_ntuple_maker.sh
index ae925ed988f5d668c256f55195389b3668a74838..97022aeef8a3402a51a7062ea1497f8d1e2686f5 100755
--- a/PhysicsAnalysis/NtupleDumper/scripts/submit_faser_ntuple_maker.sh
+++ b/PhysicsAnalysis/NtupleDumper/scripts/submit_faser_ntuple_maker.sh
@@ -265,6 +265,19 @@ else
     cp -r $cond_directory .
     ls -R data
 fi
+# 
+# Further check if there is a pool conditions override
+if [[ -d "data/poolcond" ]]; then
+    echo "Local POOL directory found!"
+    echo "Change ATLAS_POOLCOND_PATH"
+    echo " from $ATLAS_POOLCOND_PATH"
+    export ATLAS_POOLCOND_PATH=`pwd -P`/data
+    echo " to $ATLAS_POOLCOND_PATH"
+else
+    echo "No local pool files found, use default:"
+    echo " $ATLAS_POOLCOND_PATH"
+fi
+echo "Final ATLAS_POOLCOND_PATH: $ATLAS_POOLCOND_PATH"
 #
 # Run job
 #
diff --git a/PhysicsAnalysis/NtupleDumper/src/NtupleDumperAlg.cxx b/PhysicsAnalysis/NtupleDumper/src/NtupleDumperAlg.cxx
index 284cf59e713f1b61b12196b6d48eda70ea2a30e6..05e31bc208ad3c0a4f1492250e98cfa2c548f7c1 100644
--- a/PhysicsAnalysis/NtupleDumper/src/NtupleDumperAlg.cxx
+++ b/PhysicsAnalysis/NtupleDumper/src/NtupleDumperAlg.cxx
@@ -47,9 +47,12 @@ void NtupleDumperAlg::addBranch(const std::string &name,
   m_tree->Branch(name.c_str(),var,(name+"/I").c_str());
 }
 
+// Return channel map from mappingTool
 std::map<std::string, std::list<int>>&
 NtupleDumperAlg::getChannelMap() const {
 
+  ATH_MSG_DEBUG("getChannelMap");
+  
   // Use waveform map to find all defined waveform channels
   auto mapping = m_mappingTool->getCableMapping();
   ATH_MSG_DEBUG("Cable mapping contains " << mapping.size() << " entries");
@@ -58,15 +61,23 @@ NtupleDumperAlg::getChannelMap() const {
   // use this to fill my own map of channel lists keyed by type
   static std::map<std::string, std::list<int>> wave_map;
 
+  std::string detector;
+
   for (const auto& [key, value] : mapping) {
-    wave_map[value.first].push_back(key);
-    ATH_MSG_DEBUG("Found mapping " << value.first << " chan " << key);
+    // Special handling for Veto to differentiate veto1 from veto2
+    detector = value.first;
+    if (value.first == std::string("veto")) {
+      // Append station to key string
+      detector += std::to_string(m_vetoID->station(value.second)+1);
+    }
+    wave_map[detector].push_back(key);
+    ATH_MSG_DEBUG("Found mapping " << detector << " chan " << key);
   }
 
   return wave_map;
 }
 
-// Have to declare this cost to call during execute
+// Have to declare this const to call during execute
 void NtupleDumperAlg::defineWaveBranches() const {
 
   ATH_MSG_DEBUG("defineWaveBranches called");
@@ -78,17 +89,30 @@ void NtupleDumperAlg::defineWaveBranches() const {
   for (const auto& [key, value] : wave_map) {
 
     if (key == std::string("calo")) {
-      addWaveBranches("CaloLo", value);
+      m_calolo_channels = value;
+      // Figure out ntuple below
     }
     else if (key == std::string("calo2")) {
-      addWaveBranches("CaloHi", value);
+      m_calohi_channels = value;
+      // Figure out ntuple below
     }
     else if (key == std::string("calonu")) {
+      m_calonu_channels = value;
       addWaveBranches("CaloNu", value);
+      addCalibratedBranches("CaloNu", value);
+      addCaloSumBranches("CaloNu");
     }
+    // Old way (depends on cable map order)
     else if (key == std::string("veto")) {
       addWaveBranches("Veto", value);
     }
+    // New way (better, differentiates veto1 and veto2
+    else if (key == std::string("veto1")) {
+      addWaveBranches("Veto1", value);
+    }
+    else if (key == std::string("veto2")) {
+      addWaveBranches("Veto2", value);
+    }    
     else if (key == std::string("vetonu")) {
       addWaveBranches("VetoNu", value);
     }
@@ -97,6 +121,12 @@ void NtupleDumperAlg::defineWaveBranches() const {
     }
     else if (key == std::string("preshower")) {
       addWaveBranches("Preshower", value);
+      addCalibratedBranches("Preshower", value);
+      addBranch("Preshower_total_nMIP", &m_preshower_total_nMIP);
+      addBranch("Preshower_total_E_dep", &m_preshower_total_E_dep);      
+    }
+    else if (key == std::string("muon")) {
+      addWaveBranches("Muon", value);
     }
     else if (key == std::string("clock")) {
       // ignore this
@@ -107,35 +137,88 @@ void NtupleDumperAlg::defineWaveBranches() const {
     else {
       ATH_MSG_WARNING("Found unknown mapping type " << key);
     }
+  } // End of loop over wave_map entries
+
+  // Figure out calorimeter
+  if (m_calolo_channels.size() && !m_calohi_channels.size()) {
+    // Only "calo" type found, 2022/23 configuration
+    ATH_MSG_INFO("defineWaveBranches found " << m_calolo_channels.size() << " calo channels => 2022/23 configuration");
+    m_dual_gain = false;
+    m_calo_channels = m_calolo_channels;
+    m_calolo_channels.clear();
+    addWaveBranches("Calo", m_calo_channels);
+    addCalibratedBranches("Calo", m_calo_channels);
+    addCaloSumBranches("Calo");
   }
-
+  else if (m_calolo_channels.size() && m_calohi_channels.size()) {
+    // Both found, 2024/25 configuration (both defined)
+    ATH_MSG_INFO("defineWaveBranches found " << m_calolo_channels.size() << " calo and " << m_calohi_channels.size() << " calo2 channels => 2024/25 configuration");
+    m_dual_gain = true;
+    addWaveBranches("CaloLo", m_calolo_channels);
+    addWaveBranches("CaloHi", m_calohi_channels);
+    addCalibratedBranches("CaloLo", m_calolo_channels);    
+    addCalibratedBranches("CaloHi", m_calohi_channels);
+    addCaloSumBranches("CaloLo");
+    addCaloSumBranches("CaloHi");
+  }
+  else {
+    // Unknown configuration
+    ATH_MSG_WARNING("defineWaveBranches found " << m_calolo_channels.size() << " calo channels and " << m_calohi_channels.size() << " calo2 channels!");
+    m_dual_gain = false;
+    return;
+  }
+  
   ATH_MSG_DEBUG("defineWaveBranches done");
-
 }
 
-void NtupleDumperAlg::addWaveBranches(const std::string &name,
-				      int nchannels,
-				      int first) const {
-  for(int ch=0;ch<nchannels;ch++) {
-    std::string base=name+std::to_string(ch)+"_";
-    addBranch(base+"time",&m_wave_localtime[first]);
-    addBranch(base+"peak",&m_wave_peak[first]);
-    addBranch(base+"width",&m_wave_width[first]);
-    addBranch(base+"charge",&m_wave_charge[first]);
-    addBranch(base+"raw_peak",&m_wave_raw_peak[first]);
-    addBranch(base+"raw_charge",&m_wave_raw_charge[first]);
-    addBranch(base+"baseline",&m_wave_baseline_mean[first]);
-    addBranch(base+"baseline_rms",&m_wave_baseline_rms[first]);
-    addBranch(base+"status",&m_wave_status[first]);
-    first++;
+void
+NtupleDumperAlg::addCaloSumBranches(const std::string &name) const {
+
+  ATH_MSG_DEBUG("addCaloSumBranches " << name << " called");
+  
+  // Utility to define the calorimeter sum branches
+  if (name == std::string("Calo")) {
+    addBranch("Calo_total_nMIP", &m_calo_total_nMIP);
+    addBranch("Calo_total_E_dep", &m_calo_total_E_dep);
+    addBranch("Calo_total_fit_E_EM", &m_calo_total_fit_E_EM);
+    addBranch("Calo_total_raw_E_EM", &m_calo_total_raw_E_EM);
+    addBranch("Calo_total_E_EM", &m_calo_total_E_EM);
+
+    addBranch("Calo_total_fit_E_EM_fudged", &m_calo_total_fit_E_EM_fudged);
+    addBranch("Calo_total_raw_E_EM_fudged", &m_calo_total_raw_E_EM_fudged);
+    addBranch("Calo_total_E_EM_fudged", &m_calo_total_E_EM_fudged);
+  }
+  else if (name == std::string("CaloLo")) {
+    addBranch("CaloLo_total_nMIP", &m_calolo_total_nMIP);
+    addBranch("CaloLo_total_E_dep", &m_calolo_total_E_dep);
+    addBranch("CaloLo_total_fit_E_EM", &m_calolo_total_fit_E_EM);
+    addBranch("CaloLo_total_raw_E_EM", &m_calolo_total_raw_E_EM);
+    addBranch("CaloLo_total_E_EM", &m_calolo_total_E_EM);
+  }
+  else if (name == std::string("CaloHi")) {
+    addBranch("CaloHi_total_nMIP", &m_calohi_total_nMIP);
+    addBranch("CaloHi_total_E_dep", &m_calohi_total_E_dep);
+    addBranch("CaloHi_total_fit_E_EM", &m_calohi_total_fit_E_EM);
+    addBranch("CaloHi_total_raw_E_EM", &m_calohi_total_raw_E_EM);
+    addBranch("CaloHi_total_E_EM", &m_calohi_total_E_EM);
   }
+  else if (name == std::string("CaloNu")) {
+    addBranch("CaloNu_total_nMIP", &m_calonu_total_nMIP);
+    addBranch("CaloNu_total_E_dep", &m_calonu_total_E_dep);
+    addBranch("CaloNu_total_fit_E_EM", &m_calonu_total_fit_E_EM);
+    addBranch("CaloNu_total_raw_E_EM", &m_calonu_total_raw_E_EM);
+    addBranch("CaloNu_total_E_EM", &m_calonu_total_E_EM);
+  }
+  else {
+    ATH_MSG_WARNING("addCaloSumBranches - Unknown type " << name << "!");
+  }    
 }
 
 // Use channel list to add branches
 void NtupleDumperAlg::addWaveBranches(const std::string &name,
 				      std::list<int> channel_list) const {
 
-  ATH_MSG_DEBUG("Adding " << name << " with channels " << channel_list);
+  ATH_MSG_DEBUG("Adding waveforms " << name << " with channels " << channel_list);
 
   int nchannels = channel_list.size();
   for(int i=0;i<nchannels;i++) {
@@ -192,17 +275,25 @@ void NtupleDumperAlg::FillWaveBranches(const xAOD::WaveformHitContainer &wave, b
 }
 
 void NtupleDumperAlg::addCalibratedBranches(const std::string &name,
-                      int nchannels,
-                      int first) {
-  for(int ch=0;ch<nchannels;ch++) {
-    std::string base=name+std::to_string(ch)+"_";
-    addBranch(base+"nMIP",&m_calibrated_nMIP[first]);
-    addBranch(base+"E_dep",&m_calibrated_E_dep[first]);
-    addBranch(base+"E_EM",&m_calibrated_E_EM[first]);
-    first++;
+					    std::list<int> channel_list) const {
+
+  ATH_MSG_DEBUG("Adding calibrated " << name << " with channels " << channel_list);
+
+  int nchannels = channel_list.size();
+  for(int i=0;i<nchannels;i++) {
+    int ch = channel_list.front();
+    channel_list.pop_front();
+    
+    std::string base=name+std::to_string(i);
+    addBranch(base+"_nMIP", &m_calibrated_nMIP[ch]);
+    addBranch(base+"_E_dep",&m_calibrated_E_dep[ch]);
+    addBranch(base+"_E_EM", &m_calibrated_E_EM[ch]);    
+    ATH_MSG_DEBUG("Added "  << base << " ch " << ch);
+
   }
 }
 
+
 StatusCode NtupleDumperAlg::initialize() 
 {
 
@@ -217,10 +308,12 @@ StatusCode NtupleDumperAlg::initialize()
   ATH_CHECK(m_trackSegmentCollection.initialize());
   ATH_CHECK(m_trackTrueSegmentCollection.initialize());
 
-  ATH_CHECK(m_vetoNuContainer.initialize());
   ATH_CHECK(m_vetoContainer.initialize());
+  ATH_CHECK(m_vetoNuContainer.initialize());
   ATH_CHECK(m_triggerContainer.initialize());
   ATH_CHECK(m_preshowerContainer.initialize());
+  ATH_CHECK(m_muonContainer.initialize());
+
   ATH_CHECK(m_ecalContainer.initialize());
   ATH_CHECK(m_ecal2Container.initialize());
   ATH_CHECK(m_caloNuContainer.initialize());
@@ -237,8 +330,11 @@ StatusCode NtupleDumperAlg::initialize()
   ATH_CHECK(m_eventInfoKey.initialize());
 
   ATH_CHECK(detStore()->retrieve(m_sctHelper,       "FaserSCT_ID"));
-
+  
   ATH_CHECK(detStore()->retrieve(m_detMgr, "SCT"));
+
+  ATH_CHECK(detStore()->retrieve(m_vetoID, "VetoID"));
+    
   ATH_CHECK(m_extrapolationTool.retrieve());
   ATH_CHECK(m_trackingGeometryTool.retrieve());
   ATH_CHECK(m_trackTruthMatchingTool.retrieve());
@@ -305,19 +401,6 @@ StatusCode NtupleDumperAlg::initialize()
   
   m_tree->Branch("ScintHit", &m_scintHit);
 
-  addCalibratedBranches("Calo",4,0);
-  addBranch("Calo_total_nMIP", &m_calo_total_nMIP);
-  addBranch("Calo_total_E_dep", &m_calo_total_E_dep);
-  addBranch("Calo_total_fit_E_EM", &m_calo_total_fit_E_EM);
-  addBranch("Calo_total_raw_E_EM", &m_calo_total_raw_E_EM);
-  addBranch("Calo_total_E_EM", &m_calo_total_E_EM);
-  addBranch("Calo_total_fit_E_EM_fudged", &m_calo_total_fit_E_EM_fudged);
-  addBranch("Calo_total_raw_E_EM_fudged", &m_calo_total_raw_E_EM_fudged);
-  addBranch("Calo_total_E_EM_fudged", &m_calo_total_E_EM_fudged);
-
-  addCalibratedBranches("Preshower",2,12);
-  addBranch("Preshower_total_nMIP", &m_preshower_total_nMIP);
-  addBranch("Preshower_total_E_dep", &m_preshower_total_E_dep);
 
   //TRACKER
   addBranch("nClusters0",&m_station0Clusters);
@@ -340,7 +423,7 @@ StatusCode NtupleDumperAlg::initialize()
   m_tree->Branch("TrackSegment_py", &m_trackseg_py);
   m_tree->Branch("TrackSegment_pz", &m_trackseg_pz);
 
-    addBranch("TrueTrackSegments",&m_nTruetracksegs);
+  addBranch("TrueTrackSegments",&m_nTruetracksegs);
   m_tree->Branch("TrueTrackSegment_Chi2", &m_Truetrackseg_Chi2);
   m_tree->Branch("TrueTrackSegment_nDoF", &m_Truetrackseg_DoF);
   m_tree->Branch("TrueTrackSegment_x", &m_Truetrackseg_x);
@@ -715,6 +798,11 @@ StatusCode NtupleDumperAlg::execute(const EventContext &ctx) const
     FillWaveBranches(*preshowerContainer, isMC);
   }
 
+  SG::ReadHandle<xAOD::WaveformHitContainer> muonContainer { m_muonContainer, ctx };
+  if (muonContainer.isValid()) {
+    FillWaveBranches(*muonContainer, isMC);
+  }
+  
   SG::ReadHandle<xAOD::WaveformHitContainer> ecalContainer { m_ecalContainer, ctx };
   if (ecalContainer.isValid()) {
     FillWaveBranches(*ecalContainer, isMC);
@@ -762,26 +850,24 @@ StatusCode NtupleDumperAlg::execute(const EventContext &ctx) const
         return StatusCode::SUCCESS;
       }
     }
+    
     if (m_doRandomFilter) {
-    bool trig_random = m_tap & 16;
-    if ( !(trig_random)) { 
+      bool trig_random = m_tap & 16;
+      if ( !(trig_random)) { 
         // don't process events that fail to activate random trigger
         ATH_MSG_DEBUG("event did not pass random trigger filter");
         return StatusCode::SUCCESS;
       }
+    }
 
-  }
-
-  if (m_doRandomOnlyFilter) {
-    bool trig_random = m_tap == 16;
-    if ( !(trig_random)) { 
+    if (m_doRandomOnlyFilter) {
+      bool trig_random = m_tap == 16;
+      if ( !(trig_random)) { 
         // don't process events that fail to activate random only trigger
         ATH_MSG_DEBUG("event did not pass random trigger filter");
         return StatusCode::SUCCESS;
-      }
-
-  }
-
+      } 
+    }
 
     if (m_doScintFilter) {
       // Get channel mapping
@@ -824,6 +910,13 @@ StatusCode NtupleDumperAlg::execute(const EventContext &ctx) const
 	    vetoSt1_trig &= m_wave_raw_peak[chan] > 25.0;
 	  }
 	}
+      } else if (wave_map.contains(std::string("veto1"))) {
+	for (auto chan : wave_map[std::string("veto1")]) {
+	  vetoSt1_trig &= m_wave_raw_peak[chan] > 25.0;
+	}
+	for (auto chan : wave_map[std::string("veto2")]) {
+	  vetoSt2_trig &= m_wave_raw_peak[chan] > 25.0;
+	}
       } else {
 	vetoSt1_trig = false;
 	vetoSt2_trig = false;
@@ -920,30 +1013,33 @@ StatusCode NtupleDumperAlg::execute(const EventContext &ctx) const
   } // done with processing only on real data
 
   // fill scintHit word with bits that reflect if a scintillator was hit (1 = vetoNu0, 2 = vetoNu1, 4 = vetoSt1_1, 8 vetoSt2_0, 16 = vetoSt2_1, 32 = Timing scint, 64 = preshower0, 128 = preshower1)
-  if (m_wave_raw_charge[4] > 40.0) {
-    m_scintHit = m_scintHit | 1;
-  }
-  if (m_wave_raw_charge[5] > 40.0) {
-    m_scintHit = m_scintHit | 2;
-  }
-  if (m_wave_raw_charge[14] > 40.0) {
-    m_scintHit = m_scintHit | 4;
-  }
-  if (m_wave_raw_charge[6] > 40.0) {
-    m_scintHit = m_scintHit | 8;
-  }
-  if (m_wave_raw_charge[7] > 40.0) {
-    m_scintHit = m_scintHit | 16;
-  }
-  if (m_wave_raw_charge[8]+m_wave_raw_charge[9]+m_wave_raw_charge[10]+m_wave_raw_charge[11] > 25.0) {
-    m_scintHit = m_scintHit | 32;
-  }
-  if (m_wave_raw_charge[12] > 2.5) {
-    m_scintHit = m_scintHit | 64;
-  }
-  if (m_wave_raw_charge[13] > 2.5) {
-    m_scintHit = m_scintHit | 128;
-  }
+
+  // This either needs to be updated to use cable map, or skipped
+  // Skip for now
+  // if (m_wave_raw_charge[4] > 40.0) {
+  //   m_scintHit = m_scintHit | 1;
+  // }
+  // if (m_wave_raw_charge[5] > 40.0) {
+  //   m_scintHit = m_scintHit | 2;
+  // }
+  // if (m_wave_raw_charge[14] > 40.0) {
+  //   m_scintHit = m_scintHit | 4;
+  // }
+  // if (m_wave_raw_charge[6] > 40.0) {
+  //   m_scintHit = m_scintHit | 8;
+  // }
+  // if (m_wave_raw_charge[7] > 40.0) {
+  //   m_scintHit = m_scintHit | 16;
+  // }
+  // if (m_wave_raw_charge[8]+m_wave_raw_charge[9]+m_wave_raw_charge[10]+m_wave_raw_charge[11] > 25.0) {
+  //   m_scintHit = m_scintHit | 32;
+  // }
+  // if (m_wave_raw_charge[12] > 2.5) {
+  //   m_scintHit = m_scintHit | 64;
+  // }
+  // if (m_wave_raw_charge[13] > 2.5) {
+  //   m_scintHit = m_scintHit | 128;
+  // }
 
   if (isMC) { // if simulation find MC cross section and primary lepton
     // Work out effective cross section for MC
@@ -1085,25 +1181,56 @@ StatusCode NtupleDumperAlg::execute(const EventContext &ctx) const
 
   // load in calibrated calo container
   SG::ReadHandle<xAOD::CalorimeterHitContainer> ecalCalibratedContainer { m_ecalCalibratedContainer, ctx };
-  ATH_CHECK(ecalCalibratedContainer.isValid());
-  for (auto hit : *ecalCalibratedContainer) {
-    int ch=hit->channel();
-    m_calibrated_nMIP[ch] = hit->Nmip();
-    m_calibrated_E_dep[ch] = hit->E_dep(); 
-    m_calibrated_E_EM[ch] = hit->E_EM();
-
-    m_calo_total_nMIP += hit->Nmip();
-    m_calo_total_E_dep += hit->E_dep();
-    m_calo_total_fit_E_EM += hit->E_EM();
-    m_calo_total_raw_E_EM += (hit->E_EM()*hit->fit_to_raw_ratio());
-
-    if (m_wave_status[ch]&4) {
-        m_calo_total_E_EM += hit->E_EM();
-    } else {
-        m_calo_total_E_EM += (hit->E_EM()*hit->fit_to_raw_ratio());
-    }
+  if (ecalCalibratedContainer.isValid()) {
+    for (auto hit : *ecalCalibratedContainer) {
+      int ch=hit->channel();
+      m_calibrated_nMIP[ch] = hit->Nmip();
+      m_calibrated_E_dep[ch] = hit->E_dep(); 
+      m_calibrated_E_EM[ch] = hit->E_EM();
+
+      ATH_MSG_DEBUG("Calibrated calo: ch is " << ch
+		  << ", edep is " << hit->E_dep()
+		  << ", E_EM is " << hit->E_EM()
+		  << ", Nmip is " << hit->Nmip()
+		  << ", fit_to_raw_ratio is " << hit->fit_to_raw_ratio());
+    
+      if (m_dual_gain) {
+	m_calolo_total_nMIP += hit->Nmip();
+	m_calolo_total_E_dep += hit->E_dep();
+	m_calolo_total_fit_E_EM += hit->E_EM();
+	m_calolo_total_raw_E_EM += (hit->E_EM()*hit->fit_to_raw_ratio());
+	
+	if (m_wave_status[ch]&4) { // Overflows
+	  m_calolo_total_E_EM += hit->E_EM();
+	} else {
+	  m_calolo_total_E_EM += (hit->E_EM()*hit->fit_to_raw_ratio());
+	}
+      } else {
+	m_calo_total_nMIP += hit->Nmip();
+	m_calo_total_E_dep += hit->E_dep();
+	m_calo_total_fit_E_EM += hit->E_EM();
+	m_calo_total_raw_E_EM += (hit->E_EM()*hit->fit_to_raw_ratio());
+	
+	if (m_wave_status[ch]&4) { // Overflows
+	  m_calo_total_E_EM += hit->E_EM();
+	} else {
+	  m_calo_total_E_EM += (hit->E_EM()*hit->fit_to_raw_ratio());
+	}
 
-    ATH_MSG_DEBUG("Calibrated calo: ch is " << ch << ", edep is " << hit->E_dep() << ", E_EM is " << hit->E_EM() << ", Nmip is " << hit->Nmip() << ", fit_to_raw_ratio is " << hit->fit_to_raw_ratio());
+	// add a fudged energy variable that corrects the MC to agree with the testbeam results
+	if (isMC) {
+	  // Add fudge factor for MC
+	  m_calo_total_fit_E_EM_fudged = m_calo_total_fit_E_EM * m_caloMC_FudgeFactor;
+	  m_calo_total_raw_E_EM_fudged = m_calo_total_raw_E_EM * m_caloMC_FudgeFactor;
+	  m_calo_total_E_EM_fudged = m_calo_total_E_EM * m_caloMC_FudgeFactor;
+	} else {
+	  // Unchanged in data
+	  m_calo_total_fit_E_EM_fudged = m_calo_total_fit_E_EM;
+	  m_calo_total_raw_E_EM_fudged = m_calo_total_raw_E_EM;
+	  m_calo_total_E_EM_fudged = m_calo_total_E_EM;
+	}
+      }
+    }
 
     //// the following is an example of how to access the linked waveform data from the calibrated data
     //auto measurements = &(hit->WaveformLinks())[0];
@@ -1117,32 +1244,80 @@ StatusCode NtupleDumperAlg::execute(const EventContext &ctx) const
     //}
   }
 
-  // add a fudged energy variable that corrects the MC to agree with the testbeam results
-  m_calo_total_fit_E_EM_fudged = m_calo_total_fit_E_EM;
-  m_calo_total_raw_E_EM_fudged = m_calo_total_raw_E_EM;
-  m_calo_total_E_EM_fudged = m_calo_total_E_EM;
-  if (isMC) {
-    m_calo_total_fit_E_EM_fudged = m_calo_total_fit_E_EM_fudged * m_caloMC_FudgeFactor;
-    m_calo_total_raw_E_EM_fudged = m_calo_total_raw_E_EM_fudged * m_caloMC_FudgeFactor;
-    m_calo_total_E_EM_fudged = m_calo_total_E_EM_fudged * m_caloMC_FudgeFactor;
+  // load in calibrated calo2 container
+  SG::ReadHandle<xAOD::CalorimeterHitContainer> ecal2CalibratedContainer { m_ecal2CalibratedContainer, ctx };
+  if (ecal2CalibratedContainer.isValid()) {
+    for (auto hit : *ecal2CalibratedContainer) {
+      int ch=hit->channel();
+      m_calibrated_nMIP[ch] = hit->Nmip();
+      m_calibrated_E_dep[ch] = hit->E_dep(); 
+      m_calibrated_E_EM[ch] = hit->E_EM();
+      
+      ATH_MSG_DEBUG("Calibrated calo: ch is " << ch
+		    << ", edep is " << hit->E_dep()
+		    << ", E_EM is " << hit->E_EM()
+		    << ", Nmip is " << hit->Nmip()
+		    << ", fit_to_raw_ratio is " << hit->fit_to_raw_ratio());
+      
+      m_calohi_total_nMIP += hit->Nmip();
+      m_calohi_total_E_dep += hit->E_dep();
+      m_calohi_total_fit_E_EM += hit->E_EM();
+      m_calohi_total_raw_E_EM += (hit->E_EM()*hit->fit_to_raw_ratio());
+      
+      if (m_wave_status[ch]&4) { // Overflows
+	m_calohi_total_E_EM += hit->E_EM();
+      } else {
+	m_calohi_total_E_EM += (hit->E_EM()*hit->fit_to_raw_ratio());
+      }     
+    }
   }
-
+  
+  // load in calibrated calo2 container
+  SG::ReadHandle<xAOD::CalorimeterHitContainer> calonuCalibratedContainer { m_calonuCalibratedContainer, ctx };
+  if (calonuCalibratedContainer.isValid()) {
+    for (auto hit : *calonuCalibratedContainer) {
+      int ch=hit->channel();
+      m_calibrated_nMIP[ch] = hit->Nmip();
+      m_calibrated_E_dep[ch] = hit->E_dep(); 
+      m_calibrated_E_EM[ch] = hit->E_EM();
+      
+      ATH_MSG_DEBUG("Calibrated calo: ch is " << ch
+		    << ", edep is " << hit->E_dep()
+		    << ", E_EM is " << hit->E_EM()
+		    << ", Nmip is " << hit->Nmip()
+		    << ", fit_to_raw_ratio is " << hit->fit_to_raw_ratio());
+      
+      m_calonu_total_nMIP += hit->Nmip();
+      m_calonu_total_E_dep += hit->E_dep();
+      m_calonu_total_fit_E_EM += hit->E_EM();
+      m_calonu_total_raw_E_EM += (hit->E_EM()*hit->fit_to_raw_ratio());
+      
+      if (m_wave_status[ch]&4) { // Overflows
+	m_calonu_total_E_EM += hit->E_EM();
+      } else {
+	m_calonu_total_E_EM += (hit->E_EM()*hit->fit_to_raw_ratio());
+      }     
+    }
+  }
+  
   // load in calibrated preshower container
   SG::ReadHandle<xAOD::CalorimeterHitContainer> preshowerCalibratedContainer { m_preshowerCalibratedContainer, ctx };
-  ATH_CHECK(preshowerCalibratedContainer.isValid());
-  for (auto hit : *preshowerCalibratedContainer) {
-    int ch=hit->channel();
-    m_calibrated_nMIP[ch] = hit->Nmip() * hit->fit_to_raw_ratio();
-    m_calibrated_E_dep[ch] = hit->E_dep() * hit->fit_to_raw_ratio();
-
-    m_preshower_total_nMIP += hit->Nmip() * hit->fit_to_raw_ratio();
-    m_preshower_total_E_dep += hit->E_dep() * hit->fit_to_raw_ratio();
-
-    ATH_MSG_DEBUG("Calibrated preshower: ch is " << ch << ", edep is " << hit->E_dep() << ", E_EM is " << hit->E_EM() << ", Nmip is " << hit->Nmip() << ", fit_to_raw_ratio is " << hit->fit_to_raw_ratio());
+  if (preshowerCalibratedContainer.isValid()) {
+    for (auto hit : *preshowerCalibratedContainer) {
+      int ch=hit->channel();
+      m_calibrated_nMIP[ch] = hit->Nmip() * hit->fit_to_raw_ratio();
+      m_calibrated_E_dep[ch] = hit->E_dep() * hit->fit_to_raw_ratio();
+      
+      m_preshower_total_nMIP += hit->Nmip() * hit->fit_to_raw_ratio();
+      m_preshower_total_E_dep += hit->E_dep() * hit->fit_to_raw_ratio();
+      
+      ATH_MSG_DEBUG("Calibrated preshower: ch is " << ch << ", edep is " << hit->E_dep() << ", E_EM is " << hit->E_EM() << ", Nmip is " << hit->Nmip() << ", fit_to_raw_ratio is " << hit->fit_to_raw_ratio());
+    }
   }
-
+  
   // enforce blinding such that events that miss the veto layers and have a large calo signal are skipped and not in the output root file
   // Only blind colliding BCIDs (+/- 1)
+  // This needs to be fixed!!!
   bool blinded_event = false;
   if ((!isMC) && abs(m_distanceToCollidingBCID) <= 1) {
     if (m_calo_total_E_EM > m_blindingCaloThreshold ) { // energy is in MeV
@@ -1218,13 +1393,13 @@ StatusCode NtupleDumperAlg::execute(const EventContext &ctx) const
     }
     m_hitSet.push_back(hitSet.to_ulong());
     if (stationMap.count(1) == 0 || stationMap.count(2) == 0 || stationMap.count(3) == 0) continue;
-
+    
     const Trk::TrackParameters* upstreamParameters = track->trackParameters()->front();
     const Trk::TrackParameters* downstreamParameters = track->trackParameters()->back();
 
     if ((upstreamParameters == nullptr) || (downstreamParameters == nullptr)) continue;
 
-	m_nLayers.push_back(layerMap.size());
+    m_nLayers.push_back(layerMap.size());
 
     m_Chi2.push_back(track->fitQuality()->chiSquared());
     m_DoF.push_back(track->fitQuality()->numberDoF());
@@ -1743,6 +1918,24 @@ NtupleDumperAlg::clearTree() const
   m_calo_total_raw_E_EM_fudged=0;
   m_calo_total_E_EM_fudged=0;
 
+  m_calolo_total_nMIP=0;
+  m_calolo_total_E_dep=0;
+  m_calolo_total_fit_E_EM=0;
+  m_calolo_total_raw_E_EM=0;
+  m_calolo_total_E_EM=0;
+
+  m_calohi_total_nMIP=0;
+  m_calohi_total_E_dep=0;
+  m_calohi_total_fit_E_EM=0;
+  m_calohi_total_raw_E_EM=0;
+  m_calohi_total_E_EM=0;
+
+  m_calonu_total_nMIP=0;
+  m_calonu_total_E_dep=0;
+  m_calonu_total_fit_E_EM=0;
+  m_calonu_total_raw_E_EM=0;
+  m_calonu_total_E_EM=0;
+
   m_preshower_total_nMIP=0;
   m_preshower_total_E_dep=0;
 
diff --git a/PhysicsAnalysis/NtupleDumper/src/NtupleDumperAlg.h b/PhysicsAnalysis/NtupleDumper/src/NtupleDumperAlg.h
index ef4c227c2661a1c1faa115d19b6bb9d2d59f09c8..82601707399b0b0cc0c3e304bcbfb513e3d7cf9e 100644
--- a/PhysicsAnalysis/NtupleDumper/src/NtupleDumperAlg.h
+++ b/PhysicsAnalysis/NtupleDumper/src/NtupleDumperAlg.h
@@ -25,6 +25,7 @@
 #include "FaserActsVertexing/IVertexingTool.h"
 #include "GeneratorObjects/McEventCollection.h"
 #include <boost/dynamic_bitset.hpp>
+#include "ScintIdentifier/VetoID.h"
 
 #include "WaveformConditionsTools/IWaveformCableMappingTool.h"
 
@@ -36,11 +37,7 @@ using HitSet = boost::dynamic_bitset<>;
 class TTree;
 class TH1;
 class FaserSCT_ID;
-class VetoNuID;
-class VetoID;
-class TriggerID;
-class PreshowerID;
-class EcalID;
+
 namespace  TrackerDD
 {
     class SCT_DetectorManager;
@@ -58,6 +55,7 @@ public:
 private:
 
   mutable bool m_first;
+  const VetoID* m_vetoID{nullptr};
   
   bool waveformHitOK(const xAOD::WaveformHit* hit) const;
   void clearTree() const;
@@ -65,10 +63,11 @@ private:
   void addBranch(const std::string &name,float* var) const;
   void addBranch(const std::string &name,unsigned int* var) const;
   void defineWaveBranches() const;
-  void addWaveBranches(const std::string &name, int nchannels, int first) const;
   void addWaveBranches(const std::string &name, std::list<int> channel_list) const;
   void FillWaveBranches(const xAOD::WaveformHitContainer &wave, bool isMC) const;
-  void addCalibratedBranches(const std::string &name, int nchannels, int first);
+  void addCalibratedBranches(const std::string &name, std::list<int> channel_list) const;
+  void addCaloSumBranches(const std::string &name) const ;
+  
   double radius(const Acts::Vector3 &position) const;
 
   // Return map with string as key and list<int> as value
@@ -93,6 +92,8 @@ private:
   SG::ReadHandleKey<xAOD::WaveformHitContainer> m_vetoContainer { this, "VetoContainer", "VetoWaveformHits", "Veto hit container name" };
   SG::ReadHandleKey<xAOD::WaveformHitContainer> m_triggerContainer { this, "TriggerContainer", "TriggerWaveformHits", "Trigger hit container name" };
   SG::ReadHandleKey<xAOD::WaveformHitContainer> m_preshowerContainer { this, "PreshowerContainer", "PreshowerWaveformHits", "Preshower hit container name" };
+    SG::ReadHandleKey<xAOD::WaveformHitContainer> m_muonContainer { this, "MuonContainer", "MuonWaveformHits", "Muon hit container name" };
+
   SG::ReadHandleKey<xAOD::WaveformHitContainer> m_ecalContainer { this, "EcalContainer", "CaloWaveformHits", "Ecal hit container name" };
   SG::ReadHandleKey<xAOD::WaveformHitContainer> m_ecal2Container { this, "Ecal2Container", "Calo2WaveformHits", "Ecal hit container name" };
   SG::ReadHandleKey<xAOD::WaveformHitContainer> m_caloNuContainer { this, "CaloNuContainer", "CaloNuWaveformHits", "CaloNu hit container name" };
@@ -157,6 +158,23 @@ private:
   double m_baseEventCrossSection {1.0};
   const double kfemtoBarnsPerMilliBarn {1.0e12};
 
+  // Flag for dual-gain calorimeter configuration
+  mutable bool m_dual_gain {false};
+  
+  // Helper lists to hold channel lists
+  mutable std::list<int> m_calo_channels;
+  mutable std::list<int> m_calolo_channels;
+  mutable std::list<int> m_calohi_channels;
+  mutable std::list<int> m_calonu_channels;
+
+  
+  // Output statistics  
+  mutable int    m_eventsPassed = 0;
+  mutable int    m_eventsFailedGRL = 0;
+  mutable int    m_two_tracks = 0;
+  mutable int    m_verticies = 0;
+
+  // Output tree
   mutable TTree* m_tree;
 
   //mutable unsigned int n_wave_chan;  // Actual number of waveform channels
@@ -213,19 +231,28 @@ private:
   mutable float m_calo_total_fit_E_EM_fudged;
   mutable float m_calo_total_raw_E_EM_fudged;
   mutable float m_calo_total_E_EM_fudged;
+  
+  mutable float m_calolo_total_nMIP;
+  mutable float m_calolo_total_E_dep;
+  mutable float m_calolo_total_fit_E_EM;
+  mutable float m_calolo_total_raw_E_EM;
+  mutable float m_calolo_total_E_EM;
+
+  mutable float m_calohi_total_nMIP;
+  mutable float m_calohi_total_E_dep;
+  mutable float m_calohi_total_fit_E_EM;
+  mutable float m_calohi_total_raw_E_EM;
+  mutable float m_calohi_total_E_EM;
+
+  mutable float m_calonu_total_nMIP;
+  mutable float m_calonu_total_E_dep;
+  mutable float m_calonu_total_fit_E_EM;
+  mutable float m_calonu_total_raw_E_EM;
+  mutable float m_calonu_total_E_EM;
 
   mutable float m_preshower_total_nMIP;
   mutable float m_preshower_total_E_dep;
 
-  mutable float m_Calo0_Edep;
-  mutable float m_Calo1_Edep;
-  mutable float m_Calo2_Edep;
-  mutable float m_Calo3_Edep;
-
-  mutable float m_Calo_Total_Edep;
-  mutable float m_Preshower12_Edep;
-  mutable float m_Preshower13_Edep;
-
   mutable float m_clock_phase;
 
   mutable unsigned int m_station0Clusters;
@@ -416,12 +443,6 @@ private:
   mutable double m_crossSection;
   mutable std::vector<double>  m_genWeights;
 
-
-  mutable int    m_eventsPassed = 0;
-  mutable int    m_eventsFailedGRL = 0;
-  mutable int    m_two_tracks = 0;
-  mutable int    m_verticies = 0;
-  
   mutable double m_vertex_x; // components of reconstructed vertex in mm
   mutable double m_vertex_y;
   mutable double m_vertex_z;
diff --git a/Scintillator/ScintDetDescr/ScintIdDictFiles/data/IdDictScintillator.xml b/Scintillator/ScintDetDescr/ScintIdDictFiles/data/IdDictScintillator.xml
index 54552a212ae62ae33650c186ea6529c383524518..b223589bb147120c22245facb36683a3e23e8536 100644
--- a/Scintillator/ScintDetDescr/ScintIdDictFiles/data/IdDictScintillator.xml
+++ b/Scintillator/ScintDetDescr/ScintIdDictFiles/data/IdDictScintillator.xml
@@ -5,6 +5,7 @@
     <label name="Trigger" value="2" />
     <label name="Preshower" value="3" />
     <label name="VetoNu" value="4" />
+    <label name="Muon" value="5" />
   </field>
 
   <region>
@@ -25,7 +26,7 @@
     <range field="part" value="Preshower" />
     <range field="station" minvalue="0" maxvalue="0" />
     <range field="plate" minvalue="0" maxvalue="1" />
-    <range field="pmt" minvalue="0" maxvalue="0" />
+    <range field="pmt" minvalue="0" maxvalue="1" />
   </region>
 
   <region>
@@ -35,4 +36,11 @@
     <range field="pmt" minvalue="0" maxvalue="0" />
   </region>
 
+  <region>
+    <range field="part" value="Muon" />
+    <range field="station" minvalue="0" maxvalue="0" />
+    <range field="plate" minvalue="0" maxvalue="1" />
+    <range field="pmt" minvalue="0" maxvalue="0" />
+  </region>
+
 </IdDictionary>
diff --git a/Scintillator/ScintDetDescr/ScintIdDictFiles/data/IdDictScintillator_2024.xml b/Scintillator/ScintDetDescr/ScintIdDictFiles/data/IdDictScintillator_2024.xml
new file mode 100644
index 0000000000000000000000000000000000000000..54552a212ae62ae33650c186ea6529c383524518
--- /dev/null
+++ b/Scintillator/ScintDetDescr/ScintIdDictFiles/data/IdDictScintillator_2024.xml
@@ -0,0 +1,38 @@
+<IdDictionary name="Scintillator">
+
+  <field name="part" >
+    <label name="Veto" value="1" />
+    <label name="Trigger" value="2" />
+    <label name="Preshower" value="3" />
+    <label name="VetoNu" value="4" />
+  </field>
+
+  <region>
+    <range field="part" value="Veto" />
+    <range field="station" minvalue="0" maxvalue="1" />
+    <range field="plate" minvalue="0" maxvalue="1" />
+    <range field="pmt" minvalue="0" maxvalue="0" />
+  </region>
+
+  <region>
+    <range field="part" value="Trigger"/>
+    <range field="station" minvalue="0" maxvalue="0" />
+    <range field="plate" minvalue="0" maxvalue="1" />
+    <range field="pmt" minvalue="0" maxvalue="1" />
+  </region>
+
+  <region>
+    <range field="part" value="Preshower" />
+    <range field="station" minvalue="0" maxvalue="0" />
+    <range field="plate" minvalue="0" maxvalue="1" />
+    <range field="pmt" minvalue="0" maxvalue="0" />
+  </region>
+
+  <region>
+    <range field="part" value="VetoNu" />
+    <range field="station" minvalue="0" maxvalue="0" />
+    <range field="plate" minvalue="0" maxvalue="1" />
+    <range field="pmt" minvalue="0" maxvalue="0" />
+  </region>
+
+</IdDictionary>
diff --git a/Scintillator/ScintDetDescr/ScintIdDictFiles/data/IdDictScintillator_2025.xml b/Scintillator/ScintDetDescr/ScintIdDictFiles/data/IdDictScintillator_2025.xml
new file mode 100644
index 0000000000000000000000000000000000000000..b223589bb147120c22245facb36683a3e23e8536
--- /dev/null
+++ b/Scintillator/ScintDetDescr/ScintIdDictFiles/data/IdDictScintillator_2025.xml
@@ -0,0 +1,46 @@
+<IdDictionary name="Scintillator">
+
+  <field name="part" >
+    <label name="Veto" value="1" />
+    <label name="Trigger" value="2" />
+    <label name="Preshower" value="3" />
+    <label name="VetoNu" value="4" />
+    <label name="Muon" value="5" />
+  </field>
+
+  <region>
+    <range field="part" value="Veto" />
+    <range field="station" minvalue="0" maxvalue="1" />
+    <range field="plate" minvalue="0" maxvalue="1" />
+    <range field="pmt" minvalue="0" maxvalue="0" />
+  </region>
+
+  <region>
+    <range field="part" value="Trigger"/>
+    <range field="station" minvalue="0" maxvalue="0" />
+    <range field="plate" minvalue="0" maxvalue="1" />
+    <range field="pmt" minvalue="0" maxvalue="1" />
+  </region>
+
+  <region>
+    <range field="part" value="Preshower" />
+    <range field="station" minvalue="0" maxvalue="0" />
+    <range field="plate" minvalue="0" maxvalue="1" />
+    <range field="pmt" minvalue="0" maxvalue="1" />
+  </region>
+
+  <region>
+    <range field="part" value="VetoNu" />
+    <range field="station" minvalue="0" maxvalue="0" />
+    <range field="plate" minvalue="0" maxvalue="1" />
+    <range field="pmt" minvalue="0" maxvalue="0" />
+  </region>
+
+  <region>
+    <range field="part" value="Muon" />
+    <range field="station" minvalue="0" maxvalue="0" />
+    <range field="plate" minvalue="0" maxvalue="1" />
+    <range field="pmt" minvalue="0" maxvalue="0" />
+  </region>
+
+</IdDictionary>
diff --git a/Scintillator/ScintDetDescr/ScintIdDictFiles/data/IdDictScintillator_TB00.xml b/Scintillator/ScintDetDescr/ScintIdDictFiles/data/IdDictScintillator_TB00.xml
index 71fd8298645674dae3bd0d54c411d099742a6416..cab75a236bab883e237b4b43371bd86ab1babf39 100644
--- a/Scintillator/ScintDetDescr/ScintIdDictFiles/data/IdDictScintillator_TB00.xml
+++ b/Scintillator/ScintDetDescr/ScintIdDictFiles/data/IdDictScintillator_TB00.xml
@@ -5,6 +5,7 @@
     <label name="Trigger" value="2" />
     <label name="Preshower" value="3" />
     <label name="VetoNu" value="4" />
+    <label name="Muon" value="5" />
   </field>
   <region>
     <range field="part" value="Veto" />
@@ -30,4 +31,10 @@
     <range field="plate" minvalue="0" maxvalue="1" />
     <range field="pmt" minvalue="0" maxvalue="0" />
   </region>
+  <region>
+    <range field="part" value="Muon" />
+    <range field="station" minvalue="0" maxvalue="0" />
+    <range field="plate" minvalue="0" maxvalue="1" />
+    <range field="pmt" minvalue="0" maxvalue="0" />
+  </region>
 </IdDictionary>
diff --git a/Scintillator/ScintDetDescr/ScintIdentifier/CMakeLists.txt b/Scintillator/ScintDetDescr/ScintIdentifier/CMakeLists.txt
index 5874ae0de68035f16d71d47887a95cdfb8f857a6..7254bb74245059c09a09a09a27ac97f778fc18d8 100644
--- a/Scintillator/ScintDetDescr/ScintIdentifier/CMakeLists.txt
+++ b/Scintillator/ScintDetDescr/ScintIdentifier/CMakeLists.txt
@@ -14,6 +14,7 @@ atlas_add_library( ScintIdentifier
 		   src/VetoNuID.cxx
                    src/TriggerID.cxx
                    src/PreshowerID.cxx
+		   src/MuonID.cxx
 #                   src/ScintillatorID.cxx
                    PUBLIC_HEADERS ScintIdentifier
                    PRIVATE_INCLUDE_DIRS ${ROOT_INCLUDE_DIRS}
diff --git a/Scintillator/ScintDetDescr/ScintIdentifier/ScintIdentifier/MuonID.h b/Scintillator/ScintDetDescr/ScintIdentifier/ScintIdentifier/MuonID.h
new file mode 100644
index 0000000000000000000000000000000000000000..6f98f5f7b6ad9c9b3164ada087e4167612045b73
--- /dev/null
+++ b/Scintillator/ScintDetDescr/ScintIdentifier/ScintIdentifier/MuonID.h
@@ -0,0 +1,541 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef SCINTIDENTIFIER_MUONID_H
+#define SCINTIDENTIFIER_MUONID_H
+/**
+ * @file MuonID.h
+ *
+ * @brief This is an Identifier helper class for the Muon
+ *  subdetector. This class is a factory for creating compact
+ *  Identifier objects and IdentifierHash or hash ids. And it also
+ *  allows decoding of these ids.
+ *
+ */
+
+//<<<<<< INCLUDES                                                       >>>>>>
+
+#include "FaserDetDescr/FaserDetectorID.h"
+#include "Identifier/Identifier.h"
+#include "Identifier/IdentifierHash.h"
+#include "Identifier/Range.h"
+#include "Identifier/IdHelper.h"
+#include "IdDict/IdDictFieldImplementation.h"
+#include "AthenaKernel/CLASS_DEF.h"
+
+#include <string>
+#include <assert.h>
+#include <algorithm>
+
+//<<<<<< PUBLIC DEFINES                                                 >>>>>>
+//<<<<<< PUBLIC CONSTANTS                                               >>>>>>
+//<<<<<< PUBLIC TYPES                                                   >>>>>>
+
+class IdDictDictionary;
+
+//<<<<<< PUBLIC VARIABLES                                               >>>>>>
+//<<<<<< PUBLIC FUNCTIONS                                               >>>>>>
+//<<<<<< CLASS DECLARATIONS                                             >>>>>>
+
+/**
+ **  @class MuonID
+ **  
+ **  @brief This is an Identifier helper class for the Muon
+ **  subdetector. This class is a factory for creating compact
+ **  Identifier objects and IdentifierHash or hash ids. And it also
+ **  allows decoding of these ids.
+ **
+ **  Definition and the range of values for the levels of the
+ **  identifier are:
+ **
+ ** @verbatim
+ **    element           range              meaning
+ **    -------           -----              -------
+ **
+ **    station          0                   longitudinal location
+ **    plate            0 to 1              two plates per station
+ **    pmt              0                   single pmt per plate
+ **
+ ** @endverbatim
+ **
+ */
+class MuonID : public FaserDetectorID
+{
+public:
+        
+    /// @name public typedefs
+    //@{
+    typedef Identifier::size_type                       size_type; 
+    typedef std::vector<Identifier>::const_iterator     const_id_iterator;
+    typedef MultiRange::const_identifier_factory        const_expanded_id_iterator;
+    //@}
+
+    /// @name strutors
+    //@{
+    MuonID(void);
+    virtual ~MuonID(void) = default;
+    //@}
+        
+    /// @name Creators for plate ids and pmt ids
+    //@{
+    /// For a single station
+    Identifier  station_id ( int station ) const;
+    Identifier  station_id ( int station,
+                             bool checks) const;
+
+    /// For a station from a plate id
+    Identifier  station_id ( const Identifier& plate_id ) const;
+
+    /// For a single plate
+    Identifier  plate_id ( int station, 
+                           int plate ) const;
+    Identifier  plate_id ( int station, 
+                           int plate,
+                           bool checks) const;
+
+    /// For a single plate from a pmt id
+    Identifier  plate_id ( const Identifier& pmt_id ) const;
+
+    /// From hash - optimized
+    Identifier  plate_id ( IdentifierHash plate_hash ) const;
+
+    /// For an individual pmt
+    Identifier  pmt_id ( int station, 
+                         int plate, 
+                         int pmt ) const; 
+
+    Identifier  pmt_id ( int station, 
+                         int plate, 
+                         int pmt,
+                         bool check ) const; 
+
+    Identifier  pmt_id ( const Identifier& plate_id, 
+                         int pmt ) const;
+
+    //@}
+
+
+    /// @name Hash table maximum sizes
+    //@{
+    size_type   plate_hash_max          (void) const;
+    size_type   pmt_hash_max            (void) const;
+    //@}
+
+    /// @name Access to all ids
+    //@{
+    /// Iterators over full set of ids. Plate iterator is sorted
+    const_id_iterator   plate_begin                     (void) const;
+    const_id_iterator   plate_end                       (void) const;
+    /// For pmt ids, only expanded id iterators are available. Use
+    /// following "pmt_id" method to obtain a compact identifier
+    const_expanded_id_iterator  pmt_begin             (void) const;  
+    const_expanded_id_iterator  pmt_end               (void) const;
+    //@}
+    
+
+    /// @name Optimized accessors  - ASSUMES id IS a muon id, i.e. NOT other
+    //@{
+    /// wafer hash from id - optimized
+    IdentifierHash      plate_hash      (Identifier plate_id) const;
+
+    /// Values of different levels (failure returns 0)
+    int         station       (const Identifier& id) const;  
+    int         plate         (const Identifier& id) const; 
+    int         pmt           (const Identifier& id) const; 
+
+    /// Max/Min values for each field (-999 == failure)
+    int         station_max  (const Identifier& id) const;
+    int         plate_max    (const Identifier& id) const;
+    int         pmt_max      (const Identifier& id) const;
+    //@}
+
+    /// @name module navigation
+    //@{
+        /// Previous plate in z
+        int get_prev_in_z(const IdentifierHash& id, IdentifierHash& prev) const;
+        /// Next plate in z
+        int get_next_in_z(const IdentifierHash& id, IdentifierHash& next) const;
+    // /// Previous wafer hash in phi (return == 0 for neighbor found)
+    // int         get_prev_in_phi (const IdentifierHash& id, IdentifierHash& prev) const;
+    // /// Next wafer hash in phi (return == 0 for neighbor found)
+    // int         get_next_in_phi (const IdentifierHash& id, IdentifierHash& next) const;
+    // /// Previous wafer hash in eta (return == 0 for neighbor found)
+    // int         get_prev_in_eta (const IdentifierHash& id, IdentifierHash& prev) const;
+    // /// Next wafer hash in eta (return == 0 for neighbor found)
+    // int         get_next_in_eta (const IdentifierHash& id, IdentifierHash& next) const;
+    // /// Wafer hash on other side
+    // int         get_other_side  (const IdentifierHash& id, IdentifierHash& other) const;
+    
+    // // To check for when phi wrap around may be needed, use
+    // bool        is_phi_module_max(const Identifier& id) const;
+    // /// For the barrel
+    // bool        is_eta_module_min(const Identifier& id) const;
+    // /// For the barrel
+    // bool        is_eta_module_max(const Identifier& id) const;
+    //@}
+
+    /// @name contexts to distinguish plate id from pixel id
+    //@{
+    IdContext   plate_context           (void) const;
+    IdContext   pmt_context             (void) const;
+    //@}
+
+    /// @name methods from abstract interface - slower than opt version
+    //@{
+    /// Create compact id from hash id (return == 0 for OK)
+    virtual int         get_id          (const IdentifierHash& hash_id,
+                                         Identifier& id,
+                                         const IdContext* context = 0) const;
+    
+    /// Create hash id from compact id (return == 0 for OK)
+    virtual int         get_hash        (const Identifier& id, 
+                                         IdentifierHash& hash_id,
+                                         const IdContext* context = 0) const;
+    //@}
+
+    /// Return the lowest bit position used in the channel id
+    int                 base_bit        (void) const;
+
+    /// Calculate a channel offset between the two identifiers.
+    Identifier::diff_type calc_offset(const Identifier& base,
+                                      const Identifier& target) const;
+
+    /// Create an identifier with a given base and channel offset
+    Identifier pmt_id_offset(const Identifier& base,
+                             Identifier::diff_type offset) const;
+
+    /// @name interaction with id dictionary
+    //@{
+    /// Create strip Identifier from expanded id, which is returned by the
+    /// id_iterators
+    Identifier          pmt_id        (const ExpandedIdentifier& pmt_id) const;
+
+    /// Create expanded id from compact id (return == 0 for OK)
+    void                get_expanded_id (const Identifier& id,
+                                         ExpandedIdentifier& exp_id,
+                                         const IdContext* context = 0) const;
+
+    /// Initialization from the identifier dictionary
+    virtual int         initialize_from_dictionary(const IdDictMgr& dict_mgr);
+
+    /// Tests of packing
+    void        test_plate_packing      (void) const;
+    //@}
+    
+private:
+        
+    enum {NOT_VALID_HASH        = 64000};
+
+    typedef std::vector<Identifier>     id_vec;
+    typedef id_vec::const_iterator      id_vec_it;
+    typedef std::vector<unsigned short> hash_vec;
+    typedef hash_vec::const_iterator    hash_vec_it;
+
+    void plate_id_checks ( int station, 
+                           int plate ) const; 
+
+    void pmt_id_checks ( int station, 
+                         int plate, 
+                         int pmt ) const;
+
+
+    int         initLevelsFromDict(void);
+
+    int         init_hashes(void);
+
+    int         init_neighbors(void);
+
+    // Temporary method for adapting an identifier for the MultiRange
+    // check - MR is missing the InnerDetector level
+    // Identifier  idForCheck      (const Identifier& id) const;
+
+    size_type                   m_muon_region_index;
+    size_type                   m_SCINT_INDEX;
+    size_type                   m_MUON_INDEX;
+    size_type                   m_STATION_INDEX;
+    size_type                   m_PLATE_INDEX;
+    size_type                   m_PMT_INDEX;
+
+    const IdDictDictionary*     m_dict;
+    MultiRange                  m_full_plate_range;
+    MultiRange                  m_full_pmt_range;
+    size_type                   m_plate_hash_max;
+    size_type                   m_pmt_hash_max;
+    // Range::field                m_barrel_field;
+    id_vec                      m_plate_vec;
+    hash_vec                    m_prev_z_plate_vec;
+    hash_vec                    m_next_z_plate_vec;
+    // hash_vec                    m_prev_phi_wafer_vec;
+    // hash_vec                    m_next_phi_wafer_vec;
+    // hash_vec                    m_prev_eta_wafer_vec;
+    // hash_vec                    m_next_eta_wafer_vec;   
+    // bool 			m_hasRows	;
+
+    IdDictFieldImplementation   m_scint_impl	;
+    IdDictFieldImplementation   m_muon_impl	;
+    IdDictFieldImplementation   m_station_impl	;
+    IdDictFieldImplementation   m_plate_impl	;
+    IdDictFieldImplementation   m_pmt_impl	;
+};
+    
+
+//<<<<<< INLINE PUBLIC FUNCTIONS                                        >>>>>>
+
+/////////////////////////////////////////////////////////////////////////////
+//<<<<<< INLINE MEMBER FUNCTIONS                                        >>>>>>
+/////////////////////////////////////////////////////////////////////////////
+
+//using the macros below we can assign an identifier (and a version)
+//This is required and checked at compile time when you try to record/retrieve
+CLASS_DEF(MuonID, 143274416, 1)
+
+//----------------------------------------------------------------------------
+inline Identifier  
+MuonID::station_id ( int station, 
+                     bool checks) const
+{
+    
+    // Build identifier
+    Identifier result((Identifier::value_type)0);
+
+    // Pack fields independently
+    m_scint_impl.pack       (scint_field_value(), result);
+    m_muon_impl.pack      (muon_field_value(),  result);
+    m_station_impl.pack     (station,             result);
+    // Do checks
+    if(checks) 
+    {
+        plate_id_checks ( station, 0 );
+    }
+
+    return result;
+}
+
+inline Identifier  
+MuonID::station_id ( int station ) const 
+{
+  return station_id (station, do_checks());
+}
+
+//----------------------------------------------------------------------------
+inline Identifier  
+MuonID::station_id ( const Identifier& plate_id ) const
+{
+    Identifier result(plate_id);
+    //  Reset the plate and pmt fields
+    m_plate_impl.reset(result);
+    m_pmt_impl.reset(result);
+    return (result);
+}
+
+//----------------------------------------------------------------------------
+inline Identifier
+MuonID::plate_id ( int station,  
+                   int plate, 
+                   bool checks) const
+{
+    // Build identifier
+    Identifier result((Identifier::value_type)0);
+
+    // Pack fields independently
+    m_scint_impl.pack    (scint_field_value(), result);
+    m_muon_impl.pack   (muon_field_value(),  result);
+    m_station_impl.pack  (station,             result);
+    m_plate_impl.pack    (plate,               result);
+
+    // Do checks
+    if(checks) 
+    {
+        plate_id_checks ( station, plate );
+    }
+    return result;
+}
+
+inline Identifier
+MuonID::plate_id ( int station,  
+                   int plate ) const
+{
+  return plate_id (station, plate, do_checks());
+}
+
+//----------------------------------------------------------------------------
+inline Identifier
+MuonID::plate_id ( const Identifier& pmt_id ) const
+{
+    Identifier result(pmt_id);
+    // reset the pmt field
+    m_pmt_impl.reset(result);
+    return (result);
+}
+
+//----------------------------------------------------------------------------
+inline Identifier  MuonID::plate_id ( IdentifierHash plate_hash ) const
+{
+    return (m_plate_vec[plate_hash]);
+}
+
+//----------------------------------------------------------------------------
+inline IdentifierHash      MuonID::plate_hash      (Identifier plate_id) const 
+{
+    // MsgStream log(m_msgSvc, "MuonID");
+    // log << MSG::VERBOSE << "m_plate_vec size: " << m_plate_vec.size() << endmsg;
+    // log << MSG::VERBOSE << "input id = " << plate_id << endmsg;
+    // for (size_t i = 0; i < m_plate_vec.size(); i++)
+    // {
+    //     log << MSG::VERBOSE << "Hash = " <<  i << " : ID = " << m_plate_vec[i] << endmsg;
+    // }
+    id_vec_it it = std::lower_bound(m_plate_vec.begin(), 
+                                    m_plate_vec.end(), 
+                                    plate_id);
+    // Require that plate_id matches the one in vector
+    if (it != m_plate_vec.end() && plate_id == (*it)) {
+        return (it - m_plate_vec.begin());
+    }
+    IdentifierHash result;
+    return (result); // return hash in invalid state
+}
+
+//----------------------------------------------------------------------------
+inline Identifier
+MuonID::pmt_id ( int station,  
+                 int plate, 
+                 int pmt,
+                 bool checks) const
+{
+    // Build identifier
+    Identifier result((Identifier::value_type)0);
+
+    // Pack fields independently
+    m_scint_impl.pack    (scint_field_value(), result);
+    m_muon_impl.pack   (muon_field_value(),result);
+    m_station_impl.pack  (station,             result);
+    m_plate_impl.pack    (plate,               result);
+    m_pmt_impl.pack      (pmt,                 result);
+
+    // Do checks
+    if(checks) {
+        pmt_id_checks ( station, plate, pmt );
+    }
+    return result;
+}
+
+inline Identifier
+MuonID::pmt_id ( int station,  
+                 int plate, 
+                 int pmt ) const
+{
+  return pmt_id (station, plate, pmt, do_checks());
+}
+
+//----------------------------------------------------------------------------
+inline Identifier               
+MuonID::pmt_id        (const ExpandedIdentifier& id) const
+{
+    // Build identifier
+    Identifier result((Identifier::value_type)0);
+
+    // Pack fields independently
+    m_scint_impl.pack    (scint_field_value(),    result);
+    m_muon_impl.pack     (muon_field_value(),     result);
+    m_station_impl.pack  (id[m_STATION_INDEX],    result);
+    m_plate_impl.pack    (id[m_PLATE_INDEX],      result);
+    m_pmt_impl.pack      (id[m_PMT_INDEX],        result);
+
+    // Do checks
+    if(m_do_checks) 
+    {
+       	pmt_id_checks ( id[m_STATION_INDEX],  
+                          id[m_PLATE_INDEX], 
+                       	  id[m_PMT_INDEX]);    
+    }
+    return result;
+}
+
+//----------------------------------------------------------------------------
+inline Identifier  
+MuonID::pmt_id ( const Identifier& plate_id, int pmt ) const
+{
+	// Build identifier
+    Identifier result(plate_id);
+  
+    // Reset strip and then add in value
+    m_pmt_impl.reset   (result);
+ 	m_pmt_impl.pack    (pmt, result);
+  
+    if(m_do_checks)
+    {          
+	    pmt_id_checks ( station(result), 
+		           		plate(result), 
+                        pmt );
+	}
+	return result;
+}
+
+//----------------------------------------------------------------------------
+inline Identifier::diff_type
+MuonID::calc_offset(const Identifier& base, const Identifier& target) const
+{
+  Identifier::diff_type tval = static_cast<Identifier::diff_type>(target.get_compact() >> base_bit());
+  Identifier::diff_type bval = static_cast<Identifier::diff_type>(base.get_compact() >> base_bit());
+  return (tval - bval);
+}
+
+//----------------------------------------------------------------------------
+inline Identifier
+MuonID::pmt_id_offset(const Identifier& base,
+                        Identifier::diff_type offset) const
+{
+  Identifier::value_type bval = base.get_compact() >> base_bit();
+  return Identifier((bval + offset) << base_bit());
+}
+
+//----------------------------------------------------------------------------
+inline int
+MuonID::base_bit ( void ) const
+{
+  int base = static_cast<int>(m_pmt_impl.shift()); // lowest field base
+  return (base > 32) ? 32 : base;
+  // max base is 32 so we can still read old strip id's and differences
+  // from non-SLHC releases.
+}
+
+//----------------------------------------------------------------------------
+inline IdContext        
+MuonID::plate_context           (void) const
+{
+    ExpandedIdentifier id;
+    return (IdContext(id, 0, m_PLATE_INDEX));
+}
+
+//----------------------------------------------------------------------------
+inline IdContext        
+MuonID::pmt_context   (void) const
+{
+    ExpandedIdentifier id;
+    return (IdContext(id, 0, m_PMT_INDEX));
+}
+
+//----------------------------------------------------------------------------
+inline int 
+MuonID::station       (const Identifier& id) const
+{
+    return (m_station_impl.unpack(id));
+}
+
+//----------------------------------------------------------------------------
+inline int 
+MuonID::plate     (const Identifier& id) const
+{
+    return (m_plate_impl.unpack(id));
+}
+
+//----------------------------------------------------------------------------
+inline int 
+MuonID::pmt           (const Identifier& id) const
+{
+    return (m_pmt_impl.unpack(id));
+}
+
+
+#endif // SCINTIDENTIFIER_MUONID_H
diff --git a/Scintillator/ScintDetDescr/ScintIdentifier/ScintIdentifier/ScintIdentifierDict.h b/Scintillator/ScintDetDescr/ScintIdentifier/ScintIdentifier/ScintIdentifierDict.h
index 0968f0b4136d48216bcea7305e4933dac7337e2d..0d7b3a899cb7194622580e6919dba542805e5f5c 100644
--- a/Scintillator/ScintDetDescr/ScintIdentifier/ScintIdentifier/ScintIdentifierDict.h
+++ b/Scintillator/ScintDetDescr/ScintIdentifier/ScintIdentifier/ScintIdentifierDict.h
@@ -17,5 +17,6 @@
 #include "ScintIdentifier/TriggerID.h"
 #include "ScintIdentifier/VetoID.h"
 #include "ScintIdentifier/VetoNuID.h"
+#include "ScintIdentifier/MuonID.h"
 
 #endif // SCINTIDENTIFIER_SCINTIDENTIFIERDICT_H 
diff --git a/Scintillator/ScintDetDescr/ScintIdentifier/ScintIdentifier/selection.xml b/Scintillator/ScintDetDescr/ScintIdentifier/ScintIdentifier/selection.xml
index bebeff9ec46d1ef9554a176ba64038033469d21b..1bb2349acc40fc37f7a1d6d284a9b2de23b735e3 100644
--- a/Scintillator/ScintDetDescr/ScintIdentifier/ScintIdentifier/selection.xml
+++ b/Scintillator/ScintDetDescr/ScintIdentifier/ScintIdentifier/selection.xml
@@ -6,4 +6,5 @@
   <class name="VetoNuID" />
   <class name="TriggerID" />
   <class name="PreshowerID" />
+  <class name="MuonID" />
 </lcgdict>
diff --git a/Scintillator/ScintDetDescr/ScintIdentifier/src/MuonID.cxx b/Scintillator/ScintDetDescr/ScintIdentifier/src/MuonID.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..c219b7d5504faa3a420363c31f9ab791259f423a
--- /dev/null
+++ b/Scintillator/ScintDetDescr/ScintIdentifier/src/MuonID.cxx
@@ -0,0 +1,1030 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+/***************************************************************************
+ Scintillator identifier package
+ -------------------------------------------
+***************************************************************************/
+
+//<<<<<< INCLUDES                                                       >>>>>>
+#include "GaudiKernel/MsgStream.h"
+
+#include "ScintIdentifier/MuonID.h"
+#include "Identifier/IdentifierHash.h"
+#include "IdDict/IdDictDefs.h"  
+#include <set>
+#include <algorithm>
+#include <iostream>
+
+//<<<<<< PRIVATE DEFINES                                                >>>>>>
+//<<<<<< PRIVATE CONSTANTS                                              >>>>>>
+//<<<<<< PRIVATE TYPES                                                  >>>>>>
+//<<<<<< PRIVATE VARIABLE DEFINITIONS                                   >>>>>>
+//<<<<<< PUBLIC VARIABLE DEFINITIONS                                    >>>>>>
+//<<<<<< CLASS STRUCTURE INITIALIZATION                                 >>>>>>
+//<<<<<< PRIVATE FUNCTION DEFINITIONS                                   >>>>>>
+//<<<<<< PUBLIC FUNCTION DEFINITIONS                                    >>>>>>
+//<<<<<< MEMBER FUNCTION DEFINITIONS                                    >>>>>>
+
+
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+
+
+MuonID::MuonID(void)
+        :
+        m_muon_region_index(0),
+        m_SCINT_INDEX(0),
+        m_MUON_INDEX(1),
+        m_STATION_INDEX(2),
+        m_PLATE_INDEX(3),
+        m_PMT_INDEX(4),
+        m_dict(0),
+        m_plate_hash_max(0),
+        m_pmt_hash_max(0)
+{
+}
+
+void
+MuonID::plate_id_checks ( int station,  
+                          int plate ) const
+{
+
+    // Check that id is within allowed range
+
+    // Fill expanded id
+    ExpandedIdentifier id;
+    id << scint_field_value() << muon_field_value()
+       << station << plate;
+
+    if (!m_full_plate_range.match(id)) {  // module range check is sufficient
+        MsgStream log(m_msgSvc, "MuonID");
+        log << MSG::ERROR << " MuonID::plate_id result is NOT ok. ID, range "
+            << (std::string)id <<  " " << (std::string)m_full_plate_range << endmsg;
+    }
+}
+
+void
+MuonID::pmt_id_checks ( int station,  
+                        int plate, 
+                        int pmt) const
+{
+
+    // Check that id is within allowed range
+
+    // Fill expanded id
+    ExpandedIdentifier id;
+    id << scint_field_value() << muon_field_value()
+       << station << plate << pmt;
+
+    if (!m_full_pmt_range.match(id)) {  
+        MsgStream log(m_msgSvc, "MuonID");
+        log << MSG::ERROR << " MuonID::pmt_id result is NOT ok. ID, range "
+            << (std::string)id << " " << (std::string)m_full_pmt_range << std::endl;
+    }
+}
+
+int 
+MuonID::station_max(const Identifier& id) const
+{
+    // get max from dictionary
+    ExpandedIdentifier expId;
+    IdContext plate_context1 = plate_context();
+    get_expanded_id(id, expId, &plate_context1);
+    for (unsigned int i = 0; i < m_full_plate_range.size(); ++i) {
+        const Range& range = m_full_plate_range[i];
+        if (range.match(expId)) {
+            const Range::field& station_field = range[m_STATION_INDEX];
+            if (station_field.has_maximum()) {
+                return (station_field.get_maximum());
+            }
+        }
+    }
+    return (-999);  // default
+}
+
+int     
+MuonID::pmt_max       (const Identifier& id) const
+{
+    ExpandedIdentifier expId;
+    IdContext station_context(expId, 0, m_STATION_INDEX);
+    get_expanded_id(id, expId, &station_context);
+    int result = -999;
+    for (unsigned int i = 0; i < m_full_pmt_range.size(); ++i) {
+        const Range& range = m_full_pmt_range[i];
+        if (range.match(expId)) {
+            const Range::field& pmt_field = range[m_PMT_INDEX];
+            if (pmt_field.has_maximum()) {
+                int pmt = pmt_field.get_maximum();
+                if (result < pmt) result = pmt;
+            }
+        }
+    }
+    return (result);
+}
+
+int 
+MuonID::plate_max(const Identifier& id) const
+{
+    // get max from dictionary
+    ExpandedIdentifier expId;
+    IdContext plate_context1 = plate_context();
+    get_expanded_id(id, expId, &plate_context1);
+    for (unsigned int i = 0; i < m_full_plate_range.size(); ++i) {
+        const Range& range = m_full_plate_range[i];
+        if (range.match(expId)) {
+            const Range::field& plate_field = range[m_PLATE_INDEX];
+            if (plate_field.has_maximum()) {
+                return (plate_field.get_maximum());
+            }
+        }
+    }
+    return -1;
+}
+
+int
+MuonID::initialize_from_dictionary(const IdDictMgr& dict_mgr)
+{
+    MsgStream log(m_msgSvc, "MuonID");
+    log << MSG::INFO << "Initialize from dictionary" << endmsg;
+  
+    // Check whether this helper should be reinitialized
+    if (!reinitialize(dict_mgr)) {
+        log << MSG::INFO << "Request to reinitialize not satisfied - tags have not changed" << endmsg;
+        return (0);
+    }
+    else {
+        if (m_msgSvc) {
+            log << MSG::DEBUG << "(Re)initialize" << endmsg;
+        }
+        else {
+            std::cout  << " DEBUG (Re)initialize" << std::endl;
+        }
+    }
+
+    // init base object
+    if(FaserDetectorID::initialize_from_dictionary(dict_mgr)) return (1);
+
+    // Register version of InnerDetector dictionary 
+    if (register_dict_tag(dict_mgr, "Scintillator")) return(1);
+
+    m_dict = dict_mgr.find_dictionary ("Scintillator"); 
+    if(!m_dict) {
+        log << MSG::ERROR << " MuonID::initialize_from_dict - cannot access Scintillator dictionary " << endmsg;
+        return 1;
+    }
+
+    // Initialize the field indices
+    if(initLevelsFromDict()) return (1);
+
+    //
+    // Build multirange for the valid set of identifiers
+    //
+
+
+    // Find value for the field Scintillator
+    const IdDictDictionary* faserDict = dict_mgr.find_dictionary ("FASER"); 
+    int scintField   = -1;
+    if (faserDict->get_label_value("subdet", "Scintillator", scintField)) {
+        log << MSG::ERROR << "Could not get value for label 'Scintillator' of field 'subdet' in dictionary " 
+            << faserDict->m_name
+            << endmsg;
+        return (1);
+    }
+
+    // Find value for the field Muon
+    int muonField   = -1;
+    if (m_dict->get_label_value("part", "Muon", muonField)) {
+        log << MSG::ERROR << "Could not get value for label 'Muon' of field 'part' in dictionary " 
+            << m_dict->m_name
+            << endmsg;
+        return (1);
+    }
+    if (m_msgSvc) {
+        log << MSG::DEBUG << " MuonID::initialize_from_dict " 
+            << "Found field values: Muon "  
+            << muonField
+            << std::endl;
+    }
+    else {
+        std::cout << " DEBUG MuonID::initialize_from_dict " 
+                  << "Found field values: Muon "  
+                  << muonField
+                  << std::endl;
+    }
+    
+    // Set up id for region and range prefix
+    ExpandedIdentifier region_id;
+    region_id.add(scintField);
+    region_id.add(muonField);
+    Range prefix;
+    m_full_plate_range = m_dict->build_multirange(region_id, prefix, "plate");
+    m_full_pmt_range = m_dict->build_multirange(region_id, prefix);
+
+    // Setup the hash tables
+    if(init_hashes()) return (1);
+
+    // Setup hash tables for finding neighbors
+    if(init_neighbors()) return (1);
+    
+    if (m_msgSvc) {
+        log << MSG::INFO << " MuonID::initialize_from_dict "  << endmsg;
+        log << MSG::DEBUG  
+            << "Plate range -> " << (std::string)m_full_plate_range
+            <<   endmsg;
+        log << MSG::DEBUG
+            << "Pmt range -> " << (std::string)m_full_pmt_range
+            << endmsg;
+    }
+    else {
+        std::cout << " INFO MuonID::initialize_from_dict "  << std::endl;
+        std::cout << " DEBUG  Plate range -> " << (std::string)m_full_plate_range
+                  <<   std::endl;
+        std::cout << " DEBUG Pmt range -> " << (std::string)m_full_pmt_range
+                  << std::endl;
+    }
+    
+    return 0;
+}
+
+int
+MuonID::init_hashes(void)
+{
+
+    //
+    // create a vector(s) to retrieve the hashes for compact ids. For
+    // the moment, we implement a hash for plates but NOT for pmts
+    //
+    MsgStream log(m_msgSvc, "MuonID");
+    // plate hash
+    m_plate_hash_max = m_full_plate_range.cardinality();
+    m_plate_vec.resize(m_plate_hash_max);
+    unsigned int nids = 0;
+    std::set<Identifier> ids;
+    for (unsigned int i = 0; i < m_full_plate_range.size(); ++i) {
+        const Range& range = m_full_plate_range[i];
+        Range::const_identifier_factory first = range.factory_begin();
+        Range::const_identifier_factory last  = range.factory_end();
+        for (; first != last; ++first) {
+            const ExpandedIdentifier& exp_id = (*first);
+            Identifier id = plate_id(exp_id[m_STATION_INDEX],
+                                     exp_id[m_PLATE_INDEX]); 
+            if(!(ids.insert(id)).second) {
+                log << MSG::ERROR << " MuonID::init_hashes "
+                    << " Error: duplicated id for plate id. nid " << nids
+                    << " compact id " << id.getString()
+                    << " id " << (std::string)exp_id << endmsg;
+                return (1);
+            }
+            nids++;
+        }
+    }
+    if(ids.size() != m_plate_hash_max) {
+        log << MSG::ERROR << " MuonID::init_hashes "
+            << " Error: set size NOT EQUAL to hash max. size " << ids.size()
+            << " hash max " << m_plate_hash_max 
+            << endmsg;
+        return (1);
+    }
+
+    nids = 0;
+    std::set<Identifier>::const_iterator first = ids.begin();
+    std::set<Identifier>::const_iterator last  = ids.end();
+    for (; first != last && nids < m_plate_vec.size(); ++first) {
+        m_plate_vec[nids] = (*first);
+        nids++;
+    }
+
+    // pmt hash - we do not keep a vec for the pmts
+    m_pmt_hash_max = m_full_pmt_range.cardinality();
+
+    return (0);
+}
+
+    int
+    MuonID::get_prev_in_z(const IdentifierHash& id, IdentifierHash& prev) const
+    {
+        unsigned short index = id;
+        if (index < m_prev_z_plate_vec.size())
+        {
+            if (m_prev_z_plate_vec[index] == NOT_VALID_HASH) return (1);
+            prev = m_prev_z_plate_vec[index];
+            return (0);
+        }
+        return (1);
+    }
+
+    int
+    MuonID::get_next_in_z(const IdentifierHash& id, IdentifierHash& next) const
+    {
+        unsigned short index = id;
+        if (index < m_next_z_plate_vec.size())
+        {
+            if (m_next_z_plate_vec[index] == NOT_VALID_HASH) return (1);
+            next = m_next_z_plate_vec[index];
+            return (0);
+        }
+        return (1);
+    }
+
+// int             
+// MuonID::get_prev_in_phi(const IdentifierHash& id, IdentifierHash& prev) const
+// {
+//     unsigned short index = id;
+//     if (index < m_prev_phi_wafer_vec.size()) {
+//         if (m_prev_phi_wafer_vec[index] == NOT_VALID_HASH) return (1);
+//         prev =  m_prev_phi_wafer_vec[index];
+//         return (0);
+//     }
+//     return (1);
+// }
+
+// int             
+// MuonID::get_next_in_phi(const IdentifierHash& id, IdentifierHash& next) const
+// {
+//     unsigned short index = id;
+//     if (index < m_next_phi_wafer_vec.size()) {
+//         if (m_next_phi_wafer_vec[index] == NOT_VALID_HASH) return (1);
+//         next =  m_next_phi_wafer_vec[index];
+//         return (0);
+//     }
+//     return (1);
+// }
+
+// int             
+// MuonID::get_prev_in_eta(const IdentifierHash& id, IdentifierHash& prev) const
+// {
+//     unsigned short index = id;
+//     if (index < m_prev_eta_wafer_vec.size()) {
+//         if (m_prev_eta_wafer_vec[index] == NOT_VALID_HASH) return (1);
+//         prev =  m_prev_eta_wafer_vec[index];
+//         return (0);
+//     }
+//     return (1);
+// }
+
+// int
+// MuonID::get_next_in_eta(const IdentifierHash& id, IdentifierHash& next) const
+// {
+//     unsigned short index = id;
+//     if (index < m_next_eta_wafer_vec.size()) {
+//         if (m_next_eta_wafer_vec[index] == NOT_VALID_HASH) return (1);
+//         next =  m_next_eta_wafer_vec[index];
+//         return (0);
+//     }
+//     return (1);
+// }
+
+// int
+// MuonID::get_other_side  (const IdentifierHash& hashId, IdentifierHash& other) const
+// {
+//     if (m_dict) {
+//         // get max from dictionary
+//         Identifier id;
+//         IdContext wafer_context1 = wafer_context();
+//         if(!get_id(hashId, id, &wafer_context1)) {
+//             other = side(id) ? hashId - 1 : hashId + 1;
+//             return (0);
+//         }
+//     }
+//     return (1);
+// }
+
+int
+MuonID::init_neighbors(void)
+{
+    //
+    // create a vector(s) to retrieve the hashes for compact ids for
+    // plate neighbors.
+    //
+    MsgStream log(m_msgSvc, "MuonID");
+
+    m_prev_z_plate_vec.resize(m_plate_hash_max, NOT_VALID_HASH);
+    m_next_z_plate_vec.resize(m_plate_hash_max, NOT_VALID_HASH);
+    for (unsigned int i = 0; i < m_full_plate_range.size(); i++)
+    {
+        const Range& range = m_full_plate_range[i];
+        const Range::field& station_field = range[m_STATION_INDEX];
+        const Range::field& plate_field   = range[m_PLATE_INDEX];
+        Range::const_identifier_factory first = range.factory_begin();
+        Range::const_identifier_factory last  = range.factory_end();
+        for (; first != last; ++first)
+        {
+            const ExpandedIdentifier& exp_id = (*first);
+            ExpandedIdentifier::element_type previous_plate;
+            ExpandedIdentifier::element_type next_plate;
+            ExpandedIdentifier::element_type previous_station;
+            ExpandedIdentifier::element_type next_station;
+            bool pplate = plate_field.get_previous(exp_id[m_PLATE_INDEX], previous_plate);
+            bool nplate = plate_field.get_next    (exp_id[m_PLATE_INDEX], next_plate);
+            bool pstation = station_field.get_previous(exp_id[m_STATION_INDEX], previous_station);
+            bool nstation = station_field.get_next    (exp_id[m_STATION_INDEX], next_station);
+
+            IdContext  pcontext = plate_context();
+
+            IdentifierHash hash_id;
+            Identifier originalId = plate_id(exp_id[m_STATION_INDEX],
+                                             exp_id[m_PLATE_INDEX]);
+
+            if (get_hash(originalId, hash_id, &pcontext)) 
+            {
+                log << MSG::ERROR << " MuonID::init_neighbors - unable to get hash, exp/compact "
+                    << show_to_string(originalId, &pcontext)
+                    << " " << (std::string)m_full_plate_range << endmsg;
+                return (1);
+            }
+
+            // index for the subsequent arrays
+            unsigned short index = hash_id;
+            assert (hash_id < m_prev_z_plate_vec.size());
+            assert (hash_id < m_next_z_plate_vec.size());
+            
+            if (pplate) {
+                // Get previous plate hash id
+                ExpandedIdentifier expId = exp_id;
+                expId[m_PLATE_INDEX] = previous_plate;
+                Identifier id = plate_id(expId[m_STATION_INDEX],
+                                         expId[m_PLATE_INDEX]);
+
+                if (get_hash(id, hash_id, &pcontext)) {
+                    log << MSG::ERROR << " MuonID::init_neighbors - unable to get previous plate hash, exp/compact " << id.getString() << " " 
+                        << endmsg;
+                    return (1);
+                }
+                m_prev_z_plate_vec[index] = hash_id;
+            }
+            else if (pstation)
+            {
+                ExpandedIdentifier expId = exp_id;
+                expId[m_STATION_INDEX] = previous_station;
+                ExpandedIdentifier stationId;
+                stationId.add(expId[m_SCINT_INDEX]);
+                stationId.add(expId[m_MUON_INDEX]);
+                stationId.add(previous_station);
+                Range prefix;
+                MultiRange stationPlateRange = m_dict->build_multirange(stationId, prefix, "plate");
+                const Range::field& upstream_plate_field = range[m_PLATE_INDEX];
+                if (upstream_plate_field.has_maximum())
+                {
+                    expId[m_PLATE_INDEX] = upstream_plate_field.get_maximum();
+                    Identifier id = plate_id(expId[m_STATION_INDEX],
+                                             expId[m_PLATE_INDEX]);
+                    if (get_hash(id, hash_id, &pcontext)) {
+                        log << MSG::ERROR << " MuonID::init_neighbors - unable to get last plate hash from previous station, exp/compact " << id.getString() << " " 
+                            << endmsg;
+                        return (1);
+                    }
+                    m_prev_z_plate_vec[index] = hash_id;
+                }
+                else
+                {
+                    log << MSG::ERROR << "MuonID::init_neighbors - unable to get plate_max for previous station, exp/compact " << originalId.getString() << " "
+                    << endmsg;
+                    return (1);
+                }
+            }
+
+            if (nplate) {
+                // Get next plate hash id
+                ExpandedIdentifier expId = exp_id;
+                expId[m_PLATE_INDEX] = next_plate;
+                Identifier id = plate_id(expId[m_STATION_INDEX],
+                                         expId[m_PLATE_INDEX]);
+
+                if (get_hash(id, hash_id, &pcontext)) {
+                    log << MSG::ERROR << " MuonID::init_neighbors - unable to get next plate hash, exp/compact " << id.getString() << " " 
+                        << endmsg;
+                    return (1);
+                }
+                m_next_z_plate_vec[index] = hash_id;
+            }
+            else if (nstation)
+            {
+                ExpandedIdentifier expId = exp_id;
+                expId[m_STATION_INDEX] = next_station;
+                ExpandedIdentifier stationId;
+                stationId.add(expId[m_SCINT_INDEX]);
+                stationId.add(expId[m_MUON_INDEX]);
+                stationId.add(next_station);
+                Range prefix;
+                MultiRange stationPlateRange = m_dict->build_multirange(stationId, prefix, "plate");
+                const Range::field& downstream_plate_field = range[m_PLATE_INDEX];
+                if (downstream_plate_field.has_minimum())
+                {
+                    expId[m_PLATE_INDEX] = downstream_plate_field.get_minimum();
+                    Identifier id = plate_id(expId[m_STATION_INDEX],
+                                             expId[m_PLATE_INDEX]);
+                    if (get_hash(id, hash_id, &pcontext)) {
+                        log << MSG::ERROR << " MuonID::init_neighbors - unable to get previous plate hash from next station, exp/compact " << id.getString() << " " 
+                            << endmsg;
+                        return (1);
+                    }
+                    m_next_z_plate_vec[index] = hash_id;
+                }
+                else
+                {
+                    log << MSG::ERROR << "MuonID::init_neighbors - unable to get plate_min for next station, exp/compact " << originalId.getString() << " "
+                    << endmsg;
+                    return (1);
+                }
+            }
+
+        }
+    }
+
+    // m_prev_phi_wafer_vec.resize(m_wafer_hash_max, NOT_VALID_HASH);
+    // m_next_phi_wafer_vec.resize(m_wafer_hash_max, NOT_VALID_HASH);
+    // m_prev_eta_wafer_vec.resize(m_wafer_hash_max, NOT_VALID_HASH);
+    // m_next_eta_wafer_vec.resize(m_wafer_hash_max, NOT_VALID_HASH);
+
+    // for (unsigned int i = 0; i < m_full_wafer_range.size(); ++i) {
+    //     const Range& range = m_full_wafer_range[i];
+    //     const Range::field& phi_field = range[m_PHI_MODULE_INDEX];
+    //     const Range::field& eta_field = range[m_ETA_MODULE_INDEX];
+    //     Range::const_identifier_factory first = range.factory_begin();
+    //     Range::const_identifier_factory last  = range.factory_end();
+    //     for (; first != last; ++first) {
+    //         const ExpandedIdentifier& exp_id = (*first);
+    //         ExpandedIdentifier::element_type previous_phi;
+    //         ExpandedIdentifier::element_type next_phi;
+    //         ExpandedIdentifier::element_type previous_eta;
+    //         ExpandedIdentifier::element_type next_eta;
+    //         bool pphi = phi_field.get_previous(exp_id[m_PHI_MODULE_INDEX], previous_phi);
+    //         bool nphi = phi_field.get_next    (exp_id[m_PHI_MODULE_INDEX], next_phi);
+    //         bool peta = eta_field.get_previous(exp_id[m_ETA_MODULE_INDEX], previous_eta);
+    //         bool neta = eta_field.get_next    (exp_id[m_ETA_MODULE_INDEX], next_eta);
+
+    //         IdContext      wcontext = wafer_context();
+            
+    //         // First get primary hash id
+    //         IdentifierHash hash_id;
+    //         Identifier id = wafer_id(exp_id[m_BARREL_EC_INDEX],
+    //                                  exp_id[m_LAYER_DISK_INDEX], 
+    //                                  exp_id[m_PHI_MODULE_INDEX],
+    //                                  exp_id[m_ETA_MODULE_INDEX],
+    //                                  exp_id[m_SIDE_INDEX]);
+    //         if (get_hash(id, hash_id, &wcontext)) {
+    //             log << MSG::ERROR << " MuonID::init_neighbors - unable to get hash, exp/compact "
+    //                 << show_to_string(id, &wcontext)
+    //                 << " " << (std::string)m_full_wafer_range << endmsg;
+    //             return (1);
+    //         }
+
+    //         // index for the subsequent arrays
+    //         unsigned short index = hash_id;
+    //         assert (hash_id < m_prev_phi_wafer_vec.size());
+    //         assert (hash_id < m_next_phi_wafer_vec.size());
+    //         assert (hash_id < m_prev_eta_wafer_vec.size());
+    //         assert (hash_id < m_next_eta_wafer_vec.size());
+            
+    //         if (pphi) {
+    //             // Get previous phi hash id
+    //             ExpandedIdentifier expId = exp_id;
+    //             expId[m_PHI_MODULE_INDEX] = previous_phi;
+    //             Identifier id = wafer_id(expId[m_BARREL_EC_INDEX],
+    //                                      expId[m_LAYER_DISK_INDEX], 
+    //                                      expId[m_PHI_MODULE_INDEX],
+    //                                      expId[m_ETA_MODULE_INDEX],
+    //                                      expId[m_SIDE_INDEX]);
+    //             if (get_hash(id, hash_id, &wcontext)) {
+    //                 log << MSG::ERROR << " MuonID::init_neighbors - unable to get previous phi hash, exp/compact " << id.getString() << " " 
+    //                     << endmsg;
+    //                 return (1);
+    //             }
+    //             m_prev_phi_wafer_vec[index] = hash_id;
+    //         }
+            
+    //         if (nphi) {
+    //             // Get next phi hash id
+    //             ExpandedIdentifier expId = exp_id;
+    //             expId[m_PHI_MODULE_INDEX] = next_phi;
+    //             Identifier id = wafer_id(expId[m_BARREL_EC_INDEX],
+    //                                      expId[m_LAYER_DISK_INDEX], 
+    //                                      expId[m_PHI_MODULE_INDEX],
+    //                                      expId[m_ETA_MODULE_INDEX],
+    //                                      expId[m_SIDE_INDEX]);
+    //             if (get_hash(id, hash_id, &wcontext)) {
+    //                 log << MSG::ERROR << " MuonID::init_neighbors - unable to get next phi hash, exp/compact " << id.getString() << 
+    //                     " " << MSG::hex << id.getString() << MSG::dec << endmsg;
+    //                 return (1);
+    //             }
+    //             m_next_phi_wafer_vec[index] = hash_id;
+    //         }
+            
+    //         if (peta) {
+    //             // Get previous eta hash id
+    //             ExpandedIdentifier expId = exp_id;
+    //             expId[m_ETA_MODULE_INDEX] = previous_eta;
+    //             Identifier id = wafer_id(expId[m_BARREL_EC_INDEX],
+    //                                      expId[m_LAYER_DISK_INDEX], 
+    //                                      expId[m_PHI_MODULE_INDEX],
+    //                                      expId[m_ETA_MODULE_INDEX],
+    //                                      expId[m_SIDE_INDEX]);
+    //             if (get_hash(id, hash_id, &wcontext)) {
+    //                 log << MSG::ERROR << " MuonID::init_neighbors - unable to get previous eta hash, exp/compact " << id.getString() 
+    //                     << " " << std::endl;
+    //                 return (1);
+    //             }
+    //             m_prev_eta_wafer_vec[index] = hash_id;
+    //         }
+            
+    //         if (neta) {
+    //             // Get next eta hash id
+    //             ExpandedIdentifier expId = exp_id;
+    //             expId[m_ETA_MODULE_INDEX] = next_eta;
+    //             Identifier id = wafer_id(expId[m_BARREL_EC_INDEX],
+    //                                      expId[m_LAYER_DISK_INDEX], 
+    //                                      expId[m_PHI_MODULE_INDEX],
+    //                                      expId[m_ETA_MODULE_INDEX],
+    //                                      expId[m_SIDE_INDEX]);
+    //             if (get_hash(id, hash_id, &wcontext)) {
+    //                 log << MSG::ERROR << " MuonID::init_neighbors - unable to get next eta hash, exp/compact " << id.getString() 
+    //                     << " " << endmsg;
+    //                 return (1);
+    //             }
+    //             m_next_eta_wafer_vec[index] = hash_id;
+    //         }
+            
+
+//          std::cout << " MuonID::init_neighbors "
+//                    << " phi, previous, next " << id[m_PHI_MODULE_INDEX]
+//                    << " " << pphi
+//                    << " " << previous_phi
+//                    << " " << nphi
+//                    << " " << next_phi
+//                    << " eta, previous, next " << id[m_ETA_MODULE_INDEX]
+//                    << " " << peta
+//                    << " " << previous_eta
+//                    << " " << neta
+//                    << " " << next_eta
+//                    << " id " << (std::string)(*first) 
+//                    << std::endl;
+    //     }
+    // }
+    return (0);
+}
+
+
+
+int     
+MuonID::initLevelsFromDict()
+{
+
+
+    MsgStream log(m_msgSvc, "MuonID");
+    if(!m_dict) {
+        log << MSG::ERROR << " MuonID::initLevelsFromDict - dictionary NOT initialized " << endmsg;
+        return (1);
+    }
+    
+    // Find out which identifier field corresponds to each level. Use
+    // names to find each field/leve.
+
+    m_SCINT_INDEX               = 999;
+    m_MUON_INDEX                = 999;
+    m_STATION_INDEX             = 999;
+    m_PLATE_INDEX               = 999;
+    m_PMT_INDEX                 = 999;    
+
+    // Save index to a Muon region for unpacking
+    ExpandedIdentifier id; 
+    id << scint_field_value() << muon_field_value();
+    if (m_dict->find_region(id, m_muon_region_index)) {
+        log << MSG::ERROR << "MuonID::initLevelsFromDict - unable to find muon region index: id, reg "  
+            << (std::string)id << " " << m_muon_region_index
+            << endmsg;
+        return (1);
+    }
+
+    // Find a Muon region
+    IdDictField* field = m_dict->find_field("subdet");
+    if (field) {
+        m_SCINT_INDEX = field->m_index;
+    }
+    else {
+        log << MSG::ERROR << "MuonID::initLevelsFromDict - unable to find 'subdet' field "  << endmsg;
+        return (1);
+    }
+    field = m_dict->find_field("part");
+    if (field) {
+        m_MUON_INDEX = field->m_index;
+    }
+    else {
+        log << MSG::ERROR << "MuonID::initLevelsFromDict - unable to find 'part' field "  << endmsg;
+        return (1);
+    }
+    field = m_dict->find_field("station");
+    if (field) {
+        m_STATION_INDEX = field->m_index;
+    }
+    else {
+        log << MSG::ERROR << "MuonID::initLevelsFromDict - unable to find 'station' field "   << endmsg;
+        return (1);
+    }
+    field = m_dict->find_field("plate");
+    if (field) {
+        m_PLATE_INDEX = field->m_index;
+    }
+    else {
+        log << MSG::ERROR<< "MuonID::initLevelsFromDict - unable to find 'plate' field "  << endmsg;
+        return (1);
+    }
+    field = m_dict->find_field("pmt");
+    if (field) {
+        m_PMT_INDEX = field->m_index;
+    }
+    else {
+        log << MSG::ERROR << "MuonID::initLevelsFromDict - unable to find 'pmt' field " << endmsg;    
+        return (1);
+    }
+    
+    // Set the field implementations
+
+    const IdDictRegion& region = *m_dict->m_regions[m_muon_region_index];
+
+    m_scint_impl      = region.m_implementation[m_SCINT_INDEX]; 
+    m_muon_impl       = region.m_implementation[m_MUON_INDEX]; 
+    m_station_impl    = region.m_implementation[m_STATION_INDEX]; 
+    m_plate_impl      = region.m_implementation[m_PLATE_INDEX];
+    m_pmt_impl        = region.m_implementation[m_PMT_INDEX]; 
+
+    if (m_msgSvc) {
+        log << MSG::DEBUG << "decode index and bit fields for each level: " << endmsg;
+        log << MSG::DEBUG << "scint    "  << m_scint_impl.show_to_string() << endmsg;
+        log << MSG::DEBUG << "muon     "  << m_muon_impl.show_to_string() << endmsg; 
+        log << MSG::DEBUG << "station  "  << m_station_impl.show_to_string() << endmsg; 
+        log << MSG::DEBUG << "plate    "  << m_plate_impl.show_to_string() << endmsg; 
+        log << MSG::DEBUG << "pmt      "  << m_pmt_impl.show_to_string() << endmsg; 
+    }
+    else {
+        std::cout << " DEBUG decode index and bit fields for each level: " << std::endl;
+        std::cout << " DEBUG scint    "  << m_scint_impl.show_to_string() << std::endl;
+        std::cout << " DEBUG muon     "  << m_muon_impl.show_to_string() << std::endl; 
+        std::cout << " DEBUG station  "  << m_station_impl.show_to_string() << std::endl; 
+        std::cout << " DEBUG plate    "  << m_plate_impl.show_to_string() << std::endl;
+        std::cout << " DEBUG pmt      "  << m_pmt_impl.show_to_string() << std::endl; 
+    }
+    
+    std::cout << "scint "  << m_scint_impl.decode_index() << " " 
+              <<   (std::string)m_scint_impl.ored_field() << " " 
+              << std::hex    << m_scint_impl.mask() << " " 
+              << m_scint_impl.zeroing_mask() << " " 
+              << std::dec    << m_scint_impl.shift() << " "
+              << m_scint_impl.bits() << " "
+              << m_scint_impl.bits_offset()
+              << std::endl;
+    std::cout << "muon"     << m_muon_impl.decode_index() << " " 
+              <<   (std::string)m_muon_impl.ored_field() << " " 
+              << std::hex    << m_muon_impl.mask() << " " 
+              << m_muon_impl.zeroing_mask() << " " 
+              << std::dec    << m_muon_impl.shift() << " "
+              << m_muon_impl.bits() << " "
+              << m_muon_impl.bits_offset()
+              << std::endl;
+    std::cout << "station"<< m_station_impl.decode_index() << " " 
+              <<   (std::string)m_station_impl.ored_field() << " " 
+              << std::hex    << m_station_impl.mask() << " " 
+              << m_station_impl.zeroing_mask() << " " 
+              << std::dec    << m_station_impl.shift() << " "
+              << m_station_impl.bits() << " "
+              << m_station_impl.bits_offset()
+              << std::endl;
+    std::cout << "plate"    << m_plate_impl.decode_index() << " " 
+              <<   (std::string)m_plate_impl.ored_field() << " " 
+              << std::hex    << m_plate_impl.mask() << " " 
+              << m_plate_impl.zeroing_mask() << " " 
+              << std::dec    << m_plate_impl.shift() << " "
+              << m_plate_impl.bits() << " "
+              << m_plate_impl.bits_offset()
+              << std::endl;
+    std::cout << "pmt"   << m_pmt_impl.decode_index() << " " 
+              <<   (std::string)m_pmt_impl.ored_field() << " " 
+              << std::hex    << m_pmt_impl.mask() << " " 
+              << m_pmt_impl.zeroing_mask() << " " 
+              << std::dec    << m_pmt_impl.shift() << " "
+              << m_pmt_impl.bits() << " "
+              << m_pmt_impl.bits_offset()
+              << std::endl;
+
+    return (0);
+}
+
+MuonID::size_type       
+MuonID::plate_hash_max (void) const
+{
+    return m_plate_hash_max;
+}
+
+MuonID::size_type       
+MuonID::pmt_hash_max (void) const
+{
+    return m_pmt_hash_max;
+}
+
+MuonID::const_id_iterator       MuonID::plate_begin             (void) const
+{
+    return (m_plate_vec.begin());
+}
+
+MuonID::const_id_iterator       MuonID::plate_end               (void) const
+{
+    return (m_plate_vec.end());
+}
+
+MuonID::const_expanded_id_iterator      MuonID::pmt_begin     (void) const
+{
+    return (m_full_pmt_range.factory_begin());
+}
+
+MuonID::const_expanded_id_iterator      MuonID::pmt_end       (void) const
+{
+    return (m_full_pmt_range.factory_end());
+}
+
+// From hash get Identifier
+int     
+MuonID::get_id          (const IdentifierHash& hash_id,
+                         Identifier& id,
+                         const IdContext* context) const
+{
+
+    int result = 1;
+    id.clear();
+
+    size_t begin = (context) ? context->begin_index(): 0;
+    // cannot get hash if end is 0:
+    size_t end   = (context) ? context->end_index()  : 0; 
+    if (0 == begin) { 
+        // No hashes yet for ids with prefixes
+        if (m_PLATE_INDEX == end) {
+            if (hash_id < (unsigned int)(m_plate_vec.end() - m_plate_vec.begin())) {
+                id = m_plate_vec[hash_id];
+                result = 0;
+            }
+        }
+        else if (m_PMT_INDEX == end) {
+            // Do not know how to calculate strip id from hash yet!!
+            std::cout << "Do not know how to calculate pmt id from hash yet!!" << std::endl;
+        }
+    }
+    return (result);
+}
+
+void
+MuonID::get_expanded_id (const Identifier& id,
+                         ExpandedIdentifier& exp_id,
+                         const IdContext* context) const
+{
+    exp_id.clear();
+    exp_id << scint_field_value()
+           << muon_field_value()
+           << station(id)
+           << plate(id);
+    if(!context || context->end_index() == m_PMT_INDEX) 
+    {
+       	exp_id << pmt(id);
+    }
+}
+
+int     
+MuonID::get_hash        (const Identifier& id, 
+                         IdentifierHash& hash_id,
+                         const IdContext* context) const
+{
+
+    // Get the hash code from either a vec (for plate) or calculate
+    // it (pmts). For the former, we convert to compact and call
+    // get_hash again. For the latter, we calculate the hash from the
+    // Identifier.
+
+    int result = 1;
+    hash_id = 0;
+    size_t begin = (context) ? context->begin_index(): 0;
+    size_t end   = (context) ? context->end_index()  : 0; 
+    if (0 == begin) {
+        // No hashes yet for ids with prefixes
+        if (m_PLATE_INDEX  == end) {
+            hash_id = plate_hash(id);
+            if (hash_id.is_valid()) result = 0;
+        }
+        else if (context && context->end_index() == m_PMT_INDEX) {
+            // Must calculate for strip hash
+            ExpandedIdentifier new_id;
+            get_expanded_id(id, new_id);
+            hash_id =  m_full_pmt_range.cardinalityUpTo(new_id);
+            result = 0;
+        }
+    }
+    return (result);
+}
+
+
+void    
+MuonID::test_plate_packing      (void) const
+{
+    MsgStream log(m_msgSvc, "MuonID");
+
+    if (m_dict) {
+        
+        int nids = 0;
+        int nerr = 0;
+        IdContext context = plate_context();
+        const_id_iterator first = m_plate_vec.begin();
+        const_id_iterator last  = m_plate_vec.end();
+        for (; first != last; ++first, ++nids) {
+            Identifier id = (*first);
+            ExpandedIdentifier exp_id;
+            get_expanded_id(id, exp_id, &context);
+            Identifier new_id = plate_id(exp_id[m_STATION_INDEX],
+                                         exp_id[m_PLATE_INDEX]);
+            if (id != new_id) {
+                log << MSG::ERROR << "MuonID::test_plate_packing: new and old compacts not equal. New/old/expanded ids " 
+                    << MSG::hex << show_to_string(id) << " " << show_to_string(new_id) << " " << MSG::dec 
+                    << (std::string)exp_id << endmsg;
+                nerr++;
+                continue;
+            }
+            // check station id
+            if (!exp_id[m_PLATE_INDEX]) {
+                
+                Identifier new_id1 = station_id(exp_id[m_STATION_INDEX]);
+                if (id != new_id1) {
+                    log << MSG::ERROR << "MuonID::test_plate_packing: new and old station ids not equal. New/old/expanded ids " 
+                        << MSG::hex << show_to_string(id) << " " << show_to_string(new_id1) << " " << MSG::dec 
+                        << (std::string)exp_id << endmsg;
+                    nerr++;
+                    continue;
+                }
+            }
+        }
+
+        if (m_msgSvc) { 
+            log << MSG::DEBUG << "MuonID::test_plate_packing: tested plate and station ids. nids, errors " 
+                << nids << " " << nerr << endmsg;
+        }
+        else {
+            std::cout << " DEBUG MuonID::test_plate_packing: tested plate and station ids. nids, errors " 
+                      << nids << " " << nerr << std::endl;
+        }
+        
+        nids = 0;
+        context = pmt_context();
+        const_expanded_id_iterator      first_muon = pmt_begin();  
+        const_expanded_id_iterator      last_muon  = pmt_end();
+        for (; first_muon != last_muon; ++first_muon, ++nids) {
+            // if (nids%10000 != 1) continue;
+            const ExpandedIdentifier& exp_id = *first_muon;
+            ExpandedIdentifier new_exp_id;
+
+            Identifier id = plate_id(exp_id[m_STATION_INDEX],
+                                     exp_id[m_PLATE_INDEX]);
+            get_expanded_id(id, new_exp_id, &context);
+            if (exp_id[0] != new_exp_id[0] ||
+                exp_id[1] != new_exp_id[1] ||
+                exp_id[2] != new_exp_id[2] ||
+                exp_id[3] != new_exp_id[3])
+            {
+                log << MSG::ERROR << "MuonID::test_plate_packing: new and old ids not equal. New/old/compact ids "
+                    << (std::string)new_exp_id << " " << (std::string)exp_id
+                    << " " << show_to_string(id) << endmsg;
+                continue;
+            }
+
+            Identifier pmtid	;
+	        Identifier pmtid1	;
+           	pmtid = pmt_id ( 
+                       exp_id[m_STATION_INDEX],
+					   exp_id[m_PLATE_INDEX],
+					   exp_id[m_PMT_INDEX]);
+
+    	   	pmtid1 = pmt_id (	    
+                        station(pmtid),
+                        plate(pmtid),
+                        pmt(pmtid));
+
+            if (pmtid != pmtid1) {
+                log << MSG::ERROR << "MuonID::test_plate_packing: new and old pixel ids not equal. New/old ids "
+                    << " " << show_to_string(pmtid1) << " " 
+                    << show_to_string(pmtid) << endmsg;
+            }
+        }
+
+        if (m_msgSvc) {
+            log << MSG::DEBUG << "MuonID::test_plate_packing: Successful tested " 
+                << nids << " ids. " 
+                << endmsg;
+        }
+        else {
+            std::cout << " DEBUG MuonID::test_plate_packing: Successful tested " 
+                      << nids << " ids. " 
+                      << std::endl;
+        }
+    }
+    else {
+        log << MSG::ERROR << "MuonID::test_plate_packing: Unable to test plate packing - no dictionary has been defined. " 
+            << endmsg;
+    }
+}
+
diff --git a/Scintillator/ScintDetDescrCnv/ScintIdCnv/src/MuonIDDetDescrCnv.cxx b/Scintillator/ScintDetDescrCnv/ScintIdCnv/src/MuonIDDetDescrCnv.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..628c95d4af40b087a2d22cb162786921b022a603
--- /dev/null
+++ b/Scintillator/ScintDetDescrCnv/ScintIdCnv/src/MuonIDDetDescrCnv.cxx
@@ -0,0 +1,239 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+/***************************************************************************
+ Scint DetDescrCnv package
+ -----------------------------------------
+ ***************************************************************************/
+
+//<<<<<< INCLUDES                                                       >>>>>>
+
+#include "MuonIDDetDescrCnv.h"
+
+#include "DetDescrCnvSvc/DetDescrConverter.h"
+#include "DetDescrCnvSvc/DetDescrAddress.h"
+#include "GaudiKernel/MsgStream.h"
+#include "StoreGate/StoreGateSvc.h" 
+
+#include "IdDictDetDescr/IdDictManager.h"
+#include "ScintIdentifier/MuonID.h"
+
+
+//<<<<<< PRIVATE DEFINES                                                >>>>>>
+//<<<<<< PRIVATE CONSTANTS                                              >>>>>>
+//<<<<<< PRIVATE TYPES                                                  >>>>>>
+//<<<<<< PRIVATE VARIABLE DEFINITIONS                                   >>>>>>
+//<<<<<< PUBLIC VARIABLE DEFINITIONS                                    >>>>>>
+//<<<<<< CLASS STRUCTURE INITIALIZATION                                 >>>>>>
+//<<<<<< PRIVATE FUNCTION DEFINITIONS                                   >>>>>>
+//<<<<<< PUBLIC FUNCTION DEFINITIONS                                    >>>>>>
+//<<<<<< MEMBER FUNCTION DEFINITIONS                                    >>>>>>
+
+//--------------------------------------------------------------------
+
+long int   
+MuonIDDetDescrCnv::repSvcType() const
+{
+  return (storageType());
+}
+
+//--------------------------------------------------------------------
+
+StatusCode 
+MuonIDDetDescrCnv::initialize()
+{
+    // First call parent init
+    StatusCode sc = DetDescrConverter::initialize();
+    MsgStream log(msgSvc(), "MuonIDDetDescrCnv");
+    log << MSG::DEBUG << "in initialize" << endmsg;
+
+    if (sc.isFailure()) {
+        log << MSG::ERROR << "DetDescrConverter::initialize failed" << endmsg;
+	return sc;
+    }
+    
+    // The following is an attempt to "bootstrap" the loading of a
+    // proxy for MuonID into the detector store. However,
+    // MuonIDDetDescrCnv::initialize is NOT called by the conversion
+    // service.  So for the moment, this cannot be use. Instead the
+    // DetDescrCnvSvc must do the bootstrap from a parameter list.
+
+
+//      // Add Scint_DetDescrManager proxy as entry point to the detector store
+//      // - this is ONLY needed for the manager of each system
+//      sc = addToDetStore(classID(), "MuonID");
+//      if (sc.isFailure()) {
+//  	log << MSG::FATAL << "Unable to add proxy for MuonID to the Detector Store!" << endmsg;
+//  	return StatusCode::FAILURE;
+//      } else {}
+
+    return StatusCode::SUCCESS; 
+}
+
+//--------------------------------------------------------------------
+
+StatusCode 
+MuonIDDetDescrCnv::finalize()
+{
+    MsgStream log(msgSvc(), "MuonIDDetDescrCnv");
+    log << MSG::DEBUG << "in finalize" << endmsg;
+
+    return StatusCode::SUCCESS; 
+}
+
+//--------------------------------------------------------------------
+
+StatusCode
+MuonIDDetDescrCnv::createObj(IOpaqueAddress* pAddr, DataObject*& pObj) 
+{
+    //StatusCode sc = StatusCode::SUCCESS;
+    MsgStream log(msgSvc(), "MuonIDDetDescrCnv");
+    log << MSG::INFO << "in createObj: creating a MuonID helper object in the detector store" << endmsg;
+
+    // Create a new MuonID
+
+    DetDescrAddress* ddAddr;
+    ddAddr = dynamic_cast<DetDescrAddress*> (pAddr);
+    if(!ddAddr) {
+	log << MSG::FATAL << "Could not cast to DetDescrAddress." << endmsg;
+	return StatusCode::FAILURE;
+    }
+
+    // Get the StoreGate key of this container.
+    std::string helperKey  = *( ddAddr->par() );
+    if ("" == helperKey) {
+	log << MSG::DEBUG << "No Helper key " << endmsg;
+    }
+    else {
+	log << MSG::DEBUG << "Helper key is " << helperKey << endmsg;
+    }
+    
+
+    // get DetectorStore service
+    StoreGateSvc * detStore;
+    StatusCode status = serviceLocator()->service("DetectorStore", detStore);
+    if (status.isFailure()) {
+	log << MSG::FATAL << "DetectorStore service not found !" << endmsg;
+	return StatusCode::FAILURE;
+    } else {}
+ 
+    // Get the dictionary manager from the detector store
+    const IdDictManager* idDictMgr;
+    status = detStore->retrieve(idDictMgr, "IdDict");
+    if (status.isFailure()) {
+	log << MSG::FATAL << "Could not get IdDictManager !" << endmsg;
+	return StatusCode::FAILURE;
+    } 
+    else {
+	log << MSG::DEBUG << " Found the IdDictManager. " << endmsg;
+    }
+
+    // Only create new helper if it is the first pass or if there is a
+    // change in the the file or tag
+    bool initHelper               = false;
+
+    const IdDictMgr* mgr          = idDictMgr->manager();
+
+    // Internal Scint id tag
+    std::string   scintIDTag      = mgr->tag();
+
+    // DoChecks flag
+    bool doChecks                 = mgr->do_checks();
+
+    IdDictDictionary* dict = mgr->find_dictionary("Scintillator");  
+    if (!dict) {
+	log << MSG::ERROR 
+	    << "unable to find idDict for Scintillator" 
+	    << endmsg;
+	return StatusCode::FAILURE;
+    }
+
+    // File to be read for Scint ids
+    std::string   scintIDFileName = dict->file_name();
+
+    // Tag of RDB record for Scint ids
+    std::string   scintIdDictTag  = dict->dict_tag();
+
+
+    if (m_muonId) {
+
+	// Muon id helper already exists - second pass. Check for a
+	// change 
+	if (scintIDTag != m_scintIDTag) { 
+	    // Internal Scint id tag
+	    initHelper = true;
+	    log << MSG::DEBUG << " Changed internal Scint id tag: " 
+		<< scintIDTag << endmsg;
+	}
+	if (scintIDFileName != m_scintIDFileName) {
+	    // File to be read for Scint ids
+	    initHelper = true;
+	    log << MSG::DEBUG << " Changed ScintFileName:" 
+		<< scintIDFileName << endmsg;
+	}
+	if (scintIdDictTag != m_scintIdDictTag) {
+	    // Tag of RDB record for Scint ids
+	    initHelper = true;
+	    log << MSG::DEBUG << " Changed ScintIdDictTag: "
+		<< scintIdDictTag 
+		<< endmsg;
+	}
+	if (doChecks != m_doChecks) {
+	    // DoChecks flag
+	    initHelper = true;
+	    log << MSG::DEBUG << " Changed doChecks flag: "
+		<< doChecks
+		<< endmsg;
+        }
+    }
+    else {
+	// create the helper
+	m_muonId = new MuonID;
+	initHelper = true;
+        // add in message service for printout
+        m_muonId->setMessageSvc(msgSvc());
+    }
+    
+    if (initHelper) {
+	if (idDictMgr->initializeHelper(*m_muonId)) {
+	    log << MSG::ERROR << "Unable to initialize MuonID" << endmsg;
+	    return StatusCode::FAILURE;
+	} 
+	// Save state:
+	m_scintIDTag      = scintIDTag;
+	m_scintIDFileName = scintIDFileName;
+	m_scintIdDictTag  = scintIdDictTag;
+	m_doChecks        = doChecks;
+    }
+
+    // Pass a pointer to the container to the Persistency service by reference.
+    pObj = SG::asStorable(m_muonId);
+
+    return StatusCode::SUCCESS; 
+
+}
+
+//--------------------------------------------------------------------
+
+long
+MuonIDDetDescrCnv::storageType()
+{
+    return DetDescr_StorageType;
+}
+
+//--------------------------------------------------------------------
+const CLID& 
+MuonIDDetDescrCnv::classID() { 
+    return ClassID_traits<MuonID>::ID(); 
+}
+
+//--------------------------------------------------------------------
+MuonIDDetDescrCnv::MuonIDDetDescrCnv(ISvcLocator* svcloc) 
+    :
+    DetDescrConverter(ClassID_traits<MuonID>::ID(), svcloc),
+    m_muonId(0),
+    m_doChecks(false)
+
+{}
+
diff --git a/Scintillator/ScintDetDescrCnv/ScintIdCnv/src/MuonIDDetDescrCnv.h b/Scintillator/ScintDetDescrCnv/ScintIdCnv/src/MuonIDDetDescrCnv.h
new file mode 100644
index 0000000000000000000000000000000000000000..9be6e056be5290194d856d045ae18e29bc444877
--- /dev/null
+++ b/Scintillator/ScintDetDescrCnv/ScintIdCnv/src/MuonIDDetDescrCnv.h
@@ -0,0 +1,71 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+/***************************************************************************
+ Scint DetDescrCnv package
+ -----------------------------------------
+ ***************************************************************************/
+
+#ifndef SCINTIDCNV_MUONIDDETDESCRCNV_H
+#define SCINTIDCNV_MUONIDDETDESCRCNV_H
+
+//<<<<<< INCLUDES                                                       >>>>>>
+
+#include "DetDescrCnvSvc/DetDescrConverter.h"
+
+//<<<<<< PUBLIC DEFINES                                                 >>>>>>
+//<<<<<< PUBLIC CONSTANTS                                               >>>>>>
+//<<<<<< PUBLIC TYPES                                                   >>>>>>
+
+class MuonID;
+
+//<<<<<< PUBLIC VARIABLES                                               >>>>>>
+//<<<<<< PUBLIC FUNCTIONS                                               >>>>>>
+//<<<<<< CLASS DECLARATIONS                                             >>>>>>
+
+
+/**
+ **  This class is a converter for the MuonID an IdHelper which is
+ **  stored in the detector store. This class derives from
+ **  DetDescrConverter which is a converter of the DetDescrCnvSvc.
+ **
+ **/
+
+class MuonIDDetDescrCnv: public DetDescrConverter {
+
+public:
+    virtual long int   repSvcType() const;
+    virtual StatusCode initialize();
+    virtual StatusCode finalize();
+    virtual StatusCode createObj(IOpaqueAddress* pAddr, DataObject*& pObj);
+
+    // Storage type and class ID (used by CnvFactory)
+    static long storageType();
+    static const CLID& classID();
+
+    MuonIDDetDescrCnv(ISvcLocator* svcloc);
+
+private:
+    /// The helper - only will create it once
+    MuonID*       m_muonId;
+
+    /// File to be read for Scint ids
+    std::string   m_scintIDFileName;
+
+    /// Tag of RDB record for Scint ids
+    std::string   m_scintIdDictTag;
+
+    /// Internal Scint id tag
+    std::string   m_scintIDTag;
+
+    /// Whether or not 
+    bool          m_doChecks;
+
+};
+
+
+//<<<<<< INLINE PUBLIC FUNCTIONS                                        >>>>>>
+//<<<<<< INLINE MEMBER FUNCTIONS                                        >>>>>>
+
+#endif // SCINTIDCNV_MUONIDDETDESCRCNV_H
diff --git a/Scintillator/ScintDetDescrCnv/ScintIdCnv/src/ScintIdCnv_entries.cxx b/Scintillator/ScintDetDescrCnv/ScintIdCnv/src/ScintIdCnv_entries.cxx
index 0b99ec46b38a725159e9ae7f914d7df3b99b2178..0c0a07e988699d48a4002c897c7370f2a85a6ce2 100644
--- a/Scintillator/ScintDetDescrCnv/ScintIdCnv/src/ScintIdCnv_entries.cxx
+++ b/Scintillator/ScintDetDescrCnv/ScintIdCnv/src/ScintIdCnv_entries.cxx
@@ -6,6 +6,7 @@
 #include "VetoNuIDDetDescrCnv.h"
 #include "TriggerIDDetDescrCnv.h"
 #include "PreshowerIDDetDescrCnv.h"
+#include "MuonIDDetDescrCnv.h"
 
 // DECLARE_CONVERTER(SCT_IDDetDescrCnv)
 // DECLARE_CONVERTER(PixelIDDetDescrCnv)
@@ -15,3 +16,4 @@ DECLARE_CONVERTER(VetoIDDetDescrCnv)
 DECLARE_CONVERTER(VetoNuIDDetDescrCnv)
 DECLARE_CONVERTER(TriggerIDDetDescrCnv)
 DECLARE_CONVERTER(PreshowerIDDetDescrCnv)
+DECLARE_CONVERTER(MuonIDDetDescrCnv)
diff --git a/Tracker/TrackerRecAlgs/NoisyStripFinder/share/NoisyStripFinderJob.py b/Tracker/TrackerRecAlgs/NoisyStripFinder/share/NoisyStripFinderJob.py
index 6235c83623c8be6434af009a71aff25b624f91c1..778893423abac7b678dd58e3a57f1e04e3eb0aa5 100755
--- a/Tracker/TrackerRecAlgs/NoisyStripFinder/share/NoisyStripFinderJob.py
+++ b/Tracker/TrackerRecAlgs/NoisyStripFinder/share/NoisyStripFinderJob.py
@@ -40,7 +40,7 @@ for filename in args.file:
 
 configFlags = initConfigFlags()
 configFlags.Input.Files = args.file
-configFlags.IOVDb.GlobalTag = "OFLCOND-FASER-04"
+configFlags.IOVDb.GlobalTag = "OFLCOND-FASER-05"
 #configFlags.IOVDb.DatabaseInstance = "OFLP200"
 configFlags.IOVDb.DatabaseInstance = "CONDBR3"
 configFlags.Input.ProjectName = "data22"
diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/GhostBusters.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/GhostBusters.cxx
index f191ba2c72d04c5668590abcdd320a0846ba41be..14ae6f0d4f95c17bb69d384496e2edf1f7cb7358 100644
--- a/Tracking/Acts/FaserActsKalmanFilter/src/GhostBusters.cxx
+++ b/Tracking/Acts/FaserActsKalmanFilter/src/GhostBusters.cxx
@@ -34,7 +34,7 @@ StatusCode GhostBusters::initialize() {
 
 StatusCode GhostBusters::execute(const EventContext &ctx) const {
   m_event_number = ctx.eventID().event_number();
-  ATH_MSG_INFO("GHOSTBUSTING Event Number = " << m_event_number);
+  ATH_MSG_DEBUG("GHOSTBUSTING Event Number = " << m_event_number);
 
   SG::WriteHandle outputTrackCollection {m_outputTrackCollection, ctx};
   std::unique_ptr<TrackCollection> outputTracks = std::make_unique<TrackCollection>();
@@ -64,21 +64,21 @@ StatusCode GhostBusters::execute(const EventContext &ctx) const {
     double meanY = 0.5 * (minY + maxY);
     double deltaX = deltaY / (2 * std::tan(0.02));
 
-    ATH_MSG_INFO("maxX  = " << maxX);
-    ATH_MSG_INFO("maxY  = " << maxY);
-    ATH_MSG_INFO("minX  = " << minX);
-    ATH_MSG_INFO("minY  = " << minY);
-    ATH_MSG_INFO("deltaY  = " << deltaY);
-    ATH_MSG_INFO("meanX  = " << meanX);
-    ATH_MSG_INFO("meanY  = " << meanY);
-    ATH_MSG_INFO("deltaX  = " << deltaX);
+    ATH_MSG_DEBUG("maxX  = " << maxX);
+    ATH_MSG_DEBUG("maxY  = " << maxY);
+    ATH_MSG_DEBUG("minX  = " << minX);
+    ATH_MSG_DEBUG("minY  = " << minY);
+    ATH_MSG_DEBUG("deltaY  = " << deltaY);
+    ATH_MSG_DEBUG("meanX  = " << meanX);
+    ATH_MSG_DEBUG("meanY  = " << meanY);
+    ATH_MSG_DEBUG("deltaX  = " << deltaX);
 
-    ATH_MSG_INFO("yLowerBound  = " << meanY - m_yTolerance * deltaY);
-    ATH_MSG_INFO("yUpperBound  = " << meanY + m_yTolerance * deltaY);
-    ATH_MSG_INFO("xLeftLowerBound  = " << meanX - (1 + m_xTolerance) * deltaX);
-    ATH_MSG_INFO("xLeftUpperBound  = " << meanX - (1 - m_xTolerance) * deltaX);
-    ATH_MSG_INFO("xRightLowerBound  = " << meanX + (1 - m_xTolerance) * deltaX);
-    ATH_MSG_INFO("xRightUpperBound  = " << meanX + (1 + m_xTolerance) * deltaX);
+    ATH_MSG_DEBUG("yLowerBound  = " << meanY - m_yTolerance * deltaY);
+    ATH_MSG_DEBUG("yUpperBound  = " << meanY + m_yTolerance * deltaY);
+    ATH_MSG_DEBUG("xLeftLowerBound  = " << meanX - (1 + m_xTolerance) * deltaX);
+    ATH_MSG_DEBUG("xLeftUpperBound  = " << meanX - (1 - m_xTolerance) * deltaX);
+    ATH_MSG_DEBUG("xRightLowerBound  = " << meanX + (1 - m_xTolerance) * deltaX);
+    ATH_MSG_DEBUG("xRightUpperBound  = " << meanX + (1 + m_xTolerance) * deltaX);
 
 
 
@@ -89,10 +89,10 @@ StatusCode GhostBusters::execute(const EventContext &ctx) const {
           ((segment.x() > meanX + (1 - m_xTolerance) * deltaX) && (segment.x() < meanX + (1 + m_xTolerance) * deltaX)));
       if (isGhost) segment.setGhost();
       if (not isGhost && segment.size() >= 5) nGoodSegments++;
-      ATH_MSG_INFO("Segment Y  = " << segment.y());
-      ATH_MSG_INFO("Segment X  = " << segment.x());
-      ATH_MSG_INFO("Segment isGhost  = " << isGhost);
-      ATH_MSG_INFO("nGoodSegments  = " << nGoodSegments);
+      ATH_MSG_DEBUG("Segment Y  = " << segment.y());
+      ATH_MSG_DEBUG("Segment X  = " << segment.x());
+      ATH_MSG_DEBUG("Segment isGhost  = " << isGhost);
+      ATH_MSG_DEBUG("nGoodSegments  = " << nGoodSegments);
     }
     for (const Segment &segment : stationSegments) {
       m_x = segment.x();
@@ -101,16 +101,16 @@ StatusCode GhostBusters::execute(const EventContext &ctx) const {
       m_chi2 = segment.chi2();
       m_station = segment.station();
       m_size = segment.size();
-      ATH_MSG_INFO("m_x  = " << m_x);
-      ATH_MSG_INFO("m_y  = " << m_y);
-      ATH_MSG_INFO("m_z  = " << m_z);
+      ATH_MSG_DEBUG("m_x  = " << m_x);
+      ATH_MSG_DEBUG("m_y  = " << m_y);
+      ATH_MSG_DEBUG("m_z  = " << m_z);
       // m_majorityHits = segment.majorityHits();
       m_isGhost = segment.isGhost();
-      ATH_MSG_INFO("m_isGhost  = " << m_isGhost);
-      ATH_MSG_INFO("nGoodSegments  = " << nGoodSegments);
-      ATH_MSG_INFO("segment.size()  = " << segment.size());
+      ATH_MSG_DEBUG("m_isGhost  = " << m_isGhost);
+      ATH_MSG_DEBUG("nGoodSegments  = " << nGoodSegments);
+      ATH_MSG_DEBUG("segment.size()  = " << segment.size());
       // if (nGoodSegments >= 2 && segment.size() == 4) m_isGhost = true;
-      ATH_MSG_INFO("m_isGhost after if statement  = " << m_isGhost);
+      ATH_MSG_DEBUG("m_isGhost after if statement  = " << m_isGhost);
       m_tree->Fill();
       if (segment.isGhost()) continue;
       // if (nGoodSegments >= 2 && segment.size() == 4) continue;
diff --git a/Waveform/WaveEventCnv/WaveByteStream/src/RawWaveformDecoderTool.cxx b/Waveform/WaveEventCnv/WaveByteStream/src/RawWaveformDecoderTool.cxx
index d9728fa086b226b417d7af130431131f58d2d13b..5a79650dac1741a028dee4d7e8639506a91c3366 100644
--- a/Waveform/WaveEventCnv/WaveByteStream/src/RawWaveformDecoderTool.cxx
+++ b/Waveform/WaveEventCnv/WaveByteStream/src/RawWaveformDecoderTool.cxx
@@ -97,10 +97,12 @@ RawWaveformDecoderTool::convert(const DAQFormats::EventFull* re,
     ATH_MSG_DEBUG("Found valid digitizer0 fragment");
   }
 
-
   if (!digitizer1) {
     // Will happen in data before 2024
-    ATH_MSG_INFO("Failed to find digitizer1 fragment in raw event!");
+    if (cable_map.size() > 16)
+      ATH_MSG_WARNING("Failed to find digitizer1 fragment in raw event!");
+    else
+      ATH_MSG_DEBUG("Failed to find digitizer1 fragment in raw event!");
   } else {
     if (!digitizer1->valid()) {
       ATH_MSG_WARNING("Found invalid digitizer1 fragment:\n" << *digitizer1);
@@ -109,12 +111,24 @@ RawWaveformDecoderTool::convert(const DAQFormats::EventFull* re,
     }
   }    
 
+  // Check if boards are out of sync
+  int timing_shift = 0;
+  if (digitizer1 && digitizer1->valid()) {
+    if (digitizer1->trigger_time_tag() != digitizer0->trigger_time_tag()) {
+      // These are unsigned integers, make them ints so we can get -1
+      timing_shift = int(digitizer1->trigger_time_tag()) - int(digitizer0->trigger_time_tag());
+      ATH_MSG_DEBUG("Digi1 - Digi0 trigger time: " << timing_shift); 
+    }
+  }
+  
   // Detector type to match in first element of cable map
   std::string det_type;
   if (key == std::string("CaloWaveforms")) {
     det_type = std::string("calo");
   } else if (key == std::string("Calo2Waveforms")) {
     det_type = std::string("calo2");
+  } else if (key == std::string("CaloNuWaveforms")) {
+    det_type = std::string("calonu");
   } else if (key == std::string("VetoWaveforms")) {
     det_type = std::string("veto");
   } else if (key == std::string("VetoNuWaveforms")) {
@@ -123,6 +137,8 @@ RawWaveformDecoderTool::convert(const DAQFormats::EventFull* re,
     det_type = std::string("trigger");
   } else if (key == std::string("PreshowerWaveforms")) {
     det_type = std::string("preshower");
+  } else if (key == std::string("MuonWaveforms")) {
+    det_type = std::string("muon");
   } else if (key == std::string("ClockWaveforms")) {
     det_type = std::string("clock");
   } else {
@@ -142,15 +158,28 @@ RawWaveformDecoderTool::convert(const DAQFormats::EventFull* re,
     ATH_MSG_DEBUG("Converting channel "+std::to_string(channel)+" for "+key);
 
     int chan = channel;
+    int shift = 0;
     digitizer = digitizer0;
     if (channel > 15) {
       chan = channel-16;
       digitizer = digitizer1;
+      shift = timing_shift;  // Only apply timing shift to 2nd digitizer
+    }
+
+    // Check if digitizer is OK
+    if (!digitizer) {
+      ATH_MSG_WARNING("Channel " << channel << " has missing digitizer!");
+      continue;
+    }
+      
+    if (!digitizer->valid()) {
+      ATH_MSG_WARNING("Channel " << channel << " has invalid digitizer!");
+      continue;
     }
     
     // Check if this has data
     if (!digitizer->channel_has_data(chan)) {
-      ATH_MSG_DEBUG("Channel " << channel << " has no data - skipping!");
+      ATH_MSG_WARNING("Channel " << channel << " has no data - skipping!");
       continue;
     } 
 
@@ -184,6 +213,9 @@ RawWaveformDecoderTool::convert(const DAQFormats::EventFull* re,
     // Set ADC range
     wfm->setRange(range_map.at(channel));
 
+    // Set timing shift
+    wfm->setTriggerOffset(shift);
+    
     container->push_back(wfm);    
 
     // Sanity check
diff --git a/Waveform/WaveRawEvent/WaveRawEvent/RawWaveform.h b/Waveform/WaveRawEvent/WaveRawEvent/RawWaveform.h
index a1f42f6e86db846ea544daedb482ba8aba8fbdf5..d66250b56ec1c174774348142749523fa3b87e71 100644
--- a/Waveform/WaveRawEvent/WaveRawEvent/RawWaveform.h
+++ b/Waveform/WaveRawEvent/WaveRawEvent/RawWaveform.h
@@ -58,7 +58,8 @@ public:
   unsigned int event_counter() const;
   unsigned int trigger_time_tag() const;
   unsigned int n_samples() const;
-
+  int trigger_offset() const;
+  
   // Waveform data
   unsigned int channel() const;
   const std::vector<unsigned int>& adc_counts() const;
@@ -94,6 +95,7 @@ public:
   void setChannel(unsigned int chan) {m_channel = chan;}
   void setSamples(unsigned int samp) {m_samples = samp;}
   void setCounts(const std::vector<unsigned int>& counts) {m_adc_counts = counts;}
+  void setTriggerOffset(int off) {m_trigger_offset = off;}
 
   void setRange(float range) {m_range = range;}
 
@@ -114,7 +116,8 @@ private:
 
   Identifier32 m_ID;
 
-  float m_range;  
+  float m_range;
+  int m_trigger_offset;
 };
 
 
@@ -158,6 +161,9 @@ RawWaveform::identify32() const { return m_ID; }
 inline float
 RawWaveform::range() const { return m_range; }
 
+inline int
+RawWaveform::trigger_offset() const { return m_trigger_offset; }
+
 std::ostream 
 &operator<<(std::ostream &out, const RawWaveform &wfm);
 
diff --git a/Waveform/WaveRawEvent/src/RawWaveform.cxx b/Waveform/WaveRawEvent/src/RawWaveform.cxx
index 64c401dfad6a9fe9794737a953eca31eff110bc1..d13617a5c9393cca1d89b1afe07f39a1f1577f00 100644
--- a/Waveform/WaveRawEvent/src/RawWaveform.cxx
+++ b/Waveform/WaveRawEvent/src/RawWaveform.cxx
@@ -18,7 +18,8 @@ RawWaveform::RawWaveform( ) :
   m_channel(0),
   m_adc_counts(),
   m_ID(0xffff),
-  m_range(2.)
+  m_range(2.),
+  m_trigger_offset(0)
 {
 
 }
diff --git a/Waveform/WaveRecAlgs/python/WaveRecAlgsConfig.py b/Waveform/WaveRecAlgs/python/WaveRecAlgsConfig.py
index b1b586585f93de7142951e7b293e0a3f25ef0b88..c836a33481d4c0f8ecccca9feab5b3d88a314ac5 100644
--- a/Waveform/WaveRecAlgs/python/WaveRecAlgsConfig.py
+++ b/Waveform/WaveRecAlgs/python/WaveRecAlgsConfig.py
@@ -25,6 +25,7 @@ def WaveformReconstructionCfg(flags):
         acc.merge(WaveformHitRecCfg(flags, "CaloWaveformRecAlg", "Calo"))
 
         # Make preshower/veto window 200 ns wide (100 digitizer clock ticks)
+        # Adjust baseline range for early signals (CaloNu, VetoNu)
         acc.merge(WaveformHitRecCfg(flags, "VetoWaveformRecAlg", "Veto", FitWindowWidth=100 ))
         acc.merge(WaveformHitRecCfg(flags, "PreshowerWaveformRecAlg", "Preshower", FitWindowWidth=100 ))
 
@@ -33,13 +34,17 @@ def WaveformReconstructionCfg(flags):
         if flags.Input.isMC:
             print("Calo2WaveformRecAlg diabled for MC in WaveformReconstructionCfg!")
         else:
+            # 2024/25 detectors (not in MC yet)
             acc.merge(WaveformHitRecCfg(flags, "Calo2WaveformRecAlg", "Calo2"))
+            acc.merge(WaveformHitRecCfg(flags, "CaloNuWaveformRecAlg", "CaloNu", BaselineSampleHi=50))
+            acc.merge(WaveformHitRecCfg(flags, "MuonWaveformRecAlg", "Muon", FitWindowWidth=100, BaselineSampleHi=60))
 
         # Make preshower window 200 ns wide (value in digitizer clock ticks)
+        # Limit range to determine baseline for early channels
         acc.merge(WaveformHitRecCfg(flags, "VetoWaveformRecAlg", "Veto", FitWindowWidth=100 ))
-        acc.merge(WaveformHitRecCfg(flags, "PreshowerWaveformRecAlg", "Preshower", FitWindowWidth=100 ))
+        acc.merge(WaveformHitRecCfg(flags, "PreshowerWaveformRecAlg", "Preshower", FitWindowWidth=100, BaselineSampleHi=60 ))
         acc.merge(WaveformHitRecCfg(flags, "TriggerWaveformRecAlg", "Trigger", FitWindowWidth=100))
-        acc.merge(WaveformHitRecCfg(flags, "VetoNuWaveformRecAlg", "VetoNu", FitWindowWidth=100))
+        acc.merge(WaveformHitRecCfg(flags, "VetoNuWaveformRecAlg", "VetoNu", FitWindowWidth=100, BaselineSampleHi=60))
 
     acc.merge(WaveformTimingCfg(flags))
 
@@ -75,7 +80,8 @@ def WaveformHitRecCfg(flags, name="WaveformRecAlg", source="", **kwargs):
     # Remove arguments intended for WaveRecTool
     if "PeakThreshold" in kwargs: kwargs.pop("PeakThreshold")
     if "FitWindowWidth" in kwargs: kwargs.pop("FitWindowWidth")
-
+    if "BaselineSampleHi" in kwargs: kwargs.pop("BaselineSampleHi")
+    
     kwargs.setdefault("WaveformContainerKey", source+"Waveforms")
     kwargs.setdefault("WaveformHitContainerKey", source+"WaveformHits")
     kwargs.setdefault("WaveformReconstructionTool", tool)
diff --git a/Waveform/WaveRecTools/src/ClockReconstructionTool.cxx b/Waveform/WaveRecTools/src/ClockReconstructionTool.cxx
index 825cc755862200c0dd008eaf3c273cb23b37f83a..26a4dd9a435726a9e2177135dd72b5cca147f91e 100644
--- a/Waveform/WaveRecTools/src/ClockReconstructionTool.cxx
+++ b/Waveform/WaveRecTools/src/ClockReconstructionTool.cxx
@@ -147,6 +147,13 @@ ClockReconstructionTool::reconstruct(const RawWaveform& raw_wave,
 
   if (m_checkResult) checkResult(raw_wave, clockdata);
 
+  // Finally, set the time offset if the 2nd digitizer triggered late
+  if (raw_wave.trigger_offset() >= 1) {
+    clockdata->set_time_offset(-16.);  // 16 ns
+  } else {
+    clockdata->set_time_offset(0.);  
+  }
+  
   return StatusCode::SUCCESS;
 }
 
diff --git a/Waveform/WaveRecTools/src/WaveformReconstructionTool.cxx b/Waveform/WaveRecTools/src/WaveformReconstructionTool.cxx
index 1caf49d4a3be081da8c8b8339324125ee6df788b..e69a6fb8440a312505b2d8c8a31b69825b1a4d42 100644
--- a/Waveform/WaveRecTools/src/WaveformReconstructionTool.cxx
+++ b/Waveform/WaveRecTools/src/WaveformReconstructionTool.cxx
@@ -91,19 +91,27 @@ WaveformReconstructionTool::reconstructPrimary(
   float trigger_time = m_timingTool->nominalTriggerTime();
 
   // Set range for windowed data in digitizer samples
-  float offset = m_timingTool->triggerTimeOffset(wave.channel());
+  float trigger_offset = m_timingTool->triggerTimeOffset(wave.channel());
 
-  int lo_edge = int((trigger_time+offset)/2.) + m_windowStart;
-  int hi_edge = int((trigger_time+offset)/2.) + m_windowStart + m_windowWidth;
+  
+  int lo_edge = int((trigger_time+trigger_offset)/2.) + m_windowStart;
+  int hi_edge = int((trigger_time+trigger_offset)/2.) + m_windowStart + m_windowWidth;
 
   if (hi_edge >= int(wave.size())) {
     // This likely means we have the wrong digitizer range
     ATH_MSG_WARNING("Found channel " << wave.channel() << " with low edge: " << lo_edge << " hi edge: " << hi_edge << " > wave.size() " << wave.size());
-    ATH_MSG_WARNING("  trigger_time + offset: " << (trigger_time+offset) << " => " << int((trigger_time+offset)/2.));
+    ATH_MSG_WARNING("  trigger_time + trigger_offset: " << (trigger_time+trigger_offset) << " => " << int((trigger_time+trigger_offset)/2.));
     newhit->set_status_bit(xAOD::WaveformStatus::WAVEFORM_INVALID);
     return StatusCode::SUCCESS;
   }
   
+  // Adjust window time if 2nd digitizer triggered late
+  // Waveform will arrive early by 16ns
+  if (wave.trigger_offset() >= 1) {
+    lo_edge -= 8;
+    hi_edge -= 8;
+  }
+
   // Fill raw hit values
   fillRawHitValues(wave, lo_edge, hi_edge, newhit);
 
@@ -309,7 +317,7 @@ WaveformReconstructionTool::setLocalTime(const xAOD::WaveformClock* clock,
   }
 
   float trigger_time = m_timingTool->nominalTriggerTime();
-  float offset;
+  float trigger_offset;
 
   // Should actually find the time of the trigger here 
   // and set bcid time offset from that
@@ -317,17 +325,28 @@ WaveformReconstructionTool::setLocalTime(const xAOD::WaveformClock* clock,
   for( const auto& hit : *container) {
 
     //
-    // Find time from clock
+    // Do we need to add an additional 16ns shift for the second
+    // digitizer triggering early?
+    float digi_offset = 0.;
+    if (hit->status_bit(xAOD::WaveformStatus::TIMING_SHIFTED)) {
+      digi_offset = -16.;
+    }
+    
+    // Set time with respect to nominal trigger
+    trigger_offset = m_timingTool->triggerTimeOffset(hit->channel());
+    hit->set_trigger_time(hit->localtime() - (trigger_time + trigger_offset + digi_offset));
+
+    //
+    // Find time from LHC clock
+    // Take out any relative offsets to align signals, but not the trigger_time
+    // This will also correct for the trigger time variation
     if (clock_valid) {
-      hit->set_bcid_time(clock->time_from_clock(hit->localtime()));
+      hit->set_bcid_time(clock->time_from_clock(hit->localtime()-(trigger_offset + digi_offset)));
     } else {
       hit->set_status_bit(xAOD::WaveformStatus::CLOCK_INVALID);
       hit->set_bcid_time(-1.);
     }
 
-    // Also set time with respect to nominal trigger
-    offset = m_timingTool->triggerTimeOffset(hit->channel());
-    hit->set_trigger_time(hit->localtime() - (trigger_time + offset));
   }
 
   return StatusCode::SUCCESS;
@@ -371,7 +390,7 @@ void
 WaveformReconstructionTool::fillRawHitValues(const RawWaveform& wave,
 					   int lo_edge, int hi_edge, 
 					   xAOD::WaveformHit* hit) const {
-
+  
   // First, make sure we don't overflow the waveform range
   if (lo_edge < 0) lo_edge = 0;
   if (hi_edge >= int(wave.size())) hi_edge = wave.size() - 1;
@@ -406,6 +425,12 @@ WaveformReconstructionTool::fillRawHitValues(const RawWaveform& wave,
   hit->set_raw_peak(raw.peak);
   hit->set_raw_integral(raw.integral);
 
+  // Indicate digitizer timing shift
+  if (wave.trigger_offset() >= 1) {
+    hit->set_status_bit(xAOD::WaveformStatus::TIMING_SHIFTED);
+  }
+      
+
 }
 
 // Reconstruct a hit from the RawWaveform in the range specified
@@ -693,6 +718,7 @@ WaveformReconstructionTool::findRawHitValues(const std::vector<float> time, cons
   double sum2 = 0.;
   for (unsigned int i=0; i<time.size(); i++) {
     //ATH_MSG_DEBUG("findRawHitValues Time: " << time[i] << " Wave: " << wave[i]);
+    if (wave[i] <= 0.) continue; // Don't sum negative values, causes problems with RMS
     tot += wave[i];
     sum += time[i] * wave[i];
     sum2 += time[i] * time[i] * wave[i];
diff --git a/Waveform/WaveformConditions/WaveCondUtils/scripts/makeTimingDB.py b/Waveform/WaveformConditions/WaveCondUtils/scripts/makeTimingDB.py
index 640b684042565ad09468a951f2b83923e4bb217b..1c02b6edf6537eb43a3cf7efbde1be1b3ea63c5e 100755
--- a/Waveform/WaveformConditions/WaveCondUtils/scripts/makeTimingDB.py
+++ b/Waveform/WaveformConditions/WaveCondUtils/scripts/makeTimingDB.py
@@ -58,7 +58,13 @@ offset_data = {
 # IFT and VetoNu installed
   6525: [ -10., -10., -10., -10., -25., -25., 0., 0., 0., 0., 0., 0., 18., 18., 0., 0. ],
 # 2024, add 2nd digitizer
-  13847: [ -10., -10., -10., -10., -25., -25., 0., 0., 0., 0., 0., 0., 18., 18., 0., 0., -10., -10., -10., -10. ]
+  13847: [ -10., -10., -10., -10.,
+           -25., -25., 0., 0.,
+           0., 0., 0., 0.,
+           18., 18., 0., 0.,
+           
+           -10., -10., -10., -10. ]
+    
 }
 
 attr_list_desc = '<timeStamp>run-lumi</timeStamp><addrHeader><address_header service_type="71" clid="40774348" /></addrHeader><typeName>AthenaAttributeList</typeName>'
diff --git a/Waveform/WaveformConditions/WaveCondUtils/scripts/makeTimingOffsetDB.py b/Waveform/WaveformConditions/WaveCondUtils/scripts/makeTimingOffsetDB.py
new file mode 100755
index 0000000000000000000000000000000000000000..73519ba36525dfaeb607854630d1ab3c5ec9e02d
--- /dev/null
+++ b/Waveform/WaveformConditions/WaveCondUtils/scripts/makeTimingOffsetDB.py
@@ -0,0 +1,208 @@
+#!/bin/env python
+
+# Requires python 3.8 or higher
+#
+# Can test results with
+# AtlCoolConsole.py "sqlite://;schema=waveform_reco.db;dbname=OFLP200"
+#
+# This script only sets the timing offset
+#
+filename = 'timing_offset.db'
+#filename = 'ALLP200.db'
+
+# offset_channels = 20
+
+# Run 
+# 0 - initial data
+# 3395 - Testbeam
+# 
+
+ehn1_offsets = [ -20., -20., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0. ]
+ti12_offsets = [ -20., -20., -20., -20., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0. ]
+
+offset_data = {
+  0:    [ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0. ],
+# Initial TI12
+  1324: [ -10., -10., -10., -10.,   0.,   0., 0., 0., 0., 0., 0., 0., 18., 18., 0., 0. ],
+# Testbeam geometry
+  3247: [ -10., -10., -10., -10., -10., -10., 15., 15., -20., -20., 0., 0., 0., 0., 0., 0. ],
+# TI12
+  4272: ti12_offsets,
+# EHN1 (interleaved with TI12 running)
+  4360: ehn1_offsets,
+  4399: ti12_offsets,
+  4409: ehn1_offsets,
+  4411: ti12_offsets,
+  4429: ehn1_offsets,
+  4439: ti12_offsets,
+  4876: ehn1_offsets,
+  4892: ti12_offsets,
+  4904: ehn1_offsets,
+  4912: ti12_offsets,
+  4954: ehn1_offsets,
+  4989: ti12_offsets,
+  4991: ehn1_offsets,
+  4993: ti12_offsets,
+  4996: ehn1_offsets,
+  4997: ti12_offsets,
+  5042: ehn1_offsets,
+  5050: ti12_offsets,
+# IFT and VetoNu installed
+  6525: [ -10., -10., -10., -10., -35., -35., 0., 0.,
+            0.,   0.,   0.,   0.,  18.,  18., 0., 0. ],
+# 2024, add 2nd digitizer
+    13847: [ -4., -4., -4., -4., -35., -35., 0., 0.,
+              0.,  0.,  0.,  0.,  18.,  18., 0., 0.,
+             -4., -4., -4., -4. ],
+# 2024, add CaloNu
+    15821: [ -4., -4., -4., -4., -35., -35., 0., 0.,
+              0.,  0.,  0.,  0.,  18.,  18., 0., 0.,
+             -4., -4., -4., -4., -48., -48., -48., -48. ],
+# Move CaloNu to trigger
+    15845: [ -4., -4., -4., -4., -35., -35., -48., -48.,
+              0.,  0.,  0.,  0.,  18.,  18., -48., -48.,
+             -4., -4., -4., -4.,   0.,   0.,   0.,   0. ],
+# CaloNu removed
+    16925: [ -4., -4., -4., -4., -35., -35., 0., 0.,
+              0.,  0.,  0.,  0.,  18.,  18., 0., 0.,
+             -4., -4., -4., -4., ],
+# 2025 startup
+    18193: [ -4., -4., -4., -4., -35., -35., 0., 0.,
+              0.,  0.,  0.,  0.,  18.,  18., 0., 0.,
+             -4., -4., -4., -4.,   0.,   0., 0., 0.,
+             -35., -35., 0., 0.],
+# Fix 2025 startup
+#
+# VetoNu (4,5) is early
+# Preshower (12, 13, 24, 25) is also now early
+# Muon (26, 27) is 20 ns late
+    18195: [ -4., -4., -4., -4., -35., -35., 0., 0.,
+              0.,  0.,  0.,  0., -24., -24., 0., 0.,
+             -4., -4., -4., -4.,   0.,   0., 0., 0.,
+             -24., -24., 20., 20.],
+    
+}
+
+attr_list_desc = '<timeStamp>run-lumi</timeStamp><addrHeader><address_header service_type="71" clid="40774348" /></addrHeader><typeName>AthenaAttributeList</typeName>'
+
+cond_attr_list_desc = '<timeStamp>run-lumi</timeStamp><addrHeader><address_header clid="1238547719" service_type="71" /></addrHeader><typeName>CondAttrListCollection</typeName>'
+
+maxInt32 = 0xFFFFFFFF
+
+# Look for data entry errors
+
+print('Validating offset data')
+lastRun = -1
+for run, data in offset_data.items():
+    assert isinstance(run, int), 'Run number is not integer'
+    assert run > lastRun, 'Run numbers out of order'
+    assert run <= maxInt32, 'Run number out of range'
+    lastRun = run
+    #assert len(data) == offset_channels, 'Offset data does not have '+str(offset_channels)+' entries'
+    for i in range(len(data)):
+        assert isinstance(data[i], float), 'Offset time is not float'
+
+# Data looks OK
+
+from PyCool import cool
+from CoolConvUtilities.AtlCoolLib import indirectOpen
+
+dbSvc = cool.DatabaseSvcFactory.databaseService()
+connectString = f'sqlite://;schema={filename};dbname=CONDBR3'
+
+print('Opening database')
+
+# Try to open existing, but if not create new
+try:
+    db = indirectOpen(connectString, readOnly=False)
+except Exception as e:
+    print(e)
+    print("Couldn't open, try creating new")
+    #dbSvc.dropDatabase( connectString )
+    db = dbSvc.createDatabase( connectString )
+
+# Trigger offset times
+
+offsetSpec = cool.RecordSpecification()
+offsetSpec.extend( 'TriggerOffset', cool.StorageType.Float )
+
+offsetFolderSpec = cool.FolderSpecification(cool.FolderVersioning.SINGLE_VERSION, offsetSpec)
+offsetFolder = db.createFolder('/WAVE/DAQ/TimingOffset', offsetFolderSpec, cond_attr_list_desc, True)
+
+# There should be one record entered per IOV
+lastValid = cool.ValidityKeyMax
+for firstValidRun, offset_list in reversed(offset_data.items()):
+    firstValid = (firstValidRun << 32)
+    for channel in range(len(offset_list)):
+        offsetRecord = cool.Record(offsetSpec)
+        offsetRecord[ 'TriggerOffset' ] = float(offset_list[channel])
+        offsetFolder.storeObject( firstValid, lastValid, offsetRecord, cool.ChannelId(channel) )
+
+    lastValid = ((firstValidRun - 1) << 32) | (cool.ValidityKeyMax & 0x00000000FFFFFFFF)
+
+
+db.closeDatabase()
+
+print('Database completed')
+
+print('Working on MC database')
+
+# No offsets by default
+# Expand this to 20 channels for 2024 data
+offset_data = {
+  0: [0., 0., 0., 0., 0., 0., 0., 0.,
+      0., 0., 0., 0., 0., 0., 0., 0.,
+      0., 0., 0., 0.]
+}
+
+# Validate again just in case
+
+print('Validating offset data')
+lastRun = -1
+for run, data in offset_data.items():
+    assert isinstance(run, int), 'Run number is not integer'
+    assert run > lastRun, 'Run numbers out of order'
+    assert run <= maxInt32, 'Run number out of range'
+    lastRun = run
+    #assert len(data) == offset_channels, 'Offset data does not have '+str(offset_channels)+' entries'
+    for i in range(len(data)):
+        assert isinstance(data[i], float), 'Offset time is not float'
+
+# Data looks OK
+
+connectString = f'sqlite://;schema={filename};dbname=OFLP200'
+
+print('Opening database')
+
+# Try to open existing, but if not create new
+try:
+    db = indirectOpen(connectString, readOnly=False)
+except Exception as e:
+    print(e)
+    print("Couldn't open, try creating new")
+    #dbSvc.dropDatabase( connectString )
+    db = dbSvc.createDatabase( connectString )
+
+# Trigger offset times
+
+offsetSpec = cool.RecordSpecification()
+offsetSpec.extend( 'TriggerOffset', cool.StorageType.Float )
+
+offsetFolderSpec = cool.FolderSpecification(cool.FolderVersioning.SINGLE_VERSION, offsetSpec)
+offsetFolder = db.createFolder('/WAVE/DAQ/TimingOffset', offsetFolderSpec, cond_attr_list_desc, True)
+
+# There should be one record entered per IOV
+lastValid = cool.ValidityKeyMax
+for firstValidRun, offset_list in reversed(offset_data.items()):
+    firstValid = (firstValidRun << 32)
+    for channel in range(len(offset_list)):
+        offsetRecord = cool.Record(offsetSpec)
+        offsetRecord[ 'TriggerOffset' ] = float(offset_list[channel])
+        offsetFolder.storeObject( firstValid, lastValid, offsetRecord, cool.ChannelId(channel) )
+
+    lastValid = ((firstValidRun - 1) << 32) | (cool.ValidityKeyMax & 0x00000000FFFFFFFF)
+
+
+db.closeDatabase()
+
+print('Database completed')
diff --git a/Waveform/WaveformConditions/WaveformConditionsTools/src/WaveformCableMappingTool.cxx b/Waveform/WaveformConditions/WaveformConditionsTools/src/WaveformCableMappingTool.cxx
index 8771650cf2d39b947ccaffcee901020331f1d59b..9fc8c75d4853f5d9acc46af5374eb0815400acaa 100644
--- a/Waveform/WaveformConditions/WaveformConditionsTools/src/WaveformCableMappingTool.cxx
+++ b/Waveform/WaveformConditions/WaveformConditionsTools/src/WaveformCableMappingTool.cxx
@@ -26,10 +26,12 @@ WaveformCableMappingTool::initialize() {
 
   // Set up helpers
   ATH_CHECK(detStore()->retrieve(m_ecalID, "EcalID"));
+  ATH_CHECK(detStore()->retrieve(m_caloNuID, "CaloNuID"));
   ATH_CHECK(detStore()->retrieve(m_vetoID, "VetoID"));
   ATH_CHECK(detStore()->retrieve(m_vetoNuID, "VetoNuID"));
   ATH_CHECK(detStore()->retrieve(m_triggerID, "TriggerID"));
   ATH_CHECK(detStore()->retrieve(m_preshowerID, "PreshowerID"));
+  ATH_CHECK(detStore()->retrieve(m_muonID, "MuonID"));
 
   return StatusCode::SUCCESS;
 }
@@ -97,21 +99,21 @@ WaveformCableMappingTool::getCableMapping(const EventContext& ctx) const {
 	// Do checks of PMT identifier
 	identifier = m_ecalID->pmt_id(rowVal, moduleVal, pmtVal, true);
 	// Test a few things
-	ATH_MSG_DEBUG("Calo  ID:" << identifier);
+	ATH_MSG_DEBUG("Calo   ID:" << identifier);
 	ATH_MSG_DEBUG("PMT:" << m_ecalID->pmt(identifier) << " PMT Max:" << m_ecalID->pmt_max(identifier));
       }
       else if (det_type == "calo2") {
 	// Do checks of PMT identifier
 	identifier = m_ecalID->pmt_id(rowVal, moduleVal, pmtVal, true);
-	ATH_MSG_DEBUG("Calo2 ID:" << identifier);
+	ATH_MSG_DEBUG("Calo2  ID:" << identifier);
 	ATH_MSG_DEBUG("PMT:" << m_ecalID->pmt(identifier) << " PMT Max:" << m_ecalID->pmt_max(identifier));
       }
-      else if (det_type == "calo2") {
+      else if (det_type == "calonu") {
 	// Do checks of PMT identifier
-	identifier = m_ecalID->pmt_id(rowVal, moduleVal, pmtVal, true);
-	ATH_MSG_DEBUG("Calo2 ID:" << identifier);
-	ATH_MSG_DEBUG("PMT:" << m_ecalID->pmt(identifier) << " PMT Max:" << m_ecalID->pmt_max(identifier));
-      }
+	identifier = m_caloNuID->pmt_id(rowVal, moduleVal, pmtVal, true);
+	ATH_MSG_DEBUG("CaloNu ID:" << identifier);
+	ATH_MSG_DEBUG("PMT:" << m_caloNuID->pmt(identifier) << " PMT Max:" << m_caloNuID->pmt_max(identifier));
+      }	
       else if (det_type == "veto") {
 	identifier = m_vetoID->pmt_id(stationVal, plateVal, pmtVal);
       }
@@ -124,6 +126,9 @@ WaveformCableMappingTool::getCableMapping(const EventContext& ctx) const {
       else if (det_type == "preshower") {
 	identifier = m_preshowerID->pmt_id(stationVal, plateVal, pmtVal);
       }
+      else if (det_type == "muon") {
+	identifier = m_muonID->pmt_id(stationVal, plateVal, pmtVal);
+      }	
       else if (det_type == "clock") {
 	// No valid identifiers for these
 	identifier = -1;
@@ -205,6 +210,9 @@ WaveformCableMappingTool::getChannelMapping(const EventContext& ctx, const Ident
       else if (det_type == "calo2") {
 	identifier = m_ecalID->pmt_id(rowVal, moduleVal, pmtVal);
       }
+      else if (det_type == "calonu") {
+	identifier = m_caloNuID->pmt_id(rowVal, moduleVal, pmtVal);
+      }
       else if (det_type == "veto") {
 	identifier = m_vetoID->pmt_id(stationVal, plateVal, pmtVal);
       }
@@ -217,6 +225,9 @@ WaveformCableMappingTool::getChannelMapping(const EventContext& ctx, const Ident
       else if (det_type == "preshower") {
 	identifier = m_preshowerID->pmt_id(stationVal, plateVal, pmtVal);
       }
+      else if (det_type == "muon") {
+	identifier = m_muonID->pmt_id(stationVal, plateVal, pmtVal);
+      }
       else if (det_type == "clock") {
 	// No valid identifiers for these
 	identifier = -1;
diff --git a/Waveform/WaveformConditions/WaveformConditionsTools/src/WaveformCableMappingTool.h b/Waveform/WaveformConditions/WaveformConditionsTools/src/WaveformCableMappingTool.h
index 8443cb1815e4db7a9c0181515b5fd405cd27d48c..0d458314374fb293312f1cce4dcc5e4acb4ddf74 100644
--- a/Waveform/WaveformConditions/WaveformConditionsTools/src/WaveformCableMappingTool.h
+++ b/Waveform/WaveformConditions/WaveformConditionsTools/src/WaveformCableMappingTool.h
@@ -20,10 +20,12 @@
 // Identifiers
 #include "Identifier/Identifier.h"
 #include "FaserCaloIdentifier/EcalID.h"
+#include "FaserCaloIdentifier/CaloNuID.h"
 #include "ScintIdentifier/VetoID.h"
 #include "ScintIdentifier/VetoNuID.h"
 #include "ScintIdentifier/TriggerID.h"
 #include "ScintIdentifier/PreshowerID.h"
+#include "ScintIdentifier/MuonID.h"
 
 // Include Athena stuff
 #include "AthenaPoolUtilities/CondAttrListCollection.h"
@@ -70,10 +72,13 @@ class WaveformCableMappingTool: public extends<AthAlgTool, IWaveformCableMapping
 
   // ID helpers
   const EcalID* m_ecalID{nullptr};
+  const CaloNuID* m_caloNuID{nullptr};
+  
   const VetoID* m_vetoID{nullptr};
   const VetoNuID* m_vetoNuID{nullptr};
   const TriggerID* m_triggerID{nullptr};
   const PreshowerID* m_preshowerID{nullptr};
+  const MuonID* m_muonID{nullptr};
 
 
 };
diff --git a/xAOD/xAODFaserWaveform/Root/WaveformClockAuxInfo_v1.cxx b/xAOD/xAODFaserWaveform/Root/WaveformClockAuxInfo_v1.cxx
index 61d5dc8e8d736c44ceba480964551bed85ccf981..87234028f27533873de487fba72439d09b634090 100644
--- a/xAOD/xAODFaserWaveform/Root/WaveformClockAuxInfo_v1.cxx
+++ b/xAOD/xAODFaserWaveform/Root/WaveformClockAuxInfo_v1.cxx
@@ -9,10 +9,11 @@ namespace xAOD {
 
   WaveformClockAuxInfo_v1::WaveformClockAuxInfo_v1()
     : AuxInfoBase(), 
-      frequency(0), phase(0), dc_offset(0), amplitude(0) {
+      frequency(0), phase(0), dc_offset(0), amplitude(0), time_offset(0) {
     AUX_VARIABLE( frequency );
     AUX_VARIABLE( phase );
     AUX_VARIABLE( dc_offset );
     AUX_VARIABLE( amplitude );
+    AUX_VARIABLE( time_offset );
   }
 } // namespace xAOD
diff --git a/xAOD/xAODFaserWaveform/Root/WaveformClock_v1.cxx b/xAOD/xAODFaserWaveform/Root/WaveformClock_v1.cxx
index 04498ccc8ecfc6e0a2c62d1c404318988229b891..c05d5cdc1cf18fd6389a62a25d0fa6a2086f301e 100644
--- a/xAOD/xAODFaserWaveform/Root/WaveformClock_v1.cxx
+++ b/xAOD/xAODFaserWaveform/Root/WaveformClock_v1.cxx
@@ -21,12 +21,19 @@ namespace xAOD {
 
   AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( WaveformClock_v1, double, amplitude, set_amplitude )
 
+  AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( WaveformClock_v1, double, time_offset, set_time_offset )
+
   float WaveformClock_v1::time_from_clock(float time) const {
     // Figure out which integer cycle we are on, must add 1/4 of a cycle
     // because FFT finds phase of cosine, which would be middle of 
     // clock HI region.  frequency is in MHz, so convert here to GHz
-    int ncycle = int(time*frequency() / 1.E3 + phase() / (2*M_PI) + 0.25);
-    float dt = time - (ncycle - phase() / (2*M_PI) - 0.25) * 1.E3 / frequency();
+
+    // Because the clock is in digitizer 2, it may be early
+    // Adjust the time to take this into account
+    // These times should also be corrected if they are shifted
+    int ncycle = int((time+time_offset())*frequency() / 1.E3 + phase() / (2*M_PI) + 0.25);
+    float dt = (time + time_offset()) - (ncycle - phase() / (2*M_PI) - 0.25) * 1.E3 / frequency();
+    // Also apply 
     return dt;
   }
 
@@ -39,6 +46,7 @@ namespace xAOD {
       << " phase=" << clk.phase()
       << " amplitude=" << clk.amplitude()
       << " offset=" << clk.dc_offset()
+      << " time_offset=" << clk.time_offset()
       << std::endl;
 
     return s;
diff --git a/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformClockAuxInfo_v1.h b/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformClockAuxInfo_v1.h
index 24741e2476ab952f316a8ceeaf7611361bdd291d..75b462829678451213c92c9cc2e2328497bc885c 100644
--- a/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformClockAuxInfo_v1.h
+++ b/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformClockAuxInfo_v1.h
@@ -32,6 +32,7 @@ namespace xAOD {
     double phase;
     double dc_offset;
     double amplitude;
+    double time_offset;
     ///@}
 
   }; // class WaveformClockAuxInfo_v1
diff --git a/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformClock_v1.h b/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformClock_v1.h
index 437b3ecabf1f71c9be0c353d27bebec1d0916d11..cc1fbc858d7e2ddb28dee4430ad2d7f23026c6b4 100644
--- a/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformClock_v1.h
+++ b/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformClock_v1.h
@@ -43,6 +43,10 @@ namespace xAOD {
     double amplitude() const;
     void set_amplitude(double value);
 
+    /// Possible time shift due to 2nd digitizer trigger
+    double time_offset() const;
+    void set_time_offset(double value);
+    
     /// Distance of time (in ns) from previous rising clock edge
     float time_from_clock(float time) const;
 
diff --git a/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformHit_v1.h b/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformHit_v1.h
index 4f15e8152fa7ea2d00ae6eed970d9341ffc6fba4..33fccbc3c224f5e3de4bd47b859805062c5f17a3 100644
--- a/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformHit_v1.h
+++ b/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformHit_v1.h
@@ -30,7 +30,8 @@ namespace xAOD {
     CBFIT_FAILED,        // CrystalBall fit failed
     CLOCK_INVALID,
     WAVEFORM_MISSING,    // Input waveform data missing
-    WAVEFORM_INVALID     // Input waveform data length mismatch
+    WAVEFORM_INVALID,    // Input waveform data length mismatch
+    TIMING_SHIFTED       // Time of digitizer 2 hits shifted for trigger
   };
 
   // Cllss describing pulses in the waveform digitizer