diff --git a/Calorimeter/CaloTools/CaloTools/CaloAffectedTool.h b/Calorimeter/CaloTools/CaloTools/CaloAffectedTool.h
new file mode 100755
index 0000000000000000000000000000000000000000..260e11efb79dde6f7cb14f1f5a613914d82d52f0
--- /dev/null
+++ b/Calorimeter/CaloTools/CaloTools/CaloAffectedTool.h
@@ -0,0 +1,61 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+/** 
+    @class CaloAffectedTool
+    @brief Tool to check if object is in an affected region
+    @author G.Unal
+*/
+
+#ifndef CALOTOOLS_CaloAffectedTool_H
+#define CALOTOOLS_CaloAffectedTool_H
+
+
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "GaudiKernel/IIncidentListener.h"
+#include "GaudiKernel/IIncidentSvc.h"
+#include "CaloInterface/ICaloAffectedTool.h"
+#include "CaloConditions/CaloAffectedRegionInfoVec.h"
+#include "AthenaKernel/IOVSvcDefs.h"
+
+namespace xAOD {
+  class IParticle;
+}
+
+class StoreGateSvc;
+
+class CaloAffectedTool: public AthAlgTool,
+	             virtual public ICaloAffectedTool, virtual public IIncidentListener
+{
+private: 
+  
+  CaloAffectedRegionInfoVec* m_affectedRegions;
+
+  StatusCode updateAffectedRegionsFromDB(IOVSVC_CALLBACK_ARGS);
+
+  StatusCode readDB();
+
+    void handle(const Incident& inc);
+
+  bool m_read;
+
+  bool m_readRaw;
+  
+public:    
+  
+  CaloAffectedTool(const std::string& type, 
+		const std::string& name, 
+		const IInterface* parent); 
+  virtual ~CaloAffectedTool();  
+
+  virtual bool isAffected(const xAOD::IParticle *p, float deta=0., float dphi=0., int layer_min=0, int layer_max=-1, int problemType=-1);
+
+  virtual bool listAffected(const xAOD::IParticle* p, std::vector<int>& layer_list, std::vector<int>& problem_list, float deta=0, float dphi=0, int problemType=-1);
+
+  StatusCode initialize();
+
+
+};
+
+#endif
diff --git a/Calorimeter/CaloTools/CaloTools/CaloCellPackerUtils.h b/Calorimeter/CaloTools/CaloTools/CaloCellPackerUtils.h
new file mode 100644
index 0000000000000000000000000000000000000000..d612a3c3d3702d28a1dfb3db068866175059031e
--- /dev/null
+++ b/Calorimeter/CaloTools/CaloTools/CaloCellPackerUtils.h
@@ -0,0 +1,176 @@
+// This file's extension implies that it's C, but it's really -*- C++ -*-.
+
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+// $Id: CaloCellPackerUtils.h,v 1.1 2007-11-08 18:14:20 ssnyder Exp $
+
+/**
+ * @file CaloTools/CaloCellPackerUtils.h
+ * @author scott snyder
+ * @date Nov 2007
+ * @brief Utilities for compacting calorimeter cells.
+ */
+
+
+#ifndef CALOCELLPACKERUTILS_H
+#define CALOCELLPACKERUTILS_H
+
+
+#include "GaudiKernel/Kernel.h"  // For LIKELY
+
+
+namespace CaloCellPackerUtils {
+
+
+/**
+ * @brief Helper for packing into/out of a bit field.
+ *
+ * The bitfield is identified by a bitmask, which should
+ * contain a contiguous string of 1's.  The @c in function
+ * will then take a value and shift and mask it appropriately
+ * for the bitfield.  The @c out function will extract a value
+ * from the bitfield.
+ */
+class Bitfield
+{
+public:
+  /**
+   * @brief Constructor.
+   * @param The bit mask.  Should contain a single contiguous string of 1's.
+   */
+  Bitfield (unsigned int mask = 1);
+
+
+  /**
+   * @brief Shift and mask a value into the bitfield.
+   * @param x The input value.
+   * @return The value shifted and masked to go into the bitfield.
+   */
+  unsigned int in (unsigned int x) const;
+
+
+  /**
+   * @brief Extract a value from the bitfield.
+   * @param x The input bitfield.
+   * @return The value extracted from the bitfield.
+   */
+  unsigned int out (unsigned int x) const;
+
+
+protected:
+  /// Bitmask.  Lower bit should be 1.
+  unsigned int m_mask;
+
+  /// Shift count.
+  unsigned int m_shift;
+};
+
+
+/**
+ * @brief Helper for packing a float into/out of a bit field.
+ *
+ * This works like the bitfield class above, except that the
+ * @c in/@c out methods take floating-point values.
+ * The field takes a min/max range of values; the input value is converted
+ * to a fraction within the range, and that fraction is stored.
+ */
+class Floatfield
+  : public Bitfield
+{
+public:
+  /**
+   * @brief Constructor.
+   * @param The bit mask.  Should contain a single contiguous string of 1's.
+   * @param xmin The smallest storable value.
+   * @param xmax The largest storable value.
+   */
+  Floatfield (unsigned int mask=1, double xmin=1, double xmax=0);
+
+
+  /**
+   * @brief Shift and mask a value into the bitfield.
+   * @param x The input value.
+   * @return The converted value shifted and masked to go into the bitfield.
+   */
+  unsigned int in (double x) const;
+
+
+  /**
+   * @brief Extract a value from the bitfield.
+   * @param x The input bitfield.
+   * @param underflag[out] Set to 1 if the value was the lowest possible.
+   * @return The value extracted from the bitfield.
+   */
+  double out (unsigned int x, int& underflow) const;
+
+
+private:
+  /// Smallest representable value.
+  double m_xmin;
+
+  /// Largest representable value.
+  double m_xmax;
+
+  /// Cached factor for int->float conversions.
+  double m_fact;
+
+  /// Cached factor for float->int conversions.
+  double m_ifact;
+};
+
+
+/**
+ * @brief Helper for packing a float into/out of a bit field, with
+ *        a minimum of 0.
+ *
+ * This is just like @c Floatfield, specialized for the case where @c xmin==0.
+ */
+class Floatfield2
+  : public Bitfield
+{
+public:
+  /**
+   * @brief Constructor.
+   * @param The bit mask.  Should contain a single contiguous string of 1's.
+   * @param xmax The largest storable value.
+   */
+  Floatfield2 (unsigned int mask=1, double xmax=1);
+
+
+  /**
+   * @brief Shift and mask a value into the bitfield.
+   * @param x The input value.
+   * @return The converted value shifted and masked to go into the bitfield.
+   */
+  unsigned int in (double x) const;
+
+
+  /**
+   * @brief Extract a value from the bitfield.
+   * @param x The input bitfield.
+   * @return The value extracted from the bitfield.
+   */
+  double out (unsigned int x) const;
+
+
+private:
+  /// Largest representable value.
+  double m_xmax;
+
+  /// Cached factor for int->float conversions.
+  double m_fact;
+
+  /// Cached factor for float->int conversions.
+  double m_ifact;
+};
+
+
+} // namespace CaloCellPackerUtils
+
+
+#include "CaloTools/CaloCellPackerUtils.icc"
+
+
+#endif // not CALOCELLPACKERUTILS_H
diff --git a/Calorimeter/CaloTools/CaloTools/CaloCellPackerUtils.icc b/Calorimeter/CaloTools/CaloTools/CaloCellPackerUtils.icc
new file mode 100644
index 0000000000000000000000000000000000000000..d61d3d5a1965423b57fb8593a685a80d3c2ba632
--- /dev/null
+++ b/Calorimeter/CaloTools/CaloTools/CaloCellPackerUtils.icc
@@ -0,0 +1,127 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+// $Id: CaloCellPackerUtils.icc,v 1.1 2007-11-08 18:14:20 ssnyder Exp $
+/**
+ * @file CaloTools/CaloCellPackerUtils.icc
+ * @author scott snyder
+ * @date Nov 2007
+ * @brief Utilities for compacting calorimeter cells.
+ */
+
+
+namespace CaloCellPackerUtils {
+
+
+/**
+ * @brief Shift and mask a value into the bitfield.
+ * @param x The input value.
+ * @return The value shifted and masked to go into the bitfield.
+ */
+inline
+unsigned int Bitfield::in (unsigned int x) const
+{
+  return (x&m_mask)<<m_shift;
+}
+
+
+/**
+ * @brief Extract a value from the bitfield.
+ * @param x The input bitfield.
+ * @return The value extracted from the bitfield.
+ */
+inline
+unsigned int Bitfield::out (unsigned int x) const
+{
+  return (x>>m_shift)&m_mask;
+}
+
+
+/**
+ * @brief Shift and mask a value into the bitfield.
+ * @param x The input value.
+ * @return The converted value shifted and masked to go into the bitfield.
+ */
+inline
+unsigned int Floatfield::in (double x) const
+{
+  // Handle over/underflow.
+  if (UNLIKELY(x >= m_xmax))
+    return Bitfield::in (m_mask);
+  else if (UNLIKELY(x <= m_xmin))
+    return 0;
+
+  // Convert to an int, and pack.
+  return Bitfield::in (static_cast<unsigned int> ((x - m_xmin) * m_ifact));
+}
+
+
+/**
+ * @brief Extract a value from the bitfield.
+ * @param x The input bitfield.
+ * @param underflag[out] Set to 1 if the value was the lowest possible.
+ * @return The value extracted from the bitfield.
+ */
+inline
+double Floatfield::out (unsigned int x, int& underflow) const
+{
+  // Unpack the value.
+  unsigned int xx = Bitfield::out(x);
+
+  // Did we underflow?
+  if (UNLIKELY(!xx)) {
+    underflow = 1;
+    return m_xmin;
+  }
+
+  // Convert back to a float.
+  // Note: the cast to int here is important for performance: converting
+  // an unsigned to a double takes much longer than converting an int.
+  underflow = 0;
+  return m_xmin + ((int)xx+0.5) * m_fact;
+}
+
+
+/**
+ * @brief Shift and mask a value into the bitfield.
+ * @param x The input value.
+ * @return The converted value shifted and masked to go into the bitfield.
+ */
+inline
+unsigned int Floatfield2::in (double x) const
+{
+  // Handle over/underflow.
+  if (UNLIKELY(x >= m_xmax))
+    return Bitfield::in (m_mask);
+  else if (UNLIKELY(x <= 0))
+    return 0;
+
+  // Convert to an int, and pack.
+  return Bitfield::in (static_cast<unsigned int> (x * m_ifact));
+}
+
+
+/**
+ * @brief Extract a value from the bitfield.
+ * @param x The input bitfield.
+ * @return The value extracted from the bitfield.
+ */
+inline
+double Floatfield2::out (unsigned int x) const
+{
+  // Unpack the value.
+  unsigned int xx = Bitfield::out(x);
+
+  // Did we underflow?
+  // (The branch hint here gives a small but measureable improvement.)
+  if (UNLIKELY(xx == 0)) return 0;
+
+  // Convert back to a float.
+  // Note: the cast to int here is important for performance: converting
+  // an unsigned to a double takes much longer than converting an int.
+  return ((int)xx+0.5) * m_fact;
+}
+
+
+} // namespace CaloCellPackerUtils
diff --git a/Calorimeter/CaloTools/CaloTools/CaloCellPacker_400_500.h b/Calorimeter/CaloTools/CaloTools/CaloCellPacker_400_500.h
new file mode 100644
index 0000000000000000000000000000000000000000..a17b6bb783189b5b6bafa76fa7caf23caf9b94bc
--- /dev/null
+++ b/Calorimeter/CaloTools/CaloTools/CaloCellPacker_400_500.h
@@ -0,0 +1,483 @@
+// This file's extension implies that it's C, but it's really -*- C++ -*-.
+
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+// $Id: CaloCellPacker_400_500.h,v 1.3 2009-03-19 01:42:14 ssnyder Exp $
+
+/**
+ * @file CaloTools/CaloCellPacker_400_500.h
+ * @author scott snyder, from earlier code by Ilija Vukotic and Sven Menke
+ * @date Jan 2009
+ * @brief Calo cell packer/unpacker v400/500.
+ *
+ * This class handles both versions 400 and 500.
+ */
+
+
+#ifndef CALOCELLPACKER_400_500_H
+#define CALOCELLPACKER_400_500_H
+
+
+#include "CaloTools/CaloCellPackerUtils.h"
+#include "CaloIdentifier/CaloCell_ID.h"
+#include "LArRecEvent/LArCell.h"
+#include "TileEvent/TileCell.h"
+#include "DataModel/DataPool.h"
+#include "CaloEvent/CaloCompactCellContainer.h"
+#include "CaloInterface/ICaloCompactCellTool.h"
+class CaloCellContainer;
+class CaloCell;
+struct CaloCellPacker_400_500_test;
+
+/**
+ * @brief Calo cell packer/unpacker v400/500.
+ *
+ * This class handles packing and unpacking of calorimeter cells
+ * into a CaloCompactCellContainer.  This holds data as a vector
+ * of integers, but for our purposes, we treat it as an array
+ * of 16-bit values.  We use the special iterator-like objects
+ * that that class defines for access.
+ *
+ * A summary of the format is given here.  Most constants and bit assignments
+ * are specified within the method @c init_header().  Though some of them
+ * are spelled out here, the possibility is left open that they can change.
+ * The constants are stored in a header along with the data; for reading,
+ * those stored constants are the ones used to interpret the data.
+ *
+ * The difference between versions 400 and 500 is the inclusion
+ * of quality and provenance data.
+ * Quality is like a chi**2 comparing the observed pulse shape
+ * (with 5 samples) to the expected one. It is different cell by cell,
+ * event by event (it is like energy and time from this point of view)
+ *
+ * The idea to store provenance is to know when reading back the ESD
+ * how the energy was estimated.
+ * For instance, when doing the OFC iteration method on the cosmics on
+ * high energy cell there is one bit which tells if the iteration
+ * converges or not and this is useful when analyzing back the event
+ * (and this bit can vary from event to event for the same cell).
+ *
+ * The packed data start with an instance of either @c header400
+ * or @c header500, containing
+ * the packing constants as well as cell/sequence counts.  Note that the
+ * first word is the length of the header, in units of @c int.
+ *
+ * Following the header is a set of @e sequences, each containing
+ * a range of cells with consecutive hash IDs.  The cells are stored
+ * in hash order, which implies that the subcalorimeters are strictly
+ * in the order LAREM, LARHEC, LARFCAL, TILE.  A single sequence
+ * contains cells from only a single subcalorimeter.
+ *
+ * Each sequence starts with a 32-bit value; where the high word
+ * is stored first, and the low word second.  (Note that this is
+ * @e opposite from the order in which the x86 would naturally store
+ * the data.)  The lower 18 bits
+ * of this give the hash value of the first cell in the sequence
+ * (others follow sequentially), and the upper 14 bits give the number
+ * of cells in the sequence.  (Note: if the number of cells in a sequence
+ * is more than can be represented in 14 bits, the sequence is simply
+ * split into several.)  Following this is the information for the cells
+ * themselves.
+ *
+ * For LAr cells, there is a 16-bit word, containing, starting
+ * from the low bit, 12 bits of energy, one sign bit for energy,
+ * two bits for the gain, and one bit for the quality.  The quality
+ * bit is 1 for good quality and 0 for bad quality.  The gain bits
+ * are one of:
+ *     0 ENLOW   for LARLOWGAIN
+ *     1 ENMED   for LARMEDIUMGAIN, unless cell is in the HEC with e < e1_high
+ *     2 ENHIG   for LARHIGHGAIN, unless cell is not in the HEC with e< e1_high
+ *     3 EHHIG   for LARMEDIUMGAIN if cell is in the HEC with e < e1_high or
+ *               for LARHIGHGAIN if cell is not in the HEC with e < e1_high
+ *
+ * The maximum energy is taken to be 50 GeV (e1_high) for EHHIG and 3.2 TeV
+ * otherwise.  We take the cube root of the absolute value of the energy,
+ * convert it into a fraction of fullscale (as a cube root), and store
+ * that fraction as a fixed-point number.
+ *
+ * If the quality is good, this is followed by two additional 16-bit
+ * words.  The first gives the time information.  This has 15 bits of time
+ * information and one sign bit.  We take the natural log of the time, and then
+ * encode this as a fraction of the range from 0.001ns to 1250ns.
+ * This is then followed by the quality word.
+ *
+ * For tile cells, information for each of the two PMTs is stored separately.
+ * First is a 16-bit word containing 13 bits of energy information,
+ * one sign bit, one gain bit, and one quality bit.  The quality
+ * bit is 1 for good quality and 0 for bad.  The gain bit is 0 for
+ * low gain and 1 for high gain.  The energy is again stored as
+ * a scaled cube root, where the upper limit is 50 GeV for high gain
+ * and 3.2 TeV for low gain.   If the quality is good, this is followed
+ * by 16 bits of time information, encoded as before.  Following both
+ * cells is a 16-bit quality word; the lower 8 bits are for the
+ * first PMT, and the upper eight bits are for the second PMT.
+ * If the quality flags for both PMTs are bad, then this word
+ * is omitted.
+ *
+ * Following the cell information is the provenance information.
+ * Each provenance entry consists of a cell hash code (19 bits)
+ * plus a provenance word (13 bits) packed into two 16-bit words.
+ * The high 13 bits of the first word are the provenance; the low
+ * three bits of the first word plus the second word give the
+ * hash code.  Each provenance entry says that cells starting
+ * at the given hash code have the given provenance value (until
+ * the hash code of the next provenance entry).  Cells with a hash
+ * code less than that of the first provenance entry have a provenance
+ * word of 0.
+ *
+ * Version 501 adds a status bitmask to the header, with the flag
+ * STATUS_UNORDERED.  This is set if the packer finds that the cells
+ * are not in subcalo order.  (This is the case for cell collections
+ * produced by the HLT, which are concatenations of per-ROI cell collections.)
+ *
+ * Version 502 adds quality words and provenance for tile.
+ *
+ * Version 503 reduces slightly the range for negative energies,
+ * to avoid confusion with error flags.
+ *
+ * Version 504 introduces a flag for SuperCell 
+ */
+class CaloCellPacker_400_500
+{
+public:
+  /**
+   * @brief Pack cells.
+   * @param cells The input cell container.
+   * @param packed The output packed cell container.
+   * @param version The version of the header to initialize.
+   */
+  void pack (const CaloCellContainer& cells,
+             CaloCompactCellContainer& packed,
+             int version) const;
+
+
+  /**
+   * @brief Unpack cells.
+   * @param packed The input packed cell container.
+   * @param vheader The header part of the packed data.
+   * @param cells The output cell container.
+   * @param larpool Pool for allocating LAr cells.
+   * @param tilepool Pool for allocating Tile cells.
+   *
+   * Note that allocations will be done from the provided pools,
+   * and the pools retain ownership of the cells.
+   * The @a cells container will be changed to a view container.
+   */
+  void unpack (const CaloCompactCellContainer& packed,
+               const std::vector<CaloCompactCellContainer::value_type>&vheader,
+               CaloCellContainer& cells,
+               DataPool<LArCell>& larpool,
+               DataPool<TileCell>& tilepool) const;
+
+private:
+
+  //==========================================================================
+  /** @name Header and parameter definitions. */
+  //@{
+
+  /**
+   * @brief Packing parameters header (v400).
+   *
+   * This structure is written at the beginning of the packed data.
+   * It contains both the basic packing constants as well as counters
+   * for the number of cells and sequences.
+   *
+   * These values are initialized in @c init_header.
+   *
+   * Since this is written directly to the persistent data,
+   * don't rearrange fields!
+   */
+  struct header400 {
+    int m_length;                      // Header length, in units of int.
+
+    int m_version;                     // Version code (ICaloCompactCellTool).
+
+    /// Counters of number of cells in each subcalo.
+    int m_ncells_larem;
+    int m_ncells_larhec;
+    int m_ncells_larfcal;
+    int m_ncells_tile;
+
+    /// Masks defining the bit positions used for various quantities.
+    /// These should all contain a single consecutive string of 1'.s
+    unsigned int m_qualy_mask;        // Quality.
+    unsigned int m_egain_mask;        // LAr gain.
+    unsigned int m_esign_mask;        // LAr energy sign bit.
+    unsigned int m_crtae_mask;        // LAr cbrt(energy).
+    unsigned int m_egain_tile_mask;   // Tile gain.
+    unsigned int m_esign_tile_mask;   // Tile energy sign bit.
+    unsigned int m_crtae_tile_mask;   // Tile cbrt(energy).
+    unsigned int m_tsign_mask;        // Time sign bit.
+    unsigned int m_logat_mask;        // log(time).
+
+    /// Various enumeration constants.
+    int m_qabad;                      // Bad quality flag.
+    int m_enlow;                      // LAr low gain.
+    int m_enmed;                      // LAr medium gain.
+    int m_enhig;                      // LAr high gain.
+    int m_ehhig;                      // LAr high gain with 50 GeV range.
+    int m_glow;                       // Tile low range.
+    int m_ghigh;                      // Tile high range.
+
+    /// Counts of number of sequences in each subcalo.
+    /// Note: in early versions of the v400 packer, these words would
+    /// be left uninitialized if there were no cells.
+    int m_seq_larem;
+    int m_seq_larhec;
+    int m_seq_larfcal;
+    int m_seq_tile;
+
+    /// Packing ranges for floats.
+    float m_e1_norm_res;              // Normal LAr energy range.
+    float m_e1_high_res;              // High gain LAr energy range.
+    float m_high_tile;                // High gain tile energy range.
+    float m_low_tile;                 // Low gain tile energy range.
+    float m_t0;                       // Lower time range.
+    float m_t1;                       // Upper time range.
+  };
+
+
+  /**
+   * @brief Packing parameters header (v500).
+   *
+   * This adds a count of the number of provenance entries.
+   */
+  struct header500
+    : public header400
+  {
+    // The number of provenance entries (in 16-bit units).
+    // In order to know from where to start reading provenance.
+    unsigned int m_lengthProvenance;
+  };
+
+
+  /**
+   * @brief Packing parameters header (v501).
+   *
+   * Also for 502.
+   *
+   * This adds a status flag.
+   */
+  struct header501
+    : public header500
+  {
+    // A bitmask for additional status information.
+    // Added for version 501.
+    unsigned int m_status;
+
+    enum {
+      // Set if the cells are not in subcalo order.
+      STATUS_UNORDERED = (1 << 0),
+      // Set if the cells are SuperCell
+      STATUS_IS_SUPERCELL = (1 << 1)
+    };
+  };
+
+
+  /// The most recent header version.
+  typedef header501 header;
+
+
+  /**
+   * @brief Derived packing parmeters.
+   *
+   * This structure contains parameters derived from those in @c header.
+   * It is filled in by @c init_derived.
+   *
+   * It derives from @c header, so that we just need to pass one of these
+   * around to access all parameters.
+   */
+  struct pars500
+    : public header
+  {
+    /// Good quality flag.
+    int m_qgood;
+
+    /// Maximum number of cells in a sequence.
+    unsigned int m_nseq_max;
+    unsigned int m_prov_max;
+    unsigned int m_prov_max_tile;
+
+    /// Transformed packing ranges for floats.
+    double m_cbrt_e1_norm_res;       // cbrt(e1_norm_res)
+    double m_cbrt_e1_high_res;       // cbrt(e1_high_res)
+    double m_cbrt_low_tile;          // cbrt(low_tile)
+    double m_cbrt_high_tile;         // cbrt(high_tile)
+    double m_log_t0;                 // log(t0)
+    double m_log_t1;                 // log(t1)
+
+    /// Bitfields for various quantities.
+    CaloCellPackerUtils::Bitfield m_hash_field;
+    CaloCellPackerUtils::Bitfield m_nseq_field;
+    CaloCellPackerUtils::Bitfield m_prov_field;
+
+    CaloCellPackerUtils::Bitfield m_egain_field;
+    CaloCellPackerUtils::Bitfield m_qualy_field;
+    CaloCellPackerUtils::Floatfield m_logat_field;
+    CaloCellPackerUtils::Floatfield2 m_crtae_norm_field;
+    CaloCellPackerUtils::Floatfield2 m_crtae_high_field;
+    CaloCellPackerUtils::Floatfield2 m_crtae_tile_low_field;
+    CaloCellPackerUtils::Floatfield2 m_crtae_tile_high_field;
+    CaloCellPackerUtils::Bitfield m_egain_tile_field;
+
+    CaloCellPackerUtils::Bitfield m_tile_qual1_field;
+    CaloCellPackerUtils::Bitfield m_tile_qual2_field;
+
+    // Some errors are flagged by setting all bits on; the resulting packed
+    // values are stored in @c m_lar_dummy and @c m_tile_dummy.
+    // These are, however, still valid encodings.  If we would legitimately
+    // pack a value that gives the dummy word, we replace it with @c subst,
+    // which has the low bit of the energy cleared.  This effectively reduces
+    // the range on the low side slightly.
+    CaloCompactCell::value_type m_lar_dummy;
+    CaloCompactCell::value_type m_lar_dummy_subst;
+    CaloCompactCell::value_type m_tile_dummy;
+    CaloCompactCell::value_type m_tile_dummy_subst;
+  };
+
+
+  /**
+   * @brief Initialize header with the current version of the packing
+   *        parameters.  (Almost) all the constants are defined here.
+   * @param header The header to initialize.
+   * @param version The version of the header to initialize.
+   */
+  void init_header (header& header, int version) const;
+
+
+  /**
+   * @brief Clear the counters in the event header.
+   * @param header The header to clear.
+   */
+  void clear_header (header& header) const;
+
+
+  /**
+   * @brief Initialize the derived packing parameters from the constants
+   *        in the header.
+   * @param pars The packing parameters.
+   */
+  void init_derived (pars500& pars) const;
+
+
+  //@}
+  //==========================================================================
+  /** @name Packing. */
+  //@{
+
+
+  /**
+   * @brief Pack a time value.
+   * @param time The time to pack.
+   * @param it The iterator into which to pack.
+   * @param pars The packing parameters.
+   */
+  void pack_time (float time,
+                  CaloCompactCellContainer::compact_output_iterator& it,
+                  const pars500& pars) const;
+
+
+  /**
+   * @brief Pack one LAr cell.
+   * @param cell The cell to pack.
+   * @param subcalo The cell's subcalorimeter code.
+   * @param it The iterator into which to pack.
+   * @param pars The packing parameters.
+   */
+  void pack_lar (const CaloCell* cell,
+                 CaloCell_ID::SUBCALO subcalo,
+                 CaloCompactCellContainer::compact_output_iterator& it,
+                 const pars500& pars) const;
+
+
+  /**
+   * @brief Pack one tile cell.
+   * @param cell The cell to pack.
+   * @param it The iterator into which to pack.
+   * @param pars The packing parameters.
+   */
+  void pack_tile (const TileCell* cell,
+                  CaloCompactCellContainer::compact_output_iterator& it,
+                  const pars500& pars) const;
+
+
+  /**
+   * @brief Finish up one cell sequence.
+   * @param hash The hash of the first cell in the sequence.
+   * @param nseq The number of cells in the sequence.
+   * @param it Iterator pointing at the beginning of the sequence.
+   * @param subcalo Subcalorimeter code for the sequence.
+   * @param pars The packing parameters.
+   */
+  void finish_seq (unsigned int hash,
+                   unsigned int nseq,
+                   CaloCompactCellContainer::compact_output_iterator& it,
+                   CaloCell_ID::SUBCALO subcalo,
+                   pars500& pars) const;
+
+
+  /**
+   * @brief Write the header to the output container.
+   * @param header The header to write.
+   * @param packed The container to which to write.
+   */
+  void write_header (const header& header,
+                     CaloCompactCellContainer& packed) const;
+
+
+  //@}
+  //==========================================================================
+  /** @name Unpacking. */
+  //@{
+
+
+  /**
+   * @brief Unpack the time word.
+   * @param it Input iterator.
+   * @param pars Unpacking parameters.
+   * @return The unpacked time.
+   */
+  double unpack_time (CaloCompactCellContainer::compact_input_iterator& it,
+                      const pars500& pars) const;
+
+
+  /**
+   * @brief Unpack a LAr cell.
+   * @param it Input iterator.
+   * @param subcalo Subcalorimeter code for the cell.
+   * @param cell Pointer to the cell in which to write.
+   * @param pars Unpacking parameters.
+   * @param provenance The provenance word for this cell.
+   * @return @a cell, as a @c CaloCell*.
+   *
+   * The DDE and ID will be set in the cell separately; here, we need only
+   * fill in the cell data.
+   */
+  CaloCell* unpack_lar (CaloCompactCellContainer::compact_input_iterator& it,
+                        CaloCell_ID::SUBCALO subcalo,
+                        LArCell* cell,
+                        const pars500& pars,
+                        uint16_t provenance) const;
+
+
+  /**
+   * @brief Unpack a tile cell.
+   * @param it Input iterator.
+   * @param dde Descriptor element for the cell.
+   * @param pars Unpacking parameters.
+   * @param provenance The provenance word for this cell.
+   * @return The new cell.
+   */
+  TileCell unpack_tile (CaloCompactCellContainer::compact_input_iterator& it,
+                        const CaloDetDescrElement* dde,
+                        const pars500& pars,
+                        uint16_t provenance) const;
+  //@}
+
+  friend struct CaloCellPacker_400_500_test;
+};
+
+
+#endif // not CALOCELLPACKER_400_500_H
diff --git a/Calorimeter/CaloTools/CaloTools/CaloCompactCellTool.h b/Calorimeter/CaloTools/CaloTools/CaloCompactCellTool.h
new file mode 100755
index 0000000000000000000000000000000000000000..73db569f8ba1ad617b9ab2cb0b97061fbcda2960
--- /dev/null
+++ b/Calorimeter/CaloTools/CaloTools/CaloCompactCellTool.h
@@ -0,0 +1,121 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef CALOTOOLS_CALOCOMPACTCELLTOOL_H
+#define CALOTOOLS_CALOCOMPACTCELLTOOL_H
+
+/**
+    @class CaloCompactCellTool
+    @brief Tool to convert from CaloCellContainer to CaloCompactCellContainer and back
+    @author Sven Menke
+*/
+
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "CaloEvent/CaloCellContainer.h"
+#include "CaloEvent/CaloCompactCellContainer.h"
+#include "CaloIdentifier/CaloCell_ID.h"
+#include "CLHEP/Units/SystemOfUnits.h"
+
+#include <math.h>
+
+#include "CaloInterface/ICaloCompactCellTool.h"
+
+class IChronoStatSvc;
+
+class CaloCompactCellTool: public AthAlgTool,
+			   virtual public ICaloCompactCellTool
+{
+
+ public:
+
+  CaloCompactCellTool(const std::string& type, const std::string& name,
+		      const IInterface* parent);
+
+  virtual ~CaloCompactCellTool();
+  virtual StatusCode initialize();
+  virtual StatusCode finalize();
+
+  StatusCode getTransient(const CaloCompactCellContainer & theCompactContainer,
+			  CaloCellContainer * theCellContainer);
+  // fills a CaloCellContainer ; caller has the responsibility
+  // of creating and deleting the object again
+
+  StatusCode getPersistent(const CaloCellContainer & theCellContainer,
+			   CaloCompactCellContainer * theCompactContainer,
+			   int theVersion = ICaloCompactCellTool::VERSION_LATEST);
+  // fills a CaloCompactCellContainer ; caller has the responsibility
+  // of creating and deleting the object again
+
+ private:
+
+  int getLogCompact(const double & x, const double & log_x0, const double & log_x1, const int & n);
+
+  double unpackLog(const int & log_x, const double & log_x0, const double & log_x1, const int & n);
+
+  int getCubRootCompact(const double & x, const double & cbrt_x1, const int & n);
+
+  double unpackCubRoot(const int & cbrt_x, const double & cbrt_x1, const int & n);
+
+};
+
+inline int CaloCompactCellTool::getLogCompact(const double & x,
+				       const double & log_x0,
+				       const double & log_x1,
+				       const int & n)
+{
+  int result = 0;
+  if ( x > 0 ) {
+    double log_x = log(x);
+    if ( log_x >= log_x1 ) {
+      result = (1<<n)-1;
+    }
+    else if ( log_x > log_x0 ) {
+      int nmax=1<<n;
+      result = (int)((log_x - log_x0)/(log_x1 - log_x0)*nmax);
+    }
+  }
+  return result;
+}
+
+inline int CaloCompactCellTool::getCubRootCompact(const double & x,
+					   const double & cbrt_x1,
+					   const int & n){
+  int result = 0;
+  double cbrt_x=cbrt(x);
+  if ( cbrt_x >= cbrt_x1 ) {
+      result = (1<<n)-1;
+      } else {
+      int nmax=1<<n;
+      result = (int)(cbrt_x/cbrt_x1*nmax);
+      }
+  return result;
+}
+
+inline double CaloCompactCellTool::unpackLog(const int & log_x,
+				      const double & log_x0,
+				      const double & log_x1,
+				      const int & n){
+  double result = 0;
+  if ( log_x > 0 ) {
+    int nmax=1<<n;
+    result = exp((log_x+0.5)*(log_x1-log_x0)/nmax+log_x0);
+    }
+  return result;
+}
+
+inline double CaloCompactCellTool::unpackCubRoot(const int & cbrt_x,
+					  const double & cbrt_x1,
+					  const int & n){
+  double result = 0;
+  if ( cbrt_x > 0 ) {
+    int nmax=1<<n;
+    double r = (cbrt_x+0.5)*cbrt_x1/nmax;
+    result =r*r*r;
+    }
+  return result;
+}
+
+
+#endif
+
diff --git a/Calorimeter/CaloTools/CaloTools/CaloLumiBCIDTool.h b/Calorimeter/CaloTools/CaloTools/CaloLumiBCIDTool.h
new file mode 100755
index 0000000000000000000000000000000000000000..de006bf824295f9bfd4d3b0c8a8ca31c8826513a
--- /dev/null
+++ b/Calorimeter/CaloTools/CaloTools/CaloLumiBCIDTool.h
@@ -0,0 +1,108 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+//Dear emacs, this is -*-c++-*-
+
+/** 
+    @class CaloLumiBCIDTool
+    @brief Tool to provide expected pedestal shift for Pileup from first principle computation (relevant for non 25ns bunch spacing)
+    @author G.Unal
+*/
+
+#ifndef CALOTOOLS_CaloLumiBCIDTool_H
+#define CALOTOOLS_CaloLumiBCIDTool_H
+
+class Identifier; 
+class StoreGateSvc; 
+class CaloIdManager;
+class CaloCell_ID;
+class CaloDetDescrElement;
+
+#include "LArElecCalib/ILArShape.h"
+#include "LArElecCalib/ILArMinBiasAverage.h"
+#include "LArElecCalib/ILArOFC.h"
+#include "LArElecCalib/ILArOFCTool.h"
+#include "LArElecCalib/ILArMCSymTool.h"
+#include "LArIdentifier/LArOnlineID.h"
+#include "LArTools/LArCablingService.h"
+
+#include "LumiBlockComps/ILuminosityTool.h"
+#include "TrigAnalysisInterfaces/IBunchCrossingTool.h"
+
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "GaudiKernel/ToolHandle.h"
+#include "StoreGate/DataHandle.h"
+#include "CaloInterface/ICaloLumiBCIDTool.h"
+#include "AthenaKernel/IOVSvcDefs.h"
+#include "GaudiKernel/IIncidentListener.h"
+#include "GaudiKernel/IIncidentSvc.h"
+
+
+class CaloLumiBCIDTool: public AthAlgTool,
+			virtual public ICaloLumiBCIDTool, virtual public IIncidentListener
+{
+private: 
+  
+//Database  
+
+  const DataHandle<ILArShape> m_dd_shape;
+  const DataHandle<ILArMinBiasAverage> m_dd_minbiasAverage; 
+  const DataHandle<ILArOFC> m_dd_ofc;
+  ToolHandle<LArCablingService> m_cablingService;
+  ToolHandle<ILArMCSymTool>  m_larmcsym;
+  ToolHandle<ILArOFCTool> m_OFCTool;
+  ToolHandle<ILuminosityTool> m_lumiTool;
+  ToolHandle<Trig::IBunchCrossingTool> m_bunchCrossingTool;
+
+  const LArOnlineID*        m_lar_on_id;
+  const CaloIdManager* m_caloIdMgr;
+  const CaloCell_ID* m_calocell_id;
+
+
+  bool m_isMC;
+  std::string m_keyShape, m_keyMinBiasAverage, m_keyOFC;
+
+  unsigned int m_bcidMax;
+  int m_ncell;
+
+  mutable bool m_cacheValid;
+
+  //Internal cache:
+  std::vector<HWIdentifier> m_hwid_sym;
+  std::vector<float> m_eshift_sym;
+  std::vector<int> m_symCellIndex;
+  unsigned int m_bcid;
+
+
+//Functions
+  StatusCode initialize();
+
+  virtual StatusCode LoadCalibration(IOVSVC_CALLBACK_ARGS);
+
+  void handle(const Incident& inc);
+
+  void getListOfCells();
+
+
+  /** Callback added to handle Data-driven GeoModel initialisation
+   */
+  virtual StatusCode geoInit(IOVSVC_CALLBACK_ARGS);
+
+  StatusCode computeValues(unsigned int bcid);
+
+public:    
+  
+  CaloLumiBCIDTool(const std::string& type, 
+		const std::string& name, 
+		const IInterface* parent); 
+  virtual ~CaloLumiBCIDTool();  
+
+  float average(const CaloCell* caloCell, unsigned int bcid);
+
+  float average(const CaloDetDescrElement* caloDDE,unsigned int bcid);
+
+
+};
+
+#endif
diff --git a/Calorimeter/CaloTools/CaloTools/CaloMBAverageTool.h b/Calorimeter/CaloTools/CaloTools/CaloMBAverageTool.h
new file mode 100755
index 0000000000000000000000000000000000000000..be0b9904d383a7a0d5f2481239879b0496f58973
--- /dev/null
+++ b/Calorimeter/CaloTools/CaloTools/CaloMBAverageTool.h
@@ -0,0 +1,78 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+/** 
+    @class CaloMBAverageTool
+    @brief Tool to provide expected pedestal shift for Pileup from first principle computation (relevant for non 25ns bunch spacing)
+    @author G.Unal
+*/
+
+#ifndef CALOTOOLS_CaloMBAverageTool_H
+#define CALOTOOLS_CaloMBAverageTool_H
+
+class Identifier; 
+class StoreGateSvc; 
+class CaloIdManager;
+class CaloCell_ID;
+class CaloDetDescrElement;
+
+#include "CaloIdentifier/CaloGain.h"
+#include "LArElecCalib/ILArShape.h"
+#include "LArElecCalib/ILArfSampl.h"
+#include "LArElecCalib/ILArMinBiasAverage.h"
+#include "LArElecCalib/ILArOFCTool.h"
+
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "GaudiKernel/ToolHandle.h"
+#include "StoreGate/DataHandle.h"
+#include "CaloInterface/ICaloMBAverageTool.h"
+#include "AthenaKernel/IOVSvcDefs.h"
+
+
+class CaloMBAverageTool: public AthAlgTool,
+	             virtual public ICaloMBAverageTool
+{
+private: 
+//Database  
+
+  const DataHandle<ILArShape> m_dd_shape;
+  const DataHandle<ILArfSampl> m_dd_fsampl;
+  const DataHandle<ILArMinBiasAverage> m_dd_minbiasAverage; 
+  ToolHandle<ILArOFCTool> m_OFCTool;
+
+  const DataHandle<CaloIdManager> m_caloIdMgr;
+  const CaloCell_ID*       m_calo_id;
+
+
+  float m_Nminbias;
+  int m_deltaBunch;
+  std::string m_keyShape, m_keyfSampl, m_keyMinBiasAverage;
+
+  unsigned int m_ncell;
+  std::vector<float> m_shift;
+
+//Functions
+  StatusCode initialize();
+
+  virtual StatusCode LoadCalibration(IOVSVC_CALLBACK_ARGS);
+
+  /** Callback added to handle Data-driven GeoModel initialisation
+   */
+  virtual StatusCode geoInit(IOVSVC_CALLBACK_ARGS);
+
+public:    
+  
+  CaloMBAverageTool(const std::string& type, 
+		const std::string& name, 
+		const IInterface* parent); 
+  virtual ~CaloMBAverageTool();  
+
+  float average(const CaloCell* caloCell);
+
+  float average(const CaloDetDescrElement* caloDDE,const CaloGain::CaloGain gain);
+
+
+};
+
+#endif
diff --git a/Calorimeter/CaloTools/CaloTools/CaloNoiseTool.h b/Calorimeter/CaloTools/CaloTools/CaloNoiseTool.h
new file mode 100755
index 0000000000000000000000000000000000000000..1a42bef454e68d75dd20381c629eb0f8855740bb
--- /dev/null
+++ b/Calorimeter/CaloTools/CaloTools/CaloNoiseTool.h
@@ -0,0 +1,482 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+/** 
+    @class CaloNoiseTool
+    @brief Tool to provide electronic and pile up noise in MeV
+    @author David Rousseau
+    @author Mathieu Lechowski
+*/
+
+#ifndef CALOTOOLS_CALONOISETOOL_H
+#define CALOTOOLS_CALONOISETOOL_H
+
+class Identifier; 
+class StoreGateSvc; 
+
+#include "AtlasDetDescr/AtlasDetectorID.h"
+#include "CaloDetDescr/CaloDetDescrManager.h"
+#include "CaloIdentifier/CaloCell_ID.h"
+#include "CaloIdentifier/LArID.h"
+
+#include "CaloIdentifier/TileID.h"
+#include "CaloIdentifier/CaloIdManager.h"
+#include "LArTools/LArCablingService.h"
+#include "CaloIdentifier/LArID_Exception.h"
+ 
+#include "CaloIdentifier/CaloGain.h"
+
+#include "StoreGate/DataHandle.h"
+#include "LArElecCalib/ILArOFC_Shape.h"
+#include "LArElecCalib/ILArAutoCorr.h" 
+#include "LArElecCalib/ILArNoise.h"
+#include "LArElecCalib/ILArPedestal.h"
+#include "LArElecCalib/ILArAdc2GeV.h"
+#include "LArElecCalib/ILArShape.h"
+#include "LArElecCalib/ILArfSampl.h"
+#include "LArElecCalib/ILArMinBias.h"
+
+#include "LArElecCalib/ILArOFCTool.h"
+#include "LArElecCalib/ILArADC2MeVTool.h" 
+
+#include "TileConditions/TileInfo.h"
+
+#include "CaloEvent/CaloCell.h"
+#include "LArRecEvent/LArCell.h"
+#include "TileEvent/TileCell.h"
+#include "AthenaBaseComps/AthAlgTool.h"
+
+#include "GaudiKernel/ToolHandle.h"
+#include "CaloInterface/ICaloNoiseTool.h"
+#include "AthenaKernel/IOVSvcDefs.h"
+
+#include "GaudiKernel/IIncidentListener.h"
+
+
+typedef std::vector< std::vector<float> > VectorContainer;
+typedef std::vector< float >              SingleContainer;
+
+enum VALUE_ENUM{BADVALUE=-999,BADVALUE_TO_RETURN=-1};
+enum DATABASE_ENUM{iADC2MEV,iSIGMANOISE,iAUTOCORR,iOFC,iSHAPE,
+		   iMINBIASRMS,iFSAMPL,nDATABASE};
+
+class CaloNoiseTool: public AthAlgTool,
+	             virtual public ICaloNoiseTool,
+		     public IIncidentListener 
+{
+private: 
+  typedef float (CaloNoiseTool::*GETNOISE_CDDE)(const CaloDetDescrElement*,
+						const CaloGain::CaloGain,
+						const float,
+						const int);
+  typedef float (CaloNoiseTool::*GETNOISE_CELL)(const CaloCell*,
+						const CaloGain::CaloGain,
+						const float,
+						const int);
+  
+  float elecNoiseRMS(const CaloCell* caloCell,
+		     const CaloGain::CaloGain gain,
+		     const float Nminbias,
+		     const int step);
+  float pileupNoiseRMS(const CaloCell* caloCell,
+		       const CaloGain::CaloGain gain,
+		       const float Nminbias,
+		       const int step);
+  float totalNoiseRMS(const CaloCell* caloCell,
+		      const CaloGain::CaloGain gain,
+		      const float Nminbias,
+		      const int step);
+  float pileupNoiseRMS(const CaloDetDescrElement* caloDDE, 
+		       const CaloGain::CaloGain gain,
+		       const float Nminbias,
+		       const int step);
+  float totalNoiseRMS(const CaloDetDescrElement* caloDDE, 
+		      const CaloGain::CaloGain gain,
+		      const float Nminbias,
+		      const int step);
+  GETNOISE_CDDE m_CachedGetNoiseCDDE;
+  GETNOISE_CELL m_CachedGetNoiseCELL;
+  
+  std::string   m_ReturnNoiseName;
+  int m_gain_from_joboption;
+
+
+//Constants
+  static const int m_nCalos=4;// number of calorimeters
+
+  float m_LowGainThresh[m_nCalos];
+  float m_HighGainThresh[m_nCalos];  
+  CaloGain::CaloGain  m_highestGain[m_nCalos];
+
+//Switches
+  bool m_WithOF;
+
+//Identifiers
+  const AtlasDetectorID* m_atlas_id; 
+
+  const CaloIdManager* m_calo_id_man;
+
+  //  const LArDetDescrManager* m_lar_dd_man; 
+  const LArEM_ID*    m_lar_em_id; 
+  const LArHEC_ID*   m_lar_hec_id;
+  const LArFCAL_ID*  m_lar_fcal_id; 
+   
+  //const TileDetDescrManager* m_tile_dd_man; 
+  const TileID*      m_tile_id;
+
+  const CaloDetDescrManager* m_calo_dd_man; 
+  const CaloCell_ID* m_calocell_id;
+
+  IdentifierHash m_LArHashMax;
+  IdentifierHash m_TileHashMax;
+  IdentifierHash m_CaloHashMax;
+  IdentifierHash m_CaloHashMin;
+
+  ToolHandle<LArCablingService> m_cablingService;
+
+  std::string     m_tileInfoName;
+  const TileInfo* m_tileInfo;
+
+//Database  
+
+  bool m_retrieve[15];
+
+  float  Adc2MeVFactor;
+  const  DataHandle<ILArAdc2GeV> m_dd_adc2gev;
+  double AdcPerMev;
+  ToolHandle<ILArADC2MeVTool> m_adc2mevTool;
+
+  const  DataHandle<ILArNoise> m_dd_noise; 
+  float  SigmaNoise;
+  double CNoise;
+ 
+  bool m_useRMSpedestal;
+  const DataHandle<ILArPedestal> m_dd_pedestal;
+  float RMSpedestal;
+
+  const DataHandle<ILArAutoCorr> m_dd_acorr;
+  ILArAutoCorr::AutoCorrRef_t AutoCorr;
+  float c[32][32];
+
+  const DataHandle<ILArOFC_Shape> m_detDHOFC ;
+  ToolHandle<ILArOFCTool> m_OFCTool;
+  ILArOFCTool::OFCRef_t OFC;  
+   
+  const DataHandle<ILArShape> m_dd_shape;
+  ILArShape::ShapeRef_t Shape; 
+  int m_nsamples;
+
+  const DataHandle<ILArfSampl> m_dd_fsampl;
+  float fSampl;
+
+  const DataHandle<ILArMinBias> m_dd_minbias; 
+  float MinBiasRMS;
+  float m_Nminbias;
+  float m_Nminbias_usedForCache;
+// 
+  int m_WorkMode;
+  bool m_NormalizeAutoCorr;
+  //bool m_Geant3;
+  bool m_UseLAr;
+  bool m_UseTile;
+  bool m_UseSymmetry;
+  bool m_DumpDatabase[3];
+  bool m_DumpDatabaseHG,m_DumpDatabaseMG,m_DumpDatabaseLG;
+  bool m_isMC;
+  bool m_loadAtBegin; // load constant at BeginRun time.
+ 
+  std::string m_keyNoise, m_keyPedestal, m_keyADC2GeV, m_keyOFShape, m_keyAutoCorr;
+  std::string m_keyShape, m_keyfSampl, m_keyMinBias;
+
+  unsigned int m_Nmessages_forTilePileUp;
+
+//DIAGNOSTIC (for TESTBEAM, since limited to 5000 cells)
+  bool m_noiseOK;
+  bool m_DiagnosticHG,m_DiagnosticMG,m_DiagnosticLG;
+  bool m_diagnostic[3];
+  int m_nCellsWithProblem[3];
+  int m_nReason[5000][3];
+  int m_itReason[10][3];
+  int m_idHash[5000][3];
+  int m_reason[5000][10][3];
+  std::string m_reasonName[10];
+
+  // state of the Cache
+  bool m_cacheValid ;
+
+  int m_deltaBunch;
+  unsigned int m_firstSample;
+
+//Containers    
+  std::vector<IdentifierHash>  m_indexContainer;
+    // = vector indexed with all the hashids, 
+    //containing which index (of container) should be used with a hashid
+  std::vector<IdentifierHash>  m_idSymmCaloHashContainer;
+    //used only to initialize m_indexOfContainer 
+
+  // experimental
+  // typedef std::map<IdentifierHash, unsigned int> CaloHashIdMap;
+  // CaloHashIdMap m_idSymmCaloHashMap ;
+
+  VectorContainer              m_elecNoiseRAWContainer;
+  VectorContainer              m_elecNoiseCELLContainer;
+  SingleContainer              m_pileupNoiseContainer;
+  //SingleContainer              m_scaleContainer;
+  VectorContainer              m_adc2mevContainer;
+
+
+//Functions
+  StatusCode initialize();
+  StatusCode retrieveDatabase();
+  StatusCode initContainers();
+  StatusCode initData();
+  StatusCode initAdc2MeV();
+  StatusCode initElecNoise();
+  StatusCode initPileUpNoise();
+
+  virtual StatusCode LoadCalibration(IOVSVC_CALLBACK_ARGS);
+
+  /** Callback added to handle Data-driven GeoModel initialisation
+   */
+  virtual StatusCode geoInit(IOVSVC_CALLBACK_ARGS);
+
+  bool checkIfConnected(const Identifier &id);
+  void commonCalculations(float & OFC_AC_OFC,float & OFC_OFC, int icase, unsigned int firstSample=0);
+  StatusCode retrieveCellDatabase(const IdentifierHash & idCaloHash,
+				  const Identifier & id,int igain,
+				  const float &Nminbias,
+				  std::string function_name);
+  StatusCode checkCellDatabase(const Identifier & id, int igain,
+			       std::string function_name);
+  void updateDiagnostic(int reason,std::string reason_name,int igain);
+
+  std::vector<float> 
+    calculateElecNoiseForLAR(const IdentifierHash &idCaloHash,
+			     const CaloCell_ID::SUBCALO iCalo,
+			     const float &Nminbias);
+  std::vector<float> 
+    calculateElecNoiseForTILE(const IdentifierHash &idCaloHash);
+
+  float
+    calculatePileUpNoise(const IdentifierHash &idCaloHash,
+			 const float &Nminbias);
+
+  void initIndex();
+  int  index(const IdentifierHash &idCaloHash);  
+  CaloCell_ID::SUBCALO caloNum(const IdentifierHash idCaloHash);  
+  bool isBadValue(float tested_value); 
+
+  CaloGain::CaloGain estimatedLArGain(const CaloCell_ID::SUBCALO &iCalo,
+				      const CaloDetDescrElement* caloDDE,
+				      const float &energy,
+				      const int &step);
+  CaloGain::CaloGain estimatedTileGain(const CaloCell* caloCell,
+				       const CaloDetDescrElement* caloDDE,
+				       const int &step);
+
+
+public:    
+  
+  CaloNoiseTool(const std::string& type, 
+		const std::string& name, 
+		const IInterface* parent); 
+  //virtual ~CaloNoiseTool();  
+
+
+//-------------- user interfaces ------------------------------------------
+
+// Note on NMinBias : if you use the interface without it or if you take -1, 
+//                    the returned data will be the one calculated at the 
+//                    initialization with the default value (0) or the 
+//                    specified one (with the property m_Nminbias).
+//                    In all cases, the NMinBias used to calculate the OFCs 
+//                    is NOT known by CaloNoiseTool (CaloNoiseTool always 
+//                    recomputes OFCs for its own needs)
+
+
+  
+//== just one function for the interface to the CaloNoiseTool ==
+  // which noise to return is defined via jobOptions or via the
+  // optional parameter CalorimeterNoiseType
+  
+  float getNoise(const CaloCell* caloCell,
+		 CalorimeterNoiseType type=JOBOPTION );
+  float getNoise(const CaloDetDescrElement* caloDDE,
+		 CalorimeterNoiseType type=JOBOPTION );
+
+  bool isEOverNSigma(const CaloCell* caloCell, float sigmaCut , 
+                     CalorimeterNoiseSymmetryHandling symmetryHandling=ONLYRIGHTSIDEINTEGRATION,
+                     CalorimeterNoiseType type=JOBOPTION );
+
+  float getRandomisedE(const CaloCell* caloCell , CLHEP::HepRandomEngine* engine, CalorimeterNoiseType type=JOBOPTION);
+
+  float getEffectiveSigma(const CaloCell* caloCell,
+                     CalorimeterNoiseSymmetryHandling symmetryHandling=ONLYRIGHTSIDEINTEGRATION,
+                     CalorimeterNoiseType type=JOBOPTION );
+
+
+  
+
+//== ELECTRONIC NOISE ==  
+
+  //''''''''' functions to use currently
+
+  float elecNoiseRMS(const CaloCell* caloCell, 
+		     const int step=ICaloNoiseToolStep::CELLS);
+    //Returns the sigma of the electronic noise, finding itself the right gain 
+    //from the energy of the given caloCell.
+    //Can also return the sigma without the scale applied in LArG3Escale 
+    //(meaning at the level of the RawChannels) specifying the step (use ENUM)
+
+  float elecNoiseRMS(const CaloCell* caloCell, 
+		     const float Nminbias,
+		     const int step=ICaloNoiseToolStep::CELLS);
+    //same as above, but must specify the number of minimum bias events 
+    //per bunch crossing 
+    // (slower since do not use stored data -> calculate again)
+
+  float elecNoiseRMSHighestGain(const CaloCell* caloCell, 
+				const int step=ICaloNoiseToolStep::CELLS);
+    //Returns the sigma of the electronic noise for the caloDDE of the given 
+    //caloCELL and for the highest gain of the considered calorimeter 
+    //(eg: HG for LAr, MG for HEC, ...).
+    //Can also return the sigma without the scale applied in LArG3Escale 
+    //(meaning at the level of the RawChannels) specifying the step (use ENUM)
+
+  float elecNoiseRMSHighestGain(const CaloCell* caloCell, 
+				const float Nminbias,
+				const int step=ICaloNoiseToolStep::CELLS);
+    //same as above, but must specify the number of minimum bias events 
+    //per bunch crossing 
+    // (slower since do not use stored data -> calculate again)
+
+  //''''''''' functions more specialized
+
+  float elecNoiseRMSHighestGain(const CaloDetDescrElement* caloDDE, 
+				const int step=ICaloNoiseToolStep::CELLS);
+    //Returns the sigma of the electronic noise for the given caloDDE and 
+    //for the highest gain of the considered calorimeter (eg: MG for HEC).
+    //Can also return the sigma without the scale applied in LArG3Escale 
+    //(meaning at the level of the RawChannels) specifying the step (use ENUM)
+
+  float elecNoiseRMSHighestGain(const CaloDetDescrElement* caloDDE, 
+				const float Nminbias,
+				const int step=ICaloNoiseToolStep::CELLS);
+    //same as above, but must specify the number of minimum bias events 
+    //per bunch crossing 
+    // (slower since do not use stored data -> calculate again)
+
+  float elecNoiseRMS(const CaloDetDescrElement* caloDDE, 
+		     const CaloGain::CaloGain gain,
+		     const float Nminbias,
+		     const int step=ICaloNoiseToolStep::CELLS);
+    //Returns the sigma of the electronic noise for the given caloDDE, gain and
+    //the number of minimum bias events per bunch crossing. 
+    //Can also return the sigma without the scale applied in LArG3Escale 
+    //(meaning at the level of the RawChannels) specifying the step (use ENUM)
+
+  std::vector<float> 
+    elecNoiseRMS3gains(const CaloDetDescrElement* caloDDE,
+		       const int step=ICaloNoiseToolStep::CELLS);
+    //Returns a vector containing the sigma of the electronic noise for the 
+    //given caloDDE, for each gain of the considered calorimeter 
+    //(eg: vector of 3 sigma3 gains for LAr)
+    //Can also return the sigma without the scale applied in LArG3Escale 
+    //(meaning at the level of the RawChannels) specifying the step (use ENUM)
+
+  std::vector<float> 
+    elecNoiseRMS3gains(const CaloDetDescrElement* caloDDE,
+		       const float Nminbias, 
+		       const int step=ICaloNoiseToolStep::CELLS);
+    //same as above, but must specify the number of minimum bias events 
+    //per bunch crossing 
+    // (slower since do not use stored data -> calculate again)
+
+  VectorContainer* elecNoiseRMSContainer(const int &iCalo);
+    //TO BE USED ONLY FOR SPECIAL CASES
+    //Returns a vector containing, for each Hash Identifier of the calorimeter 
+    //iCalo, a vector  containing the sigma of the electronic noise for all 
+    //gains. 
+    //So it's a vector (indexed by hashID) of vectors (sigma for each gain)
+    //(see typedef VectorContainer).
+
+
+//== PILEUP NOISE ==  
+
+  float pileupNoiseRMS(const CaloCell* caloCell, 
+		       const float Nminbias=-1); 
+  float pileupNoiseRMS(const CaloDetDescrElement* caloDDE, 
+		       const float Nminbias=-1);
+  //Nminbias is the number of minimum-bias events per bunch-crossing
+  // (default is 0 (set in the constructor) ) 
+
+//== TOTAL NOISE ==   (only at the "Cells" step)
+
+  float totalNoiseRMS(const CaloCell* caloCell, 
+		      const float Nminbias=-1); 
+  float totalNoiseRMS(const CaloDetDescrElement* caloDDE, 
+		      const CaloGain::CaloGain gain,
+		      const float Nminbias=-1);
+  float totalNoiseRMSHighestGain(const CaloCell* caloCell, 
+				 const float Nminbias=-1);
+  float totalNoiseRMSHighestGain(const CaloDetDescrElement* caloDDE, 
+				 const float Nminbias=-1);
+
+
+
+//== GAIN == 
+  CaloGain::CaloGain estimatedGain(const CaloCell* caloCell,
+				   const int &step);
+  CaloGain::CaloGain estimatedGain(const CaloCell* caloCell,
+				   const CaloDetDescrElement* caloDDE,
+				   const int &step);
+  CaloGain::CaloGain estimatedGain(const CaloDetDescrElement* caloDDE,
+				   const float &energy,
+				   const int &step);
+
+//== ADDITIONNAL STUFF ==
+  // these functions will be replaced soon by dedicated tools,
+  // so please AVOID TO USING THEM
+
+  //float eScale(const CaloDetDescrElement* caloDDE);
+    //Returns the scale between RawChannels and Cells, i.e 
+    //what returns LArG3Escale
+
+  float adc2mev(const CaloDetDescrElement* caloDDE,
+		const CaloGain::CaloGain gain);
+    //Returns adc2mev factor for the given caloDDE and gain
+
+  float adc2mev(const Identifier& id,const CaloGain::CaloGain gain);
+    //Returns adc2mev factor for the given ID and gain
+    //SHOULD NOT BE USED ANYMORE, prefer the one above with caloDDE
+
+
+  /** 
+    implement IIncidentListener interface 
+  */
+  virtual void handle(const Incident&);
+
+
+};
+
+//------------------------------------------------------------
+
+inline bool 
+CaloNoiseTool::isBadValue(float tested_value) 
+{
+  if(tested_value<BADVALUE+1) return true;
+  return false;
+}
+
+//////////////////////////////////////////////////
+
+inline CaloCell_ID::SUBCALO  
+CaloNoiseTool::caloNum(const IdentifierHash idCaloHash)
+{
+  return 
+    static_cast<CaloCell_ID::SUBCALO>(m_calocell_id->sub_calo(idCaloHash));
+}
+
+#endif
+
diff --git a/Calorimeter/CaloTools/CaloTools/CaloNoiseToolDB.h b/Calorimeter/CaloTools/CaloTools/CaloNoiseToolDB.h
new file mode 100755
index 0000000000000000000000000000000000000000..f7c9bb72f1463375070c9299d83b16391bf34a24
--- /dev/null
+++ b/Calorimeter/CaloTools/CaloTools/CaloNoiseToolDB.h
@@ -0,0 +1,321 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+/** 
+    @class CaloNoiseToolDB
+    @brief Tool to provide electronic and pile up noise in MeV from reading values stored in DB
+    @brief  Implementing ICaloNoiseTool interface
+    @author  G.Unal
+*/
+
+#ifndef CALOTOOLS_CaloNoiseToolDB_H
+#define CALOTOOLS_CaloNoiseToolDB_H
+
+
+//#include "GaudiKernel/AlgTool.h"
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "CaloInterface/ICaloNoiseTool.h"
+
+#include "AtlasDetDescr/AtlasDetectorID.h"
+#include "CaloDetDescr/CaloDetDescrManager.h"
+#include "CaloIdentifier/CaloCell_ID.h"
+#include "CaloIdentifier/CaloIdManager.h"
+#include "CaloIdentifier/CaloGain.h"
+#include "CaloEvent/CaloCell.h"
+#include "AthenaPoolUtilities/CondAttrListCollection.h"
+#include "AthenaKernel/IOVSvcDefs.h"
+#include "StoreGate/DataHandle.h"
+#include <string>
+#include <boost/multi_array.hpp>
+
+#define sqrt2 1.4142135623730950
+#define invsqrt2 0.707106781186547524
+
+
+class CaloCondBlobFlt;
+
+
+class CaloNoiseToolDB: public AthAlgTool,
+	             virtual public ICaloNoiseTool
+{
+public:    
+
+  typedef std::vector< std::vector<float> > VectorContainer;
+  
+  CaloNoiseToolDB(const std::string& type, 
+		const std::string& name, 
+		const IInterface* parent); 
+
+  enum SYSTEM{EMECZNEG = 0,
+              EMBZNEG  = 1,
+              EMBZPOS  = 2,
+              EMECZPOS = 3,
+              HEC      =16,
+              FCAL     =32,
+              TILE     =48};
+
+
+
+//-------------- user interfaces ------------------------------------------
+
+// Note on NMinBias : if you use the interface without it or if you take -1, 
+//                    the returned data will be the one calculated at the 
+//                    initialization with the default value (0) or the 
+//                    specified one (with the property m_Nminbias).
+// FIXME : to be updated using the proper luminosity information from lumi block
+//   (and then should also register a call back on the lumi block for cached data)
+
+  
+//== just one function for the interface to the CaloNoiseToolDB ==
+  // which noise to return is defined via jobOptions or via the
+  // optional parameter CalorimeterNoiseType
+  
+  float getNoise(const CaloCell* caloCell,
+		 CalorimeterNoiseType type=JOBOPTION );
+  float getNoise(const CaloDetDescrElement* caloDDE,
+		 CalorimeterNoiseType type=JOBOPTION );
+  float getNoise(const CaloCell* caloCell, float energy,
+		 CalorimeterNoiseType type=JOBOPTION );
+
+  bool isEOverNSigma(const CaloCell* caloCell, float sigmaCut , 
+                     CalorimeterNoiseSymmetryHandling symmetryHandling=ONLYRIGHTSIDEINTEGRATION,
+                     CalorimeterNoiseType type=JOBOPTION );
+  float calcSig(double e, double sigma1, double ratio, double sigma2);
+
+  float getRandomisedE(const CaloCell* caloCell , CLHEP::HepRandomEngine* engine, CalorimeterNoiseType type=JOBOPTION);
+
+  float getEffectiveSigma(const CaloCell* caloCell,
+                     CalorimeterNoiseSymmetryHandling symmetryHandling=ONLYRIGHTSIDEINTEGRATION,
+                     CalorimeterNoiseType type=JOBOPTION );
+
+
+
+//== ELECTRONIC NOISE ==  
+
+  //''''''''' functions to use currently
+
+  float elecNoiseRMS(const CaloCell* caloCell, 
+		     const int step=ICaloNoiseToolStep::CELLS);
+    //Returns the sigma of the electronic noise, finding itself the right gain 
+    //from the energy of the given caloCell.
+
+  float elecNoiseRMS(const CaloCell* caloCell, 
+		     const float Nminbias,
+		     const int step=ICaloNoiseToolStep::CELLS);
+  // returns the same as above (Nminbias ignored in this implementation from database)
+
+  float elecNoiseRMSHighestGain(const CaloCell* caloCell, 
+				const int step=ICaloNoiseToolStep::CELLS);
+    //Returns the sigma of the electronic noise for the caloDDE of the given 
+    //caloCELL and for the highest gain of the considered calorimeter 
+    //(eg: HG for LAr, MG for HEC, ...).
+
+  float elecNoiseRMSHighestGain(const CaloCell* caloCell, 
+				const float Nminbias,
+				const int step=ICaloNoiseToolStep::CELLS);
+   // same as above
+
+  //''''''''' functions more specialized
+
+  float elecNoiseRMSHighestGain(const CaloDetDescrElement* caloDDE, 
+				const int step=ICaloNoiseToolStep::CELLS);
+    //Returns the sigma of the electronic noise for the given caloDDE and 
+    //for the highest gain of the considered calorimeter (eg: MG for HEC).
+
+  float elecNoiseRMSHighestGain(const CaloDetDescrElement* caloDDE, 
+				const float Nminbias,
+				const int step=ICaloNoiseToolStep::CELLS);
+    //same as above
+
+  float elecNoiseRMS(const CaloDetDescrElement* caloDDE, 
+		     const CaloGain::CaloGain gain,
+		     const float Nminbias,
+		     const int step=ICaloNoiseToolStep::CELLS);
+    //Returns the sigma of the electronic noise for the given caloDDE, gain 
+    // Nminbias is ignored
+
+  float elecNoiseRMS(const CaloDetDescrElement* caloDDE, 
+		     const CaloGain::CaloGain gain,
+		     const float Nminbias,
+		     const float energy,
+		     const int step=ICaloNoiseToolStep::CELLS);
+    //Returns the sigma of the electronic noise for the given caloDDE in 
+    //case of 2-gaussian noise, gain 
+    // Nminbias is ignored
+
+  std::vector<float> 
+    elecNoiseRMS3gains(const CaloDetDescrElement* caloDDE,
+		       const int step=ICaloNoiseToolStep::CELLS);
+    //Returns a vector containing the sigma of the electronic noise for the 
+    //given caloDDE, for each gain of the considered calorimeter 
+    //(eg: vector of 3 sigma3 gains for LAr)
+
+  std::vector<float> 
+    elecNoiseRMS3gains(const CaloDetDescrElement* caloDDE,
+		       const float Nminbias, 
+		       const int step=ICaloNoiseToolStep::CELLS);
+    //same as above, Nminbias ignored
+
+  VectorContainer* elecNoiseRMSContainer(const int &iCalo);
+    //TO BE USED ONLY FOR SPECIAL CASES
+    //Returns a vector containing, for each Hash Identifier of the calorimeter 
+    //iCalo, a vector  containing the sigma of the electronic noise for all 
+    //gains. 
+    //So it's a vector (indexed by hashID) of vectors (sigma for each gain)
+    //(see typedef VectorContainer).
+    // empty for the time being
+
+
+//== PILEUP NOISE ==  
+
+  float pileupNoiseRMS(const CaloCell* caloCell, 
+		       const float Nminbias=-1); 
+  float pileupNoiseRMS(const CaloDetDescrElement* caloDDE, 
+		       const float Nminbias=-1);
+  //Nminbias is the number of minimum-bias events per bunch-crossing
+  // (default is 0 (set in the constructor) ) 
+
+//== TOTAL NOISE ==   (only at the "Cells" step)
+
+  float totalNoiseRMS(const CaloCell* caloCell, 
+		      const float Nminbias=-1); 
+  float totalNoiseRMS(const CaloDetDescrElement* caloDDE, 
+		      const CaloGain::CaloGain gain,
+		      const float Nminbias=-1);
+  float totalNoiseRMSHighestGain(const CaloCell* caloCell, 
+				 const float Nminbias=-1);
+  float totalNoiseRMSHighestGain(const CaloDetDescrElement* caloDDE, 
+				 const float Nminbias=-1);
+
+
+
+//== GAIN ==   Only there to fulfill the interface, returns INVALID values...
+  CaloGain::CaloGain estimatedGain(const CaloCell* caloCell,
+				   const int &step);
+  CaloGain::CaloGain estimatedGain(const CaloCell* caloCell,
+				   const CaloDetDescrElement* caloDDE,
+				   const int &step);
+  CaloGain::CaloGain estimatedGain(const CaloDetDescrElement* caloDDE,
+				   const float &energy,
+				   const int &step);
+
+  StatusCode LoadCalibration(IOVSVC_CALLBACK_ARGS);
+
+
+  /** Callback added to handle Data-driven GeoModel initialisation 
+      ( even needed to retrieve Identifiers )
+   */
+  virtual StatusCode geoInit(IOVSVC_CALLBACK_ARGS);
+
+private: 
+  
+
+  ICalorimeterNoiseTool::CalorimeterNoiseType m_cached;
+
+  // cached noise per cell
+  boost::multi_array<float, 2> m_noise;   // float[MaxGains][MaxCells]
+
+  typedef float (CaloNoiseToolDB::*GETNOISE_CDDE)(const CaloDetDescrElement*,
+                                                const CaloGain::CaloGain,
+                                                const float,
+                                                const int);
+  typedef float (CaloNoiseToolDB::*GETNOISE_CELL)(const CaloCell*,
+                                                const CaloGain::CaloGain,
+                                                const float,
+                                                const int);
+  
+  float elecNoiseRMS(const CaloCell* caloCell,
+                     const CaloGain::CaloGain gain,
+                     const float Nminbias,
+                     const int step);
+  float pileupNoiseRMS(const CaloCell* caloCell,
+                       const CaloGain::CaloGain gain,
+                       const float Nminbias,
+                       const int step);
+  float totalNoiseRMS(const CaloCell* caloCell,
+                      const CaloGain::CaloGain gain,
+                      const float Nminbias,
+                      const int step);
+  float pileupNoiseRMS(const CaloDetDescrElement* caloDDE, 
+                       const CaloGain::CaloGain gain,
+                       const float Nminbias,
+                       const int step);
+  float totalNoiseRMS(const CaloDetDescrElement* caloDDE, 
+                      const CaloGain::CaloGain gain,
+                      const float Nminbias,
+                      const int step);
+  float totalNoiseRMS(const CaloDetDescrElement* caloDDE, 
+                      const CaloGain::CaloGain gain,
+                      const float Nminbias,
+                      const float energy,
+                      const int step);
+  GETNOISE_CDDE m_CachedGetNoiseCDDE;
+  GETNOISE_CELL m_CachedGetNoiseCELL;
+  
+  int m_gain_from_joboption;
+  bool m_speedTwoGauss;
+
+//Constants
+  static const int m_nCalos=4;// number of calorimeters
+  int m_ncell;   // total number of calo cells
+
+  CaloGain::CaloGain  m_highestGain[m_nCalos];
+
+  float m_Nminbias;
+  float m_lumi0;
+
+//Functions
+  StatusCode initialize();
+  StatusCode finalize();
+  
+// provate methods to access database
+  float getA(SYSTEM sysId, unsigned int cellHash, CaloGain::CaloGain caloGain) const;
+  float getB(SYSTEM sysId, unsigned int cellHash, CaloGain::CaloGain caloGain) const ;
+  float getC(SYSTEM sysId, unsigned int cellHash, CaloGain::CaloGain caloGain) const ;
+  float getD(SYSTEM sysId, unsigned int cellHash, CaloGain::CaloGain caloGain) const ;
+  float getE(SYSTEM sysId, unsigned int cellHash, CaloGain::CaloGain caloGain) const ;
+  float getDBNoise(SYSTEM sysId, unsigned int cellHash, CaloGain::CaloGain caloGain, float lumi) const;
+
+  float getA(unsigned int cellHash, CaloGain::CaloGain caloGain) const;
+  float getB(unsigned int cellHash, CaloGain::CaloGain caloGain) const ;
+  float getC(unsigned int cellHash, CaloGain::CaloGain caloGain) const ;
+  float getD(unsigned int cellHash, CaloGain::CaloGain caloGain) const ;
+  float getE(unsigned int cellHash, CaloGain::CaloGain caloGain) const ;
+  float getDBNoise(unsigned int cellHash, CaloGain::CaloGain caloGain, float lumi) const;
+
+  int checkObjLength(unsigned int cellHash) const;
+
+  SYSTEM caloSystem(unsigned int cellHash, unsigned int& subHash) const;
+
+    //=== callback function to update noise map
+    virtual StatusCode updateMap(IOVSVC_CALLBACK_ARGS);
+    void updateCache();
+
+    //=== callback function for luminosity storate
+    virtual StatusCode updateLumi(IOVSVC_CALLBACK_ARGS);
+
+
+    //=== blob storage
+    std::vector<DataHandle<CondAttrListCollection> > m_noiseAttrListColl;
+    std::map<SYSTEM, const CaloCondBlobFlt*> m_noiseBlobMap;
+
+   bool m_cacheValid;
+
+   std::string   m_ReturnNoiseName;
+
+  const DataHandle<CaloIdManager> m_caloIdMgr;
+  const DataHandle<CaloDetDescrManager> m_calodetdescrmgr;
+  const CaloCell_ID*       m_calo_id;
+
+  // number of EM systems in SYSTEM enum
+  enum { NUM_EM_SYS = 4 };
+
+  // First IdHash for each system in EM Barrel and EndCap (indexed by SYSTEM, only first NUM_EM_SYS SYSTEMs)
+  IdentifierHash m_firstSysHash[NUM_EM_SYS];
+
+  std::vector<std::string> m_folderNames;//jobOption
+  std::string m_lumiFolderName;
+};
+
+#endif
diff --git a/Calorimeter/CaloTools/CaloTools/SimpleNoiseTool.h b/Calorimeter/CaloTools/CaloTools/SimpleNoiseTool.h
new file mode 100755
index 0000000000000000000000000000000000000000..d46ade69d705743a850ff285d4edddf38a4e765c
--- /dev/null
+++ b/Calorimeter/CaloTools/CaloTools/SimpleNoiseTool.h
@@ -0,0 +1,62 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+/** 
+    @class SimpleNoiseTool
+    @brief Tool to provide noise from hardcoded numbers
+    @author Rolf Seuster
+*/
+
+#ifndef CALOTOOLS_SIMPLENOISETOOL_H
+#define CALOTOOLS_SIMPLENOISETOOL_H
+
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "GaudiKernel/IIncidentListener.h"
+
+#include "CaloGeoHelpers/CaloSampling.h"
+
+#include "CaloIdentifier/CaloGain.h"
+#include "CaloDetDescr/CaloDetDescrElement.h"
+
+#include "CaloInterface/ICalorimeterNoiseTool.h"
+
+#include <map>
+#include <string>
+
+class CaloCell;
+
+class StoreGateSvc;
+
+class SimpleNoiseTool : public AthAlgTool,
+			virtual public ICalorimeterNoiseTool
+{
+ public:
+
+  typedef std::pair<CaloSampling::CaloSample,CaloGain::CaloGain> index_t;
+  typedef std::map<index_t,double>                               store_t;
+  
+  SimpleNoiseTool(const std::string& type, const std::string& name,
+		  const IInterface* parent);
+  
+  virtual ~SimpleNoiseTool();
+  
+  StatusCode initialize();
+  
+  float getNoise(const CaloCell* aCell, CalorimeterNoiseType type=JOBOPTION);
+  float getNoise(const CaloDetDescrElement *caloCell, CalorimeterNoiseType type=JOBOPTION);
+
+  bool isEOverNSigma(const CaloCell* caloCell, float sigmaCut , 
+                     CalorimeterNoiseSymmetryHandling symmetryHandling=ONLYRIGHTSIDEINTEGRATION,
+                     CalorimeterNoiseType type=JOBOPTION );
+
+  float getRandomisedE(const CaloCell* caloCell , CLHEP::HepRandomEngine* engine, CalorimeterNoiseType type=JOBOPTION);
+
+  float getEffectiveSigma(const CaloCell* caloCell,
+                     CalorimeterNoiseSymmetryHandling symmetryHandling=ONLYRIGHTSIDEINTEGRATION,
+                     CalorimeterNoiseType type=JOBOPTION );
+
+
+  
+};
+#endif
diff --git a/Calorimeter/CaloTools/CaloTools/SimpleNoiseToolFromTextFile.h b/Calorimeter/CaloTools/CaloTools/SimpleNoiseToolFromTextFile.h
new file mode 100755
index 0000000000000000000000000000000000000000..15df6f21ec83af78d2300936adcdf3d7ac5e170f
--- /dev/null
+++ b/Calorimeter/CaloTools/CaloTools/SimpleNoiseToolFromTextFile.h
@@ -0,0 +1,79 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+/** 
+    @class SimpleNoiseToolFromTextFile
+    @brief Tool to provide noise from numbers read in a text file
+    @author Rolf Seuster
+*/
+
+#ifndef CALOTOOLS_SIMPLENOISETOOLFROMTEXTFILE_H
+#define CALOTOOLS_SIMPLENOISETOOLFROMTEXTFILE_H
+
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "GaudiKernel/IIncidentListener.h"
+
+#include "CaloIdentifier/CaloGain.h"
+#include "CaloDetDescr/CaloDetDescrManager.h"
+#include "CaloIdentifier/CaloCell_ID.h"
+#include "CaloInterface/ICalorimeterNoiseTool.h"
+#include "Identifier/Identifier.h"
+#include "AthenaKernel/IOVSvcDefs.h"
+
+#include <map>
+
+class CaloCell;
+class CaloDetDescrElement;
+
+class StoreGateSvc;
+
+class SimpleNoiseToolFromTextFile : public AthAlgTool,
+				    virtual public ICalorimeterNoiseTool
+{
+ public:
+  
+  SimpleNoiseToolFromTextFile(const std::string& type, const std::string& name,
+		  const IInterface* parent);
+  
+  virtual ~SimpleNoiseToolFromTextFile();
+  
+  StatusCode initialize();
+
+  /** Callback added to handle Data-driven GeoModel initialisation
+   */
+  virtual StatusCode geoInit(IOVSVC_CALLBACK_ARGS);
+  
+  float getNoise(const CaloCell* aCell, CalorimeterNoiseType type=JOBOPTION);
+  float getNoise(const CaloDetDescrElement* caloDDE, CalorimeterNoiseType type=JOBOPTION);
+
+  bool isEOverNSigma(const CaloCell* caloCell, float sigmaCut , 
+                     CalorimeterNoiseSymmetryHandling symmetryHandling=ONLYRIGHTSIDEINTEGRATION,
+                     CalorimeterNoiseType type=JOBOPTION );
+
+  float getRandomisedE(const CaloCell* caloCell , CLHEP::HepRandomEngine* engine, CalorimeterNoiseType type=JOBOPTION);
+
+  float getEffectiveSigma(const CaloCell* caloCell,
+                     CalorimeterNoiseSymmetryHandling symmetryHandling=ONLYRIGHTSIDEINTEGRATION,
+                     CalorimeterNoiseType type=JOBOPTION );
+
+
+  
+ private:
+  // access calo detector managers and calo identifier helper
+  // only needed for debug printout
+  const CaloDetDescrManager* m_caloDDM;
+  const CaloCell_ID* m_caloIDH;
+  
+  // Identifier keyed map of calo cell noise
+  std::map<Identifier, float> m_cellNoise;
+  
+  // Properties
+  std::string m_cellNoiseFileName;
+  double m_cellNoiseUnits;           // CLHEP units of cell noise in noise file
+  float m_cellNoiseDefault;          // noise value to return if cell noise not in noise file
+  bool m_cellNoiseDefaultWarning;    // if true, print a MSG::WARNING if noise default is used
+  
+  float getNoiseHelper(Identifier id);
+};
+#endif
diff --git a/Calorimeter/CaloTools/cmt/requirements b/Calorimeter/CaloTools/cmt/requirements
new file mode 100755
index 0000000000000000000000000000000000000000..5252137f70f3ca954cf00063704ee9734a60937b
--- /dev/null
+++ b/Calorimeter/CaloTools/cmt/requirements
@@ -0,0 +1,58 @@
+package CaloTools
+
+use AtlasPolicy AtlasPolicy-*
+use AtlasDetDescr AtlasDetDescr-* DetectorDescription
+use AthenaKernel AthenaKernel-*  Control
+use AthenaPoolUtilities     AthenaPoolUtilities-*  Database/AthenaPOOL
+use Identifier Identifier-* DetectorDescription
+use CaloDetDescr CaloDetDescr-* Calorimeter
+use CaloInterface CaloInterface-* Calorimeter
+use CaloEvent CaloEvent-* Calorimeter
+use CaloGeoHelpers  CaloGeoHelpers-*  Calorimeter
+use CaloIdentifier CaloIdentifier-* Calorimeter
+use CaloConditions     CaloConditions-*           Calorimeter
+use DataModel DataModel-* Control
+use GaudiInterface GaudiInterface-* External
+use LArElecCalib LArElecCalib-* LArCalorimeter
+use LArRecEvent LArRecEvent-* LArCalorimeter
+use LArTools LArTools-* LArCalorimeter
+use StoreGate StoreGate-* Control
+use TileConditions TileConditions-* TileCalorimeter
+use TileEvent TileEvent-* TileCalorimeter
+use LumiBlockComps LumiBlockComps-* LumiBlock
+use TrigAnalysisInterfaces TrigAnalysisInterfaces-* Trigger/TrigAnalysis
+use LArIdentifier LArIdentifier-* LArCalorimeter
+use AthenaBaseComps AthenaBaseComps-* Control
+
+use AtlasCLHEP AtlasCLHEP-* External
+use AtlasBoost      AtlasBoost-*      External
+use AthenaPoolUtilities AthenaPoolUtilities-*        Database/AthenaPOOL
+
+private
+use xAODBase xAODBase-*   Event/xAOD
+use AthAllocators   AthAllocators-*   Control
+use CaloTriggerTool CaloTriggerTool-* Calorimeter
+end_private
+
+library CaloTools *.cxx components/*.cxx
+apply_pattern component_library 
+
+apply_pattern declare_joboptions files="*.txt *.py"
+
+apply_pattern declare_python_modules files="*.py"
+
+private
+use AtlasCORAL         AtlasCORAL-*         External
+use AtlasROOT          AtlasROOT-*          External
+use TestTools          TestTools-*          AtlasTest 
+use xAODEventInfo      xAODEventInfo-*      Event/xAOD
+use IdDictParser       IdDictParser-*       DetectorDescription
+use GeoModelInterfaces GeoModelInterfaces-* DetectorDescription/GeoModel
+use CaloCondBlobObjs   CaloCondBlobObjs-*   Calorimeter
+use TileIdentifier     TileIdentifier-*     TileCalorimeter
+
+apply_pattern UnitTest_run unit_test=CaloCellPackerUtils
+
+apply_pattern UnitTest_run unit_test=CaloCompactCellTool \
+  extrapatterns="SGAudSvc +INFO|^lar  decode|^HistogramPersis.* INFO|initialize_from_dict|mask/zero|^JobOptionsSvc +INFO|^AtlasDetectorID::"
+
diff --git a/Calorimeter/CaloTools/doc/mainpage.h b/Calorimeter/CaloTools/doc/mainpage.h
new file mode 100644
index 0000000000000000000000000000000000000000..9e53fca440116d96b0b66a9ab8b6b755b9215448
--- /dev/null
+++ b/Calorimeter/CaloTools/doc/mainpage.h
@@ -0,0 +1,15 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+/**
+
+@mainpage CaloTols Package
+
+This package provides some tools used in the calorimeter reconstruction.
+
+@author David Rousseau rousseau@lal.in2p3.fr
+@authour Sven Menke Sven.Menke@cern.ch
+
+
+*/
diff --git a/Calorimeter/CaloTools/python/CaloAffectedToolDefault.py b/Calorimeter/CaloTools/python/CaloAffectedToolDefault.py
new file mode 100644
index 0000000000000000000000000000000000000000..5756483e242c453b08f2b5d070522a2b5288a312
--- /dev/null
+++ b/Calorimeter/CaloTools/python/CaloAffectedToolDefault.py
@@ -0,0 +1,28 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+from AthenaCommon.Logging import logging
+
+def CaloAffectedToolDefault(name='CaloAffectedToolDefault'):
+
+    # check if tool already exists
+    from AthenaCommon.AppMgr import ServiceMgr as svcMgr
+    if hasattr(svcMgr.ToolSvc, name):
+        # re-use previously configured (public) tool
+        return getattr(svcMgr.ToolSvc, name)
+
+    mlog = logging.getLogger( 'CaloAffectedToolDefault' )
+
+    from CaloTools.CaloToolsConf import CaloAffectedTool
+
+
+    theTool = CaloAffectedTool(name)
+
+    from RecExConfig.RecFlags import rec
+    if rec.readRDO():
+       theTool.readRaw = True
+    else:
+       theTool.readRaw = False
+       from IOVDbSvc.CondDB import conddb
+       conddb.addFolder ('', '/LAR/LArAffectedRegionInfo<metaOnly/>')
+
+    return theTool
diff --git a/Calorimeter/CaloTools/python/CaloLumiBCIDToolDefault.py b/Calorimeter/CaloTools/python/CaloLumiBCIDToolDefault.py
new file mode 100644
index 0000000000000000000000000000000000000000..6424531cb506bac896aceebdba7a65149e091a28
--- /dev/null
+++ b/Calorimeter/CaloTools/python/CaloLumiBCIDToolDefault.py
@@ -0,0 +1,37 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+from AthenaCommon.Logging import logging
+from AthenaCommon.SystemOfUnits import *
+
+def CaloLumiBCIDToolDefault(name='CaloLumiBCIDToolDefault'):
+    mlog = logging.getLogger( 'CaloLumiBCIDToolDefault' )
+
+    from CaloTools.CaloToolsConf import CaloLumiBCIDTool
+
+    from AthenaCommon.GlobalFlags import globalflags
+    if globalflags.DataSource()=='data':
+      from LumiBlockComps.LuminosityToolDefault import LuminosityToolDefault
+      theLumiTool = LuminosityToolDefault()
+      from AthenaCommon.AppMgr import ToolSvc
+      ToolSvc += theLumiTool
+      from IOVDbSvc.CondDB import conddb
+      #conddb.addFolder("","/LAR/ElecCalibOfl/LArPileupShape<db>sqlite://;schema=/afs/cern.ch/user/g/gunal/public/DB/bcid/shape.db;dbname=COMP200</db><key>LArShape32</key><tag>LARElecCalibOflLArPileupShape-mc</tag>")
+      #conddb.addFolder("","/LAR/ElecCalibOfl/LArPileupAverage<db>sqlite://;schema=/afs/cern.ch/user/g/gunal/public/DB/bcid/LArPileupAverage-data.db;dbname=COMP200</db><tag>LARElecCalibOflLArPileupAverage-data11-00</tag>")
+      conddb.addFolder("LAR_OFL","/LAR/ElecCalibOfl/LArPileupShape<key>LArShape32</key>")
+      conddb.addFolder("LAR_OFL","/LAR/ElecCalibOfl/LArPileupAverage")
+      theTool = CaloLumiBCIDTool(name,isMC=False,LumiTool=theLumiTool,keyShape="LArShape32")
+    else:
+      from LArRecUtils.LArOFCToolDefault import LArOFCToolDefault
+      theOFCTool = LArOFCToolDefault()
+      from AthenaCommon.AppMgr import ToolSvc
+      ToolSvc += theOFCTool
+      from TrigBunchCrossingTool.BunchCrossingTool import BunchCrossingTool
+      theBunchCrossingTool = BunchCrossingTool()
+      from IOVDbSvc.CondDB import conddb
+      conddb.addFolder("LAR_OFL","/LAR/ElecCalibMC/Shape")
+      #conddb.addFolder("","/LAR/ElecCalibMC/LArPileupAverage<db>sqlite://;schema=/afs/cern.ch/user/g/gunal/public/DB/bcid/LArPileupAverage-mc.db;dbname=OFLP200</db><tag>LARElecCalibMCLArPileupAverage-mc11b-00</tag>")
+      conddb.addFolder("LAR_OFL","/LAR/ElecCalibMC/LArPileupAverage")
+      theTool = CaloLumiBCIDTool(name,
+                      isMC=True,
+                      LArOFCTool = theOFCTool,BunchCrossingTool = theBunchCrossingTool)
+    return theTool
diff --git a/Calorimeter/CaloTools/python/CaloMBAverageToolDefault.py b/Calorimeter/CaloTools/python/CaloMBAverageToolDefault.py
new file mode 100644
index 0000000000000000000000000000000000000000..fb395da59be38509655175d603f83836df9b1d31
--- /dev/null
+++ b/Calorimeter/CaloTools/python/CaloMBAverageToolDefault.py
@@ -0,0 +1,27 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+from AthenaCommon.Logging import logging
+from AthenaCommon.SystemOfUnits import *
+
+def CaloMBAverageToolDefault(name='CaloMBAverageToolDefault'):
+    mlog = logging.getLogger( 'CaloMBAverageToolDefault' )
+
+    from CaloTools.CaloToolsConf import CaloMBAverageTool
+    # get public tool LArOFCTool
+    from LArRecUtils.LArOFCToolDefault import LArOFCToolDefault
+    theOFCTool = LArOFCToolDefault()
+    from AthenaCommon.AppMgr import ToolSvc
+    ToolSvc += theOFCTool
+    from AthenaCommon.BeamFlags import jobproperties
+    if jobproperties.Beam.zeroLuminosity(): 
+        NMinBias=0
+        deltaBunch=1
+    else:
+        NMinBias=jobproperties.Beam.numberOfCollisions()
+        deltaBunch=int(jobproperties.Beam.bunchSpacing()/( 25.*ns)+0.5)
+
+    theTool = CaloMBAverageTool(name,
+                      LArOFCTool = theOFCTool,
+                      NMinBias = NMinBias,
+                      deltaBunch = deltaBunch)
+    return theTool
diff --git a/Calorimeter/CaloTools/python/CaloNoiseFlags.py b/Calorimeter/CaloTools/python/CaloNoiseFlags.py
new file mode 100644
index 0000000000000000000000000000000000000000..6f7d09b94c14ebfcdd8704f2f4eaed79e9610f03
--- /dev/null
+++ b/Calorimeter/CaloTools/python/CaloNoiseFlags.py
@@ -0,0 +1,51 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+""" Flags for define calo noise tool configuration
+"""
+#
+#
+__author__  = 'G.Unal'
+
+
+#=======================================================================
+# imports
+#=======================================================================
+from AthenaCommon.JobProperties import JobProperty, JobPropertyContainer
+from AthenaCommon.JobProperties import jobproperties
+
+class FixedLuminosity(JobProperty):
+   """ Flag to force luminosity (10**33 units) to a given value corresponding to a given mu 
+        Lumi is related to mu by   Lumi = (mu/2.3) * 25ns/BunchSpacing(ns)
+         BunchSpacing should be consistent with what is used from DB, as noise/sqrt(Lumi) depends on BunchSpacing
+       if -1 uses lumi from database (Data) or Beam properties (MC) to perform the sqrt(Lumi) pileup noise scaling
+   """
+   statusOn = True
+   allowedType=['float']
+   StoredValue = -1.
+
+class UseCaloLuminosity(JobProperty):
+   """ Flag to tell to use the luminosity normalization for pileup noise from dedicated calo folder
+       instead of online per LumiBlock
+       Only active if FixedLuminosity is not >0
+   """
+   statusOn = True
+   allowedType=['bool']
+   StoredValue = True
+
+class CaloNoiseFlags(JobPropertyContainer):
+   """ The CaloNoiseFlag container
+   """
+   pass
+
+
+# add container to jobProperties
+jobproperties.add_Container(CaloNoiseFlags)
+
+list_jobproperties = [
+  FixedLuminosity,UseCaloLuminosity
+  ]
+
+for i in list_jobproperties:
+    jobproperties.CaloNoiseFlags.add_JobProperty(i)
+
+del list_jobproperties
diff --git a/Calorimeter/CaloTools/python/CaloNoiseToolDBData.py b/Calorimeter/CaloTools/python/CaloNoiseToolDBData.py
new file mode 100644
index 0000000000000000000000000000000000000000..c01d1ccf48a708aa1583a6e895c60b06d11802a7
--- /dev/null
+++ b/Calorimeter/CaloTools/python/CaloNoiseToolDBData.py
@@ -0,0 +1,71 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+# example of use of CaloNoiseToolDB returning cell noise from Cool DB
+
+from AthenaCommon.Logging import logging 
+from AthenaCommon.SystemOfUnits import *
+from AthenaCommon.Constants import *
+
+# import the base class
+from CaloTools.CaloToolsConf import CaloNoiseToolDB
+
+class CaloNoiseToolDBData(CaloNoiseToolDB) :
+
+    def __init__(self, name="CaloNoiseToolDBData"): 
+        # call base class constructor
+        CaloNoiseToolDB.__init__( self, name)
+
+        mlog = logging.getLogger( 'CaloNoiseToolDBData::__init__ ' )
+        mlog.info("entering")
+
+        from IOVDbSvc.CondDB import conddb
+
+        from CaloTools.CaloNoiseFlags import jobproperties
+        fixedLumi = jobproperties.CaloNoiseFlags.FixedLuminosity()
+        caloLumi  = jobproperties.CaloNoiseFlags.UseCaloLuminosity()
+
+        if conddb.isOnline:
+            folder  = "/CALO/Noise/CellNoise"
+            conddb.addFolder('CALO_ONL',folder)
+            CaloNoiseToolDB.FolderNames=[folder,]
+            if fixedLumi >= 0 :
+                CaloNoiseToolDB.Luminosity = fixedLumi
+                mlog.info("online mode: use fixed luminosity for scaling pileup noise: %f"%fixedLumi)
+            else:
+                if caloLumi:
+                    lumiFolder='/CALO/Noise/PileUpNoiseLumi'
+                    conddb.addFolder('CALO',lumiFolder)
+                    CaloNoiseToolDB.LumiFolderName = lumiFolder
+                    CaloNoiseToolDB.Luminosity = -1.
+                    mlog.info("online mode: use luminosity from /CALO/Noise/PileUpNoiseLumi to scale pileup noise")
+                else:
+                    CaloNoiseToolDB.Luminosity = 0.
+                    mlog.info("online mode: ignore pileup noise")
+        else:
+            folders=[("LAR_OFL","/LAR/NoiseOfl/CellNoise"),
+                     ("TILE_OFL","/TILE/OFL02/NOISE/CELL")
+                     ]
+            #The noise for runs before 2012 is a different folder:
+            if conddb.dbdata=="COMP200":
+                folders.append(("CALO_OFL","/CALO/Ofl/Noise/CellNoise")),
+                
+            for (db,fldr) in folders:
+                conddb.addFolder(db,fldr)
+            CaloNoiseToolDB.FolderNames=[f[1] for f in folders]
+
+            # for luminosity
+            if fixedLumi >= 0 :
+                CaloNoiseToolDB.Luminosity = fixedLumi
+                mlog.info("offline mode: use fixed luminosity for scaling pileup noise: %f"%fixedLumi)
+            else :
+                CaloNoiseToolDB.Luminosity = -1
+                if caloLumi:
+                    lumiFolder='/CALO/Ofl/Noise/PileUpNoiseLumi'
+                    conddb.addFolder('CALO_OFL',lumiFolder)
+                    mlog.info("offline mode: use luminosity from /CALO/Ofl/Noise/PileUpNoiseLumi to scale pileup noise")
+                else:
+                    lumiFolder = '/TRIGGER/LUMI/LBLESTONL'
+                    conddb.addFolder('TRIGGER_ONL',lumiFolder);
+                    mlog.info("offline mode: use luminosity = f(Lumiblock) to scale pileup noise")
+                CaloNoiseToolDB.LumiFolderName = lumiFolder
+
diff --git a/Calorimeter/CaloTools/python/CaloNoiseToolDBMC.py b/Calorimeter/CaloTools/python/CaloNoiseToolDBMC.py
new file mode 100644
index 0000000000000000000000000000000000000000..d8892ad4d255fd93d0dd2e08edb025458e53ab9e
--- /dev/null
+++ b/Calorimeter/CaloTools/python/CaloNoiseToolDBMC.py
@@ -0,0 +1,46 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+# example of use of CaloNoiseToolDB returning cell noise from Cool DB
+
+from AthenaCommon.Logging import logging 
+from AthenaCommon.SystemOfUnits import *
+from AthenaCommon.Constants import *
+
+# import the base class
+from CaloTools.CaloToolsConf import CaloNoiseToolDB
+
+class CaloNoiseToolDBMC(CaloNoiseToolDB) :
+
+    def __init__(self, name="CaloNoiseToolDBMC"): 
+        # call base class constructor
+        CaloNoiseToolDB.__init__( self, name)
+
+        mlog = logging.getLogger( 'CaloNoiseToolDBMC::__init__ ' )
+        mlog.info("entering")
+
+        from IOVDbSvc.CondDB import conddb
+
+        # do the configuration
+        from CaloTools.CaloNoiseFlags import jobproperties
+        if jobproperties.CaloNoiseFlags.FixedLuminosity() >= 0 :
+            self.Luminosity=jobproperties.CaloNoiseFlags.FixedLuminosity()
+            mlog.info("  Luminosity (in 10**33) units used for pileup noise from CaloNoiseFlags : %f"%self.Luminosity)
+        else:
+            if jobproperties.CaloNoiseFlags.UseCaloLuminosity():
+                lumiFolder='/CALO/Ofl/Noise/PileUpNoiseLumi'
+                conddb.addFolder('CALO_OFL',lumiFolder)
+                mlog.info("offline mode: use luminosity from /CALO/Ofl/Noise/PileuUpNoiseLumi to scale pileup noise")
+                self.LumiFolderName = lumiFolder
+                self.Luminosity=-1.
+            else:
+                from AthenaCommon.BeamFlags import jobproperties
+                self.Luminosity=jobproperties.Beam.estimatedLuminosity()/1e+33
+                mlog.info("  Luminosity (in 10**33) units used for pileup noise from BeamFlags : %f"%self.Luminosity)
+
+        folders  = (("CALO_OFL","/CALO/Ofl/Noise/CellNoise"),
+                    ("LAR_OFL","/LAR/NoiseOfl/CellNoise"),
+                    ("TILE_OFL","/TILE/OFL02/NOISE/CELL")
+                   ) 
+        for (db,fldr) in folders:
+            conddb.addFolder(db,fldr)
+        CaloNoiseToolDB.FolderNames=[f[1] for f in folders]
diff --git a/Calorimeter/CaloTools/python/CaloNoiseToolDefault.py b/Calorimeter/CaloTools/python/CaloNoiseToolDefault.py
new file mode 100644
index 0000000000000000000000000000000000000000..9af276d7929e7f8e06146d7373f0866271193ba7
--- /dev/null
+++ b/Calorimeter/CaloTools/python/CaloNoiseToolDefault.py
@@ -0,0 +1,94 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+from AthenaCommon.Logging import logging
+from AthenaCommon.SystemOfUnits import *
+
+def CaloNoiseToolDefault(flag='',name='CaloNoiseToolDefault'):
+
+    # check if tool already exists
+    from AthenaCommon.AppMgr import ServiceMgr as svcMgr
+    if hasattr(svcMgr.ToolSvc, name):
+        # re-use previously configured (public) tool
+        return getattr(svcMgr.ToolSvc, name)
+
+    mlog = logging.getLogger( 'CaloNoiseToolDefault' )
+
+    if flag=='db' :
+       _useDB = True
+    elif flag=='tool' :
+       _useDB = False
+    else :
+       # will put here logic to select according to global flag
+       from AthenaCommon.GlobalFlags import globalflags
+       from AthenaCommon.BeamFlags import jobproperties
+       if globalflags.DataSource()=='data' and globalflags.DetGeo()!='ctbh6' and globalflags.DetGeo()!='ctbh8':
+           _useDB = True
+       elif globalflags.DataSource()=='geant4' and jobproperties.Beam.zeroLuminosity():
+           _useDB = True
+       else:
+          # now uses also calonoisetoolDB for MC with pileup.. requires a new global tag for pileup reco to have the noise properly read
+           _useDB = True
+
+    if _useDB :
+        mlog.info(" Using CaloNoiseToolDB" )
+        from AthenaCommon.GlobalFlags import globalflags
+        if globalflags.DataSource()=='data':
+            from CaloTools.CaloNoiseToolDBData import CaloNoiseToolDBData
+            theTool = CaloNoiseToolDBData(name)
+        else:
+            from CaloTools.CaloNoiseToolDBMC import CaloNoiseToolDBMC
+            theTool = CaloNoiseToolDBMC(name)
+        return theTool
+    else :
+        mlog.info("Using CaloNoiseTool")
+        from CaloTools.CaloToolsConf import CaloNoiseTool
+        # Tile configuration
+        from TileConditions.TileInfoConfigurator import TileInfoConfigurator
+        tileInfoConfigurator = TileInfoConfigurator()
+        tileInfoConfigurator.setupCOOL()
+        
+        # CaloNoiseTool configuration
+        WorkMode=1
+        WithOF=True
+        TileInfoName="TileInfo"
+        # get public tool LArADC2MeVTool
+        from LArRecUtils.LArADC2MeVToolDefault import LArADC2MeVToolDefault
+        theADC2MeVTool = LArADC2MeVToolDefault()
+        from AthenaCommon.AppMgr import ToolSvc
+        ToolSvc += theADC2MeVTool
+        # get public tool LArOFCTool
+        from LArRecUtils.LArOFCToolDefault import LArOFCToolDefault
+        theOFCTool = LArOFCToolDefault()
+        from AthenaCommon.AppMgr import ToolSvc
+        ToolSvc += theOFCTool
+        from AthenaCommon.BeamFlags import jobproperties
+        if jobproperties.Beam.zeroLuminosity(): 
+            ReturnNoise="electronicNoise"
+            NMinBias=0
+            deltaBunch=1
+        else:
+            ReturnNoise="totalNoise"
+            NMinBias=jobproperties.Beam.numberOfCollisions()
+            deltaBunch=int(jobproperties.Beam.bunchSpacing()/( 25.*ns)+0.5)
+        from AthenaCommon.GlobalFlags import globalflags
+        if globalflags.DataSource()=='data':
+            IsMC = False
+            UseSymmetry= False
+        else:
+            IsMC = True
+            UseSymmetry= True
+
+        from LArROD.LArRODFlags import larRODFlags
+        theTool = CaloNoiseTool(name,
+                          WorkMode = WorkMode,
+                          WithOF = WithOF,
+                          TileInfoName = TileInfoName,
+                          LArADC2MeVTool = theADC2MeVTool,
+                          LArOFCTool = theOFCTool,
+                          ReturnNoise = ReturnNoise,
+                          NMinBias = NMinBias,
+                          deltaBunch = deltaBunch,
+                          IsMC = IsMC,
+                          UseSymmetry = UseSymmetry,
+                          firstSample=larRODFlags.firstSample())
+        return theTool
diff --git a/Calorimeter/CaloTools/python/__init__.py b/Calorimeter/CaloTools/python/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..74583d364ec2ca794156596c7254d9b234a940c6
--- /dev/null
+++ b/Calorimeter/CaloTools/python/__init__.py
@@ -0,0 +1,2 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
diff --git a/Calorimeter/CaloTools/share/CaloBadChannelTool_jobOptions.py b/Calorimeter/CaloTools/share/CaloBadChannelTool_jobOptions.py
new file mode 100755
index 0000000000000000000000000000000000000000..abf4bb9b06afd5e1f1dc3a6683d7a31539066356
--- /dev/null
+++ b/Calorimeter/CaloTools/share/CaloBadChannelTool_jobOptions.py
@@ -0,0 +1,15 @@
+#
+# jobOptions for the instance CaloBadChannelTool of ICaloBadChannelTool 
+# 
+theApp.Dlls += [ "CaloTools" ]
+
+ToolSvc = Service( "ToolSvc" )
+
+if 'GlobalFlags.DetGeo' in dir():
+    if( GlobalFlags.DetGeo.is_ctbh8() ) : 
+        ToolSvc.CaloBadChannelTool.geometry='H8'
+    else :
+        ToolSvc.CaloBadChannelTool.geometry='Atlas'
+
+else :
+    ToolSvc.CaloBadChannelTool.geometry='Atlas'
diff --git a/Calorimeter/CaloTools/share/CaloCellPackerUtils_test.ref b/Calorimeter/CaloTools/share/CaloCellPackerUtils_test.ref
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/Calorimeter/CaloTools/share/CaloCompactCellTool_test.txt b/Calorimeter/CaloTools/share/CaloCompactCellTool_test.txt
new file mode 100644
index 0000000000000000000000000000000000000000..0dc9dec0ecec08f4dd40a8450ee42ed712681d19
--- /dev/null
+++ b/Calorimeter/CaloTools/share/CaloCompactCellTool_test.txt
@@ -0,0 +1,2 @@
+ApplicationMgr.DLLs += { "StoreGate", "CLIDComps", "CaloTriggerTool" };
+ApplicationMgr.ExtSvc += { "StoreGateSvc", "StoreGateSvc/DetectorStore" };
diff --git a/Calorimeter/CaloTools/share/CaloNoiseTool_TB_jobOptions.py b/Calorimeter/CaloTools/share/CaloNoiseTool_TB_jobOptions.py
new file mode 100644
index 0000000000000000000000000000000000000000..68ba7964907c8d6a541280bb091f061cb4867af8
--- /dev/null
+++ b/Calorimeter/CaloTools/share/CaloNoiseTool_TB_jobOptions.py
@@ -0,0 +1,81 @@
+
+#jobOptions for Tile part
+include( "TileConditions/TileConditions_jobOptions.py" )
+
+from AthenaCommon.AppMgr import ToolSvc
+#from AthenaCommon.GlobalFlags import globalflags
+from AthenaCommon.GlobalFlags import jobproperties
+
+include("LArRecUtils/LArOFCTool_jobOptions.py")
+include("LArRecUtils/LArAutoCorrTotalTool_jobOptions.py")
+include("LArRecUtils/LArADC2MeVTool_jobOptions.py")
+
+from CaloTools.CaloToolsConf import CaloNoiseTool
+theCaloNoiseTool=CaloNoiseTool("calonoisetool")
+
+
+# Properties
+theCaloNoiseTool.WorkMode=1
+theCaloNoiseTool.WithOF= True
+theCaloNoiseTool.TileInfoName="TileInfo"
+
+# Luminosity
+from AthenaCommon.BeamFlags import jobproperties
+        
+if jobproperties.Beam.zeroLuminosity(): 
+    theCaloNoiseTool.ReturnNoise="electronicNoise"
+    theCaloNoiseTool.NMinBias=0
+    ToolSvc.LArAutoCorrTotalTool.NMinBias=0
+else:
+    theCaloNoiseTool.ReturnNoise="totalNoise"
+    theCaloNoiseTool.NMinBias=jobproperties.Beam.numberOfCollisions()
+    ToolSvc.LArAutoCorrTotalTool.NMinBias=jobproperties.Beam.numberOfCollisions()
+
+_deltaBunch=int(jobproperties.Beam.bunchSpacing()/( 25.*ns)+0.5)
+theCaloNoiseTool.deltaBunch = _deltaBunch
+ToolSvc.LArAutoCorrTotalTool.deltaBunch = _deltaBunch
+del _deltaBunch
+
+ # Concerning CaloNoiseTool and luminosity:
+ # It will take AutoCorr and OFC calculated at the initialization
+ # according to the NMinBias set above (in LArAutoCorrTotalTool).
+ # However if you want/need the expected noise at another luminosity
+ # you can specify another value, then it will take AutoCorr and OFC
+ # accordingly recomputed on-fly
+ # (without affecting the cache of LArAutoCorrTotalTool and LArOFCTool,
+ # so without affecting the reconstruction)
+ # Same thing if you specify the luminosity in the calling functions of
+ # CaloNoiseTool
+
+
+# AutoCorrelation
+#(if the matrix is not normalized (default cse for the moment), normalize it
+# REMOVED
+#if globalflags.DetGeo()=='ctbh8' and globalflags.DataSource()=='data':
+#    theCaloNoiseTool.NormalizeAutoCorr=True
+#    ToolSvc.LArOFCTool.NormalizeAutoCorr=True
+
+# Set data type (needed to decide wether to retrieve LArNoise or LArPedestal for the noise)
+if jobproperties.Global.DataSource()=='data':
+    theCaloNoiseTool.IsMC=False
+
+# No symmetry for testbeam
+if( jobproperties.Global.DetGeo()=='ctbh8' or  jobproperties.Global.DetGeo()=='ctbh6' ) : 
+    theCaloNoiseTool.UseSymmetry=False
+    ToolSvc.LArAutoCorrTotalTool.MCSym = False
+    ToolSvc.LArADC2MeVTool.MCSym = False
+    ToolSvc.LArOFCTool.MCSym = False
+else:    
+    theCaloNoiseTool.UseSymmetry= True
+    ToolSvc.LArAutoCorrTotalTool.MCSym = True
+    ToolSvc.LArADC2MeVTool.MCSym = True
+    ToolSvc.LArOFCTool.MCSym = True
+
+
+    
+# Dump the database (ADC2MEV, OFC, AC, ...) used for each cell (long dump !)
+#theCaloNoiseTool.DumpDatabaseHG=TRUE
+#theCaloNoiseTool.DumpDatabaseMG=TRUE
+#theCaloNoiseTool.DumpDatabaseLG=TRUE
+
+ToolSvc+=theCaloNoiseTool
diff --git a/Calorimeter/CaloTools/share/CaloNoiseTool_jobOptions.py b/Calorimeter/CaloTools/share/CaloNoiseTool_jobOptions.py
new file mode 100755
index 0000000000000000000000000000000000000000..ff440166ff189680ab0bbf8e6e121cc8620bb6ed
--- /dev/null
+++ b/Calorimeter/CaloTools/share/CaloNoiseTool_jobOptions.py
@@ -0,0 +1,80 @@
+
+#jobOptions for Tile part
+include( "TileConditions/TileConditions_jobOptions.py" )
+
+from AthenaCommon.AppMgr import ToolSvc
+from AthenaCommon.GlobalFlags import globalflags
+
+include("LArRecUtils/LArOFCTool_jobOptions.py")
+include("LArRecUtils/LArAutoCorrTotalTool_jobOptions.py")
+include("LArRecUtils/LArADC2MeVTool_jobOptions.py")
+
+from CaloTools.CaloToolsConf import CaloNoiseTool
+theCaloNoiseTool=CaloNoiseTool("calonoisetool")
+
+
+# Properties
+theCaloNoiseTool.WorkMode=1
+theCaloNoiseTool.WithOF= True
+theCaloNoiseTool.TileInfoName="TileInfo"
+
+# Luminosity
+from AthenaCommon.BeamFlags import jobproperties
+        
+if jobproperties.Beam.zeroLuminosity(): 
+    theCaloNoiseTool.ReturnNoise="electronicNoise"
+    theCaloNoiseTool.NMinBias=0
+    ToolSvc.LArAutoCorrTotalTool.NMinBias=0
+else:
+    theCaloNoiseTool.ReturnNoise="totalNoise"
+    theCaloNoiseTool.NMinBias=jobproperties.Beam.numberOfCollisions()
+    ToolSvc.LArAutoCorrTotalTool.NMinBias=jobproperties.Beam.numberOfCollisions()
+
+_deltaBunch=int(jobproperties.Beam.bunchSpacing()/( 25.*ns)+0.5)
+theCaloNoiseTool.deltaBunch = _deltaBunch
+ToolSvc.LArAutoCorrTotalTool.deltaBunch = _deltaBunch
+del _deltaBunch
+
+ # Concerning CaloNoiseTool and luminosity:
+ # It will take AutoCorr and OFC calculated at the initialization
+ # according to the NMinBias set above (in LArAutoCorrTotalTool).
+ # However if you want/need the expected noise at another luminosity
+ # you can specify another value, then it will take AutoCorr and OFC
+ # accordingly recomputed on-fly
+ # (without affecting the cache of LArAutoCorrTotalTool and LArOFCTool,
+ # so without affecting the reconstruction)
+ # Same thing if you specify the luminosity in the calling functions of
+ # CaloNoiseTool
+
+
+# AutoCorrelation
+#(if the matrix is not normalized (default cse for the moment), normalize it
+# REMOVED
+#if globalflags.DetGeo()=='ctbh8' and globalflags.DataSource()=='data':
+#    theCaloNoiseTool.NormalizeAutoCorr=True
+#    ToolSvc.LArOFCTool.NormalizeAutoCorr=True
+
+# Set data type (needed to decide wether to retrieve LArNoise or LArPedestal for the noise)
+if GlobalFlags.DataSource()=='data':
+    theCaloNoiseTool.IsMC=False
+
+# No symmetry for testbeam
+if( GlobalFlags.DetGeo()=='ctbh8' or  GlobalFlags.DetGeo()=='ctbh6' ) : 
+    theCaloNoiseTool.UseSymmetry=False
+    ToolSvc.LArAutoCorrTotalTool.MCSym = False
+    ToolSvc.LArADC2MeVTool.MCSym = False
+    ToolSvc.LArOFCTool.MCSym = False
+else:    
+    theCaloNoiseTool.UseSymmetry= True
+    ToolSvc.LArAutoCorrTotalTool.MCSym = True
+    ToolSvc.LArADC2MeVTool.MCSym = True
+    ToolSvc.LArOFCTool.MCSym = True
+
+
+    
+# Dump the database (ADC2MEV, OFC, AC, ...) used for each cell (long dump !)
+#theCaloNoiseTool.DumpDatabaseHG=TRUE
+#theCaloNoiseTool.DumpDatabaseMG=TRUE
+#theCaloNoiseTool.DumpDatabaseLG=TRUE
+
+ToolSvc+=theCaloNoiseTool
diff --git a/Calorimeter/CaloTools/share/SimpleNoiseToolFromTextFile_jobOptions.py b/Calorimeter/CaloTools/share/SimpleNoiseToolFromTextFile_jobOptions.py
new file mode 100755
index 0000000000000000000000000000000000000000..529cafc37979f0dd2edcb864e6be6d0f1b7638b2
--- /dev/null
+++ b/Calorimeter/CaloTools/share/SimpleNoiseToolFromTextFile_jobOptions.py
@@ -0,0 +1,9 @@
+#
+# jobOptions for the instance simplenoisetool of SimpleNoiseToolFromTextFile
+# 
+ToolSvc = Service( "ToolSvc" )
+ToolSvc.simplenoisetool.CellNoiseFileName = "/afs/cern.ch/user/h/hectbmon/public/tb/aug02/noise/H6_2002NoiseMuons.dat"
+ToolSvc.simplenoisetool.CellNoiseUnits = MeV
+ToolSvc.simplenoisetool.CellNoiseDefault = 100.*MeV
+ToolSvc.simplenoisetool.CellNoiseDefaultWarning = TRUE
+ToolSvc.simplenoisetool.OutputLevel = INFO
diff --git a/Calorimeter/CaloTools/src/CaloAffectedTool.cxx b/Calorimeter/CaloTools/src/CaloAffectedTool.cxx
new file mode 100755
index 0000000000000000000000000000000000000000..ea20542449df4fba2f375a72cd25bb49e7e5962f
--- /dev/null
+++ b/Calorimeter/CaloTools/src/CaloAffectedTool.cxx
@@ -0,0 +1,265 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "CaloTools/CaloAffectedTool.h" 
+//#include "EventKernel/I4Momentum.h"
+#include "xAODBase/IParticle.h"
+#include "GaudiKernel/MsgStream.h"
+#include "StoreGate/StoreGateSvc.h"
+#include "CaloConditions/CaloAffectedRegionInfoVec.h"
+#include "AthenaPoolUtilities/CondAttrListCollection.h"
+#include "CaloGeoHelpers/CaloPhiRange.h"
+
+
+CaloAffectedTool::CaloAffectedTool (const std::string& type, 
+				  const std::string& name, 
+				  const IInterface* parent) :
+    AthAlgTool(type, name, parent),
+    m_readRaw(true)
+{ 
+  m_affectedRegions=0;
+  declareInterface<ICaloAffectedTool>(this);
+  declareProperty("readRaw",m_readRaw);
+}
+                                                                                
+//-----------------------------------------------------------------
+
+CaloAffectedTool::~CaloAffectedTool() {
+  if (m_affectedRegions && !m_readRaw) delete m_affectedRegions;
+}
+
+
+//-------------------------------------------------------------------
+
+StatusCode CaloAffectedTool::initialize() {
+
+  MsgStream log( msgSvc(), name() );
+
+  if (!m_readRaw) {
+   if (detStore()->contains<CondAttrListCollection>("/LAR/LArAffectedRegionInfo")) {
+      const DataHandle<CondAttrListCollection> affectedRegionH;
+      if (detStore()->regFcn(&CaloAffectedTool::updateAffectedRegionsFromDB,
+                          this,
+                          affectedRegionH,
+                          "/LAR/LArAffectedRegionInfo").isSuccess()) {
+            if (log.level() <= MSG::DEBUG)
+                log << MSG::DEBUG << "Registered callback for  LArAffectedRegion " << endreq; 
+      }
+        else {
+             log << MSG::WARNING << "Cannot register callback for LArAffectedRegion " << endreq; 
+      }
+   }
+    else {  
+      log << MSG::WARNING << " no LArAffectedRegion information available from metadata " << endreq; 
+   }
+  }
+  else {
+    // register incident handler for begin event
+    IIncidentSvc* incSvc; 
+    if (service( "IncidentSvc", incSvc ).isFailure()) {
+      log << MSG::ERROR << "Unable to get the IncidentSvc" << endreq; 
+      return StatusCode::FAILURE;
+    }
+    long int priority=100;
+    incSvc->addListener(this,"BeginEvent",priority);
+
+  }
+
+  m_read=false;
+  return StatusCode::SUCCESS;
+}
+
+//---------------------------------------------------------
+
+void CaloAffectedTool::handle(const Incident& inc) {
+
+   MsgStream log(msgSvc(), name()); 
+
+  if (inc.type()!="BeginEvent")
+    return; 
+
+  if (detStore()->contains<CaloAffectedRegionInfoVec>("LArAffectedRegion")) {
+     if (detStore()->retrieve(m_affectedRegions,"LArAffectedRegion").isFailure()) {
+      log << MSG::WARNING << " cannot read LArAffectedRegion at begin of event " << endreq;
+      return;
+     }
+     m_read=true;
+     //std::cout << " got affected regions at beginning of event " << std::endl;
+     return;
+  }
+  return;
+
+}
+
+
+//--------------------------------------------------
+
+StatusCode CaloAffectedTool::updateAffectedRegionsFromDB(IOVSVC_CALLBACK_ARGS) {
+
+  return this->readDB();
+}
+
+StatusCode  CaloAffectedTool::readDB() {
+
+  MsgStream log(msgSvc(), name());   // Part 1: Get the messaging service, print where you are
+  log << MSG::INFO << "updateAffectedRegionsFromDB()" << endreq;
+
+  // retrieve from detStore
+  const CondAttrListCollection* attrListColl = 0;
+  StatusCode sc = detStore()->retrieve(attrListColl, "/LAR/LArAffectedRegionInfo");
+  if (sc.isFailure()) {
+     log << MSG::WARNING  << "attrrListColl not found for /LAR/CaloAffectedRegionInfo " << endreq;
+     return StatusCode::SUCCESS;
+  }
+
+  if (m_affectedRegions) {
+     m_affectedRegions->clear();
+  }
+  else  {
+     m_affectedRegions =  new CaloAffectedRegionInfoVec();
+  }
+
+  // Loop over collection
+  CondAttrListCollection::const_iterator first = attrListColl->begin();
+  CondAttrListCollection::const_iterator last  = attrListColl->end();
+  for (; first != last; ++first) {
+      std::ostringstream attrStr1;
+      (*first).second.toOutputStream( attrStr1 );
+      log << MSG::DEBUG << "ChanNum " << (*first).first <<
+          " Attribute list " << attrStr1.str() << endreq;
+      //      const AttributeList& attrList = (*first).second;
+      const coral::AttributeList& attrList = (*first).second;
+      CaloAffectedRegionInfo info;
+      float eta_min = attrList["eta_min"].data<float>();
+      float eta_max = attrList["eta_max"].data<float>();
+      float phi_min = attrList["phi_min"].data<float>();
+      float phi_max = attrList["phi_max"].data<float>();
+      int layer_min = attrList["layer_min"].data<int>();
+      int layer_max = attrList["layer_max"].data<int>();
+      //std::cout << " affected region found " << eta_min << " " << eta_max << " " << phi_min << " " << phi_max << " " << layer_min << " " << layer_max << " " << attrList["problem"].data<int>() << std::endl;
+      CaloAffectedRegionInfo::type_problem problem = (CaloAffectedRegionInfo::type_problem)(attrList["problem"].data<int>());
+
+      info.FillCaloAffectedRegionInfo(eta_min,eta_max,phi_min,phi_max,layer_min,layer_max,problem);
+      m_affectedRegions->push_back(info);
+  }
+
+  m_read = true;
+  return StatusCode::SUCCESS;
+
+}
+
+//-------------------------------------------------
+
+bool CaloAffectedTool::isAffected(const xAOD::IParticle *p, float deta, float dphi, int layer_min, int layer_max, int problemType) 
+{
+
+  static CaloPhiRange _range;
+ static float epsilon=1e-6;
+
+  //std::cout << " in isAffected " << p->eta() << " " << p->phi() << std::endl;
+  if (!m_read &&  !m_readRaw) {
+   if (this->readDB().isFailure()) return false;
+  }
+  if (!m_read) return false;
+  if (!m_affectedRegions) return false;
+
+  std::vector<CaloAffectedRegionInfo>::const_iterator reg1 = m_affectedRegions->begin();
+  std::vector<CaloAffectedRegionInfo>::const_iterator reg2 = m_affectedRegions->end();
+  for (;reg1 != reg2; ++reg1) {
+    const CaloAffectedRegionInfo* region = &(*reg1);
+
+    int problem=region->get_problem();
+    //std::cout << " problem,problemType " << problem << " " << problemType << std::endl;
+    if (problemType>=0 && (problem != problemType)) continue;
+
+    int layermin=region->get_layer_min();
+    int layermax=region->get_layer_max();
+    //std::cout << " layermin, layermax " << layermin << " " << layermax << std::endl;
+    if ((layer_max>=layer_min) && (layermax < layer_min || layermin > layer_max)) continue;
+
+
+    float etamin=region->get_eta_min();
+    float etamax=region->get_eta_max();
+    float eta = p->eta();
+    //std::cout << " eta region " << etamin << " " << etamax << std::endl;
+    if ((eta+deta)<etamin || (eta-deta)>etamax) continue;
+
+    float phimin=region->get_phi_min();
+    float phimax=region->get_phi_max();
+    float phi = p->phi();
+    //std::cout << " phi region " << phimin << " " << phimax << std::endl;
+    float phi2 =_range.fix(phi+dphi+epsilon);
+    float phi1 =_range.fix(phi-dphi-epsilon);
+
+    if ((phimax >= phimin) && (phi2 >= phi1) && (phi2<phimin || phi1>phimax)) continue;
+    if ((phimax >= phimin) && (phi2 <= phi1) && (phi1>phimax && phi2<phimin)) continue;
+    if ((phimax <= phimin) && (phi2 >= phi1) && (phi1>phimax && phi2<phimin)) continue;
+
+    //std::cout << " in region " << std::endl;
+
+    return true;
+
+  }
+
+  return false;
+
+}
+//-------------------------------------------------
+
+bool CaloAffectedTool::listAffected(const xAOD::IParticle*p, std::vector<int>& layer_list, std::vector<int>& problem_list, float deta, float dphi, int problemType)
+{
+
+  bool found = false;
+
+  static CaloPhiRange _range;
+  static float epsilon=1e-6;
+
+  layer_list.clear();
+  problem_list.clear();
+
+  if (!m_read && !m_readRaw ) {
+   if (this->readDB().isFailure()) return false;
+  }
+  if (!m_read) return false;
+  if (!m_affectedRegions) return false;
+
+  std::vector<CaloAffectedRegionInfo>::const_iterator reg1 = m_affectedRegions->begin();
+  std::vector<CaloAffectedRegionInfo>::const_iterator reg2 = m_affectedRegions->end();
+  for (;reg1 != reg2; ++reg1) {
+    const CaloAffectedRegionInfo* region = &(*reg1);
+
+    int problem=region->get_problem();
+    if (problemType>=0 && (problem != problemType)) continue;
+
+    int layermin=region->get_layer_min();
+    int layermax=region->get_layer_max();
+
+    float etamin=region->get_eta_min();
+    float etamax=region->get_eta_max();
+    float eta = p->eta();
+    if ((eta+deta)<etamin || (eta-deta)>etamax) continue;
+
+    float phimin=region->get_phi_min();
+    float phimax=region->get_phi_max();
+    float phi = p->phi();
+    float phi2 =_range.fix(phi+dphi+epsilon);
+    float phi1 =_range.fix(phi-dphi-epsilon);
+
+    if ((phimax >= phimin) && (phi2 >= phi1) && (phi2<phimin || phi1>phimax)) continue;
+    if ((phimax >= phimin) && (phi2 <= phi1) && (phi1>phimax && phi2<phimin)) continue;
+    if ((phimax <= phimin) && (phi2 >= phi1) && (phi1>phimax && phi2<phimin)) continue;
+
+    found = true;
+
+    for (int ilayer=layermin;ilayer<=layermax;ilayer++) {
+        layer_list.push_back(ilayer);
+        problem_list.push_back(problem);
+    }
+
+
+  }
+
+  return found;
+
+}
diff --git a/Calorimeter/CaloTools/src/CaloCellPackerUtils.cxx b/Calorimeter/CaloTools/src/CaloCellPackerUtils.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..5d290cebb8de21bca49e645f6dbbe7a200c2aaad
--- /dev/null
+++ b/Calorimeter/CaloTools/src/CaloCellPackerUtils.cxx
@@ -0,0 +1,71 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+// $Id: CaloCellPackerUtils.cxx,v 1.1 2007-11-08 18:14:22 ssnyder Exp $
+/**
+ * @file CaloTools/src/CaloCellPackerUtils.cxx
+ * @author scott snyder
+ * @date Nov 2007
+ * @brief Utilities for compacting calorimeter cells.
+ */
+
+
+#include "CaloTools/CaloCellPackerUtils.h"
+#include <cassert>
+
+
+namespace CaloCellPackerUtils {
+
+
+/**
+ * @brief Constructor.
+ * @param The bit mask.  Should contain a single contiguous string of 1's.
+ */
+Bitfield::Bitfield (unsigned int mask /*= 1*/)
+{
+  // Shift the mask until the rightmost bit is non-zero.
+  assert (mask != 0);
+  m_shift = 0;
+  while ((mask & 1) == 0) {
+    mask >>= 1;
+    ++m_shift;
+  }
+  m_mask = mask;
+}
+
+
+/**
+ * @brief Constructor.
+ * @param The bit mask.  Should contain a single contiguous string of 1's.
+ * @param xmin The smallest storable value.
+ * @param xmax The largest storable value.
+ */
+Floatfield::Floatfield (unsigned int mask/*=1*/,
+                        double xmin/*=1*/,
+                        double xmax/*=0*/)
+  : Bitfield (mask),
+    m_xmin (xmin),
+    m_xmax (xmax),
+    m_fact ((xmax-xmin) / (m_mask + 1)),
+    m_ifact (1/m_fact)
+{
+}
+
+
+/**
+ * @brief Constructor.
+ * @param The bit mask.  Should contain a single contiguous string of 1's.
+ * @param xmax The largest storable value.
+ */
+Floatfield2::Floatfield2 (unsigned int mask/*=1*/,
+                          double xmax/*=1*/)
+  : Bitfield (mask),
+    m_xmax (xmax),
+    m_fact (xmax / (m_mask + 1)),
+    m_ifact (1/m_fact)
+{
+}
+
+
+} // namespace CaloCellPackerUtils
diff --git a/Calorimeter/CaloTools/src/CaloCellPacker_400_500.cxx b/Calorimeter/CaloTools/src/CaloCellPacker_400_500.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..1cb8a06280183c1d407d330da9eb2e4ecc9fb332
--- /dev/null
+++ b/Calorimeter/CaloTools/src/CaloCellPacker_400_500.cxx
@@ -0,0 +1,1147 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+// $Id: CaloCellPacker_400_500.cxx,v 1.5 2009-03-31 19:04:04 ssnyder Exp $
+/**
+ * @file CaloTools/src/CaloCellPacker_400_500.cxx
+ * @author scott snyder, from earlier code by Ilija Vukotic and Sven Menke
+ * @date Jan 2009
+ * @brief Calo cell packer/unpacker v400/500.
+ */
+
+
+#include "CaloTools/CaloCellPacker_400_500.h"
+#include "CaloEvent/CaloCellContainer.h"
+#include "CaloEvent/CaloCompactCellContainer.h"
+#include "CaloEvent/CaloCell.h"
+#include "TileEvent/TileCell.h"
+#include "CaloInterface/ICaloCompactCellTool.h"
+#include "CaloDetDescr/CaloDetDescrManager.h"
+#include "AthenaKernel/errorcheck.h"
+#include "GaudiKernel/SystemOfUnits.h"
+
+
+//============================================================================
+// Common methods.
+//
+
+
+/**
+ * @brief Initialize header with the current version of the packing
+ *        parameters.  (Almost) all the constants are defined here.
+ * @param header The header to initialize.
+ * @param version The version of the header to initialize.
+ */
+void CaloCellPacker_400_500::init_header (header& header,
+                                          int version) const
+{
+  header.m_version = version;
+  switch (version) {
+  case ICaloCompactCellTool::VERSION_501:
+  case ICaloCompactCellTool::VERSION_502:
+  case ICaloCompactCellTool::VERSION_503:
+  case ICaloCompactCellTool::VERSION_504:
+    header.m_length = sizeof(header501)/sizeof(int);
+    break;
+
+  case ICaloCompactCellTool::VERSION_500:
+    header.m_length = sizeof(header500)/sizeof(int);
+    break;
+  case ICaloCompactCellTool::VERSION_400:
+    header.m_length = sizeof(header400)/sizeof(int);
+    break;
+  default:
+    std::abort();
+  }
+
+  header.m_qualy_mask = 0x8000;
+  header.m_egain_mask = 0x6000;
+  header.m_esign_mask = 0x1000;
+  // 12 bits for cbrt(|E|) and 2 ranges, one normal
+  // resolution range with upper limit 3.2 TeV and precision loss
+  // sigma_E'/E < 1.4%/sqrt(E/GeV) and one high-resolution range used
+  // whenever E < 50 GeV and the hardware gain is HIGH (HEC: MEDIUM)
+  // resulting in a precision loss of sigma_E'/E < 0.15%/sqrt(E/GeV)
+  header.m_crtae_mask = 0x0fff;
+  header.m_egain_tile_mask = 0x4000;
+  header.m_esign_tile_mask = 0x2000;
+  // 13 bits cbrt(|E|) and 2 ranges
+  // upper limit for low gain is 3.2 TeV,
+  // upper limit for high gain is 50 GeV (safety factor of ~3)
+  header.m_crtae_tile_mask = 0x1fff;
+  header.m_tsign_mask = 0x8000;
+  header.m_logat_mask = 0x7fff;
+
+  header.m_qabad = 0;
+  header.m_enlow = 0; // normal resolution LOW gain
+  header.m_enmed = 1; // normal resolution MEDIUM gain
+  header.m_enhig = 2; // normal resolution HIGH gain
+  header.m_ehhig = 3; // high resolution HIGH (HEC: MEDIUM) gain
+  header.m_glow  =  TileID::LOWGAIN;
+  header.m_ghigh = TileID::HIGHGAIN;
+
+  header.m_e1_norm_res  = 3.2*Gaudi::Units::TeV;
+  header.m_e1_high_res  = 50*Gaudi::Units::GeV;
+  header.m_high_tile = 50*Gaudi::Units::GeV;
+  header.m_low_tile  = 3.2*Gaudi::Units::TeV;
+  header.m_t0    = 0.001*Gaudi::Units::ns;
+  header.m_t1    = 1250.0*Gaudi::Units::ns;
+
+  clear_header(header);
+}
+
+
+/**
+ * @brief Clear the counters in the event header.
+ * @param header The header to clear.
+ */
+void CaloCellPacker_400_500::clear_header (header& header) const
+{
+  header.m_ncells_larem = 0;
+  header.m_ncells_larhec = 0;
+  header.m_ncells_larfcal = 0;
+  header.m_ncells_tile  = 0;
+  header.m_seq_larem = 0;
+  header.m_seq_larhec = 0;
+  header.m_seq_larfcal = 0;
+  header.m_seq_tile = 0;
+  header.m_lengthProvenance = 0;
+  header.m_status = 0;
+}
+
+
+/**
+ * @brief Initialize the derived packing parameters from the constants
+ *        in the header.
+ * @param pars The packing parameters.
+ */
+void CaloCellPacker_400_500::init_derived (pars500& pars) const
+{
+  // Good quality flag.
+  pars.m_qgood = 1;
+
+  // Set up parameters for packing/unpacking the sequence header.
+  pars.m_hash_field = CaloCellPackerUtils::Bitfield (0x0003ffff);
+  pars.m_nseq_field = CaloCellPackerUtils::Bitfield (0xfffc0000);
+  pars.m_nseq_max = 0x3fff;
+
+  // Set up parameters for packing/unpacking the provenance list.
+  pars.m_prov_field     = CaloCellPackerUtils::Bitfield (0xfff80000);
+  pars.m_prov_max = 0x1fff;
+  pars.m_prov_max_tile = 0x1f1f;
+
+  // Cube roots of energy ranges.
+  pars.m_cbrt_e1_norm_res = cbrt(pars.m_e1_norm_res);
+  pars.m_cbrt_e1_high_res = cbrt(pars.m_e1_high_res);
+  pars.m_cbrt_low_tile = cbrt(pars.m_low_tile);
+  pars.m_cbrt_high_tile = cbrt(pars.m_high_tile);
+
+  // Logarithms of time ranges.
+  pars.m_log_t0 = log(pars.m_t0);
+  pars.m_log_t1 = log(pars.m_t1);
+
+  // Fill in remaining bit fields.
+  pars.m_qualy_field = CaloCellPackerUtils::Bitfield (pars.m_qualy_mask);
+  pars.m_egain_field = CaloCellPackerUtils::Bitfield (pars.m_egain_mask);
+  pars.m_crtae_norm_field =
+    CaloCellPackerUtils::Floatfield2 (pars.m_crtae_mask,
+                                      pars.m_cbrt_e1_norm_res);
+  pars.m_crtae_high_field =
+    CaloCellPackerUtils::Floatfield2 (pars.m_crtae_mask,
+                                      pars.m_cbrt_e1_high_res);
+  pars.m_logat_field =
+    CaloCellPackerUtils::Floatfield (pars.m_logat_mask,
+                                     pars.m_log_t0, pars.m_log_t1);
+  pars.m_egain_tile_field =
+    CaloCellPackerUtils::Bitfield (pars.m_egain_tile_mask);
+  pars.m_crtae_tile_high_field =
+    CaloCellPackerUtils::Floatfield2 (pars.m_crtae_tile_mask,
+                                      pars.m_cbrt_high_tile);
+  pars.m_crtae_tile_low_field =
+    CaloCellPackerUtils::Floatfield2 (pars.m_crtae_tile_mask,
+                                      pars.m_cbrt_low_tile);
+
+  pars.m_tile_qual1_field   = CaloCellPackerUtils::Bitfield (0x00ff);
+  pars.m_tile_qual2_field   = CaloCellPackerUtils::Bitfield (0xff00);
+
+  // Dummy flags.
+  pars.m_lar_dummy =
+    pars.m_egain_field.in (pars.m_enhig) |
+    pars.m_qualy_field.in (pars.m_qabad) |
+    pars.m_crtae_norm_field.in (cbrt (pars.m_e1_norm_res)) |
+    pars.m_esign_mask;
+
+  pars.m_tile_dummy =
+        pars.m_egain_tile_field.in (pars.m_glow) |
+        pars.m_qualy_field.in (pars.m_qabad) |
+        pars.m_crtae_tile_high_field.in (pars.m_cbrt_high_tile) |
+        pars.m_esign_tile_mask;
+
+  
+  {
+    CaloCellPackerUtils::Bitfield& elar = pars.m_crtae_norm_field;
+    pars.m_lar_dummy_subst = (pars.m_lar_dummy & ~pars.m_crtae_mask) |
+      elar.in (elar.out (pars.m_lar_dummy)-1);
+
+    CaloCellPackerUtils::Bitfield& etile = pars.m_crtae_tile_high_field;
+    pars.m_tile_dummy_subst = (pars.m_tile_dummy & ~pars.m_crtae_tile_mask) |
+      etile.in (etile.out (pars.m_tile_dummy)-1);
+  }    
+}
+
+
+//============================================================================
+// Packing.
+// To ensure full inlining, don't reorder these.
+//
+
+
+/**
+ * @brief Pack a time value.
+ * @param time The time to pack.
+ * @param it The iterator into which to pack.
+ * @param pars The packing parameters.
+ */
+inline
+void CaloCellPacker_400_500::pack_time
+   (float time,
+    CaloCompactCellContainer::compact_output_iterator& it,
+    const pars500& pars) const
+{
+  // We want to pack log(abs(time)).
+  float ltime = pars.m_log_t0;
+  if (time != 0)
+    ltime = log(fabs(time));
+
+  // Pack it into the bitfield.
+  CaloCompactCell::value_type data = pars.m_logat_field.in (ltime);
+
+  // Set the sign bit.
+  if ( time < 0 )
+    data |= pars.m_tsign_mask;
+
+  // Fill output.
+  it.set (data);
+}
+
+
+/**
+ * @brief Pack one LAr cell.
+ * @param cell The cell to pack.
+ * @param subcalo The cell's subcalorimeter code.
+ * @param it The iterator into which to pack.
+ * @param pars The packing parameters.
+ */
+inline
+void CaloCellPacker_400_500::pack_lar
+   (const CaloCell* cell,
+    CaloCell_ID::SUBCALO subcalo,
+    CaloCompactCellContainer::compact_output_iterator& it,
+    const pars500& pars) const
+{
+  // Get values from the cell.
+  double energy  = cell->energy();
+  double time    = cell->time();
+  int qualflag;
+  if( (cell->provenance() & 0x2000) == 0x2000 )
+    qualflag=pars.m_qgood;
+  else
+    qualflag=pars.m_qabad;
+
+  int gain       = cell->gain();
+
+  // Figure out which gain to use.
+  // cbrt_flag is set to 1 for the high gain range (50 GeV) and 0 for
+  // the low gain range (3.2 TeV).
+  int gainflag = -999;
+  int cbrt_flag = 0;
+  switch ( gain ) {
+  case CaloGain::LARLOWGAIN:
+    gainflag = pars.m_enlow;
+    break;
+  case CaloGain::LARMEDIUMGAIN:
+    if ( subcalo == CaloCell_ID::LARHEC &&
+         fabs(energy) < pars.m_e1_high_res )
+    {
+      gainflag = pars.m_ehhig;
+      cbrt_flag = 1;
+    }
+    else
+      gainflag = pars.m_enmed;
+    break;
+  case CaloGain::LARHIGHGAIN:
+    if ( fabs(energy) < pars.m_e1_high_res &&
+         subcalo != CaloCell_ID::LARHEC )
+    {
+      gainflag = pars.m_ehhig;
+      cbrt_flag = 1;
+    }
+    else
+      gainflag = pars.m_enhig;
+    break;
+
+  default:
+    // Some invalid gain.  Mark as an error.
+    gainflag = -999;
+  }
+
+  if (gainflag == -999) {
+    it.set (pars.m_lar_dummy);
+   }
+  else {
+    // Pack the energy, gain, and quality into the output word.
+    double crtae = cbrt(fabs(energy));
+    CaloCompactCell::value_type data =
+      pars.m_egain_field.in (gainflag) |
+      pars.m_qualy_field.in (qualflag) |
+      (cbrt_flag ? pars.m_crtae_high_field.in (crtae)
+       : pars.m_crtae_norm_field.in (crtae));
+
+    // Set the sign bit.
+    if (energy < 0)
+      data |= pars.m_esign_mask;
+
+    if (data == pars.m_lar_dummy)
+      data = pars.m_lar_dummy_subst;
+
+    // Fill the output container.
+    it.set (data);
+
+    // If quality is not bad there are time and quality (chi^2) measurements.
+    if ( qualflag != pars.m_qabad){
+      pack_time (time, it, pars);
+      if (pars.m_version >= 500)
+        it.set(cell->quality());
+    }
+  }
+}
+
+
+/**
+ * @brief Pack one tile cell.
+ * @param cell The cell to pack.
+ * @param it The iterator into which to pack.
+ * @param pars The packing parameters.
+ */
+inline
+void CaloCellPacker_400_500::pack_tile
+   (const TileCell* cell,
+    CaloCompactCellContainer::compact_output_iterator& it,
+    const pars500& pars) const
+{
+  // Tile cells have two separate measurements to pack.
+  // Retrieve them both:
+  double ene[2] = {cell->ene1(), cell->ene2()};
+  double time[2] = {cell->time1(), cell->time2()};
+  int qbit[2] = {cell->qbit1(), cell->qbit2()};
+  int gain[2] = {cell->gain1(), cell->gain2()};
+
+  // Loop over the two measurements (PMTs).
+  // If no cell both gains are bad;
+  // if only one pmt per cell, second gain is bad.
+  bool write_qual = false;
+  for (int ipmt=0; ipmt<2; ++ipmt) {
+    // We'll set this to true if we want to write time information.
+    bool write_time = false;
+
+    // The data word we're building.
+    CaloCompactCell::value_type data;
+
+    // Does this measurement exist?
+    if (gain[ipmt] == CaloGain::INVALIDGAIN) {
+      // No --- make a dummy.
+      data = pars.m_tile_dummy;
+    }
+    else {
+      // Yes --- we have a measurement.  See if the quality's good.
+      // If so, then we'll want to write the time too.
+      int qualflag = pars.m_qabad;
+      if (qbit[ipmt] >= TileCell::KEEP_TIME) {
+        qualflag = pars.m_qgood;
+        write_time = true;
+        write_qual = true;
+      }
+
+      // Pack the energy, with the proper range, depending on the gain.
+      double crtae = cbrt(fabs(ene[ipmt]));
+      if (gain[ipmt] != pars.m_glow)
+        data = pars.m_crtae_tile_high_field.in (crtae);
+      else
+        data = pars.m_crtae_tile_low_field.in (crtae);
+
+      // Add in the gain and quality.
+      data |=
+        pars.m_egain_tile_field.in (gain[ipmt]) |
+        pars.m_qualy_field.in (qualflag);
+
+      // Add the sign bit.
+      if (ene[ipmt] < 0)
+        data |= pars.m_esign_tile_mask;
+
+      if (data == pars.m_tile_dummy)
+        data = pars.m_tile_dummy_subst;
+    }
+
+    // Fill to the output container.
+    it.set (data);
+
+    // Fill the time and quality, if needed.
+    if (write_time)
+      pack_time (time[ipmt], it, pars);
+  }
+
+  if (pars.m_version >= 502 && write_qual) {
+    it.set (cell->quality());
+  }
+}
+
+
+/**
+ * @brief Finish up one cell sequence.
+ * @param hash The hash of the first cell in the sequence.
+ * @param nseq The number of cells in the sequence.
+ * @param it Iterator pointing at the beginning of the sequence.
+ * @param subcalo Subcalorimeter code for the sequence.
+ * @param pars The packing parameters.
+ */
+inline
+void CaloCellPacker_400_500::finish_seq
+   (unsigned int hash,
+    unsigned int nseq,
+    CaloCompactCellContainer::compact_output_iterator& it,
+    CaloCell_ID::SUBCALO subcalo,
+    pars500& pars) const
+{
+  // Pack the hash code and number of cells into a bitfield.
+  CaloCompactCellContainer::value_type data =
+    pars.m_hash_field.in(hash) | pars.m_nseq_field.in(nseq);
+
+  // Write it into the output container.
+  it.set ((data>>16) & 0xffff);
+  it.set (data & 0xffff);
+
+  // Update counters.
+  switch (subcalo) {
+  case CaloCell_ID::LAREM:
+    pars.m_ncells_larem += nseq;
+    ++pars.m_seq_larem;
+    break;
+  case CaloCell_ID::LARHEC:
+    pars.m_ncells_larhec += nseq;
+    ++pars.m_seq_larhec;
+    break;
+  case CaloCell_ID::LARFCAL:
+    pars.m_ncells_larfcal += nseq;
+    ++pars.m_seq_larfcal;
+    break;
+  case CaloCell_ID::TILE:
+    pars.m_ncells_tile += nseq;
+    ++pars.m_seq_tile;
+    break;
+  default:
+    std::abort();
+  }
+}
+
+
+/**
+ * @brief Pack cells.
+ * @param cells The input cell container.
+ * @param packed The output packed cell container.
+ * @param version The version of the header to initialize.
+ */
+void CaloCellPacker_400_500::pack (const CaloCellContainer& cells,
+                                   CaloCompactCellContainer& packed,
+                                   int version) const
+{
+  // Set up the header and derived parameters.
+  pars500 pars;
+  init_header (pars, version);
+  init_derived (pars);
+
+  std::vector<short unsigned int> vProvenance;
+
+  // Figure out an upper limit for the container size.
+  // Header, plus one word/cell for sequence, two words/cell for data,
+  // and another word/cell for provenance.
+  // Tile cells have two additional words/cell - energy and time for second PMT.
+  // Add one more to account for possible padding before the provenance info.
+  // We'll resize this down correctly when we're done.
+  unsigned int maxsize =
+    pars.m_length + 4 * cells.size() + 2 * cells.nCellsCalo (CaloCell_ID::TILE)+1;
+  packed.resize (maxsize);
+
+  // Set up for loop over cells.
+
+  // This is the output iterator, to which we write.
+  CaloCompactCellContainer::compact_output_iterator outit
+    (packed.compact_begin_output (pars.m_length));
+
+  // Here we save the output iterator at the beginning of each sequence.
+  // We'll use that to go back and plug in the count when we're done.
+  CaloCompactCellContainer::compact_output_iterator seqit
+    (packed.compact_begin_output (pars.m_length));
+
+  // The hash of the first cell in the current sequence.
+  unsigned int seqhash = static_cast<unsigned int> (-1);
+
+  // Number of cells so far in the current sequence.
+  // 0 if not in a sequence.
+  unsigned int nseq = 0;
+
+  // The subcalorimeter code of the previous cell we looked at.
+  CaloCell_ID::SUBCALO prevcalo = CaloCell_ID::NOT_VALID;
+
+  // If all the cells have provenance 0, there is nothing in the vector.
+  short unsigned int prevCellProvenance=0;
+
+  // check if it is a SuperCell
+  bool is_SC=false; 
+  if (cells.size()>0){
+    // assuming no mixed SC and Cells. 
+    const CaloDetDescrElement* dde = cells[0]->caloDDE();
+    const CaloCell_Base_ID* idhelper =
+      dde->descriptor()->get_calo_helper();
+    is_SC = idhelper->is_supercell(cells[0]->ID());
+  }
+
+  if (is_SC)
+    pars.m_status |= header::STATUS_IS_SUPERCELL;
+
+  // Loop over input cells.
+  for (CaloCellContainer::const_iterator it = cells.begin();
+       it != cells.end();
+       ++it)
+  {
+    // Pick up values from the cell.
+    const CaloCell* cell = *it;
+    const CaloDetDescrElement* dde = cell->caloDDE();
+    unsigned int hash = dde->calo_hash();
+    CaloCell_ID::SUBCALO subcalo = dde->getSubCalo();
+
+    // Test to see if we need to start a new sequence.
+    if (// Not in a sequence now?
+        nseq == 0 ||
+        // We're at the maximum sequence length?
+        nseq >= pars.m_nseq_max ||
+        // A skip in the cell hash codes?
+        seqhash + nseq != hash ||
+        // Moving to a new subcalorimeter?
+        subcalo != prevcalo)
+    {
+      // Mark if cells aren't ordered.
+      if (prevcalo != CaloCell_ID::NOT_VALID &&
+          subcalo < prevcalo)
+        pars.m_status |= header::STATUS_UNORDERED;
+
+      // If we're already in a sequence, need to finish it.
+      if (nseq > 0)
+        finish_seq (seqhash, nseq, seqit, prevcalo, pars);
+
+      // Start a new sequence.
+      nseq = 0;
+      seqhash = hash;
+      prevcalo = subcalo;
+      // Leave space to fill in the hash/count later.
+      seqit = outit;
+      ++outit;
+      ++outit;
+    }
+
+    // Add the current cell on to sequence.
+    if (!is_SC && subcalo == CaloCell_ID::TILE) {
+      pack_tile (static_cast<const TileCell*>(cell), outit, pars);
+
+      // Check to see if the provenance changed.
+      if (version >= 502 &&
+          (cell->provenance() & pars.m_prov_max_tile) != prevCellProvenance)
+      {
+        prevCellProvenance = cell->provenance() & pars.m_prov_max_tile;
+        CaloCompactCellContainer::value_type data =
+          pars.m_hash_field.in(hash) |
+          pars.m_prov_field.in(prevCellProvenance);
+        vProvenance.push_back ((data>>16) & 0xffff);
+        vProvenance.push_back (data & 0xffff);
+      }
+    }
+    else {
+      pack_lar (cell, subcalo, outit, pars);
+
+      // Check to see if the provenance changed.
+      if (version >= 500 &&
+          (cell->provenance() & pars.m_prov_max) != prevCellProvenance)
+      {
+        prevCellProvenance = cell->provenance() & pars.m_prov_max;
+        CaloCompactCellContainer::value_type data =
+          pars.m_hash_field.in(hash) |
+          pars.m_prov_field.in(prevCellProvenance);
+        vProvenance.push_back ((data>>16) & 0xffff);
+        vProvenance.push_back (data & 0xffff);
+      }
+    }
+    ++nseq;
+  }
+
+  // Finish the last sequence.
+  if (nseq != 0)
+    finish_seq (seqhash, nseq, seqit, prevcalo, pars);
+
+  pars.m_lengthProvenance = vProvenance.size();
+
+  assert (outit.used() + pars.m_length + vProvenance.size()/2 + 1 <= maxsize);
+
+  if (pars.m_lengthProvenance > 0) {
+    // this part is making existing vector to have full number of 32 bit words.
+    int x=outit.used();
+    // dummy value of 0 is inserted
+    outit.set(0);
+    int y=outit.used();
+    // if size changed it means that vector was flat at the end and that we spoiled it.
+    // so we have to fix it.
+    if (x!=y) outit.set(0);
+    // now its surely flat.
+
+    // add provenance stuff at the end.
+    for (std::vector<short unsigned int>::iterator iter = vProvenance.begin();
+         iter != vProvenance.end();
+         ++iter)
+    {
+      outit.set (*iter);
+    }
+  }
+
+  // Now resize the container to the final size.
+  packed.resize (outit.used() + pars.m_length);
+
+  // And copy the header to the front.
+  write_header (pars, packed);
+}
+
+
+/**
+ * @brief Write the header to the output container.
+ * @param header The header to write.
+ * @param packed The container to which to write.
+ */
+void
+CaloCellPacker_400_500::write_header (const header& header,
+                                      CaloCompactCellContainer& packed) const
+{
+  const int * phead = &(header.m_length);
+  std::vector<CaloCompactCellContainer::value_type> 
+    vhead (phead, phead + header.m_length);
+  packed.setHeader(vhead);
+}
+
+
+
+//============================================================================
+// Unpacking.
+// To ensure full inlining, don't reorder these.
+//
+
+
+/**
+ * @brief Unpack the time word.
+ * @param it Input iterator.
+ * @param pars Unpacking parameters.
+ * @return The unpacked time.
+ */
+inline
+double CaloCellPacker_400_500::unpack_time
+   (CaloCompactCellContainer::compact_input_iterator& it,
+    const pars500& pars) const
+{
+  // Get the word from the input container.
+  CaloCompactCell::value_type data = it.next();
+
+  // Unpack to a float.
+  int underflow;
+  double time = pars.m_logat_field.out (data, underflow);
+  if (UNLIKELY(underflow))
+    return 0;
+
+  // Exponentiate, and restore the sign.
+  // (nb. introducing `ee' helps the gcc optimizer avoid a redundant
+  // test on the underflow flag.)
+  double ee = std::exp (time);
+  if (data & pars.m_tsign_mask)
+    return -ee;
+  return ee;
+}
+
+
+/**
+ * @brief Unpack a LAr cell.
+ * @param it Input iterator.
+ * @param subcalo Subcalorimeter code for the cell.
+ * @param cell Pointer to the cell in which to write.
+ * @param pars Unpacking parameters.
+ * @param provenance The provenance word for this cell.
+ * @return @a cell, as a @c CaloCell*.
+ *
+ * The DDE and ID will be set in the cell separately; here, we need only
+ * fill in the cell data.
+ */
+inline
+CaloCell*
+CaloCellPacker_400_500::unpack_lar
+   (CaloCompactCellContainer::compact_input_iterator& it,
+    CaloCell_ID::SUBCALO subcalo,
+    LArCell* cell,
+    const pars500& pars,
+    uint16_t provenance) const
+{
+  // Get the data word from the input.
+  CaloCompactCell::value_type data = it.next();
+
+  // Recognize cells filled with dummy values.
+  if (data == pars.m_lar_dummy)
+  {
+    cell->set (0, 0, 0, provenance, CaloGain::INVALIDGAIN);
+    return cell;
+  }
+
+  // Unpack the gain flag.
+  int gainflag = pars.m_egain_field.out (data);
+  int qualflag = pars.m_qualy_field.out (data);
+
+  CaloGain::CaloGain gain = CaloGain::UNKNOWNGAIN;
+
+  // Convert to the CaloCell gain, and convert the energy back to a float
+  // using the proper range.
+  double energy;
+  if ( gainflag == pars.m_ehhig ) {
+    if ( subcalo == CaloCell_ID::LARHEC )
+      gain = CaloGain::LARMEDIUMGAIN;
+    else
+      gain = CaloGain::LARHIGHGAIN;
+    energy = pars.m_crtae_high_field.out (data);
+  }
+  else {
+    if ( gainflag == pars.m_enhig ) {
+      gain = CaloGain::LARHIGHGAIN;
+    }
+    else if ( gainflag == pars.m_enmed ) {
+      gain = CaloGain::LARMEDIUMGAIN;
+    }
+    else if ( gainflag == pars.m_enlow) {
+      gain = CaloGain::LARLOWGAIN;
+    }
+    energy = pars.m_crtae_norm_field.out (data);
+  }
+
+  // Now undo the cube root and apply the sign bit.
+  energy = energy*energy*energy;
+  if (data & pars.m_esign_mask)
+    energy = -energy;
+
+  // If the quality's good, then we need to unpack the time/chi2 too.
+  double time = 0;
+  uint16_t quality=0;
+  if ( qualflag != pars.m_qabad ) {
+    time = unpack_time (it, pars);
+    if (pars.m_version >= 500)
+      quality=it.next();
+    provenance = provenance | 0x2000;
+  }
+
+  // Fill the data into the cell.
+  cell->set (energy, time, quality, provenance, gain);
+
+  // Return it.
+  return cell;
+}
+
+
+/**
+ * @brief Unpack a tile cell.
+ * @param it Input iterator.
+ * @param dde Descriptor element for the cell.
+ * @param pars Unpacking parameters.
+ * @return The new cell.
+ */
+inline
+TileCell CaloCellPacker_400_500::unpack_tile
+   (CaloCompactCellContainer::compact_input_iterator& it,
+    const CaloDetDescrElement* dde,
+    const pars500& pars,
+    uint16_t provenance) const
+{
+  // Loop over the two elements for the cell.
+  double ene[2];
+  double time[2];
+  int gain[2];
+  int qbit[2];
+
+  bool read_qual = false;
+
+  for (int ipmt = 0; ipmt < 2; ++ipmt) {
+    // Unpack the data word.
+    CaloCompactCell::value_type data = it.next();
+
+    // Is this measurement a dummy?
+    if (data == pars.m_tile_dummy)
+    {
+      // Yeah --- fill in dummy values and skip the rest.
+      ene[ipmt] = 0;
+      gain[ipmt] = CaloGain::INVALIDGAIN;
+      qbit[ipmt] = 0;
+      if (ipmt == 1)
+        time[ipmt] = time[0];
+      else
+        time[ipmt] = 0;
+      continue;
+    }
+
+    // Get the quality and gain.
+    int qualflag = pars.m_qualy_field.out (data);
+    int gainflag = pars.m_egain_tile_field.out (data);
+
+    gain[ipmt] = gainflag;
+
+    // Unpack the energy, using the range appropriate to the gain.
+    double e;
+    if (gainflag != pars.m_glow)
+      e = pars.m_crtae_tile_high_field.out (data);
+    else
+      e = pars.m_crtae_tile_low_field.out (data);
+    ene[ipmt] = e*e*e;
+    if (data & pars.m_esign_tile_mask)
+      ene[ipmt] = -ene[ipmt];
+
+    // If the quality is good, we need to unpack the time too.
+    if (qualflag != pars.m_qabad) {
+      read_qual = true;
+      time[ipmt] = unpack_time (it, pars);
+      qbit[ipmt] = TileCell::MASK_CMPC | TileCell::MASK_TIME;
+    }
+    else {
+      time[ipmt] = 0;
+      qbit[ipmt] = TileCell::MASK_CMPC;
+    }
+  }
+
+  uint8_t qual[2];
+  if (pars.m_version >= 502) {
+    qbit[0] |= pars.m_tile_qual1_field.out (provenance);
+    qbit[1] |= pars.m_tile_qual2_field.out (provenance);
+    if (read_qual) {
+      uint16_t qualp = it.next();
+      qual[0] = pars.m_tile_qual1_field.out (qualp);
+      qual[1] = pars.m_tile_qual2_field.out (qualp);
+    } else {
+      qual[0] = ((qbit[0] & TileCell::MASK_BADCH) != 0) ? 255 : 0;
+      qual[1] = ((qbit[1] & TileCell::MASK_BADCH) != 0) ? 255 : 0;
+    }
+  }
+  else {
+    qual[0] = qual[1] = 0;
+  }
+
+  // Make the cell.
+  return TileCell (dde, ene[0], ene[1], time[0], time[1],
+                   qual[0], qual[1], qbit[0], qbit[1], gain[0], gain[1]);
+}
+
+
+/**
+ * @brief Unpack cells.
+ * @param packed The input packed cell container.
+ * @param vheader The header part of the packed data.
+ * @param cells The output cell container.
+ * @param larpool Pool for allocating LAr cells.
+ * @param tilepool Pool for allocating Tile cells.
+ *
+ * Note that allocations will be done from the provided pools,
+ * and the pools retain ownership of the cells.
+ * The @a cells container will be changed to a view container.
+ */
+void CaloCellPacker_400_500::unpack
+   (const CaloCompactCellContainer& packed,
+    const std::vector<int>& vheader,
+    CaloCellContainer& cells,
+    DataPool<LArCell>& larpool,
+    DataPool<TileCell>& tilepool) const
+{
+  // Convert the header.
+  pars500 pars;
+
+  {
+    const int* headerbeg = &*vheader.begin();
+    const int* headerend = headerbeg + vheader.size();
+    size_t nheader = headerend - headerbeg;
+    size_t parsize = sizeof(header) / sizeof(int);
+    size_t ncopy = std::min (nheader, parsize);
+    int* parsbeg = &pars.m_length;
+    std::copy (headerbeg, headerbeg+ncopy, parsbeg);
+    if (nheader > parsize) {
+      // Header was longer than we expected --- there's something
+      // wrong with the data.  Issue a warning.
+      REPORT_MESSAGE_WITH_CONTEXT(MSG::WARNING, 
+                                  "CaloCellPacker_400_500 ")
+        << "Corrupted data: Compact cell header is "
+        << nheader << " words long, longer than the largest expected value of "
+        << parsize << ".";
+    }
+    else if (ncopy < parsize) {
+      // Header was shorter than we expected.
+      // It may be a previous version --- clear out the remainder of pars.
+      // TODO: Cross-check the size we got with what we expect based
+      // on the version number in the header.
+      std::fill (parsbeg + ncopy, parsbeg + parsize, 0);
+    }
+  }
+
+  // Initialize derived parameters from the header.
+  init_derived (pars);
+
+  // Bounds check on size of provenance.
+  unsigned nprov = pars.m_lengthProvenance/2;
+  if (nprov + vheader.size() > packed.getData().size()) {
+    REPORT_MESSAGE_WITH_CONTEXT(MSG::WARNING, 
+                                "CaloCellPacker_400_500 ")
+      << "Corrupted data: Provenance count too large "
+      << pars.m_lengthProvenance << ".";
+    pars.m_lengthProvenance = 0;
+    nprov = 0;
+  }
+
+  // need to make a new iterator and use it for provenance.
+  CaloCompactCellContainer::compact_input_iterator provIt =
+    packed.compact_begin_input_from(pars.m_lengthProvenance/2);
+  unsigned iprov=0;
+
+  // getting starting values
+  short unsigned int currProvValue=0;
+  int nextProvHash=-1;
+  short unsigned int nextProvValue=0;
+  if (pars.m_lengthProvenance) {
+    unsigned int provhash = provIt.next();
+    provhash = (provhash<<16) | provIt.next();
+    nextProvValue = pars.m_prov_field.out (provhash);
+    nextProvHash  = pars.m_hash_field.out (provhash);
+    iprov++;
+  }
+
+  bool is_SC = (pars.m_status & header::STATUS_IS_SUPERCELL);
+
+  // We need the detector description.
+  const CaloDetDescrManager_Base *ddmgr = 0;
+  if (is_SC){
+    ddmgr = CaloSuperCellDetDescrManager::instance();
+  }else
+  {
+    ddmgr = CaloDetDescrManager::instance();
+  }
+  const CaloCell_Base_ID *calo_id = ddmgr->getCaloCell_ID();
+
+  // Clear the output container and reserve the right number of elements.
+  cells.clear(SG::VIEW_ELEMENTS);
+  CaloCell_ID::size_type totcells =
+    pars.m_ncells_larem   + pars.m_ncells_larhec + 
+    pars.m_ncells_larfcal + pars.m_ncells_tile;
+  if (totcells > calo_id->calo_cell_hash_max()) {
+    REPORT_MESSAGE_WITH_CONTEXT(MSG::WARNING, 
+                                "CaloCellPacker_400_500 ")
+      << "Corrupted data: Too many cells " << totcells << ".";
+    totcells = calo_id->calo_cell_hash_max();
+  }
+  cells.reserve (totcells);
+
+  // To speed things up, we'll use the underlying vector from the cell
+  // container.
+  std::vector<CaloCell*>& cellsv =
+    const_cast<std::vector<CaloCell*>&>(cells.stdcont());
+
+  // Iterator for scanning the input.
+  CaloCompactCellContainer::compact_input_iterator it =
+    packed.compact_begin_input();
+
+  // To test for falling off the end.
+  std::vector<CaloCompactCellContainer::value_type>::const_iterator pend =
+    packed.getData().end() - (pars.m_lengthProvenance+1)/2;
+
+  // Sum up the total number of cells/sequences over all subcalos.
+  unsigned int ncells =
+    pars.m_ncells_larem +
+    pars.m_ncells_larhec +
+    pars.m_ncells_larfcal +
+    pars.m_ncells_tile;
+  unsigned int nseqs = 
+    pars.m_seq_larem +
+    pars.m_seq_larhec +
+    pars.m_seq_larfcal +
+    pars.m_seq_tile;
+
+  // Note: In the first version of the v400 packer, the sequence counts
+  // would be left uninitialized if ncells==0.
+  if (ncells == 0)
+    nseqs = 0;
+
+  // Warn if there are too many cells/sequences.
+  IdentifierHash hashmax = calo_id->calo_cell_hash_max();
+  if (ncells > hashmax || nseqs > hashmax || nseqs > ncells) {
+    REPORT_MESSAGE_WITH_CONTEXT(MSG::WARNING, 
+                                "CaloCellPacker_400_500 ")
+      << "Corrupted data: Bad counts"
+      << ": ncells " << ncells << " nseqs " << nseqs << " hashmax " << hashmax;
+  }
+
+  CaloCell_ID::SUBCALO prevcalo = CaloCell_ID::NOT_VALID;
+
+  // Loop over sequences.
+  while (nseqs--) {
+    
+    // Check for overrun.
+    if (it.base() >= pend) {
+      REPORT_MESSAGE_WITH_CONTEXT(MSG::WARNING, 
+                                  "CaloCellPacker_400_500 ")
+        << "Corrupted data: cell vector overrun.";
+      break;
+    }
+
+    // Get the starting hash code and count.
+    CaloCompactCell::value_type data = it.next();
+    unsigned int hashlength = data << 16;
+    hashlength |= it.next();
+
+    unsigned int hash = pars.m_hash_field.out (hashlength);
+    unsigned int nseq = pars.m_nseq_field.out (hashlength);
+
+    if (nseq > ncells || hash+nseq > hashmax)
+    {
+      REPORT_MESSAGE_WITH_CONTEXT(MSG::WARNING, 
+                                  "CaloCellPacker_400_500 ")
+        << "Corrupted data: bad sequence.  "
+        << "nseq " << nseq << " hash " << hash << " ncells " << ncells
+        << " hashmax " << hashmax;
+      break;
+    }
+
+    // Subcalo code for this cell.
+    CaloCell_ID::SUBCALO subcalo = 
+      static_cast<CaloCell_ID::SUBCALO> (calo_id->sub_calo (hash));
+
+    // Maintain the cell container's pointers --- only if cells were ordered!
+    if (subcalo != prevcalo) {
+      if ((pars.m_status & header::STATUS_UNORDERED) == 0) {
+        if (prevcalo != CaloCell_ID::NOT_VALID) {
+          cells.updateCaloEndIterators (prevcalo, cells.size());
+          if (subcalo < prevcalo) {
+            REPORT_MESSAGE_WITH_CONTEXT(MSG::WARNING, 
+                                        "CaloCellPacker_400_500 ")
+              << "Cells not in subcalo order; iterators will be wrong.";
+          }
+        }
+        cells.updateCaloBeginIterators (subcalo, cells.size());
+      }
+      cells.setHasCalo (subcalo);
+      prevcalo = subcalo;
+    }
+
+    // Loop over cells in the sequence.
+    while (nseq--) {
+      // Find the descriptor element for this cell.
+      const CaloDetDescrElement *dde = ddmgr->get_element(hash);
+
+      if (dde == 0) {
+        REPORT_MESSAGE_WITH_CONTEXT(MSG::WARNING, 
+                                    "CaloCellPacker_400_500 ")
+          << "Corrupted data: can't find DDE for cell with hash " << hash;
+      }
+
+      // Unpack the cell.
+      //
+      // One point here that needs explaining.
+      // The pack_tile method returns a TileCell by value.
+      // Normally, this would involve a copy; however, we're careful
+      // to allow the compiler to use the `return value optimization'
+      // to avoid this copy.  That way, we can use the TileCell constructor
+      // directly, without having to add extra set methods (or violate
+      // encapsulation, as the previous version of this code did).
+      // We get a pointer to a TileCell from the data pool and
+      // use this in a placement new to initialize a TileCell
+      // using the value returned from unpack_tile.  Due to the RVO,
+      // the copy is avoided, and the constructor in unpack_tile
+      // will run its constructor directly on the pointer gotten
+      // from the pool.  For this to work correctly, we rely
+      // on the fact that TileCell has only a trivial destructor ---
+      // thus it's safe to rerun the constructor on an object that
+      // has already been constructed.
+      //
+      // You'll notice, however, that CaloCell is done differently.
+      // CaloCell is not a simple class; it has a complicated inheritance
+      // structure.  It was found that setting up all the vtable pointers
+      // in CaloCell was taking a considerable amount of time
+      // (comparable to filling in the cell data).  So, for CaloCell,
+      // we instead add a couple new (inlined) set methods to fill
+      // in the data directly, without having to redo the vtable pointers.
+      // We split it in two, one for dde/id and the other for the cell data,
+      // to reduce the amount of data we need to pass to unpack_lar.
+      //
+      // Why wasn't the same thing done for TileCell, then?
+      //   - I don't have TC rights for TileEvent, so changing that
+      //     is more of a hassle.
+      //   - There are many fewer tile cells than LAr cells.
+      //   - The TileCell constructor we use is significantly
+      //     more complicated than LArCell.  We'd have to duplicate
+      //     this code.  Further, this, together with the previous
+      //     point, implies that the performance implications
+      //     of rebuilding the vtable pointers is much less
+      //     for tile cells than for LAr cells.
+
+      // New provenance?
+      if (hash==static_cast<unsigned int>(nextProvHash)){
+        currProvValue = nextProvValue;
+        if (iprov<nprov) {
+          unsigned int provhash = provIt.next();
+          provhash = (provhash<<16) | provIt.next();
+          nextProvValue = pars.m_prov_field.out (provhash);
+          nextProvHash  = pars.m_hash_field.out (provhash);
+          iprov++;
+        } else {
+          nextProvHash = -1;
+        }
+      }
+
+      CaloCell* cell;
+      if (!is_SC && subcalo == CaloCell_ID::TILE)
+        cell = new (tilepool.nextElementPtr())
+          TileCell (unpack_tile (it,
+                                 dde,
+                                 pars, currProvValue));
+      else {
+        cell = unpack_lar (it,
+                           subcalo,
+                           larpool.nextElementPtr(),
+                           pars,
+                           currProvValue);
+        cell->set (dde, calo_id->cell_id(hash));
+      }
+
+      // Add the cell to the container.
+      if (dde)
+        cellsv.push_back (cell);
+
+      // Move to next cell.
+      ++hash;
+    }
+  }
+
+  // Finish off the last iterator.
+  if (prevcalo != CaloCell_ID::NOT_VALID)
+    cells.updateCaloEndIterators (prevcalo, cells.size());
+
+  // Check that we've consumed all the data.
+  // Note that there may be a padding word before the provenance word.
+  if (it.base() < pend-2) {
+    REPORT_MESSAGE_WITH_CONTEXT(MSG::WARNING, 
+                                "CaloCellPacker_400_500 ")
+      << "Corrupted data: didn't consume all packed data.";
+  }
+}
+
+
+//============================================================================
diff --git a/Calorimeter/CaloTools/src/CaloCompactCellTool.cxx b/Calorimeter/CaloTools/src/CaloCompactCellTool.cxx
new file mode 100755
index 0000000000000000000000000000000000000000..b07fc7e5361004bc3dcfd9478a588ff0f4542954
--- /dev/null
+++ b/Calorimeter/CaloTools/src/CaloCompactCellTool.cxx
@@ -0,0 +1,125 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+//-----------------------------------------------------------------------
+// File and Version Information:
+// $Id: CaloCompactCellTool.cxx,v 1.35 2009-03-19 01:42:15 ssnyder Exp $
+//
+// Description: see CaloCompactCellTool.h
+//
+// Environment:
+//      Software developed for the ATLAS Detector at the CERN LHC
+//
+// All compactor versions before version 400 are removed and can be found only in
+// old versions in CVS
+//-----------------------------------------------------------------------
+
+#define private public
+#define protected public
+#include "LArRecEvent/LArCell.h"
+#include "TileEvent/TileCell.h"
+#undef private
+#undef protected
+
+#include "DataModel/DataPool.h"
+#include "CaloTools/CaloCompactCellTool.h"
+#include "CaloDetDescr/CaloDetDescrManager.h"
+#include "CaloIdentifier/CaloCell_ID.h"
+#include "CaloTools/CaloCellPacker_400_500.h"
+#include "GaudiKernel/MsgStream.h"
+
+CaloCompactCellTool::CaloCompactCellTool(const std::string& type,
+					 const std::string& name,
+					 const IInterface* parent)
+  : AthAlgTool(type,name,parent)
+{
+declareInterface< ICaloCompactCellTool >( this );
+}
+
+CaloCompactCellTool::~CaloCompactCellTool()
+{ }
+
+StatusCode CaloCompactCellTool::initialize()
+{
+  declareInterface<ICaloCompactCellTool>(this);
+  return StatusCode::SUCCESS;
+}
+
+StatusCode CaloCompactCellTool::finalize()
+{
+  return StatusCode::SUCCESS;
+}
+
+StatusCode CaloCompactCellTool::getTransient
+(const CaloCompactCellContainer & theCompactContainer,
+ CaloCellContainer * theCellContainer)
+{
+  MsgStream logStream(msgSvc(), name());
+
+  const std::vector<CaloCompactCellContainer::value_type> theHeader = theCompactContainer.getHeader();
+  logStream << MSG::DEBUG << " getTransient:    using version: "<<theHeader[1] << endreq;
+
+  static DataPool<LArCell> larCellsP(220000);//initialize for the default value will resize latter to full size
+  static DataPool<TileCell> tileCellsP(13000);
+
+  switch (theHeader[1]) {
+
+  case ICaloCompactCellTool::VERSION_400:
+  case ICaloCompactCellTool::VERSION_500:
+  case ICaloCompactCellTool::VERSION_501:
+  case ICaloCompactCellTool::VERSION_502:
+  case ICaloCompactCellTool::VERSION_503:
+  case ICaloCompactCellTool::VERSION_504:
+    {
+      CaloCellPacker_400_500 packer;
+      packer.unpack (theCompactContainer, theHeader, *theCellContainer,
+                     larCellsP, tileCellsP);
+    }
+    break;
+
+  default:
+    logStream << MSG::FATAL << " unknown version " << theHeader[1]
+	      << " requested for unpacking the CaloCompactCellContainer"
+	      << endreq;
+    return StatusCode::FAILURE;
+  }
+
+  return StatusCode::SUCCESS;
+}
+
+
+StatusCode CaloCompactCellTool::getPersistent   //fill the CaloCompactCellContainer
+(const CaloCellContainer & theCellContainer,
+ CaloCompactCellContainer * theCompactContainer,
+ int theVersion )
+{
+  MsgStream logStream(msgSvc(), name());
+
+  logStream << MSG::DEBUG << "CaloCell container contains " << theCellContainer.size() << " cells. Write compact Ver: " << theVersion <<endreq;
+
+  if (theVersion == ICaloCompactCellTool::VERSION_LATEST)
+    theVersion = ICaloCompactCellTool::VERSION_504;
+
+ switch (theVersion ) {
+
+ case ICaloCompactCellTool::VERSION_400:
+ case ICaloCompactCellTool::VERSION_500:
+ case ICaloCompactCellTool::VERSION_501:
+ case ICaloCompactCellTool::VERSION_502:
+ case ICaloCompactCellTool::VERSION_503:
+ case ICaloCompactCellTool::VERSION_504:
+   {
+     CaloCellPacker_400_500 packer;
+
+     packer.pack (theCellContainer, *theCompactContainer, theVersion);
+   }
+   break;
+
+  default:
+    logStream << MSG::FATAL << " unknown version " << theVersion
+	      << " requested for packing the CaloCellContainer" << endreq;
+    return StatusCode::FAILURE;
+  }
+  return StatusCode::SUCCESS;
+}
diff --git a/Calorimeter/CaloTools/src/CaloLumiBCIDTool.cxx b/Calorimeter/CaloTools/src/CaloLumiBCIDTool.cxx
new file mode 100755
index 0000000000000000000000000000000000000000..0ec79df58bc7c6cbcd61062dd8bb4fd18eb2ae49
--- /dev/null
+++ b/Calorimeter/CaloTools/src/CaloLumiBCIDTool.cxx
@@ -0,0 +1,418 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "CaloTools/CaloLumiBCIDTool.h" 
+#include "GaudiKernel/MsgStream.h"
+#include "StoreGate/StoreGateSvc.h"
+#include "CaloEvent/CaloCell.h"
+#include "CaloIdentifier/CaloCell_ID.h"
+#include "CaloIdentifier/CaloIdManager.h"
+#include "GeoModelInterfaces/IGeoModelSvc.h"
+//#include "xAODEventInfo/EventID.h"
+#include "xAODEventInfo/EventInfo.h"
+
+
+CaloLumiBCIDTool::CaloLumiBCIDTool (const std::string& type, 
+				  const std::string& name, 
+				  const IInterface* parent) :
+    AthAlgTool(type, name, parent),
+    m_larmcsym("LArMCSymTool"),
+    m_OFCTool("LArOFCTool"),
+    m_lumiTool("LuminosityTool"),
+    m_bunchCrossingTool("BunchCrossingTool"),
+    m_isMC(false),
+    m_keyShape("LArShape"), m_keyMinBiasAverage("LArPileupAverage"),m_keyOFC("LArOFC"),
+    m_bcidMax(3564),
+    m_ncell(0),
+    m_bcid(0xFFFF) //Larger than m_bcidmax 
+{ 
+  declareInterface<ICaloLumiBCIDTool>(this);
+  declareProperty("LArOFCTool",m_OFCTool,"Tool handle for OFC");
+  declareProperty("LumiTool",m_lumiTool,"Tool handle for Luminosity");
+  declareProperty("BunchCrossingTool",m_bunchCrossingTool,"Tool handle for bunch crossing tool");
+  declareProperty("isMC",m_isMC);
+  declareProperty("keyShape",m_keyShape);
+  declareProperty("keyMinBiasAverge",m_keyMinBiasAverage);
+  declareProperty("keyOFC",m_keyOFC);
+}
+                                                                                
+//-----------------------------------------------------------------
+
+CaloLumiBCIDTool::~CaloLumiBCIDTool() {}
+
+
+//-------------------------------------------------------------------
+
+StatusCode CaloLumiBCIDTool::initialize() {
+
+  msg(MSG::INFO) << " initialize " << endreq;
+
+  IIncidentSvc* incSvc; 
+  if (service( "IncidentSvc", incSvc ).isFailure()) {
+    msg(MSG::ERROR) << "Unable to get the IncidentSvc" << endreq; 
+    return StatusCode::FAILURE;
+  }
+  long int priority=100;
+  incSvc->addListener(this,"BeginEvent",priority);
+
+
+  const IGeoModelSvc *geoModel=0;
+  StatusCode sc = service("GeoModelSvc", geoModel);
+  if(sc.isFailure())
+  {
+    msg(MSG::ERROR) << "Could not locate GeoModelSvc" << endreq;
+    return sc;
+  }
+
+  // dummy parameters for the callback:
+  int dummyInt=0;
+  std::list<std::string> dummyList;
+
+  if (geoModel->geoInitialized())
+  {
+    return geoInit(dummyInt,dummyList);
+  }
+  else
+  {
+    sc = detStore()->regFcn(&IGeoModelSvc::geoInit,
+                          geoModel,
+                          &CaloLumiBCIDTool::geoInit,this);
+    if(sc.isFailure())
+    {
+      msg(MSG::ERROR) << "Could not register geoInit callback" << endreq;
+      return sc;
+    }
+  }
+  return sc;
+
+}
+
+// ------------------------------------------------------------------------------
+
+StatusCode CaloLumiBCIDTool::geoInit(IOVSVC_CALLBACK_ARGS) {
+
+  msg(MSG::INFO) << " geoInit " << endreq;
+
+// callback for Shape
+
+  StatusCode sc=detStore()->regFcn(&ICaloLumiBCIDTool::LoadCalibration,
+				   dynamic_cast<ICaloLumiBCIDTool*>(this),
+				   m_dd_shape,m_keyShape,true);
+  if(sc.isSuccess()){
+    msg(MSG::INFO) << "Registered callback for key: "
+		   << m_keyShape << endreq;
+  } else {
+    msg(MSG::ERROR) << "Cannot register callback function for key "
+		    << m_keyShape << endreq;
+    return sc;
+  }
+
+// callback for MinBiasAverage
+
+  sc=detStore()->regFcn(&ICaloLumiBCIDTool::LoadCalibration,
+			dynamic_cast<ICaloLumiBCIDTool*>(this),
+			m_dd_minbiasAverage,m_keyMinBiasAverage,true);
+  if(sc.isSuccess()){
+    msg(MSG::INFO) << "Registered callback for key: "
+		   << m_keyMinBiasAverage << endreq;
+  } else { 
+    msg(MSG::ERROR) << "Cannot register callback function for key "
+		    << m_keyMinBiasAverage << endreq;
+    return sc;
+  }
+
+  sc=m_cablingService.retrieve();
+  if (sc.isFailure()){
+    msg(MSG::ERROR) << "Unable to get CablingService" << endreq;
+    return sc;
+  }
+
+
+// get OFC tool and register callback
+
+  if (m_isMC) {
+    sc=m_OFCTool.retrieve();
+    if (sc.isFailure())   {
+      msg(MSG::ERROR) << "Unable to retrieve LArOFCTool" << endreq; 
+      return sc;
+    } else {
+      msg(MSG::DEBUG) << " -- LArOFCTool retrieved" << endreq;
+    }
+
+
+    sc=detStore()->regFcn(&ILArOFCTool::LoadCalibration,&(*m_OFCTool),
+			  &ICaloLumiBCIDTool::LoadCalibration,dynamic_cast<ICaloLumiBCIDTool*>(this),true);
+    if (sc.isSuccess()) {
+      msg(MSG::INFO) << "Registered callbacks for LArOFCTool -> CaloLumiBCIDTool"
+		     << endreq;
+    } else { 
+      msg(MSG::ERROR) << "Cannot register callbacks for LArOFCTool -> CaloLumiBCIDTool"
+	<< endreq;
+      return sc;
+    }
+
+  } else {
+    sc=detStore()->regFcn(&ICaloLumiBCIDTool::LoadCalibration,
+			  dynamic_cast<ICaloLumiBCIDTool*>(this),
+			  m_dd_ofc,m_keyOFC,true);
+    if(sc.isSuccess()){
+      msg(MSG::INFO) << "Registered callback for key: "
+		     << m_keyOFC << endreq;
+    } else {
+      msg(MSG::ERROR) << "Cannot register callback function for key "
+		      << m_keyOFC << endreq;
+      return sc;
+    }
+
+  }
+
+// get LumiTool
+  if (m_isMC) {
+    sc=m_bunchCrossingTool.retrieve();
+    if (sc.isFailure())   {
+      msg(MSG::ERROR) << "Unable to retrieve bunch crossing Tool" << endreq; 
+      return sc;
+    } else {
+      ATH_MSG_DEBUG(" -- bunch crossing Tool retrieved");
+    }
+
+  } else {
+      sc=m_lumiTool.retrieve();
+      if (sc.isFailure())   {
+        msg(MSG::ERROR) << "Unable to retrieve Lumi Tool" << endreq;
+        return sc;
+      } else {
+        ATH_MSG_DEBUG(" -- Lumi Tool retrieved");
+      }
+
+  }
+
+ //
+ sc = m_larmcsym.retrieve();
+ if (sc.isFailure()) {
+   msg(MSG::ERROR) << "Unable to retrieve LArMCSym tool " << endreq;
+      return sc;
+  }
+  else {
+    ATH_MSG_DEBUG(" -- LArMCSmy tool retrieved ");
+  }
+
+ sc = detStore()->retrieve(m_lar_on_id,"LArOnlineID");
+ if (sc.isFailure()) {
+   msg(MSG::ERROR) << "Cannot retrieve LArOnlineID from detector store " << endreq;
+   return sc;
+ }
+  
+  sc = detStore()->retrieve( m_caloIdMgr );
+  if (sc.isFailure()) {
+    msg(MSG::ERROR) << "Unable to retrieve CaloIdMgr in  " << endreq;
+    return StatusCode::FAILURE;
+  }
+  m_calocell_id = m_caloIdMgr->getCaloCell_ID();
+
+  return StatusCode::SUCCESS;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------
+
+void CaloLumiBCIDTool::getListOfCells()
+{
+  m_ncell = m_calocell_id->calo_cell_hash_max();
+
+  m_symCellIndex.resize(m_ncell,-1);
+  m_hwid_sym.reserve(2000);
+  m_eshift_sym.reserve(2000);
+  std::vector<int> m_doneCell;
+  m_doneCell.resize(m_ncell,-1);
+
+  int nsym=0;
+  for (int i=0;i<m_ncell;i++) {
+     IdentifierHash idHash=i;
+     Identifier id=m_calocell_id->cell_id(idHash);
+     if (m_calocell_id->is_tile(id)) continue;
+     // convert cell id to symetric identifier
+     HWIdentifier hwid2=m_larmcsym->symOnline(id);
+     Identifier id2 = m_cablingService->cnvToIdentifier(hwid2);
+     int i2 = (int) (m_calocell_id->calo_cell_hash(id2));
+     // we have already processed this hash => just need to associate cell i to the same symetric cell
+     if (m_doneCell[i2]>=0) {
+        m_symCellIndex[i]=m_doneCell[i2];
+     }
+     // we have not already processed this hash, add an entry for this new symmetric cell
+     else {
+        m_doneCell[i2]=nsym;
+        m_symCellIndex[i] = nsym;
+        m_hwid_sym.push_back(hwid2);
+        m_eshift_sym.push_back(0.);
+        nsym++;
+     }
+  }
+
+  //std::cout << " --- number of symmetric cells found " << nsym << std::endl; 
+
+  //for (int i=0;i<m_ncell;i++) {
+  //  IdentifierHash idHash=i;
+  // Identifier id=m_calocell_id->cell_id(idHash);
+  // std::cout << " Calo cell " << m_calocell_id->show_to_string(id) << "   sym index " << m_symCellIndex[i] << " symmetric hwid " << m_lar_on_id->show_to_string(m_hwid_sym[m_symCellIndex[i]]) << std::endl;
+  //}
+
+
+
+  return;
+}
+
+//-------------------------------------------------------------------------------------
+
+StatusCode CaloLumiBCIDTool::LoadCalibration(IOVSVC_CALLBACK_ARGS_K(keys)) {
+
+  msg(MSG::INFO) << "Callback invoked for " << keys.size() << " keys " << endreq;
+
+  m_cacheValid=false;
+  return StatusCode::SUCCESS;
+}
+
+//---------------------------------------------------------
+
+void CaloLumiBCIDTool::handle(const Incident& inc) {
+
+  if (inc.type()!="BeginEvent") return;
+
+  //std::cout << " in  CaloLumiBCIDTool event handle " << std::endl;
+  m_cacheValid=false;
+  return;
+
+}
+
+
+//----------------------------------------------------------------------------------------
+
+StatusCode CaloLumiBCIDTool::computeValues(unsigned int bcid)
+{
+  //std::cout << " in  CaloLumiBCIDTool::computeValues() " << m_isMC << std::endl;
+
+  if (m_ncell==0) getListOfCells();
+
+// get mu value and convert to luminosity for MC
+  float xlumiMC=0.;
+  if (m_isMC) {
+     const xAOD::EventInfo* eventInfo;
+     if (! evtStore()->retrieve(eventInfo).isSuccess() ) {
+       msg(MSG::WARNING) << " Event info not found in event store . Pileup offsets computed for 0 lumi " << endreq;
+     }
+     else {
+       xlumiMC = eventInfo->averageInteractionsPerCrossing()/6.31;            // convert from mu/bunch to lumi in 10**30 units per bunch
+                                                                              // 25ns*Nbcid*71mb*10**30 = 25e-9*3564*71e-27*1e30 = 6.31
+       //std::cout << " mu and xlumiMC for this bcid " << eventInfo->averageInteractionsPerCrossing() << " " << xlumiMC << std::endl;
+     }
+  }
+
+  if (bcid==0) {
+    const xAOD::EventInfo* eventInfo;
+    if (! evtStore()->retrieve(eventInfo).isSuccess() ) {
+      msg(MSG::WARNING) << " Event info not found in event store . Pileup offsets computed for bcid=1 " << endreq;
+       bcid=1;
+     }
+     else {
+       //const EventID* myEventID=eventInfo->event_ID();
+       bcid = eventInfo->bcid();
+     }
+  }
+  //std::cout << " start loop over cells  bcid= " << bcid << std::endl;
+  //if (!m_isMC) std::cout << "   lumi for this bcid " << m_lumiTool->lbLuminosityPerBCID(bcid) << std::endl;
+  std::vector<HWIdentifier>::iterator it = m_hwid_sym.begin(); 
+  std::vector<HWIdentifier>::iterator it_end = m_hwid_sym.end(); 
+  int index=0;
+  for(;it!=it_end;++it) {
+    const HWIdentifier id  = *it;
+    //std::cout << " Identifier " << m_lar_on_id->show_to_string(id) << std::endl;
+    float eOFC=0.; 
+    if(m_cablingService->isOnlineConnected(id)) {
+
+      //  get MinBiasAverage
+      float MinBiasAverage = m_dd_minbiasAverage->minBiasAverage(id);
+      //float MinBiasAverage=1.;
+
+      if (MinBiasAverage<0.) MinBiasAverage=0.;
+
+      //  get Shape
+      ILArShape::ShapeRef_t Shape = m_dd_shape->Shape(id,0);
+
+      //  get OFC
+      ILArOFCTool::OFCRef_t OFC;
+      if (m_isMC) OFC = m_OFCTool->OFC_a(id,0) ;
+      else  OFC = m_dd_ofc->OFC_a(id,0,0);
+
+      unsigned int nsamples = OFC.size();
+
+      unsigned int nshapes = Shape.size();
+      if (nshapes < nsamples) {
+	msg(MSG::ERROR) << " Not enough samples in Shape " << nshapes << "   less than in OFC " << nsamples << endreq;
+	return StatusCode::FAILURE;
+      }
+
+      //std::cout << " loop over bcid ";
+      for (unsigned int i=0;i<nsamples;i++) {
+          float sumShape=0.;
+          for (unsigned int j=0;j<nshapes;j++) {
+               unsigned int k;
+               if ((bcid+i)<j) k = m_bcidMax+bcid+i-j;
+               else if ((bcid+i)>=(m_bcidMax+j)) k = i-j+bcid-m_bcidMax;
+               else k = bcid+i-j;
+
+               float lumi;
+               if (m_isMC) lumi= m_bunchCrossingTool->bcIntensity(k)*xlumiMC;   // convert to luminosity per bunch in 10**30 units
+               else lumi = m_lumiTool->lbLuminosityPerBCID(k);  // luminosity in 10**30 units
+               //std::cout <<  "k:lumi " << k << " " << lumi << " ";
+
+               sumShape += Shape[j]*lumi;
+          }
+          eOFC += sumShape * (OFC[i] );
+      }
+      //std::cout << std::endl;
+      eOFC = eOFC * MinBiasAverage;
+    }     // connected cell
+    else {
+     //std::cout << " disconnected cell ? " << std::endl;
+     eOFC=0.;
+    }
+
+    //std::cout << " index, eOFC " << index << " " << eOFC << std::endl;
+    m_eshift_sym[index]=eOFC;
+    index++;
+
+  }      // loop over cells
+
+
+  m_cacheValid=true;
+  m_bcid = bcid;
+  return StatusCode::SUCCESS;
+}
+
+//-------------------------------------------------
+
+float CaloLumiBCIDTool::average(const CaloCell* caloCell,unsigned int bcid)
+{
+  return this->average(caloCell->caloDDE(),bcid);
+
+}
+
+//-------------------------------------------------
+
+float CaloLumiBCIDTool::average(const CaloDetDescrElement* caloDDE,unsigned int bcid)
+{
+  if (bcid != m_bcid && bcid !=0 ) m_cacheValid=false;
+  if (!m_cacheValid) {
+    StatusCode sc = this->computeValues(bcid);
+    if (sc.isFailure()) return 0.;
+  }
+  const Identifier CellID = caloDDE->identify();
+
+  if (m_calocell_id->is_tile(CellID)) return 0.;
+
+  int i2 = (int) (m_calocell_id->calo_cell_hash(CellID));
+  if (i2>=m_ncell) return 0.;
+  unsigned int index = m_symCellIndex[i2];
+  if (index>=m_eshift_sym.size()) return 0.;
+  return m_eshift_sym[index];
+}
diff --git a/Calorimeter/CaloTools/src/CaloMBAverageTool.cxx b/Calorimeter/CaloTools/src/CaloMBAverageTool.cxx
new file mode 100755
index 0000000000000000000000000000000000000000..f2c6a3938cebc2bc82f5ac3715f0bb46f3e66b9f
--- /dev/null
+++ b/Calorimeter/CaloTools/src/CaloMBAverageTool.cxx
@@ -0,0 +1,257 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "CaloTools/CaloMBAverageTool.h" 
+#include "GaudiKernel/MsgStream.h"
+#include "StoreGate/StoreGateSvc.h"
+#include "CaloEvent/CaloCell.h"
+#include "CaloIdentifier/CaloCell_ID.h"
+#include "CaloIdentifier/CaloIdManager.h"
+#include "GeoModelInterfaces/IGeoModelSvc.h"
+
+
+CaloMBAverageTool::CaloMBAverageTool (const std::string& type, 
+				  const std::string& name, 
+				  const IInterface* parent) :
+    AthAlgTool(type, name, parent),
+    m_OFCTool("LArOFCTool"),
+    m_Nminbias(-1),m_deltaBunch(1),m_keyShape("LArShape"), m_keyfSampl("LArfSampl"), m_keyMinBiasAverage("LArMinBiasAverage")
+{ 
+  declareInterface<ICaloMBAverageTool>(this);
+  declareProperty("NMinBias",m_Nminbias);
+  declareProperty("deltaBunch",m_deltaBunch);
+  declareProperty("keyShape",m_keyShape);
+  declareProperty("keyfSampl",m_keyfSampl);
+  declareProperty("keyMinBiasAverge",m_keyMinBiasAverage);
+  declareProperty("LArOFCTool",m_OFCTool,"Tool handle for OFC");
+
+}
+                                                                                
+//-----------------------------------------------------------------
+
+CaloMBAverageTool::~CaloMBAverageTool() {}
+
+
+//-------------------------------------------------------------------
+
+StatusCode CaloMBAverageTool::initialize() {
+
+  MsgStream log( msgSvc(), name() );
+
+  log << MSG::INFO << " initialize " << endreq;
+
+  m_ncell = 0;
+
+  const IGeoModelSvc *geoModel=0;
+  StatusCode sc = service("GeoModelSvc", geoModel);
+  if(sc.isFailure())
+  {
+    log << MSG::ERROR << "Could not locate GeoModelSvc" << endreq;
+    return sc;
+  }
+
+  // dummy parameters for the callback:
+  int dummyInt=0;
+  std::list<std::string> dummyList;
+
+  if (geoModel->geoInitialized())
+  {
+    return geoInit(dummyInt,dummyList);
+  }
+  else
+  {
+    sc = detStore()->regFcn(&IGeoModelSvc::geoInit,
+                          geoModel,
+                          &CaloMBAverageTool::geoInit,this);
+    if(sc.isFailure())
+    {
+      log << MSG::ERROR << "Could not register geoInit callback" << endreq;
+      return sc;
+    }
+  }
+  return sc;
+
+}
+
+// ------------------------------------------------------------------------------
+
+StatusCode CaloMBAverageTool::geoInit(IOVSVC_CALLBACK_ARGS) {
+
+  MsgStream log(msgSvc(), name());
+  log << MSG::INFO << " geoInit " << endreq;
+
+  StatusCode sc = detStore()->retrieve( m_caloIdMgr );
+  if (sc.isFailure()) {
+    log << MSG::ERROR << "Unable to retrieve CaloIdMgr in  " << endreq;
+   return StatusCode::FAILURE;
+  }
+  m_calo_id      = m_caloIdMgr->getCaloCell_ID();
+
+
+
+
+// callback for Shape
+
+  sc=detStore()->regFcn(&ICaloMBAverageTool::LoadCalibration,
+                         dynamic_cast<ICaloMBAverageTool*>(this),
+                         m_dd_shape,m_keyShape,true);
+  if(sc.isSuccess()){
+       log << MSG::INFO << "Registered callback for key: "
+           << m_keyShape << endreq;
+  } else {
+       log << MSG::ERROR << "Cannot register callback function for key "
+           << m_keyShape << endreq;
+        return sc;
+  }
+
+// callback for fSampl
+
+  sc=detStore()->regFcn(&ICaloMBAverageTool::LoadCalibration,
+                         dynamic_cast<ICaloMBAverageTool*>(this),
+                         m_dd_fsampl,m_keyfSampl,true);
+  if(sc.isSuccess()){
+       log << MSG::INFO << "Registered callback for key: "
+           << m_keyfSampl << endreq;
+  } else {
+       log << MSG::ERROR << "Cannot register callback function for key "
+           << m_keyfSampl << endreq;
+       return sc;
+  }
+
+// callback for MinBiasAverage
+
+  sc=detStore()->regFcn(&ICaloMBAverageTool::LoadCalibration,
+                         dynamic_cast<ICaloMBAverageTool*>(this),
+                         m_dd_minbiasAverage,m_keyMinBiasAverage,true);
+  if(sc.isSuccess()){
+       log << MSG::INFO << "Registered callback for key: "
+           << m_keyMinBiasAverage << endreq;
+  } else { 
+       log << MSG::ERROR << "Cannot register callback function for key "
+           << m_keyMinBiasAverage << endreq;
+       return sc;
+  }
+
+
+
+// get OFC tool and register callback
+
+  sc=m_OFCTool.retrieve();
+  if (sc.isFailure())   {
+        log << MSG::ERROR << "Unable to retrieve LArOFCTool" << endreq; 
+        return sc;
+  } else {
+        log << MSG::DEBUG << " -- LArOFCTool retrieved" << endreq;
+  }
+
+
+  sc=detStore()->regFcn(&ILArOFCTool::LoadCalibration,&(*m_OFCTool),
+                        &ICaloMBAverageTool::LoadCalibration,dynamic_cast<ICaloMBAverageTool*>(this),true);
+  if (sc.isSuccess()) {
+      log << MSG::INFO 
+           << "Registered callbacks for LArOFCTool -> CaloMBAverageTool"
+           << endreq;
+  } else { 
+       log << MSG::ERROR 
+           << "Cannot register callbacks for LArOFCTool -> CaloMBAverageTool"
+           << endreq;
+       return sc;
+  }
+
+
+  return StatusCode::SUCCESS;
+}
+
+//-------------------------------------------------------------------------------------
+
+StatusCode CaloMBAverageTool::LoadCalibration(IOVSVC_CALLBACK_ARGS_K(keys))
+{
+
+  MsgStream log(msgSvc(), name());
+
+  log << MSG::INFO << "Callback invoked for " << keys.size() << " keys " << endreq;
+
+  m_ncell =  m_calo_id->calo_cell_hash_max();
+  m_shift.resize(3*m_ncell,0.);
+
+  for (unsigned int icell=0;icell<m_ncell;icell++) {
+    IdentifierHash cellHash = icell;
+    Identifier id = m_calo_id->cell_id(cellHash);
+
+    if (m_calo_id->is_em(cellHash) || m_calo_id->is_hec(cellHash) || m_calo_id->is_fcal(cellHash)) {
+
+      //  get MinBiasAverage
+      float MinBiasAverage = m_dd_minbiasAverage->minBiasAverage(id);
+
+      if (MinBiasAverage<0.) MinBiasAverage=0.;
+
+      //  get fSampl
+      float fSampl = m_dd_fsampl->FSAMPL(id);
+
+      for (int igain=0;igain<3;igain++) {
+ 
+         //  get Shape
+         ILArShape::ShapeRef_t Shape = m_dd_shape->Shape(id,igain);
+
+         //  get OFC
+         ILArOFCTool::OFCRef_t OFC = m_OFCTool->OFC_a(id, igain, m_Nminbias) ;
+
+         int nsamples = OFC.size();
+
+         int nshapes = Shape.size();
+         if (nshapes < nsamples) {
+             log << MSG::ERROR << " Not enough samples in Shape " << nshapes << "   less than in OFC " << nsamples << endreq;
+             return StatusCode::FAILURE;
+         }
+
+         float e = MinBiasAverage/fSampl*m_Nminbias;
+
+         float eOFC=0.;
+  
+         for (int i=0;i<nsamples;i++) {
+           float sumShape = 0.;
+           for (int j=0;j<nshapes;j++) {
+             int k=i-j;
+             if (k%m_deltaBunch == 0 ) sumShape += Shape[j];
+           }
+           float energySample = sumShape*e;
+           eOFC += energySample * ( OFC[i] );
+         }
+
+
+         unsigned int index = igain*m_ncell + icell;
+         m_shift[index] = eOFC;
+
+      }
+
+
+    }
+
+  }
+
+
+  return StatusCode::SUCCESS;
+}
+
+//-------------------------------------------------
+
+float CaloMBAverageTool::average(const CaloCell* caloCell)
+{
+  CaloGain::CaloGain igain = caloCell->gain();
+  return this->average(caloCell->caloDDE(),igain);
+
+}
+
+//-------------------------------------------------
+
+float CaloMBAverageTool::average(const CaloDetDescrElement* caloDDE,CaloGain::CaloGain gain)
+{
+  const IdentifierHash idCaloHash = caloDDE->calo_hash();
+  int igain=static_cast<int>(gain);
+  unsigned int index = igain*m_ncell + ((int)(idCaloHash));
+  if (index < m_shift.size())
+    return m_shift[index];
+  else
+    return 0.;
+}
diff --git a/Calorimeter/CaloTools/src/CaloNoiseTool.cxx b/Calorimeter/CaloTools/src/CaloNoiseTool.cxx
new file mode 100755
index 0000000000000000000000000000000000000000..e67ba962dbfc6017de80ae874ea56ee8b28a15d0
--- /dev/null
+++ b/Calorimeter/CaloTools/src/CaloNoiseTool.cxx
@@ -0,0 +1,2256 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "CaloTools/CaloNoiseTool.h"
+
+#include "CLHEP/Units/SystemOfUnits.h"
+#include "TileIdentifier/TileHWID.h"
+#include "TileConditions/TileCablingService.h"
+
+// For Gaudi
+#include "GaudiKernel/MsgStream.h"
+//#include "GaudiKernel/IService.h"
+//#include "GaudiKernel/IToolSvc.h"
+//#include "GaudiKernel/ListItem.h"
+#include "GaudiKernel/IIncidentSvc.h"
+#include "TileIdentifier/TileRawChannelUnit.h"
+#include "GeoModelInterfaces/IGeoModelSvc.h"
+#include "CLHEP/Random/RandomEngine.h"
+#include "CLHEP/Random/RandGauss.h"
+
+// Exceptions
+#include "LArElecCalib/LArConditionsException.h"
+
+using CLHEP::GeV;
+using CLHEP::RandGauss;
+ 
+//////////////////////////////////////////////////
+
+CaloNoiseTool::CaloNoiseTool(const std::string& type, 
+			     const std::string& name, 
+			     const IInterface* parent) 
+  : AthAlgTool(type, name, parent),
+    m_WithOF(true), m_cablingService("LArCablingService"),
+    m_tileInfoName("TileInfo"),
+    m_adc2mevTool("LArADC2MeVTool"),m_OFCTool("LArOFCTool"),
+    m_Nminbias(-1), m_WorkMode(1),
+    m_UseLAr(true),m_UseTile(true),m_UseSymmetry(true),
+    m_DumpDatabaseHG(false),m_DumpDatabaseMG(false),m_DumpDatabaseLG(false),
+    m_isMC(true),
+    m_keyNoise("LArNoise"), m_keyPedestal("LArPedestal"), m_keyADC2GeV("LArADC2MeV"), 
+    m_keyOFShape("LArOFC_Shape"), m_keyAutoCorr("LArAutoCorr"),
+    m_keyShape("LArShape"), m_keyfSampl("LArfSampl"), m_keyMinBias("LArMinBias"),
+    m_DiagnosticHG(true),m_DiagnosticMG(true),m_DiagnosticLG(true),
+    m_cacheValid(false),m_deltaBunch(1),m_firstSample(0)
+
+{
+  declareInterface<ICaloNoiseTool>(this);
+  declareInterface<ICalorimeterNoiseTool>(this);
+
+  //switch on Optimal Filtering (applied or not)
+  declareProperty("WithOF",m_WithOF);
+  //name of TileInfo
+  declareProperty("TileInfoName",m_tileInfoName);
+  declareProperty("LArADC2MeVTool",m_adc2mevTool,"Tool handle for ADC2MeV");
+  declareProperty("LArOFCTool",m_OFCTool,"Tool handle for OFC");
+  declareProperty("NMinBias",m_Nminbias);
+  declareProperty("WorkMode",m_WorkMode);
+  //declareProperty("Geant3",m_Geant3);
+  declareProperty("UseLAr",m_UseLAr);
+  declareProperty("UseTile",m_UseTile);
+  declareProperty("UseSymmetry",m_UseSymmetry);
+  declareProperty("DumpDatabaseHG",m_DumpDatabaseHG);
+  declareProperty("DumpDatabaseMG",m_DumpDatabaseMG);
+  declareProperty("DumpDatabaseLG",m_DumpDatabaseLG);
+  declareProperty("DiagnosticHG",m_DiagnosticHG);
+  declareProperty("DiagnosticMG",m_DiagnosticMG);
+  declareProperty("DiagnosticLG",m_DiagnosticLG);
+  declareProperty("ReturnNoise",m_ReturnNoiseName="electronicNoise");
+  declareProperty("FixGain",m_gain_from_joboption=-1);
+  declareProperty("IsMC",m_isMC);
+  declareProperty("keyAutoCorr",m_keyAutoCorr); 
+  declareProperty("keyPedestal",m_keyPedestal); 
+  declareProperty("keyOFC",m_keyOFShape); 
+  declareProperty("keyShape",m_keyShape); 
+  declareProperty("keyfSampl",m_keyfSampl); 
+  declareProperty("keyMinBias",m_keyMinBias); 
+  declareProperty("keyNoise",m_keyNoise); 
+  declareProperty("keyADC2GeV",m_keyADC2GeV); 
+  declareProperty("LoadAtBegin",m_loadAtBegin=true);
+  declareProperty("deltaBunch",m_deltaBunch);
+  declareProperty("firstSample",m_firstSample);
+}
+ 
+//////////////////////////////////////////////////
+
+StatusCode 
+CaloNoiseTool::initialize()
+{
+
+  MsgStream log( msgSvc(), name() );
+
+  StoreGateSvc* detStore;
+  if (service("DetectorStore", detStore).isFailure()) {
+    log << MSG::ERROR   << "Unable to access DetectoreStore" << endreq ;
+    return StatusCode::FAILURE;
+  }
+
+  const IGeoModelSvc *geoModel=0;
+  StatusCode sc = service("GeoModelSvc", geoModel);
+  if(sc.isFailure())
+  {
+    log << MSG::ERROR << "Could not locate GeoModelSvc" << endreq;
+    return sc;
+  }
+
+  // dummy parameters for the callback:
+  int dummyInt=0;
+  std::list<std::string> dummyList;
+
+  if (geoModel->geoInitialized())
+  {
+    return geoInit(dummyInt,dummyList);
+  }
+  else
+  {
+    sc = detStore->regFcn(&IGeoModelSvc::geoInit,
+			  geoModel,
+			  &CaloNoiseTool::geoInit,this);
+    if(sc.isFailure())
+    {
+      log << MSG::ERROR << "Could not register geoInit callback" << endreq;
+      return sc;
+    }
+  }
+  return sc;
+}
+
+StatusCode
+CaloNoiseTool::geoInit(IOVSVC_CALLBACK_ARGS)
+{
+  MsgStream log( msgSvc(), name() );
+ 
+  log << MSG::INFO
+      << "CaloNoiseTool called " << this->name() << " initialize() begin" 
+      << endreq;
+  
+  if ((std::string)this->name()=="ToolSvc.calonoisetool") 
+    log << MSG::WARNING << "calonoisetool is obsolete. Please use CaloNoiseToolDefault.py" <<endreq;
+
+  //diagnostic
+  m_diagnostic[CaloGain::LARHIGHGAIN]  =m_DiagnosticHG;
+  m_diagnostic[CaloGain::LARMEDIUMGAIN]=m_DiagnosticMG;
+  m_diagnostic[CaloGain::LARLOWGAIN]   =m_DiagnosticLG;  
+
+  //dumps
+  m_DumpDatabase[CaloGain::LARHIGHGAIN]  =m_DumpDatabaseHG;
+  m_DumpDatabase[CaloGain::LARMEDIUMGAIN]=m_DumpDatabaseMG;
+  m_DumpDatabase[CaloGain::LARLOWGAIN]   =m_DumpDatabaseLG;
+
+  m_Nmessages_forTilePileUp=0;
+
+  if (m_cablingService.retrieve().isFailure()) {
+    log << MSG::ERROR << "Unable to get CablingService " << endreq;
+    return StatusCode::FAILURE;
+  }
+  else log << MSG::DEBUG << "CablingService retrieved" << endreq;
+  
+  //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+  //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::  
+  //retrieves helpers for LArCalorimeter
+
+  m_calo_dd_man = CaloDetDescrManager::instance();
+  m_calo_id_man = m_calo_dd_man->getCalo_Mgr();
+  
+  m_lar_em_id   = m_calo_id_man->getEM_ID();
+  m_lar_hec_id  = m_calo_id_man->getHEC_ID();
+  m_lar_fcal_id = m_calo_id_man->getFCAL_ID();
+
+  //FIXME
+  m_tile_id = m_calo_id_man->getTileID();
+  
+  if (m_tile_id==0)
+  {
+    m_UseTile=false;
+    log << MSG::WARNING
+	<<" no tile_id -> noise unavailable for Tiles !" 
+	<< endreq;
+  } 
+    
+  
+  //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+  //retrieves helpers for Calorimeter
+  m_calocell_id = m_calo_dd_man->getCaloCell_ID();
+
+  //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+  //set calohash maximums
+  m_LArHashMax =0;
+  m_TileHashMax=0;
+  if(m_UseLAr)
+    m_LArHashMax  =   m_lar_em_id->channel_hash_max()
+                    + m_lar_hec_id->channel_hash_max()
+                    + m_lar_fcal_id->channel_hash_max();
+  if(m_UseTile) 
+    m_TileHashMax = m_tile_id->cell_hash_max();
+  m_CaloHashMax = m_LArHashMax + m_TileHashMax;
+
+  //set calohash minimum
+  if(m_UseLAr) m_CaloHashMin = 0;
+  if(m_UseTile && m_UseLAr==false) m_CaloHashMin = m_LArHashMax;
+
+  log << MSG::DEBUG
+      << " UseLAr: " <<m_UseLAr<< " UseTile: " <<m_UseTile
+      << " => CaloHashMin= " <<m_CaloHashMin
+      << " CaloHashMax= " <<m_CaloHashMax
+      << endreq; 
+
+  //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+  //gain-thresholds 
+  m_LowGainThresh[CaloCell_ID::LAREM]    = 3900;//ADC counts in MediumGain 
+  m_HighGainThresh[CaloCell_ID::LAREM]   = 1300;//ADC counts in MediumGain
+  m_LowGainThresh[CaloCell_ID::LARHEC]   = 2500;//ADC counts in MediumGain 
+  m_HighGainThresh[CaloCell_ID::LARHEC]  = 0;//-> high-gain never used for HEC
+  if(m_WorkMode==0)
+  {
+    m_LowGainThresh[CaloCell_ID::LARFCAL]  = 60.*GeV;//MeV
+    m_HighGainThresh[CaloCell_ID::LARFCAL] =  6.*GeV; //MeV
+  }
+  else
+  {
+    m_LowGainThresh[CaloCell_ID::LARFCAL]  = 2000.;//ADC counts
+    m_HighGainThresh[CaloCell_ID::LARFCAL] = 1100.;//ADC counts
+  }
+  m_LowGainThresh[CaloCell_ID::TILE]  = 0.;// unit ?
+  m_HighGainThresh[CaloCell_ID::TILE] = 0.;//
+  //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+  m_highestGain[CaloCell_ID::LAREM]   = CaloGain::LARHIGHGAIN;
+  m_highestGain[CaloCell_ID::LARHEC]  = CaloGain::LARMEDIUMGAIN;
+  m_highestGain[CaloCell_ID::LARFCAL] = CaloGain::LARHIGHGAIN;
+  m_highestGain[CaloCell_ID::TILE]    = CaloGain::TILEHIGHHIGH;
+
+  
+  //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+  //retrieves TileInfo
+  if(m_UseTile)
+  {
+    StatusCode sc = detStore()->retrieve(m_tileInfo, m_tileInfoName);
+    if (sc.isFailure()) {
+      log << MSG::WARNING
+	  << "Unable to retrieve TileInfo from DetectorStore"
+	  <<"  -> noise unavailable for Tiles !" << endreq;
+      m_UseTile=false;
+    }
+  }
+
+  //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+  //retrieve the LAr tools
+  if(m_WorkMode==1 && m_UseLAr)
+  {    
+    //---- retrieve the ADC2MeV tool ----------------
+    if (m_adc2mevTool.retrieve().isFailure()) {
+      log << MSG::ERROR << "Unable to retrieve tool 'LArADC2MeVTool'" << endreq;
+      return StatusCode::FAILURE;
+    }
+    else 
+      log << MSG::DEBUG << " --ILArADC2MeVTool retrieved" << endreq;
+
+    if(m_WithOF) {      
+      //---- retrieve the OFC Tool ----------------
+      StatusCode sc=m_OFCTool.retrieve();
+      //sc = p_toolSvc->retrieveTool("LArOFCTool", algtool2);
+      if (sc.isFailure())  
+	log << MSG::ERROR << "Unable to retrieve LArOFCTool" << endreq;  
+      else 
+	log << MSG::DEBUG << " -- LArOFCTool retrieved" << endreq;
+    }
+  }
+  
+  // Cache, what noise to return
+  m_CachedGetNoiseCDDE=NULL;
+  m_CachedGetNoiseCELL=NULL;
+  if(m_ReturnNoiseName=="electronicNoise") {
+    log << MSG::INFO << "Will cache electronic noise" << endreq;  
+    m_CachedGetNoiseCDDE=&CaloNoiseTool::elecNoiseRMS;
+    m_CachedGetNoiseCELL=&CaloNoiseTool::elecNoiseRMS;
+  }
+  if(m_ReturnNoiseName=="pileupNoise") {
+    log << MSG::INFO << "Will cache pileupNoise noise" << endreq;
+    m_CachedGetNoiseCDDE=&CaloNoiseTool::pileupNoiseRMS;
+    m_CachedGetNoiseCELL=&CaloNoiseTool::pileupNoiseRMS;
+  }
+  if(m_ReturnNoiseName=="totalNoise") {
+    log << MSG::INFO << "Will cache totalNoise noise" << endreq;
+    m_CachedGetNoiseCDDE=&CaloNoiseTool::totalNoiseRMS;
+    m_CachedGetNoiseCELL=&CaloNoiseTool::totalNoiseRMS;
+  }
+  if(m_CachedGetNoiseCELL==NULL || 
+     m_CachedGetNoiseCELL==NULL) {
+    log << MSG::ERROR << "Unknown noise !" << endreq;
+    return StatusCode::FAILURE;
+  }
+
+
+  // callback functions
+  if(m_UseLAr)
+  {
+
+    if(m_isMC){
+      StatusCode sc=detStore()->regFcn(&ICaloNoiseTool::LoadCalibration,
+			     dynamic_cast<ICaloNoiseTool*>(this),
+			     m_dd_noise,m_keyNoise,true);
+      if(sc.isSuccess()){
+	log << MSG::INFO << "Registered callback for key: " 
+	    << m_keyNoise << endreq;
+      } else {
+	log << MSG::ERROR << "Cannot register callback function for key " 
+	    << m_keyNoise << endreq;
+      }
+    }else{
+      StatusCode sc=detStore()->regFcn(&ICaloNoiseTool::LoadCalibration,
+			     dynamic_cast<ICaloNoiseTool*>(this),
+			     m_dd_pedestal,m_keyPedestal,true);
+      if(sc.isSuccess()){
+	log << MSG::INFO << "Registered callback for key: " 
+	    << m_keyPedestal << endreq;
+      } else {
+	log << MSG::ERROR << "Cannot register callback function for key " 
+	    << m_keyPedestal << endreq;
+      }
+    }
+
+    if(m_WorkMode==0)
+    {      
+
+      StatusCode sc=detStore()->regFcn(&ICaloNoiseTool::LoadCalibration,
+			     dynamic_cast<ICaloNoiseTool*>(this),
+			     m_dd_adc2gev,m_keyADC2GeV,true);
+      if(sc.isSuccess()){
+	log << MSG::INFO << "Registered callback for key: " 
+	    << m_keyADC2GeV << endreq;
+      } else {
+	log << MSG::ERROR << "Cannot register callback function for key " 
+	    << m_keyADC2GeV << endreq;
+      }
+
+      sc=detStore()->regFcn(&ICaloNoiseTool::LoadCalibration,
+                            dynamic_cast<ICaloNoiseTool*>(this),
+			     m_detDHOFC,m_keyOFShape,true);
+      if(sc.isSuccess()){
+	log << MSG::INFO << "Registered callback for key: " 
+	    << m_keyOFShape << endreq;
+      } else {
+	log << MSG::ERROR << "Cannot register callback function for key " 
+	    << m_keyOFShape << endreq;
+      }
+    }
+
+    StatusCode sc=detStore()->regFcn(&ICaloNoiseTool::LoadCalibration,
+			   dynamic_cast<ICaloNoiseTool*>(this),
+			   m_dd_acorr,m_keyAutoCorr,true);
+    if(sc.isSuccess()){
+      log << MSG::INFO << "Registered callback for key: " 
+	  << m_keyAutoCorr << endreq;
+    } else {
+      log << MSG::ERROR << "Cannot register callback function for key " 
+	  << m_keyAutoCorr << endreq;
+    }
+  
+    if(m_WorkMode==1) 
+    {
+
+// get pulse shape, fSampl and minBiasRMS to compute pileup noise (MC only)
+      if(m_isMC){
+
+        StatusCode sc=detStore()->regFcn(&ICaloNoiseTool::LoadCalibration,
+			      dynamic_cast<ICaloNoiseTool*>(this),
+			      m_dd_shape,m_keyShape,true);
+        if(sc.isSuccess()){
+	  log << MSG::INFO << "Registered callback for key: " 
+	      << m_keyShape << endreq;
+        } else {
+	  log << MSG::ERROR << "Cannot register callback function for key " 
+	      << m_keyShape << endreq;
+        }
+
+        sc=detStore()->regFcn(&ICaloNoiseTool::LoadCalibration,
+			       dynamic_cast<ICaloNoiseTool*>(this),
+			       m_dd_fsampl,m_keyfSampl,true);
+        if(sc.isSuccess()){
+	  log << MSG::INFO << "Registered callback for key: " 
+	      << m_keyfSampl << endreq;
+	} else {
+	  log << MSG::ERROR << "Cannot register callback function for key " 
+	      << m_keyfSampl << endreq;
+        }
+	
+        sc=detStore()->regFcn(&ICaloNoiseTool::LoadCalibration,
+			       dynamic_cast<ICaloNoiseTool*>(this),
+			       m_dd_minbias,m_keyMinBias,true);
+        if(sc.isSuccess()){
+	  log << MSG::INFO << "Registered callback for key: " 
+	      << m_keyMinBias << endreq;
+         } else {
+	  log << MSG::ERROR << "Cannot register callback function for key " 
+	      << m_keyMinBias << endreq;
+         }
+      }
+
+
+      if (StatusCode::SUCCESS==
+	  detStore()->regFcn(&ILArADC2MeVTool::LoadCalibration,&(*m_adc2mevTool),
+			      &ICaloNoiseTool::LoadCalibration,
+			      dynamic_cast<ICaloNoiseTool*>(this),true) ) {
+	log << MSG::INFO 
+	    << "Registered callbacks for LArADC2MeVTool -> CaloNoiseTool" 
+	    << endreq;
+      } else {
+	log << MSG::ERROR 
+	    << "Cannot register callbacks for LArADC2MeVTool -> CaloNoiseTool" 
+	    << endreq;
+      }
+
+      if(m_WithOF){
+	if (StatusCode::SUCCESS==
+	    detStore()->regFcn(&ILArOFCTool::LoadCalibration,&(*m_OFCTool),
+				&ICaloNoiseTool::LoadCalibration,
+				dynamic_cast<ICaloNoiseTool*>(this),true) ) {
+	  log << MSG::INFO 
+	      << "Registered callbacks for LArOFCTool -> CaloNoiseTool" 
+	      << endreq;
+	} else {
+	  log << MSG::ERROR 
+	      << "Cannot register callbacks for LArOFCTool -> CaloNoiseTool" 
+	      << endreq;
+	}
+      }
+
+    }
+
+  }//UseLAr
+
+  if(m_UseTile)
+  {
+   //currently no database for Tile
+  }
+
+  CNoise    = 0.456E-3;
+  AdcPerMev = 5.*GeV;
+
+
+
+  if (m_loadAtBegin) {
+    log << MSG::DEBUG << "Setting callback function to load calibration at begin of run" << endreq;
+    // Incident Service: 
+    IIncidentSvc* incSvc;
+    StatusCode sc = service("IncidentSvc", incSvc);
+    if (sc.isFailure()) {
+      log << MSG::ERROR << "Unable to retrieve pointer to IncidentSvc "
+	       << endreq;
+      return sc;
+    }
+    
+    //start listening to "BeginRun". The incident should be fired AFTER the IOV callbacks and only once.
+    const long priority=std::numeric_limits<long>::min(); //Very low priority
+    incSvc->addListener(this, "BeginRun", priority ,false,true); //single-shot incident
+  }
+
+
+  //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+  log << MSG::INFO << "CaloNoiseTool initialize() end" << endreq;
+
+  return StatusCode::SUCCESS;
+}
+
+
+//////////////////////////////////////////////////
+ 
+StatusCode 
+CaloNoiseTool::initContainers()
+{
+  //initialize the maps m_ElecNoiseContainer and m_ScaleContainer 
+  //(assuming type of elements of the containers is the same for Tile and LAr)
+
+  MsgStream log( msgSvc(), name() );
+  log << MSG::INFO << "initContainers() begin " << endreq;
+
+  // intialise indices
+  this->initIndex(); 
+
+  //::::::::::::::::::::::::::::::::::::::     
+  m_elecNoiseRAWContainer.resize(m_idSymmCaloHashContainer.size());
+  m_elecNoiseCELLContainer.resize(m_idSymmCaloHashContainer.size());
+  if(m_WorkMode==1)
+    m_pileupNoiseContainer.resize(m_idSymmCaloHashContainer.size());
+  m_adc2mevContainer.resize(m_idSymmCaloHashContainer.size());
+  //::::::::::::::::::::::::::::::::::::::
+  log << MSG::INFO << "initContainers() end : "
+      <<" size of containers = "
+      <<m_idSymmCaloHashContainer.size()
+      << endreq;
+  return StatusCode::SUCCESS;
+}
+
+//////////////////////////////////////////////////
+
+void 
+CaloNoiseTool::initIndex()
+
+{
+  //::::::::::::::::::::::::::::::::::::::
+  m_indexContainer.clear();
+  m_indexContainer.resize(m_CaloHashMax,
+                          static_cast<unsigned int> (-1));
+
+  //maybe the other container sould be reset
+  m_idSymmCaloHashContainer.clear();
+  m_idSymmCaloHashContainer.reserve(5000);
+
+  
+  
+  for (unsigned int intIdCaloHash=m_CaloHashMin; intIdCaloHash<m_CaloHashMax;
+       ++intIdCaloHash)
+  {  
+    
+
+    IdentifierHash idCaloHash=static_cast<IdentifierHash>(intIdCaloHash);
+
+    //    std::cout << "DRDEBUG in initIndex loop " << intIdCaloHash << std::endl ;
+
+    
+    // initialize the vector of indexes (big vector without symmetry)
+
+
+
+
+    // o idCaloHash -> id -> idSymm (symmetry phi->0 and z->|z|)
+    // o idSymm -> idSymmCaloHash
+    // o idSymmCaloHash stored in m_idSymmCaloHashContainer
+    // o an index is associated to an idSymmCaloHash
+    // o index stored in m_indexContainer
+    
+    CaloCell_ID::SUBCALO iCalo = this->caloNum(idCaloHash); 
+    Identifier     id    = m_calocell_id->cell_id(idCaloHash);
+    Identifier     regId;
+    Identifier     idSymm;
+    IdentifierHash idSymmCaloHash;
+
+    if(m_UseSymmetry)
+    {
+      if(iCalo==CaloCell_ID::LAREM) 
+      {
+        int barrel_ec = m_lar_em_id->barrel_ec(id);
+        int sampling  = m_lar_em_id->sampling(id);
+        int region    = m_lar_em_id->region(id);
+        int eta       = m_lar_em_id->eta(id);
+        regId         = m_lar_em_id->region_id(abs(barrel_ec),sampling,region);
+        idSymm        = m_lar_em_id->channel_id(regId,
+                                                eta,
+                                                m_calocell_id->phi_min(regId));
+        idSymmCaloHash= m_calocell_id->calo_cell_hash(idSymm);
+      }
+      else if(iCalo==CaloCell_ID::LARHEC) 
+      {
+        int pos_neg  = m_lar_hec_id->pos_neg(id);
+        int sampling = m_lar_hec_id->sampling(id);
+        int region   = m_lar_hec_id->region(id);
+        int eta      = m_lar_hec_id->eta(id);
+        regId        = m_lar_hec_id->region_id(abs(pos_neg),sampling,region);
+        idSymm       = m_lar_hec_id->channel_id(regId,
+                                                eta,
+                                                m_calocell_id->phi_min(regId));
+        idSymmCaloHash= m_calocell_id->calo_cell_hash(idSymm);
+      }
+      else if(iCalo==CaloCell_ID::LARFCAL) 
+      {
+        int pos_neg = m_lar_fcal_id->pos_neg(id);
+        int module  = m_lar_fcal_id->module(id);
+        int eta     = m_lar_fcal_id->eta(id);
+        int phi     = m_lar_fcal_id->phi(id);
+        if(phi>7) phi = phi-8; //as in LArMCSymTool
+        regId       = m_lar_fcal_id->module_id(abs(pos_neg),module);
+        idSymm      = m_lar_fcal_id->channel_id(regId,
+                                                eta,
+                                                phi);
+        idSymmCaloHash= m_calocell_id->calo_cell_hash(idSymm);
+      }
+      else if(iCalo==CaloCell_ID::TILE) 
+      {
+        idSymm         = id;
+        idSymmCaloHash = m_calocell_id->calo_cell_hash(idSymm);
+      }
+      else
+      {
+        MsgStream log( msgSvc(), name() );
+        log << MSG::WARNING
+            <<"CaloNoiseTool::chooseIndex  wrong id ! " 
+            << m_lar_em_id->show_to_string(id) << endreq ;
+        continue ;
+      }
+
+      assert (idSymmCaloHash < m_CaloHashMax);
+      if (m_indexContainer[idSymmCaloHash] != static_cast<unsigned int>(-1)) {
+        m_indexContainer[idCaloHash] = m_indexContainer[idSymmCaloHash];
+        continue;
+      }
+    }
+    else idSymmCaloHash=idCaloHash;// no symmetry
+
+
+    if(iCalo!=CaloCell_ID::TILE) {
+      if(this->checkIfConnected(id)==false) {
+        std::cout << "DRDEBUG ... NOT connected " << std::endl ;
+        continue; 
+      }
+      // else { std::cout << "DRDEBUG ... connected " << std::endl ;}
+    }
+
+    //  std::cout << "DRDEBUG ... check connected OK " << intIdCaloHash << std::endl ;
+
+    /* cabling eta= 0 -> 0.8  (for private debug)
+       int samp  = m_lar_em_id->sampling(id);
+       int region= m_lar_em_id->region(id);
+       int eta   = m_lar_em_id->eta(id);
+       int phi   = m_lar_em_id->phi(id);
+       if(samp==1 && eta>=256) return;
+       if(samp==1 && eta==0) return;
+       if(samp==2 && eta>=32) return;
+       if(samp==3 && eta>=16) return;
+       if(region>0) return;
+    */
+  
+    // std::cout << "DRDEBUG ... register under  " << m_new_index << std::endl ;
+
+    //we come here if idSymmHash is not yet indexed (and is connected)   
+    m_indexContainer[idCaloHash] = 
+      m_indexContainer[idSymmCaloHash] =
+      m_idSymmCaloHashContainer.size();
+  
+    m_idSymmCaloHashContainer.push_back(idSymmCaloHash);
+  }// loop on all cells
+}
+
+//////////////////////////////////////////////////
+
+bool 
+CaloNoiseTool::checkIfConnected(const Identifier &id)
+{
+  try
+  {
+    HWIdentifier hwid = m_cablingService->createSignalChannelID(id);
+    if(!m_cablingService->isOnlineConnected(hwid)) 
+    {
+      //std::cout<<m_lar_em_id->show_to_string(id)
+      //	       <<" not connected !!"<<std::endl;
+      return false;
+    }
+  }
+  catch(LArID_Exception & except) 
+    {return false;}
+  //std::cout<<m_lar_em_id->show_to_string(id)
+  //	       <<" connected !!"<<std::endl;  
+  return true;
+}
+
+//////////////////////////////////////////////////
+
+int 
+CaloNoiseTool::index(const IdentifierHash &idCaloHash)
+{
+  return m_indexContainer[idCaloHash];
+}
+
+//////////////////////////////////////////////////
+
+StatusCode CaloNoiseTool::LoadCalibration(IOVSVC_CALLBACK_ARGS_K(keys))
+{
+
+  MsgStream log(msgSvc(), name());
+  
+  log << MSG::INFO << "Callback invoked for " << keys.size() << " keys " << endreq;
+
+  // invalidates the cache
+  m_cacheValid = false; 
+
+  return StatusCode::SUCCESS;
+}
+
+//////////////////////////////////////////////////
+ 
+StatusCode 
+CaloNoiseTool::initData()
+{
+  MsgStream log( msgSvc(), name() );
+
+  StatusCode sc ;
+  sc = this->initContainers();
+  if (sc.isFailure()) {
+    log << MSG::WARNING
+			  << "initContainers failed" << endreq ;
+    return sc;
+  }
+ 
+  // reset diagnostics
+  for(int igain=0;igain<CaloGain::LARNGAIN;++igain)
+  {
+    m_nCellsWithProblem[igain]=0;
+    for(int i=0;i<5000;++i) m_nReason[i][igain]=0;
+    for(int i=0;i<10;++i)   m_itReason[i][igain]=0;
+  }
+
+ 
+  if(m_UseLAr)
+  {
+    //stores the Adc2MeV factors 
+    sc = this->initAdc2MeV();
+    if (!sc.isSuccess())  
+      log << MSG::ERROR << "initData(): error with initAdc2MeV() " << endreq; 
+  }
+
+  //calculates and stores the electronic noise
+  sc = this->initElecNoise(); 
+  if (!sc.isSuccess())  
+    log << MSG::ERROR << "initData(): error with initElecNoise() " << endreq;
+
+  //calculates and stores the pileup noise
+  if(m_WorkMode==1) {
+    sc = this->initPileUpNoise();
+    if (!sc.isSuccess())  
+      log << MSG::ERROR << "initData(): error with initPileUpNoise() "<<endreq;
+    }
+  
+
+  m_cacheValid=true; 
+  return StatusCode::SUCCESS;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+StatusCode 
+CaloNoiseTool::initAdc2MeV() 
+{
+  MsgStream log( msgSvc(), name() );
+  log << MSG::INFO << "initAdc2MeV() begin " << endreq;
+  for (unsigned int it=0; it<m_adc2mevContainer.size(); ++it)
+  { 
+    CaloCell_ID::SUBCALO iCalo = this->caloNum(m_idSymmCaloHashContainer[it]);
+    Identifier id=m_calocell_id->cell_id(m_idSymmCaloHashContainer[it]);
+    //::::::::::::::::::::::::::::::::::::::
+    if(m_WorkMode==0)    
+    {
+      if(iCalo==CaloCell_ID::LAREM || iCalo==CaloCell_ID::LARHEC) 
+      { //only for EM and HEC
+	m_adc2mevContainer[it]=m_dd_adc2gev->AllFactors(id);
+	for(unsigned int i=0;i<(m_adc2mevContainer[it]).size();++i)
+	  (m_adc2mevContainer[it])[i] *= GeV;
+      }
+    }
+    //::::::::::::::::::::::::::::::::::::::
+    else if(m_WorkMode==1)  
+    {
+      if(iCalo!=CaloCell_ID::TILE) 
+      {
+	std::vector<float>& adc2mevVector = m_adc2mevContainer[it];
+        adc2mevVector.reserve (CaloGain::LARNGAIN);
+	for(unsigned int igain=0;igain<CaloGain::LARNGAIN;++igain)
+        {
+	  const std::vector<float> *
+	    polynom_adc2mev = &(m_adc2mevTool->ADC2MEV(id,igain));
+	  if(polynom_adc2mev->size()==0)
+	    adc2mevVector.push_back(0.);
+	  else 
+	    adc2mevVector.push_back((*polynom_adc2mev)[1]);
+	}
+      }
+    } 
+    //::::::::::::::::::::::::::::::::::::::
+  } 
+  log << MSG::INFO << "initAdc2MeV() end " << endreq;
+  return StatusCode::SUCCESS;
+}
+
+//////////////////////////////////////////////////
+
+StatusCode 
+CaloNoiseTool::initElecNoise()
+{
+  // initialize the parameters (the same for each event for each Identifier) 
+  // for the calculation of the electronic noise
+
+
+  MsgStream log( msgSvc(), name() );
+  log << MSG::DEBUG << "initElecNoise() begin " << endreq;
+ 
+  for (unsigned int it=0; it<m_elecNoiseRAWContainer.size(); ++it)
+  {
+    CaloCell_ID::SUBCALO iCalo = this->caloNum(m_idSymmCaloHashContainer[it]);
+    //::::::::::::::::::::::::::::::::::::::        
+    if(iCalo==CaloCell_ID::TILE) 
+      m_elecNoiseRAWContainer[it] =
+        this->calculateElecNoiseForTILE(m_idSymmCaloHashContainer[it]);
+    //::::::::::::::::::::::::::::::::::::::
+    else
+      m_elecNoiseRAWContainer[it] =
+	this->calculateElecNoiseForLAR(m_idSymmCaloHashContainer[it],iCalo,
+                                       m_Nminbias);
+    //::::::::::::::::::::::::::::::::::::::
+    m_elecNoiseCELLContainer[it] = m_elecNoiseRAWContainer[it];
+  }
+
+  //print diagnostic
+  if(m_UseLAr)
+    for(int igain=0;igain<CaloGain::LARNGAIN;++igain)
+      if(m_diagnostic[igain])
+      {
+	log<<MSG::INFO<<endreq;
+	log<<MSG::INFO<<"===== Diagnostic for  gain "<<igain<<" ====="<<endreq;
+	log<<MSG::INFO<<endreq;
+	for(int i=0;i<m_nCellsWithProblem[igain];++i)
+        {
+	  Identifier id = m_calocell_id->cell_id(m_idHash[i][igain]);
+	  log<<MSG::DEBUG<<m_idHash[i][igain]<<" "
+	     <<m_lar_em_id->show_to_string(id)
+	     <<" "<<m_nReason[i][igain]<<" : ";
+	  for(int j=0;j<m_nReason[i][igain];++j)
+	    log<<MSG::DEBUG<<m_reasonName[m_reason[i][j][igain]]<<" ";
+	  log << MSG::DEBUG<<endreq;
+	}
+	log<<MSG::DEBUG<<endreq;
+	log<<MSG::INFO<<"N cells with problem(s) = "
+	   <<m_nCellsWithProblem[igain]<<endreq;
+	for(int i=0;i<10;++i)
+	if(m_itReason[i][igain]>0) 
+	  log<<MSG::INFO<<i<<" "<<m_reasonName[i] 
+	     <<": for "<<m_itReason[i][igain]<<" cells"<<endreq;
+      }
+
+  log << MSG::DEBUG << "initElecNoise() end " << endreq;
+  return StatusCode::SUCCESS;
+}
+
+//////////////////////////////////////////////////
+
+StatusCode 
+CaloNoiseTool::initPileUpNoise()
+{
+  // initialize the parameters (the same for each event for each Identifier) 
+  // for the calculation of the PileUp noise
+
+  MsgStream log( msgSvc(), name() );
+  log << MSG::DEBUG << "initPileUpNoise() begin " << endreq;
+  log << MSG::INFO << "N events of Minimum Bias per bunch crossing =  " 
+                   << m_Nminbias<< endreq;
+  //::::::::::::::::::::::::::::::::::::::
+  for (unsigned int it=0; it<m_pileupNoiseContainer.size(); ++it)  
+    m_pileupNoiseContainer[it]
+      =this->calculatePileUpNoise(m_idSymmCaloHashContainer[it],m_Nminbias);
+  //::::::::::::::::::::::::::::::::::::::
+  m_Nminbias_usedForCache=m_Nminbias;
+  log << MSG::DEBUG << "initPileUpNoise() end " << endreq;
+  return StatusCode::SUCCESS;
+}
+
+//////////////////////////////////////////////////
+
+std::vector<float> 
+CaloNoiseTool::calculateElecNoiseForLAR(const IdentifierHash & idCaloHash,
+					const CaloCell_ID::SUBCALO iCalo, 
+					const float &Nminbias)
+{ 
+ /*  
+
+E=SUMi { OFCi * (short[ (PulseShapei*Ehit/Adc2MeV(gain) + Noisei(gain)  
+                       + pedestal) ]  
+                 - pedestal) * Adc2Mev(gain) ] } 
+   with Noisei =SUMj { cij*Rndm } * SigmaNoise
+
+   NB:  without short and with cij=identity (no autocorrelation) 
+        E=SUMi { NOISEi(gain)*Rndm } 
+        with  NOISEi(gain) = Adc2MeV(gain) * OFCi * SigmaNoise(gain)        
+
+   => Sigma^2=SUMi{NOISEi(gain)*NOISEj(gain)*cij} + quantification part
+             =        NOISE(gain)                 +   REST
+      Sigma  = sqrt( NOISE(gain) + REST) 
+
+
+========= for FCAL on WorkMode=0 (NOVA DB) ==================== 
+
+E=SUMi { OFCi * (short[ ( (PulseShapei*Ehit+Noisei)*gain + CNoisei ) 
+                         * AdcPerGev + pedestal] 
+                 - pedestal) } / gain
+   with Noisei =SUMj { cij*Rndm } * SigmaNoise
+        CNoisei=SUMj { cij*Rndm } * CNoise
+
+   NB:  without short and with cij=identity (no autocorrelation) 
+        E=SUMi { Ai*Rndm + Bi*Rndm } 
+        with  Ai=(AdcPerGev)     *OFCi*SigmaNoise
+              Bi=(AdcPerGev/gain)*OFCi*CNoise
+
+   => Sigma^2=SUMi{Ai*Aj*cij + Bi*Bj*cij } + quantification part
+             =        A      + (  B        +      C) / gain^2 
+ 
+*/
+
+  std::vector<float> sigmaVector (CaloGain::LARNGAIN,BADVALUE);
+  float sigma;
+
+  Identifier id = m_calocell_id->cell_id(idCaloHash);
+
+  for(int igain=0;igain<CaloGain::LARNGAIN;++igain) 
+  {
+    m_noiseOK=true;
+    //::::::::::::::::::::::::::::::::::::::::::::::::::
+    //==== retrieve the database ====
+    //::::::::::::::::::::::::::::::::::::::::::::::::::
+
+    for(int i=0;i<nDATABASE;++i) m_retrieve[i]=false; 
+    m_retrieve[iADC2MEV]=true;
+    m_retrieve[iSIGMANOISE]=true;
+    m_retrieve[iAUTOCORR]=true;
+    if(m_WithOF) m_retrieve[iOFC]=true;
+    //m_retrieve[iSHAPE]=true;
+    StatusCode sc=this->retrieveCellDatabase(idCaloHash,id,igain,Nminbias,
+					     "calculateElecNoiseForLAR");    
+    //if(sc.isFailure()) continue;
+      //NOTE: if an element of the database is empty, 
+      //      leave the iteration (on gains) => value will be BADVALUE
+      //the interfaces take care of that !   
+
+    //::::::::::::::::::::::::::::::::::::::::::::::::::
+    //==== calculations ====
+    //::::::::::::::::::::::::::::::::::::::::::::::::::
+
+    if(sc.isFailure()) {
+      sigma=float(BADVALUE_TO_RETURN);
+    }
+    else    
+    {
+      float OFC_AC_OFC,OFC_OFC;
+      this->commonCalculations(OFC_AC_OFC,OFC_OFC,1);
+      //::::::::::::::::::::::::::::::::::::::
+      if(iCalo==CaloCell_ID::LARFCAL && m_WorkMode==0)
+      {
+        float A=OFC_AC_OFC*SigmaNoise*SigmaNoise*AdcPerMev*AdcPerMev; 
+          // A is the part with SigmaNoise 
+        float B=OFC_AC_OFC*CNoise*CNoise*AdcPerMev*AdcPerMev;     
+          // B is the part with the constant noise (CNoise) 
+        float C=OFC_OFC/(12.);				 
+          // C is the quantification part (effect of the truncation  short(..) )
+          //   12.=sqrt(12)*sqrt(12)
+        float gain[3]={1.,10.,100.};  
+        sigma=A + (B+C)/(gain[igain]*gain[igain]) ;     
+      }
+      else// USUAL CASE
+      {
+        float NOISE= OFC_AC_OFC*SigmaNoise*SigmaNoise ;
+        float REST = OFC_OFC/12.;// 12.=sqrt(12)*sqrt(12)
+        sigma=(NOISE+REST) * Adc2MeVFactor*Adc2MeVFactor;   
+      }
+      //::::::::::::::::::::::::::::::::::::::
+      if(sigma>0) sigma=sqrt(sigma);
+      else  
+      {
+        sigma=-sqrt(-sigma);
+        //:::::::::::::::::
+        //      MsgStream log(msgSvc(), name());
+        //      if(igain==0) log << MSG::ERROR 
+        //	  <<m_lar_em_id->show_to_string(id)<<" gain "<<igain
+        //	  <<" : negative root square => WRONG noise "
+        //	  <<"(please check if OFC or AutoCorr are correct for this cell)"
+        //	  <<endreq;
+      }
+
+      //diagnostic    
+      if(m_diagnostic[igain]) 
+      {
+        if(m_noiseOK && sigma<0)       
+  	  this->updateDiagnostic(9,"sigma<0",igain);         
+        if(m_noiseOK==false) 
+        {
+	  m_idHash[m_nCellsWithProblem[igain]][igain]=idCaloHash;
+	  ++m_nCellsWithProblem[igain];
+	  m_nReason[m_nCellsWithProblem[igain]][igain]=0;
+        }      
+      }
+      //::::::::::::::::::::::::::::::::::::::
+      if(m_noiseOK==false || sigma<0) sigma=float(BADVALUE_TO_RETURN);
+    }
+    sigmaVector[igain]=sigma;
+
+  }//loop on gains
+  
+  return sigmaVector;  
+}
+
+//////////////////////////////////////////////////
+
+std::vector<float> 
+CaloNoiseTool::calculateElecNoiseForTILE(const IdentifierHash & idCaloHash)
+{
+  std::vector<float> sigmaVector (CaloGain::LARNGAIN,BADVALUE);
+
+  Identifier id = m_calocell_id->cell_id(idCaloHash);
+  //std::cout<<"TILE elecnoise " <<m_lar_em_id->show_to_string(id);
+  for(int igain=0;igain<CaloGain::LARNGAIN;++igain)
+  {
+    CaloGain::CaloGain gain = static_cast<CaloGain::CaloGain>(igain);
+    float sigma = m_tileInfo->CellNoiseSigma(id,gain);
+    //the LAr gain is internally (in CellNoiseSigma) converted into Tile gain
+    sigmaVector[igain]= sigma;
+    //::::::::::::::::::::::::::::::::::::::
+    //std::cout<<" "<<sigma;
+  }
+  //std::cout<<" "<<std::endl;
+  
+  return sigmaVector;
+}
+
+//////////////////////////////////////////////////
+
+float 
+CaloNoiseTool::calculatePileUpNoise(const IdentifierHash & idCaloHash, 
+				    const float &Nminbias)
+{
+  if(Nminbias<=0.000001) return 0.;
+    //only on WorkMode==1
+  if(this->caloNum(idCaloHash)==CaloCell_ID::TILE) return 0.;
+    //no pile-up for tiles, for the moment ...
+
+  /*
+    SigmaPileUp^2 = ( SigmaE * sqrt(Nmb) )^2 * Ipileup/Tc
+    where:  
+      - Ipileup = Tc * SUM(k=1->Nb) g(tk)^2 
+      - Tc is the time between bunch crossings
+      - Nb is the number of bunch crossings 
+        (over which the response function is non-zero)
+      - g is the shape
+      - SigmaE is the RMS of the energy in 1 minimum bias event
+      - Nmb is the number of minimum bias events (depending on the luminosity)
+   */ 
+  
+  Identifier id = m_calocell_id->cell_id(idCaloHash);
+
+  //::::::::::::::::::::::::::::::::::::::
+
+  for(int i=0;i<nDATABASE;++i) m_retrieve[i]=false;   
+  m_retrieve[iAUTOCORR]=true;
+  if(m_WithOF) m_retrieve[iOFC]=true;
+  m_retrieve[iSHAPE]=true;
+  m_retrieve[iMINBIASRMS]=true;
+  m_retrieve[iFSAMPL]=true;
+  StatusCode sc=this->retrieveCellDatabase(idCaloHash,id,
+					   CaloGain::LARHIGHGAIN,Nminbias,
+					   "calculatePileUpNoise");    
+  if(sc.isFailure()) return 0.;
+
+  //::::::::::::::::::::::::::::::::::::::
+
+  //in the database, RMS is at the scale of the Hits, 
+  // so we need to scale it at the e.m scale using the sampling fraction ...
+  MinBiasRMS /= fSampl;
+
+  //::::::::::::::::::::::::::::::::::::::
+
+// overall normalization factor
+  float  PileUp=MinBiasRMS*sqrt(Nminbias);
+ 
+  //::::::::::::::::::::::::::::::::::::::
+
+  float OFC_AC_OFC,OFC_OFC; 
+  unsigned int firstSample=m_firstSample; 
+  // for HEC, always use firstSample=1 when the number of samples is 4 
+  if (m_lar_hec_id->is_lar_hec(id) && m_nsamples==4 && m_firstSample==0) firstSample=1; 
+  this->commonCalculations(OFC_AC_OFC,OFC_OFC,2,firstSample); 
+ 
+  //::::::::::::::::::::::::::::::::::::::
+
+  PileUp*=sqrt(OFC_AC_OFC);
+
+  //std::cout<<"PILEUP "<<m_lar_em_id->show_to_string(id)<<" "
+  //	   <<MinBiasRMS<<" "<<OFC_AC_OFC<<" "<<PileUp<<std::endl;
+
+  return PileUp; 
+}
+
+//////////////////////////////////////////////////
+
+void
+CaloNoiseTool::commonCalculations(float & OFC_AC_OFC,float & OFC_OFC,int icase, unsigned int firstSample) 
+{
+
+  // case 1 electronic noise
+  if (icase==1) {
+     //calculate the matrix of autocorrelation
+     for(int i=0;i<m_nsamples;++i) 
+       for(int j=0;j<m_nsamples;++j)  
+       { 
+         if(i==j)               c[i][j] = 1.; 
+         for(int k=1;k<m_nsamples;++k) 
+	   if(i==j-k || i==j+k)	
+	     c[i][j] = AutoCorr[k-1];
+       }
+  }
+// other case: pileup noise
+  else {
+     for (int i=0;i<m_nsamples;i++) {
+      for (int j=0;j<m_nsamples;j++)
+      {
+        c[i][j]=0.;
+        int nsize = Shape.size();
+        for (int k=0;k<nsize;k++) {
+           if ((j-i+k)>=0 && (j-i+k)<nsize) {
+             int ibunch=0;
+             if ((i+firstSample-k)%m_deltaBunch == 0 ) ibunch=1;
+             c[i][j] += ((double) (ibunch)) * (Shape[k]) * (Shape[j-i+k]);
+           }
+        }
+      }
+     }
+  }
+
+  //::::::::::::::::::::::::::::::::::::::
+  OFC_AC_OFC=0;
+  OFC_OFC=0;
+  
+  if(m_WithOF)     
+  {
+    float tmp;
+    for(int i=0;i<m_nsamples;++i) 
+    {   
+      tmp=0.; 
+      for(int j=0;j<m_nsamples;++j)  	
+	tmp+=c[i][j]*OFC[j]; 
+      tmp*=OFC[i]; 
+      OFC_AC_OFC+=tmp;  
+      OFC_OFC+= OFC[i] * OFC[i]; 
+      //std::cout<<"    "<<i<<" "<<OFC_AC_OFC<<" "<<OFC_OFC<<std::endl;
+    }
+  }
+  else //equivalent to have only the third sample (peak)
+  {
+    // <=> (*OFC)[2]==1, others are null
+    OFC_AC_OFC=c[2][2];
+    OFC_OFC=1;
+  } 
+  //::::::::::::::::::::::::::::::::::::::
+}
+
+//////////////////////////////////////////////////
+
+StatusCode
+CaloNoiseTool::retrieveCellDatabase(const IdentifierHash & idCaloHash,
+				    const Identifier & id, 
+				    int igain,
+				    const float &Nminbias,
+				    std::string function_name)
+{
+  bool PRINT=false;
+  if(m_DumpDatabase[igain]) PRINT=true;
+
+  if(PRINT) std::cout<<"============ "<<m_lar_em_id->show_to_string(id)
+		     <<" hash="<<idCaloHash
+		     <<" gain="<<igain
+		     <<" (HG="<<CaloGain::LARHIGHGAIN
+		     << ",MG="<<CaloGain::LARMEDIUMGAIN
+		     << ",LG="<<CaloGain::LARLOWGAIN<<")"<<std::endl;
+
+  //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+  //ADC2MEV
+  if(m_retrieve[iADC2MEV])
+  {
+    if(m_WorkMode==0) 
+    {
+      const std::vector<float>& vAdc2MeVFactor = m_dd_adc2gev->AllFactors(id);
+      Adc2MeVFactor = vAdc2MeVFactor[igain]*GeV;
+    }
+    else 
+    {      
+      int index=this->index(idCaloHash);
+      Adc2MeVFactor = (m_adc2mevContainer[index])[igain];       
+    } 
+    if(PRINT) std::cout<<"Adc2MeVFactor="<<Adc2MeVFactor<<std::endl;
+  }
+
+  //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+  //SIGMANOISE
+  if(m_retrieve[iSIGMANOISE])
+  {
+    if(m_isMC)
+      SigmaNoise = m_dd_noise->noise(id,igain);
+    else          
+    {
+      RMSpedestal = m_dd_pedestal->pedestalRMS(id,igain);
+      if(RMSpedestal>(1.0+LArElecCalib::ERRORCODE)) 
+	SigmaNoise = RMSpedestal;
+      else
+      {     
+	//	MsgStream log(msgSvc(), name());
+	//	log << MSG::WARNING << function_name
+	//	    <<" PedestalRMS vector empty for "
+	//	    <<m_lar_em_id->show_to_string(id)<<" at gain "<<igain<<endreq;     
+        SigmaNoise = 0.;
+      }
+    }
+    if(PRINT) std::cout<<"SigmaNoise(inADC)="<<SigmaNoise<<std::endl;
+  }
+
+  //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+  //AUTOCORR
+  if(m_retrieve[iAUTOCORR])
+  {
+    AutoCorr = m_dd_acorr->autoCorr(id,igain);
+    ////////// 
+    if(PRINT) {
+      std::cout<<"AutoCorr= ";
+      for(unsigned int i=0;i<AutoCorr.size();++i)                
+	std::cout<<AutoCorr[i]<<" ";
+      std::cout<<std::endl;
+    }
+  }
+
+  //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+  //OFC
+  if(m_retrieve[iOFC])
+  {
+    if(m_WorkMode==0) OFC = m_detDHOFC->OFC_a(id, igain, 0) ;
+    else              OFC = m_OFCTool->OFC_a(id, igain) ;
+    /////////
+    if(PRINT) {
+      std::cout<<"OFC= ";
+      for(unsigned int i=0;i<OFC.size();++i) 
+	std::cout<<OFC[i]<<" ";
+      std::cout<<"  Nminbias="<<Nminbias<<std::endl;
+    }
+  }
+
+  //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+  //SHAPE
+  if(m_retrieve[iSHAPE])
+  {
+    Shape = m_dd_shape->Shape(id,0);
+    //////////
+    if(PRINT) {
+      std::cout<<"Shape= ";
+      for(unsigned int i=0;i<Shape.size();++i) 
+	std::cout<<Shape[i]<<" ";
+      std::cout<<std::endl;
+    }
+  }
+
+  //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+  //MinimumBias RMS 
+  if(m_retrieve[iMINBIASRMS])
+  {
+    MinBiasRMS = m_dd_minbias->minBiasRMS(id);
+    if(PRINT) std::cout<<"MinBiasRMS="<<MinBiasRMS<<std::endl;
+  }
+
+  //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+  //SAMPLING FRACTION
+  if(m_retrieve[iFSAMPL])
+  {
+    fSampl = m_dd_fsampl->FSAMPL(id);
+    if(PRINT) std::cout<<"fSampl="<<fSampl<<std::endl;
+  }
+
+  return this->checkCellDatabase(id,igain,function_name);
+}
+
+//////////////////////////////////////////////////
+
+StatusCode
+CaloNoiseTool::checkCellDatabase(const Identifier & id, int igain,
+				 std::string function_name)
+{
+  StatusCode StatusDatabase=StatusCode::SUCCESS;
+
+  //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+  //ADC2MEV
+  if(m_retrieve[iADC2MEV]) {
+    if(fabs(Adc2MeVFactor)<0.000001) {
+      StatusDatabase=StatusCode::FAILURE;
+      if(m_diagnostic[igain]) 
+	this->updateDiagnostic(0,"Adc2MeVFactor=0",igain);
+    }
+  }
+
+  //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+  //SIGMANOISE
+  if(m_retrieve[iSIGMANOISE]) {
+    if(fabs(SigmaNoise)<0.000001) {
+      StatusDatabase=StatusCode::FAILURE;
+      if(m_diagnostic[igain]) 
+	this->updateDiagnostic(1,"SigmaNoise=0",igain);	
+    }
+  }
+
+  //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+  //AUTOCORR
+  if(m_retrieve[iAUTOCORR])
+  {
+    if (!AutoCorr.valid()) 
+    {
+      MsgStream log(msgSvc(), name());
+      log << MSG::WARNING << function_name
+	  <<" AutoCorr invalid for "
+	  <<m_lar_em_id->show_to_string(id)<<" at gain "<<igain<<endreq;
+      StatusDatabase=StatusCode::FAILURE;
+    }
+    if (AutoCorr.size()==0) 
+    {
+      //      MsgStream log(msgSvc(), name());
+      //      log << MSG::WARNING << function_name
+      //	  <<"  AutoCorr vector empty for "
+      //	  <<m_lar_em_id->show_to_string(id)<<" at gain "<<igain<<endreq;
+      StatusDatabase=StatusCode::FAILURE;
+      if(m_diagnostic[igain]) this->updateDiagnostic(2,"AC empty",igain);
+    }
+    /* // autocorr can be null (and it is for low-gain !), so allow it !
+    else            
+      if(m_diagnostic[igain])
+      {
+	unsigned int n_ACnull=0;
+	for(unsigned int i=0;i<(*AutoCorr).size();++i)
+	  if(fabs((*AutoCorr)[i])<0.000001) ++n_ACnull;
+	if(n_ACnull==(*AutoCorr).size()) 
+	  this->updateDiagnostic(3,"AC=0",igain);
+      }
+    */
+    m_nsamples=AutoCorr.size()+1;
+  }
+
+  //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+  //OFC
+  if(m_retrieve[iOFC])
+  {
+    if (!OFC.valid()) 
+    {
+      MsgStream log(msgSvc(), name());
+      log<<MSG::WARNING<< function_name
+	 <<"  OFC pointer null for "
+	 <<m_lar_em_id->show_to_string(id)<<" at gain "<<igain<<endreq;
+      StatusDatabase=StatusCode::FAILURE;
+    }
+    if (OFC.size()==0) 
+    {
+      //      MsgStream log(msgSvc(), name());
+      //      log<<MSG::WARNING<< function_name
+      //	 <<"  OFC vector empty for "
+      //	 <<m_lar_em_id->show_to_string(id)<<" at gain "<<igain<<endreq;
+      StatusDatabase=StatusCode::FAILURE;
+      if(m_diagnostic[igain]) this->updateDiagnostic(4,"OFC empty",igain);
+    }
+    else
+      if(m_diagnostic[igain]) 
+      {
+	unsigned int n_OFCnull=0;
+	for(unsigned int i=0;i<OFC.size();++i)
+	  if(fabs(OFC[i])<0.000001) ++n_OFCnull;
+	if(n_OFCnull==OFC.size()) this->updateDiagnostic(5,"OFC=0",igain);
+      }
+    m_nsamples=OFC.size();
+  }
+
+  //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+  //SHAPE
+  if(m_retrieve[iSHAPE])
+  {
+    if (!Shape.valid()) 
+    {
+      MsgStream log(msgSvc(), name());
+      log<<MSG::WARNING<< function_name
+	 <<"  Shape pointer null -> PileUp will be 0 for "
+	 <<m_lar_em_id->show_to_string(id)<<endreq;
+      StatusDatabase=StatusCode::FAILURE;
+    }
+    if (Shape.size()==0) 
+    {      
+      //      MsgStream log(msgSvc(), name());
+      //      log<<MSG::WARNING<< function_name
+      //       <<"  Shape vector empty -> PileUp will be 0 for "
+      //       <<m_lar_em_id->show_to_string(id)<<endreq;
+      StatusDatabase=StatusCode::FAILURE;
+      if(m_diagnostic[igain]) this->updateDiagnostic(6,"Shape empty",igain);
+    }
+    else
+      if(m_diagnostic[igain]) 
+      {
+	unsigned int n_SHAPEnull=0;
+	for(unsigned int i=0;i<Shape.size();++i)
+	  if(fabs(Shape[i])<0.000001) ++n_SHAPEnull;
+	if(n_SHAPEnull==Shape.size()) 	  
+	  this->updateDiagnostic(7,"Shape=0",igain);
+      }	
+  }
+
+  //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+  //NSAMPLES
+  if(m_retrieve[iOFC] && m_retrieve[iAUTOCORR] 
+     && OFC.size()!=AutoCorr.size()+1)
+  {
+    m_nsamples=std::min(OFC.size(),AutoCorr.size()+1);
+    MsgStream log( msgSvc(), name() );
+    log<<MSG::DEBUG
+       <<"AutoCorr and OFC vectors have not the same "
+       <<"number of elements"
+       <<" ("<<AutoCorr.size()<<"/"<<OFC.size()
+       <<" ) => will take into account only " << m_nsamples << " samples !"
+       <<endreq;
+  }
+
+  //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+  if(m_retrieve[iOFC] && m_retrieve[iSHAPE] && OFC.size()==Shape.size())
+  {
+    float scalar=0;
+    for(unsigned int i=0;i<Shape.size();++i)
+      scalar+=Shape[i]*OFC[i];
+    if((scalar-1)>0.05)
+      this->updateDiagnostic(8,"[Shape].[OFC] not 1",igain);
+  }
+
+  //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+  //SAMPLING FRACTION
+  if(m_retrieve[iFSAMPL])
+  {
+    if (fSampl<0.000001) 
+    {
+      MsgStream log(msgSvc(), name());
+      log<<MSG::WARNING<< function_name
+	 <<"  fSampl null -> PileUp will be 0 for "
+	 <<m_lar_em_id->show_to_string(id)<<endreq;
+      StatusDatabase=StatusCode::FAILURE;
+    }
+  }
+
+  //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+  return StatusDatabase;
+}
+
+//////////////////////////////////////////////////
+// functions for the getNoise interface
+float
+CaloNoiseTool::getNoise(const CaloDetDescrElement* caloDDE, CalorimeterNoiseType type)
+{
+  float Nminbias=-1;
+  if( m_Nminbias>0 )
+    Nminbias=m_Nminbias;
+  
+  CaloGain::CaloGain igain = m_highestGain[caloDDE->getSubCalo()];
+  if( m_gain_from_joboption>=0 &&
+      (type == ICalorimeterNoiseTool::ELECTRONICNOISE ||
+       type == ICalorimeterNoiseTool::PILEUPNOISE ||
+       type == ICalorimeterNoiseTool::TOTALNOISE ))
+    igain = static_cast<CaloGain::CaloGain>(m_gain_from_joboption);
+  
+  switch(type) {
+  case ICalorimeterNoiseTool::JOBOPTION:
+    return (this->*m_CachedGetNoiseCDDE)(caloDDE,igain,Nminbias,
+					 ICaloNoiseToolStep::CELLS);
+    break;
+  case ICalorimeterNoiseTool::ELECTRONICNOISE_HIGHESTGAIN:
+  case ICalorimeterNoiseTool::ELECTRONICNOISE:
+    return elecNoiseRMS(caloDDE,igain,Nminbias,
+			ICaloNoiseToolStep::CELLS);
+    break;
+  case ICalorimeterNoiseTool::PILEUPNOISE_HIGHESTGAIN:
+  case ICalorimeterNoiseTool::PILEUPNOISE:
+    return pileupNoiseRMS(caloDDE,igain,Nminbias,
+			  ICaloNoiseToolStep::CELLS);
+    break;
+  case ICalorimeterNoiseTool::TOTALNOISE_HIGHESTGAIN:
+  case ICalorimeterNoiseTool::TOTALNOISE:
+    return totalNoiseRMS(caloDDE,igain,Nminbias,
+			 ICaloNoiseToolStep::CELLS);
+    break;
+    
+  default:
+    return 0.;
+    break;
+  }
+}
+
+float
+CaloNoiseTool::getNoise(const CaloCell* caloCell, CalorimeterNoiseType type)
+{
+  const CaloDetDescrElement* caloDDE = caloCell->caloDDE();
+  float Nminbias=-1;
+  if( m_Nminbias>0 )
+    Nminbias=m_Nminbias;
+  
+  CaloGain::CaloGain igain = caloCell->gain();
+  
+  if( m_gain_from_joboption>=0 &&
+      (type == ICalorimeterNoiseTool::ELECTRONICNOISE ||
+       type == ICalorimeterNoiseTool::PILEUPNOISE ||
+       type == ICalorimeterNoiseTool::TOTALNOISE ))
+    igain = static_cast<CaloGain::CaloGain>(m_gain_from_joboption);
+  
+  switch(type) {
+  case ICalorimeterNoiseTool::JOBOPTION:
+    return (this->*m_CachedGetNoiseCELL)(caloCell,igain,Nminbias,
+					 ICaloNoiseToolStep::CELLS);
+    break;
+  case ICalorimeterNoiseTool::ELECTRONICNOISE_HIGHESTGAIN:
+    // overwrite iGain with highest gain for that detector and
+    // continue into normal code (NO break !!)
+    igain=m_highestGain[caloDDE->getSubCalo()];
+  case ICalorimeterNoiseTool::ELECTRONICNOISE:
+    return elecNoiseRMS(caloDDE,igain,Nminbias,
+			ICaloNoiseToolStep::CELLS);
+    break;
+    
+  case ICalorimeterNoiseTool::PILEUPNOISE_HIGHESTGAIN:
+    // overwrite iGain with highest gain for that detector and
+    // continue into normal code (NO break !!)
+    igain=m_highestGain[caloDDE->getSubCalo()];
+    //  NOTE: igain is not used at the moment for pileupnoise
+  case ICalorimeterNoiseTool::PILEUPNOISE:
+    return pileupNoiseRMS(caloDDE,igain,Nminbias,
+			  ICaloNoiseToolStep::CELLS);
+    break;
+    
+  case ICalorimeterNoiseTool::TOTALNOISE_HIGHESTGAIN:
+    // overwrite iGain with highest gain for that detector and
+    // continue into normal code (NO break !!)
+    igain=m_highestGain[caloDDE->getSubCalo()];
+    //  NOTE: igain is only used for the electronics noise at the moment
+  case ICalorimeterNoiseTool::TOTALNOISE:
+    return totalNoiseRMS(caloDDE,igain,Nminbias,
+			 ICaloNoiseToolStep::CELLS);
+    break;
+    
+  default:
+    return 0.;
+    break;
+  }
+}
+
+//////////////////////////////////////////////////
+
+void
+CaloNoiseTool::updateDiagnostic(int ireason,std::string nameReason,int igain)
+{
+  int nTmp=m_nCellsWithProblem[igain];
+  if (nTmp >= 5000) return;
+  int nr = m_nReason[nTmp][igain];
+  if (nr >= 10) return;
+  m_reason[nTmp][nr][igain]=ireason;
+  m_reasonName[ireason]=nameReason;
+  ++m_nReason[nTmp][igain];
+  ++m_itReason[ireason][igain]; 
+  m_noiseOK=false;
+  //std::cout<<nTmp<<" "<<n_reason[nTmp][igain]<<" "
+  //         <<it_reason[ireason][igain]<<std::endl;
+}
+
+//////////////////////////////////////////////////
+
+
+//========================  USER INTERFACES ===================================
+
+
+//////////////////////////////////////////////////
+
+float 
+CaloNoiseTool::elecNoiseRMS(const CaloCell* caloCell, 
+		 	    const int step)
+{
+  const CaloDetDescrElement* caloDDE = caloCell->caloDDE();
+  //CaloGain::CaloGain igain = this->estimatedGain(caloCell,caloDDE,step);
+  CaloGain::CaloGain igain = caloCell->gain();
+  return this->elecNoiseRMS(caloDDE,igain,-1,step);  
+}
+
+//////////////////////////////////////////////////
+
+float 
+CaloNoiseTool::elecNoiseRMS(const CaloCell* caloCell, 
+			    const float Nminbias, const int step)
+{
+  const CaloDetDescrElement* caloDDE = caloCell->caloDDE();
+  //CaloGain::CaloGain igain = this->estimatedGain(caloCell,caloDDE,step);
+  CaloGain::CaloGain igain = caloCell->gain();
+  return this->elecNoiseRMS(caloDDE,igain,Nminbias,step);  
+}
+
+//////////////////////////////////////////////////
+
+float
+CaloNoiseTool::elecNoiseRMSHighestGain(const CaloCell* caloCell, 
+				       const int step)
+{    
+  return this->elecNoiseRMSHighestGain(caloCell->caloDDE(),step);
+}
+
+//////////////////////////////////////////////////
+
+float
+CaloNoiseTool::elecNoiseRMSHighestGain(const CaloCell* caloCell, 
+				       const float Nminbias, const int step)
+{   
+  //WARNING: this function is almost 200 times slower than the previous one
+  return this->elecNoiseRMSHighestGain(caloCell->caloDDE(),Nminbias,step);
+}
+
+//////////////////////////////////////////////////
+
+float
+CaloNoiseTool::elecNoiseRMSHighestGain(const CaloDetDescrElement* caloDDE, 
+				       const int step)
+{    
+  CaloCell_ID::SUBCALO iCalo = caloDDE->getSubCalo();
+  CaloGain::CaloGain highestGain=m_highestGain[iCalo];
+  return this->elecNoiseRMS(caloDDE,highestGain,-1,step);    
+}
+
+//////////////////////////////////////////////////
+
+float
+CaloNoiseTool::elecNoiseRMSHighestGain(const CaloDetDescrElement* caloDDE, 
+				       const float Nminbias, const int step)
+{    
+  //CaloCell_ID::SUBCALO iCalo = this->caloNum(caloDDE->calo_hash());
+  CaloCell_ID::SUBCALO iCalo = caloDDE->getSubCalo();
+  CaloGain::CaloGain highestGain=m_highestGain[iCalo];
+  return this->elecNoiseRMS(caloDDE,highestGain,Nminbias,step);    
+}
+
+//////////////////////////////////////////////////
+
+float 
+CaloNoiseTool::elecNoiseRMS(const CaloDetDescrElement* caloDDE, 
+			    const CaloGain::CaloGain gain,
+			    const float Nminbias, 
+			    const int step)
+// << base class >>
+{  
+
+  if(!m_cacheValid){
+    MsgStream log( msgSvc(), name() );
+    log<<MSG::DEBUG<< " in elecNoiseRMS, cache not valid yet"<<endreq;
+    StatusCode sc = this->initData();
+    if (sc.isFailure()) {
+      throw LArConditionsException("Could not compute elecNoiseRMS ");
+    }
+  }
+
+
+  float sigma=0.;
+
+  const IdentifierHash idCaloHash = caloDDE->calo_hash();
+  //CaloCell_ID::SUBCALO iCalo = this->caloNum(idCaloHash);
+  CaloCell_ID::SUBCALO iCalo = caloDDE->getSubCalo();
+  int index=this->index(idCaloHash);
+
+  
+  int igain=static_cast<int>(gain);//for LAr  
+  if(iCalo==CaloCell_ID::TILE)     //for Tile 
+  {
+    CaloGain::CaloGain convertedGain;
+    switch(gain)
+    {
+  //convert Tile gain into LAr gain (the one used to store the noise in arrays)
+    case CaloGain::TILEHIGHHIGH : convertedGain=CaloGain::LARHIGHGAIN;   break;
+    case CaloGain::TILEHIGHLOW :  convertedGain=CaloGain::LARMEDIUMGAIN; break;
+    case CaloGain::TILELOWHIGH :  convertedGain=CaloGain::LARMEDIUMGAIN; break;
+    case CaloGain::TILELOWLOW :   convertedGain=CaloGain::LARLOWGAIN;    break;
+    case CaloGain::TILEONEHIGH :  convertedGain=CaloGain::LARHIGHGAIN;   break;
+    case CaloGain::TILEONELOW :   convertedGain=CaloGain::LARLOWGAIN;    break;
+    default: convertedGain = CaloGain::INVALIDGAIN;
+    }
+    igain=static_cast<int>(convertedGain);
+  } 
+
+  if (gain==CaloGain::INVALIDGAIN || gain==CaloGain::UNKNOWNGAIN) {
+    MsgStream log( msgSvc(), name() );
+    log << MSG::WARNING << " ask noise for invalid/unknown gain, will return noise for high gain " << endreq;
+    igain=static_cast<int>(CaloGain::LARHIGHGAIN);
+  }
+
+  if (iCalo<0 || index<0)
+  {
+    MsgStream log(msgSvc(), name());
+    log<<MSG::WARNING
+       << "CaloNoiseTool::elecNoiseRMS  wrong id ! " 
+       << "iCalo="<<iCalo
+       << "index="<<index
+       << "id:" << m_lar_em_id->show_to_string(caloDDE->identify())
+       << endreq;
+    return 0.;
+  } 
+  else 
+  {         
+    const std::vector<float>* sigmaVector = 0;
+    if(step==ICaloNoiseToolStep::CELLS)	
+      sigmaVector = &m_elecNoiseCELLContainer[index];
+    else if(step==ICaloNoiseToolStep::RAWCHANNELS)    
+      sigmaVector = &m_elecNoiseRAWContainer[index];
+    else 
+    {
+      MsgStream log(msgSvc(), name());
+      log<<MSG::WARNING<< "CaloNoiseTool::elecNoiseRMS  wrong step !!!  "
+	 <<step
+	 <<endreq;
+      return 0.;
+    }
+
+    bool retry=true;
+    int shift_gain=0;
+    int gain_wanted=igain;    
+    if(m_WorkMode==0) gain_wanted=2-igain;
+    int gain_shifted=gain_wanted;
+
+    while(retry)
+    {      
+      //:::::::::::::::::
+      retry=false;
+      //:::::::::::::::::
+      if(m_WorkMode==0)      gain_shifted=gain_wanted+shift_gain;
+      else if(m_WorkMode==1) gain_shifted=gain_wanted-shift_gain;
+      //:::::::::::::::::
+      sigma = (*sigmaVector)[gain_shifted];
+      //:::::::::::::::::
+      if(m_WorkMode==1 && Nminbias>=0 && Nminbias!=m_Nminbias_usedForCache &&
+	 iCalo != CaloCell_ID::TILE )
+      {
+	sigma = this->calculateElecNoiseForLAR(idCaloHash,
+                                               this->caloNum(idCaloHash),
+                                               Nminbias) [gain_shifted];
+// 	if(m_Geant3 && step==ICaloNoiseToolStep::CELLS) 
+// 	  sigma = sigma*m_scaleContainer[index];
+      }  
+      //:::::::::::::::::
+      if(this->isBadValue(sigma)) 
+      {
+	++shift_gain;
+	if(shift_gain<=igain) retry=true;
+	MsgStream log(msgSvc(), name());
+	log<<MSG::WARNING<< "noise is missing for this cell " << m_lar_em_id->show_to_string(caloDDE->identify())
+	   << " at this gain ("
+	   <<gain_wanted<<"), return the noise at next gain ("
+	   <<gain_shifted<<")"
+	   <<endreq;
+      }
+      //:::::::::::::::::
+    }
+    return sigma;   
+  }  
+}
+
+//////////////////////////////////////////////////
+
+std::vector<float> 
+CaloNoiseTool::elecNoiseRMS3gains(const CaloDetDescrElement* caloDDE, 
+				  const int step)
+{  
+  std::vector<float> sigma;
+  sigma.reserve (CaloGain::LARNGAIN);
+
+  for(int igain=0;igain<CaloGain::LARNGAIN;++igain)
+    sigma.push_back(this->elecNoiseRMS(caloDDE,
+				       static_cast<CaloGain::CaloGain>(igain),
+				       -1,
+				       step));
+  return sigma;
+}
+
+//////////////////////////////////////////////////
+
+std::vector<float> 
+CaloNoiseTool::elecNoiseRMS3gains(const CaloDetDescrElement* caloDDE, 
+				  const float NMinBias,const int step)
+{  
+  std::vector<float> sigma;
+  sigma.reserve (CaloGain::LARNGAIN);
+  for(int igain=0;igain<CaloGain::LARNGAIN;++igain)
+    sigma.push_back(this->elecNoiseRMS(caloDDE,
+				       static_cast<CaloGain::CaloGain>(igain),
+				       NMinBias,
+				       step));
+  for(int igain=0;igain<CaloGain::LARNGAIN;++igain)
+    if(this->isBadValue(sigma[igain]) && 
+       igain!=CaloGain::LARHIGHGAIN) 
+      sigma[igain]=sigma[igain-1];//take the next gain (low->medium->high)
+  return sigma;
+}
+
+//////////////////////////////////////////////////
+
+VectorContainer* 
+CaloNoiseTool::elecNoiseRMSContainer(const int &iCalo) 
+{
+  MsgStream log( msgSvc(), name() );
+  log << MSG::WARNING << " elecNoiseRMSContainer not implemented " << iCalo << endreq ;
+  //return &m_elecNoiseContainer_old[iCalo];
+  return 0;
+}
+
+//////////////////////////////////////////////////
+// new interfaces to enable caching of the pointer to member
+
+float 
+CaloNoiseTool::elecNoiseRMS(const CaloCell* theCell,
+			    const CaloGain::CaloGain /*gain*/,
+			    const float Nminbias, 
+			    const int step) {
+  return this->elecNoiseRMS(theCell,Nminbias,step);
+}
+
+float 
+CaloNoiseTool::pileupNoiseRMS(const CaloCell* theCell,
+			      const CaloGain::CaloGain /*gain*/,
+			      const float Nminbias, 
+			      const int /*step*/) {
+  return this->pileupNoiseRMS(theCell,Nminbias);
+}
+
+float 
+CaloNoiseTool::totalNoiseRMS(const CaloCell* theCell,
+			     const CaloGain::CaloGain gain,
+			     const float Nminbias, 
+			     const int step) {
+  float elecNoiseRMS_tmp   = this->elecNoiseRMS(theCell,gain,Nminbias,step);
+  float pileupNoiseRMS_tmp = this->pileupNoiseRMS(theCell,gain,Nminbias,step);
+  
+  if(elecNoiseRMS_tmp>=0)
+    return sqrt((elecNoiseRMS_tmp*elecNoiseRMS_tmp) + (pileupNoiseRMS_tmp*pileupNoiseRMS_tmp));
+  return(-1);
+}
+
+float 
+CaloNoiseTool::pileupNoiseRMS(const CaloDetDescrElement* caloDDE, 
+			      const CaloGain::CaloGain /*gain*/,
+			      const float Nminbias, 
+			      const int /*step*/) {
+  return this->pileupNoiseRMS(caloDDE,Nminbias);
+}
+
+float 
+CaloNoiseTool::totalNoiseRMS(const CaloDetDescrElement* caloDDE, 
+			     const CaloGain::CaloGain gain,
+			     const float Nminbias, 
+			     const int step) {
+  float elecNoiseRMS_tmp   = this->elecNoiseRMS(caloDDE,gain,Nminbias,step);
+  float pileupNoiseRMS_tmp = this->pileupNoiseRMS(caloDDE,gain,Nminbias,step);
+  
+  return sqrt((elecNoiseRMS_tmp*elecNoiseRMS_tmp) + (pileupNoiseRMS_tmp*pileupNoiseRMS_tmp) );
+}
+//////////////////////////////////////////////////
+
+float 
+CaloNoiseTool::pileupNoiseRMS(const CaloCell* caloCell, const float Nminbias)
+{
+  const CaloDetDescrElement* caloDDE = caloCell->caloDDE();
+  return this->pileupNoiseRMS(caloDDE,Nminbias);
+}
+
+//////////////////////////////////////////////////
+
+float 
+CaloNoiseTool::pileupNoiseRMS(const CaloDetDescrElement* caloDDE, 
+			      const float Nminbias)
+// << base class >>
+{
+
+
+  if(!m_cacheValid){
+    StatusCode sc = this->initData();
+    if (sc.isFailure()) {
+      throw LArConditionsException("Could not compute pileupNoiseRMS ");
+    }
+  }
+
+  const IdentifierHash idCaloHash = caloDDE->calo_hash();
+  CaloCell_ID::SUBCALO iCalo = this->caloNum(idCaloHash);
+  
+  if(iCalo!=CaloCell_ID::TILE)
+  {
+    int index=this->index(idCaloHash);
+    float PileUp;
+    // check if noise stored in container was calcualted with this Nminbias
+    if ((Nminbias==m_Nminbias_usedForCache) || (Nminbias<=0)) //default 
+      PileUp=m_pileupNoiseContainer[index];
+    else
+      PileUp=this->calculatePileUpNoise(idCaloHash,Nminbias);//slower !!
+    return PileUp;
+  }
+  else//TILE
+  {
+    if(m_Nmessages_forTilePileUp<10)// to not have thousands of messages
+    {
+      MsgStream log( msgSvc(), name() );
+      log<<MSG::INFO
+	 <<"CaloNoiseTool::pileupNoiseRMS : NOT IMPLEMENTED "
+	 <<"for TILEs ! (-> returns 0. for the moment)"
+	 <<endreq;    
+      ++m_Nmessages_forTilePileUp;
+    }
+    return 0.;   
+  }
+}
+
+//////////////////////////////////////////////////
+
+float 
+CaloNoiseTool::totalNoiseRMS(const CaloCell* caloCell, const float Nminbias) 
+{
+  CaloGain::CaloGain igain = caloCell->gain();
+  return this->totalNoiseRMS(caloCell->caloDDE(),igain,Nminbias);
+}
+
+//////////////////////////////////////////////////
+
+float 
+CaloNoiseTool::totalNoiseRMS(const CaloDetDescrElement* caloDDE, 
+			     const CaloGain::CaloGain gain, 
+			     const float Nminbias)
+{
+  float elecNoiseRMS_tmp   = this->elecNoiseRMS(caloDDE,gain,Nminbias,
+						ICaloNoiseToolStep::CELLS);
+  float pileupNoiseRMS_tmp = this->pileupNoiseRMS(caloDDE,Nminbias);
+  
+  float totalNoiseRMS = -1;
+  
+  // checks that elecNoise is valid
+  if(elecNoiseRMS_tmp>0) 
+    totalNoiseRMS= sqrt((elecNoiseRMS_tmp*elecNoiseRMS_tmp) + (pileupNoiseRMS_tmp*pileupNoiseRMS_tmp) );
+  
+  return totalNoiseRMS;
+}
+
+//////////////////////////////////////////////////
+
+float 
+CaloNoiseTool::totalNoiseRMSHighestGain(const CaloCell* caloCell, 
+					const float Nminbias)
+{
+  return this->totalNoiseRMSHighestGain(caloCell->caloDDE(),Nminbias);
+}
+
+//////////////////////////////////////////////////
+
+float 
+CaloNoiseTool::totalNoiseRMSHighestGain(const CaloDetDescrElement* caloDDE, 
+					const float Nminbias)
+{
+  //CaloCell_ID::SUBCALO iCalo = caloNum(caloDDE->calo_hash());
+  CaloCell_ID::SUBCALO iCalo = caloDDE->getSubCalo();
+  CaloGain::CaloGain highestGain=m_highestGain[iCalo];
+  return this->totalNoiseRMS(caloDDE,highestGain,Nminbias);
+}
+
+
+//////////////////////////////////////////////////
+//////////////////////////////////////////////////
+
+CaloGain::CaloGain 
+CaloNoiseTool::estimatedGain(const CaloCell* caloCell,
+			     const int &step)
+{
+  return this->estimatedGain(caloCell,caloCell->caloDDE(),step);
+}
+
+//////////////////////////////////////////////////
+
+CaloGain::CaloGain
+CaloNoiseTool::estimatedGain(const CaloCell* caloCell, 
+			     const CaloDetDescrElement* caloDDE,
+			     const int &step)
+{
+  //CaloCell_ID::SUBCALO iCalo = caloNum(caloDDE->calo_hash());
+  CaloCell_ID::SUBCALO iCalo = caloDDE->getSubCalo();
+
+  if(iCalo==CaloCell_ID::LAREM || 
+     iCalo==CaloCell_ID::LARHEC || 
+     iCalo==CaloCell_ID::LARFCAL) 
+    return this->estimatedLArGain(iCalo,caloDDE,caloCell->energy(),step);
+  else if(iCalo==CaloCell_ID::TILE)
+    return this->estimatedTileGain(caloCell,caloDDE,step);
+  else
+  {
+    MsgStream log( msgSvc(), name() );
+    log<<MSG::WARNING
+       <<"CaloNoiseTool::estimatedGain  wrong id ! " 
+       <<m_lar_em_id->show_to_string(caloDDE->identify()) 
+       <<endreq;
+    return CaloGain::INVALIDGAIN;
+  } 
+}
+
+//////////////////////////////////////////////////
+
+CaloGain::CaloGain 
+CaloNoiseTool::estimatedGain(const CaloDetDescrElement* caloDDE,
+			     const float &energy, 			     
+			     const int &step)
+{
+  //CaloCell_ID::SUBCALO iCalo = caloNum(caloDDE->calo_hash());
+  CaloCell_ID::SUBCALO iCalo = caloDDE->getSubCalo();
+
+  if(iCalo==CaloCell_ID::LAREM || 
+     iCalo==CaloCell_ID::LARHEC || 
+     iCalo==CaloCell_ID::LARFCAL) 
+    return this->estimatedLArGain(iCalo,caloDDE,energy,step);
+  else if(iCalo==CaloCell_ID::TILE)
+  {
+    MsgStream log( msgSvc(), name() );
+    log<<MSG::WARNING
+       <<"CaloNoiseTool::estimatedGain  NOT IMPLEMENTED FOR TILE "
+       <<"with these arguments! " 
+       << m_lar_em_id->show_to_string(caloDDE->identify()) 
+       <<endreq;
+    return CaloGain::INVALIDGAIN;
+  } 
+  else
+  {
+    MsgStream log( msgSvc(), name() );
+    log<<MSG::WARNING
+       <<"CaloNoiseTool::estimatedGain  wrong id ! " 
+       << m_lar_em_id->show_to_string(caloDDE->identify()) 
+       <<endreq;
+    return CaloGain::INVALIDGAIN;
+  } 
+}
+
+//////////////////////////////////////////////////
+
+CaloGain::CaloGain 
+CaloNoiseTool::estimatedLArGain(const CaloCell_ID::SUBCALO &iCalo,
+                                const CaloDetDescrElement* caloDDE,
+				const float &energy, 
+				const int &step)
+{
+  //returns the gain of a cell according to the energy 
+  //(converts in ADC counts in MediumGain and uses thresholds in ADC counts 
+  //to determine the gain)
+
+  //  the function could be called before (step=0, RawChannels) 
+  //  or after  (step=1, Cells) LArG3Escale
+
+  CaloGain::CaloGain igain=CaloGain::INVALIDGAIN; 
+
+  //--EM/HEC--
+  if( iCalo==CaloCell_ID::LAREM || iCalo==CaloCell_ID::LARHEC ||
+     (iCalo==CaloCell_ID::LARFCAL && m_WorkMode==1) )
+  {     
+    //We choose the gain in applying thresholds on the energy 
+    //converted in ADC counts in MediumGain (index "1" of adc2mev(id,1)).
+    //Indeed, thresholds in ADC counts are defined with respect 
+    //to the MediumGain.
+    //
+    //              1300              3900 
+    // ---------------|----------------|-------------> ADC counts in MediumGain
+    //    HighGain  <---  MediumGain  --->  LowGain
+
+    float adc=0.;
+    
+    //Cells (with E scale and weights from LArG3Escale)
+    if(step==ICaloNoiseToolStep::CELLS) 
+      adc=energy/(this->adc2mev(caloDDE,CaloGain::LARMEDIUMGAIN)) + 1000 ;
+    //RawChannels    
+    else if(step==ICaloNoiseToolStep::RAWCHANNELS) 
+      adc=energy/(this->adc2mev(caloDDE,CaloGain::LARMEDIUMGAIN)) + 1000 ;
+    else 
+    {
+      MsgStream log( msgSvc(), name() );
+      log<<MSG::WARNING<< "CaloNoiseTool::estimatedGain   wrong step"<<endreq;
+    }  
+    if(adc<m_HighGainThresh[iCalo])     igain=CaloGain::LARHIGHGAIN;  
+    else if(adc>m_LowGainThresh[iCalo]) igain=CaloGain::LARLOWGAIN; 
+    else                                igain=CaloGain::LARMEDIUMGAIN;  
+  }
+  //--FCAL--
+  else if(iCalo==CaloCell_ID::LARFCAL && m_WorkMode==0)
+  { 
+    if(energy<m_HighGainThresh[iCalo])     igain=CaloGain::LARHIGHGAIN; 
+    else if(energy>m_LowGainThresh[iCalo]) igain=CaloGain::LARLOWGAIN; 
+    else                                       igain=CaloGain::LARMEDIUMGAIN;
+  }  
+  
+  return igain;
+}
+
+//////////////////////////////////////////////////
+
+CaloGain::CaloGain
+CaloNoiseTool::estimatedTileGain(const CaloCell* caloCell,
+				 const CaloDetDescrElement* caloDDE,
+				 const int &/*step*/)
+{
+  const TileCell * tileCell = (TileCell *)caloCell;
+  //double eneTot = tileCell->energy();
+
+    // threshold (1023 counts) is the same for all channels
+  double thr = m_tileInfo->ADCmax(); 
+
+  static const TileHWID * tileHWID = TileCablingService::getInstance()->getTileHWID();
+  static const IdContext chContext = tileHWID->channel_context();
+  HWIdentifier hwid;
+  
+  tileHWID->get_id(caloDDE->onl1(), hwid, &chContext ); // pmt id
+  hwid = tileHWID->adc_id(hwid,TileHWID::HIGHGAIN); // high gain ADC id
+  
+  // first PMT, convert energy to ADC counts
+  double amp = tileCell->ene1();
+  amp /= m_tileInfo->ChannelCalib(hwid,TileRawChannelUnit::ADCcounts,TileRawChannelUnit::MegaElectronVolts);
+  double ped = m_tileInfo->DigitsPedLevel(hwid); 
+
+  int igain1;
+
+  if (amp + ped < thr )
+    igain1 = TileID::HIGHGAIN;
+  else
+    igain1 = TileID::LOWGAIN;
+
+  // second PMT, if it exists
+  if (caloDDE->onl2() !=  TileID::NOT_VALID_HASH ) 
+  {
+    tileHWID->get_id(caloDDE->onl2(), hwid, &chContext ); // pmt id
+    hwid = tileHWID->adc_id(hwid,TileHWID::HIGHGAIN); // high gain ADC id
+
+    amp = tileCell->ene2();
+    amp /= m_tileInfo->ChannelCalib(hwid,TileRawChannelUnit::ADCcounts,TileRawChannelUnit::MegaElectronVolts);
+    ped = m_tileInfo->DigitsPedLevel(hwid); 
+
+    if (amp + ped < thr ) {
+      // igain2 high
+      return igain1 == TileID::LOWGAIN ? CaloGain::TILEHIGHLOW : CaloGain::TILEHIGHHIGH;
+    }
+    else {
+      // igain2 low
+      return igain1 == TileID::LOWGAIN ? CaloGain::TILELOWLOW : CaloGain::TILEHIGHLOW;
+    }
+    // nb. Having HIGHLOW in two places seems wrong, but that's what the
+    // original code was doing.
+  } 
+
+  // igain2 doesn't exist.
+  return igain1 == TileID::LOWGAIN ? CaloGain::TILEONELOW : CaloGain::TILEONEHIGH;
+}
+
+//////////////////////////////////////////////////
+
+float 
+CaloNoiseTool::adc2mev(const CaloDetDescrElement* caloDDE,
+		       const CaloGain::CaloGain gain)
+{
+
+  if(!m_cacheValid){
+    StatusCode sc = this->initData();
+    if (sc.isFailure()) {
+      throw LArConditionsException("Could not compute adc2mev ");
+    }
+  }
+
+
+  float factor=1.;
+  IdentifierHash idCaloHash = caloDDE->calo_hash();
+  CaloCell_ID::SUBCALO iCalo = this->caloNum(idCaloHash);
+ 
+  if(iCalo==CaloCell_ID::LAREM || iCalo==CaloCell_ID::LARHEC)
+  {      
+    int index=this->index(idCaloHash);
+    if(m_WorkMode==0)
+      factor=(m_adc2mevContainer[index])[2-gain];
+    else if(m_WorkMode==1)
+      factor=(m_adc2mevContainer[index])[gain];
+  }
+  else if(iCalo==CaloCell_ID::LARFCAL)
+  {
+    if(m_WorkMode==0)
+    {
+      MsgStream log( msgSvc(), name() );
+      log<<MSG::WARNING
+	 <<"CaloNoiseTool::adc2mev(id,gain) : NOT IMPLEMENTED !"
+	 <<"for FCAL (-> returns 5000. for the moment)"
+	 <<endreq;     
+      //NOT CLEAR what we should return 
+      //(for the moment, returns AdcPerGev from LArDigitMaker)
+      factor=AdcPerMev;
+    }
+    else if(m_WorkMode==1)
+    {
+      int index=this->index(idCaloHash);
+      factor=(m_adc2mevContainer[index])[gain];
+    }
+  }  
+  else if(iCalo==CaloCell_ID::TILE)
+  {
+    //TILE_PART
+    MsgStream log( msgSvc(), name() );
+    log<<MSG::WARNING
+       <<"CaloNoiseTool::adc2mev(id,gain) : NOT IMPLEMENTED !"
+       <<"for TILE (-> returns 1. for the moment)"
+       <<endreq;    
+    factor=1.; 
+  }  
+  else
+  {
+    MsgStream log( msgSvc(), name() );
+    log<<MSG::WARNING
+       <<"CaloNoiseTool::adc2mev(id,gain)  wrong id ! " 
+       <<m_lar_em_id->show_to_string(caloDDE->identify()) 
+       <<endreq;
+    factor=0.;
+  }  
+  return factor;
+}
+
+//////////////////////////////////////////////////
+
+float 
+CaloNoiseTool::adc2mev(const Identifier& id,const CaloGain::CaloGain gain)
+{
+  return adc2mev(m_calo_dd_man->get_element(id),gain);
+}
+
+
+
+void CaloNoiseTool::handle(const Incident&) {
+  MsgStream log( msgSvc(), name() );
+  log << MSG::DEBUG << "In Incident-handle" << endreq;
+  if (m_cacheValid) {
+    log << MSG::DEBUG << "Cached data already computed." << endreq;
+    return;
+  }
+  
+  StatusCode sc = this->initData();
+
+  if (sc.isFailure()) {
+    log << MSG::ERROR << "handle:  error with initData() " << endreq;
+    log << MSG::ERROR << "Failed to update CaloNoiseTool Cache at the begin of run." << endreq;
+    m_cacheValid=false;
+  }
+}
+
+/////////////////////////////////////////////////////////////////////////
+
+bool CaloNoiseTool::isEOverNSigma(const CaloCell* caloCell, float sigmaCut ,
+                     CalorimeterNoiseSymmetryHandling symmetryHandling,
+                     CalorimeterNoiseType type )
+{
+  float noise_cut = fabs(sigmaCut*this->getEffectiveSigma(caloCell, symmetryHandling, type));
+  float energy = fabs(caloCell->e());
+  return (energy>noise_cut);
+
+}
+
+////////////////////////////////////////////////////////////////////
+
+float CaloNoiseTool::getRandomisedE(const CaloCell* caloCell , CLHEP::HepRandomEngine* engine, CalorimeterNoiseType type)
+{
+  double rms = this->getNoise(caloCell,type);
+  return RandGauss::shoot(engine,0.,rms);
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+float CaloNoiseTool::getEffectiveSigma(const CaloCell* caloCell,
+                     CalorimeterNoiseSymmetryHandling /*symmetryHandling*/,
+                     CalorimeterNoiseType type )
+{
+     // simple implementation for gaussian noise
+     return this->getNoise(caloCell,type);
+}
+
+
diff --git a/Calorimeter/CaloTools/src/CaloNoiseToolDB.cxx b/Calorimeter/CaloTools/src/CaloNoiseToolDB.cxx
new file mode 100755
index 0000000000000000000000000000000000000000..135458b2805fce3199d67a4f1caeb029f616617e
--- /dev/null
+++ b/Calorimeter/CaloTools/src/CaloNoiseToolDB.cxx
@@ -0,0 +1,1178 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "CaloTools/CaloNoiseToolDB.h"
+
+
+//=== AttributeList
+#include "CoralBase/Blob.h"
+#include "AthenaPoolUtilities/CondAttrListCollection.h"
+//=== TileCalibBlobObjs
+#include "CaloCondBlobObjs/CaloCondBlobFlt.h"
+#include "CaloCondBlobObjs/CaloCondUtils.h"
+
+#include "CLHEP/Random/RandomEngine.h"
+#include "CLHEP/Random/RandGauss.h"
+
+#include "GeoModelInterfaces/IGeoModelSvc.h"
+
+#include "TMath.h"
+
+using CLHEP::RandGauss;
+
+//////////////////////////////////////////////////
+
+CaloNoiseToolDB::CaloNoiseToolDB(const std::string& type, 
+			     const std::string& name, 
+			     const IInterface* parent) 
+  : AthAlgTool(type, name, parent),
+    m_cacheValid(false)
+
+{
+  declareInterface<ICaloNoiseTool>(this);
+  declareInterface<ICalorimeterNoiseTool>(this);
+
+  declareProperty("Luminosity",m_lumi0=0,"Luminosity in 10**33 units");
+  declareProperty("CachedNoise",m_ReturnNoiseName="totalNoise","Cached Noise");
+  declareProperty("FixGain",m_gain_from_joboption=-1);
+  declareProperty("SpeedTwoGauss",m_speedTwoGauss=true);
+  declareProperty("FolderNames",m_folderNames);
+  declareProperty("LumiFolderName",m_lumiFolderName="/TRIGGER/LUMI/LBLESTONL");
+}
+ 
+//////////////////////////////////////////////////
+
+StatusCode 
+CaloNoiseToolDB::initialize()
+{
+
+  m_cached = ICalorimeterNoiseTool::TOTALNOISE;
+
+  if (m_folderNames.size()==0) {
+    msg(MSG::ERROR) << "No database folder name give to read noise! Please set " << name() << ".FolderNames=[...]" << endreq;
+    return StatusCode::FAILURE;
+  }
+
+
+  const IGeoModelSvc *geoModel=0;
+  StatusCode sc = service("GeoModelSvc", geoModel);
+  if(sc.isFailure())
+  {
+    msg(MSG::ERROR) << "Could not locate GeoModelSvc" << endreq;
+    return sc;
+  }
+
+  // dummy parameters for the callback:
+  int dummyInt=0;
+  std::list<std::string> dummyList;
+
+  if (geoModel->geoInitialized())
+  {
+    return geoInit(dummyInt,dummyList);
+  }
+  else
+  {
+    sc = detStore()->regFcn(&IGeoModelSvc::geoInit,
+			  geoModel,
+			  &CaloNoiseToolDB::geoInit,this);
+    if(sc.isFailure())
+    {
+      msg(MSG::ERROR) << "Could not register geoInit callback" << endreq;
+      return sc;
+    }
+  }
+
+
+  return sc;
+}
+
+
+StatusCode 
+CaloNoiseToolDB::finalize()
+{
+  msg(MSG::INFO)
+      << "CaloNoiseToolDB final(), cleaning m_noiseBlobMap, size = " <<m_noiseBlobMap.size() <<endreq;
+
+  //=== delete old CaloCondBlobFlt (which does not own the blob)
+  std::map<SYSTEM, const CaloCondBlobFlt*>::iterator it = m_noiseBlobMap.begin();
+  std::map<SYSTEM, const CaloCondBlobFlt*>::iterator it_e = m_noiseBlobMap.end();
+  for (; it!=it_e; ++it ){
+    delete it->second;
+  }
+
+  return StatusCode::SUCCESS; 
+
+}
+StatusCode
+CaloNoiseToolDB::geoInit(IOVSVC_CALLBACK_ARGS)
+{
+  StatusCode sc;
+
+  msg(MSG::INFO)
+      << "CaloNoiseToolDB initialize() begin" 
+      << endreq;
+
+  //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::  
+  //retrieves helpers for Identifier
+
+  //retrieve ID helpers 
+  sc = detStore()->retrieve( m_caloIdMgr );
+  if (sc.isFailure()) {
+    msg(MSG::ERROR) << "Unable to retrieve CaloIdMgr in LArHitEMap " << endreq;
+   return StatusCode::FAILURE;
+  }
+  m_calo_id      = m_caloIdMgr->getCaloCell_ID();
+
+  m_Nminbias = m_lumi0*2.3;
+
+  m_highestGain[CaloCell_ID::LAREM]   = CaloGain::LARHIGHGAIN;
+  m_highestGain[CaloCell_ID::LARHEC]  = CaloGain::LARMEDIUMGAIN;
+  m_highestGain[CaloCell_ID::LARFCAL] = CaloGain::LARHIGHGAIN;
+  m_highestGain[CaloCell_ID::TILE]    = CaloGain::TILEHIGHHIGH;
+
+  // register callback for luminosity (only if not hardcoded from jobOptions)
+
+  if (m_lumi0<0) {
+    m_lumi0=0;
+    if (detStore()->contains<CondAttrListCollection>(m_lumiFolderName)) {
+      const DataHandle<CondAttrListCollection> lumiData;
+      sc = detStore()->regFcn(&CaloNoiseToolDB::updateLumi, this , lumiData, m_lumiFolderName, true);
+      if (sc.isFailure()) {
+          msg(MSG::ERROR) << " cannot register callback for luminosity " << endreq;
+          return StatusCode::FAILURE;
+      }
+      msg(MSG::INFO) << " Registered a callback for " << m_lumiFolderName << " Cool folder " << endreq;
+    }
+  }
+
+
+  m_noiseAttrListColl.resize(m_folderNames.size());
+  std::vector<std::string>::const_iterator fldr_it=m_folderNames.begin();
+  std::vector<std::string>::const_iterator fldr_it_e=m_folderNames.end();
+  unsigned i=0;
+  for(;fldr_it!=fldr_it_e;++fldr_it) {
+    const std::string& folderName=*fldr_it;
+    
+    msg(MSG::INFO) << "Registering callback on folder " << folderName << endreq;
+    sc=detStore()->regFcn(&CaloNoiseToolDB::updateMap, this, const_cast<const DataHandle<CondAttrListCollection>&>(m_noiseAttrListColl[i++]), folderName, true);
+     if (sc.isFailure()) {
+       msg(MSG::ERROR) << " cannot register callback to folder " << folderName <<  endreq;
+       return StatusCode::FAILURE;
+     }
+  }
+
+  msg(MSG::INFO) << "CaloNoiseToolDB initialize() end" << endreq;
+
+  return StatusCode::SUCCESS;
+}
+
+//______________________________________________________________________________________
+StatusCode
+CaloNoiseToolDB::updateLumi( IOVSVC_CALLBACK_ARGS )
+{
+
+  msg(MSG::INFO) << " in updateLumi() " << endreq;
+
+  const CondAttrListCollection* attrListColl = 0;
+  StatusCode sc = detStore()->retrieve(attrListColl, m_lumiFolderName);
+  if (sc.isFailure() || !attrListColl) {
+     msg(MSG::WARNING)  << "attrrListColl not found for " << m_lumiFolderName << endreq;
+     return StatusCode::SUCCESS;
+  }
+  // Loop over collection
+  CondAttrListCollection::const_iterator first = attrListColl->begin();
+  CondAttrListCollection::const_iterator last  = attrListColl->end();
+  for (; first != last; ++first) {
+   if ((*first).first == 0) {
+      std::ostringstream attrStr1;
+      (*first).second.toOutputStream( attrStr1 );
+      ATH_MSG_DEBUG("ChanNum " << (*first).first << " Attribute list " << attrStr1.str());
+      const coral::AttributeList& attrList = (*first).second;
+      if (attrList["LBAvInstLumi"].isNull()) {
+          msg(MSG::WARNING) << " NULL Luminosity information in database ... set it to 0 " << endreq;
+          m_lumi0 = 0.;
+      } else {
+        m_lumi0 = attrList["LBAvInstLumi"].data<float>() *1e-3;  // luminosity (from 10**30 units in db to 10*33 units)
+      }
+      if ( !(m_lumi0 == m_lumi0) ) {
+        msg(MSG::WARNING) << " Luminosity is not a number.. " << m_lumi0 << "  ... set it to 0 " << endreq;
+        m_lumi0=0.;
+      }
+      m_Nminbias = m_lumi0*2.3;
+      m_cacheValid = false;    
+      break;
+   }
+  }
+  return StatusCode::SUCCESS;
+}
+
+//_______________________________________________________________________________________
+StatusCode
+CaloNoiseToolDB::updateMap( IOVSVC_CALLBACK_ARGS_K(keys) )
+{
+  std::set<unsigned> channelsFound;
+  std::list<std::string>::const_iterator itr;
+  for (itr=keys.begin(); itr!=keys.end(); ++itr) {
+    msg(MSG::INFO) <<  " updateMap callback for kye " << *itr << endreq;
+    const CondAttrListCollection* noiseAttrListColl;
+    StatusCode sc=detStore()->retrieve(noiseAttrListColl,*itr);
+    if (sc.isFailure()) {
+      msg(MSG::ERROR) << "Failed to retrieve CondAttrListCollection with key " << *itr << endreq;
+      return sc;
+    }
+
+    //=== loop over collection (all cool channels)
+    CondAttrListCollection::const_iterator iColl = noiseAttrListColl->begin();
+    CondAttrListCollection::const_iterator last  = noiseAttrListColl->end();
+    for (; iColl != last; ++iColl) {
+      ATH_MSG_DEBUG("Working on folder " << *itr << " Channel " << iColl->first);
+      const coral::Blob& blob = (iColl->second)["CaloCondBlob16M"].data<coral::Blob>();
+      if (blob.size()<1) {
+	ATH_MSG_DEBUG("Empty blob in folder " << *itr << ", channel " << iColl->first << ". Ignored.");
+	continue;
+      }
+
+      if (channelsFound.insert(iColl->first).second==false) {
+	msg(MSG::ERROR) << "Channel " << iColl->first << " encountered twice during this callback! Don't know what to do." << endreq;
+	return StatusCode::FAILURE;
+      }
+      //=== COOL channel number is system id
+      SYSTEM sysId = static_cast<SYSTEM>(iColl->first);
+      
+      //=== delete old CaloCondBlobFlt (which does not own the blob)
+      std::map<SYSTEM, const CaloCondBlobFlt*>::iterator iOld = m_noiseBlobMap.find(sysId);
+      if(iOld != m_noiseBlobMap.end()){
+        delete iOld->second;
+      }
+      
+      //=== Get new CaloCondBlobFlt instance, interpreting current BLOB
+      
+      const CaloCondBlobFlt* flt = CaloCondBlobFlt::getInstance(blob);
+    
+      //=== store new pointer in map
+      m_noiseBlobMap[sysId] = flt;
+      
+    }//end iColl
+  }
+  
+  if (m_noiseBlobMap.size()==7) {
+     this->updateCache();
+  }
+  return StatusCode::SUCCESS;
+}
+//_______________________________________________________________________________________
+void 
+CaloNoiseToolDB::updateCache()
+  //
+  // This function is called when /CALO/Noise/CellNoise goes out of IOV.
+  // It ensures that the pointers to the CaloCondBlobFlt objects stored in 
+  // the different COOL channels are also up to date. 
+  //
+{
+ msg(MSG::INFO) << " in update Cache " << endreq;
+
+  // Cache, what noise to return
+  m_CachedGetNoiseCDDE=NULL;
+  if(m_ReturnNoiseName=="electronicNoise") {
+    msg(MSG::INFO) << "Will cache electronic noise" << endreq;
+    m_CachedGetNoiseCDDE=&CaloNoiseToolDB::elecNoiseRMS;
+    m_CachedGetNoiseCELL=&CaloNoiseToolDB::elecNoiseRMS;
+    m_cached = ICalorimeterNoiseTool::ELECTRONICNOISE;
+  }
+  if(m_ReturnNoiseName=="pileupNoise") {
+    msg(MSG::INFO) << "Will cache pileupNoise noise" << endreq;
+    m_CachedGetNoiseCDDE=&CaloNoiseToolDB::pileupNoiseRMS;
+    m_CachedGetNoiseCELL=&CaloNoiseToolDB::pileupNoiseRMS;
+    m_cached = ICalorimeterNoiseTool::PILEUPNOISE;
+  }
+  if(m_ReturnNoiseName=="totalNoise") {
+    msg(MSG::INFO) << "Will cache totalNoise noise" << endreq;
+    m_CachedGetNoiseCDDE=&CaloNoiseToolDB::totalNoiseRMS;
+    m_CachedGetNoiseCELL=&CaloNoiseToolDB::totalNoiseRMS;
+    m_cached = ICalorimeterNoiseTool::TOTALNOISE;
+  }
+  if(m_CachedGetNoiseCDDE==NULL ||
+     m_CachedGetNoiseCELL==NULL) {
+    msg(MSG::ERROR) << "Unknown noise !" << endreq;
+  }
+
+
+  // total number of cells in calorimeter
+  m_ncell=m_calo_id->calo_cell_hash_max();
+
+  // Number of cells per system in EM Barrel and EndCap (indexed by SYSTEM, only first NUM_EM_SYS SYSTEMs)
+  // This is not used later, only for printing
+  int ncellEM[NUM_EM_SYS];
+
+  std::fill_n(ncellEM, NUM_EM_SYS, 0);
+  std::fill_n(m_firstSysHash, NUM_EM_SYS, IdentifierHash());
+
+  IdentifierHash cellHash, cellHashEnd;
+  m_calo_id->calo_cell_hash_range(CaloCell_ID::LAREM, cellHash, cellHashEnd);
+  for (; cellHash != cellHashEnd; cellHash += 1) {
+    Identifier id = m_calo_id->cell_id(cellHash);
+    int sys = 0;
+    if (m_calo_id->is_em_barrel(id)) {
+      sys = (m_calo_id->pos_neg(id) > 0) ? EMBZPOS : EMBZNEG;
+    } else if (m_calo_id->is_em_endcap(id)) {
+      sys = (m_calo_id->pos_neg(id) > 0) ? EMECZPOS : EMECZNEG;
+    }
+    if (not m_firstSysHash[sys].is_valid()) m_firstSysHash[sys] = cellHash;
+    ++ ncellEM[sys];
+  }
+
+  msg(MSG::INFO) << " starting cell hash in EM calo " << m_firstSysHash[EMECZNEG] << " " << m_firstSysHash[EMBZNEG]  << " " << m_firstSysHash[EMBZPOS] << " " << m_firstSysHash[EMECZPOS] << endreq;
+  msg(MSG::INFO) << " number of cells in EM calo " << ncellEM[EMECZNEG] << " " << ncellEM[EMBZNEG]  << " " << ncellEM[EMBZPOS] << " " << ncellEM[EMECZPOS] << endreq;
+  msg(MSG::INFO) << " number from Cools " <<  m_noiseBlobMap[EMECZNEG]->getNChans() << " " << m_noiseBlobMap[EMBZNEG]->getNChans() << " " 
+                   << m_noiseBlobMap[EMBZPOS]->getNChans() << " " << m_noiseBlobMap[EMECZPOS]->getNChans() << endreq;
+
+  const int MaxGains = 4;  // make sure that code below does not exceed this size
+  // m_noise is quite large and memory layout is important; profiling shows that
+  // [MaxGains][m_ncell] ordering makes fewer cache misses than opposite order.
+  m_noise.resize(boost::extents[MaxGains][m_ncell]);
+
+  bool tile_not_found = true;
+  
+  msg(MSG::INFO) << " m_lumi0 " << m_lumi0 << endreq;
+  float lumi = m_lumi0;
+  for (int i=0;i<m_ncell;i++) {
+      IdentifierHash idHash = i;
+      int ngain=3;
+      if (m_calo_id->is_tile(idHash)) {
+          ngain=4;
+          if (tile_not_found) {
+              tile_not_found = false;
+              if (this->checkObjLength(i) < 5) {
+                  msg(MSG::WARNING) 
+                      << "Old CALO DB detected, double gaussian noise option has no effect" << endreq;
+              } else {
+                  msg(MSG::INFO) 
+                      << "New CALO DB detected, double gaussian noise option can be used" << endreq;
+              }
+          }
+      }
+      for (int igain=0;igain<ngain;igain++) {
+         CaloGain::CaloGain caloGain=CaloGain::INVALIDGAIN;;
+         if (!m_calo_id->is_tile(idHash)) caloGain = static_cast<CaloGain::CaloGain> (igain);
+         else {
+           if (igain==0) caloGain=CaloGain::TILELOWLOW;
+           if (igain==1) caloGain=CaloGain::TILELOWHIGH;
+           if (igain==2) caloGain=CaloGain::TILEHIGHLOW;
+           if (igain==3) caloGain=CaloGain::TILEHIGHHIGH;
+         }
+         if (m_cached==ICalorimeterNoiseTool::TOTALNOISE) {
+           float noise = this->getDBNoise(i,caloGain,lumi);
+           m_noise[igain][i] = noise;
+           if (i==0) {
+            msg(MSG::INFO) << " NoiseDB parameters for first cell at gain " << igain << endreq;
+            msg(MSG::INFO) << " a  " << this->getA(i,caloGain) << endreq;
+            msg(MSG::INFO) << " b  " << this->getB(i,caloGain) << endreq;
+            msg(MSG::INFO) << " lumi " << lumi << endreq;
+            msg(MSG::INFO) << " noise " << noise << endreq;
+           }
+         }
+         if (m_cached==ICalorimeterNoiseTool::ELECTRONICNOISE) {
+           float noise = this->getA(i,caloGain);
+           m_noise[igain][i] = noise;
+         }
+         if (m_cached==ICalorimeterNoiseTool::PILEUPNOISE) {
+           float noise = this->getB(i,caloGain)*sqrt(lumi);
+           m_noise[igain][i] = noise;
+         }
+      }
+  }
+  m_cacheValid = true; 
+}
+
+//_______________________________________________________________________________________
+float 
+CaloNoiseToolDB::getDBNoise(unsigned int cellHash,
+                             CaloGain::CaloGain caloGain, 
+                             float lumi) const
+{
+ unsigned int subHash;
+ SYSTEM sysId = this->caloSystem(cellHash,subHash);
+ return this->getDBNoise(sysId, subHash, caloGain, lumi);
+}
+
+
+//
+float
+CaloNoiseToolDB::getA(unsigned int cellHash, CaloGain::CaloGain caloGain) const
+{
+ unsigned int subHash;
+ SYSTEM sysId = this->caloSystem(cellHash,subHash);
+ return this->getA(sysId,subHash,caloGain);
+}
+
+//
+float
+CaloNoiseToolDB::getB(unsigned int cellHash, CaloGain::CaloGain caloGain) const
+{
+ unsigned int subHash;
+ SYSTEM sysId = this->caloSystem(cellHash,subHash);
+ return this->getB(sysId,subHash,caloGain);
+}
+
+//
+float
+CaloNoiseToolDB::getC(unsigned int cellHash, CaloGain::CaloGain caloGain) const
+{
+ unsigned int subHash;
+ SYSTEM sysId = this->caloSystem(cellHash,subHash);
+ return this->getC(sysId,subHash,caloGain);
+}
+
+//
+float
+CaloNoiseToolDB::getD(unsigned int cellHash, CaloGain::CaloGain caloGain) const
+{
+ unsigned int subHash;
+ SYSTEM sysId = this->caloSystem(cellHash,subHash);
+ return this->getD(sysId,subHash,caloGain);
+}
+
+//
+float
+CaloNoiseToolDB::getE(unsigned int cellHash, CaloGain::CaloGain caloGain) const
+{
+ unsigned int subHash;
+ SYSTEM sysId = this->caloSystem(cellHash,subHash);
+ return this->getE(sysId,subHash,caloGain);
+}
+
+CaloNoiseToolDB::SYSTEM CaloNoiseToolDB::caloSystem(unsigned int cellHash, unsigned int& subHash) const
+{
+  int subCalo;
+  subHash = m_calo_id->subcalo_cell_hash (cellHash, subCalo);
+  if (subCalo == CaloCell_ID::LAREM) { // EM calo
+    for (int i = 0; i != NUM_EM_SYS-1; ++ i) {
+      if (cellHash < m_firstSysHash[i+1].value()) {
+        subHash = cellHash - m_firstSysHash[i].value();
+        return SYSTEM(i);
+      }
+    }
+    subHash = cellHash - m_firstSysHash[NUM_EM_SYS-1].value();
+    return SYSTEM(NUM_EM_SYS-1);
+  } else if (subCalo == CaloCell_ID::LARHEC) { // HEC
+    return HEC;
+  } else if (subCalo == CaloCell_ID::LARFCAL) { // Fcal
+    return FCAL;
+  } else {
+    if (subCalo != CaloCell_ID::TILE) {
+      std::cout << " something wrong. either LAr not tile..." << std::endl;
+    }
+    return TILE;
+  }
+}
+
+
+
+//_______________________________________________________________________________________
+float 
+CaloNoiseToolDB::getA(SYSTEM sysId, unsigned int cellHash, CaloGain::CaloGain caloGain) const
+{
+  const CaloCondBlobFlt* const flt = m_noiseBlobMap.find(sysId)->second;
+  unsigned int dbGain = CaloCondUtils::getDbCaloGain(caloGain);
+  return flt->getData(cellHash,dbGain,0);
+}
+
+//
+//_______________________________________________________________________________________
+float 
+CaloNoiseToolDB::getB(SYSTEM sysId, unsigned int cellHash, CaloGain::CaloGain caloGain) const
+{
+  const CaloCondBlobFlt* const flt = m_noiseBlobMap.find(sysId)->second;
+  unsigned int dbGain = CaloCondUtils::getDbCaloGain(caloGain);
+  return flt->getData(cellHash,dbGain,1);
+}
+
+//
+//_______________________________________________________________________________________
+float 
+CaloNoiseToolDB::getC(SYSTEM sysId, unsigned int cellHash, CaloGain::CaloGain caloGain) const
+{
+  const CaloCondBlobFlt* const flt = m_noiseBlobMap.find(sysId)->second;
+  unsigned int dbGain = CaloCondUtils::getDbCaloGain(caloGain);
+  return flt->getData(cellHash,dbGain,2);
+}
+
+//
+//_______________________________________________________________________________________
+float 
+CaloNoiseToolDB::getD(SYSTEM sysId, unsigned int cellHash, CaloGain::CaloGain caloGain) const
+{
+  const CaloCondBlobFlt* const flt = m_noiseBlobMap.find(sysId)->second;
+  unsigned int dbGain = CaloCondUtils::getDbCaloGain(caloGain);
+  return flt->getData(cellHash,dbGain,3);
+}
+
+//
+//_______________________________________________________________________________________
+float 
+CaloNoiseToolDB::getE(SYSTEM sysId, unsigned int cellHash, CaloGain::CaloGain caloGain) const
+{
+  const CaloCondBlobFlt* const flt = m_noiseBlobMap.find(sysId)->second;
+  unsigned int dbGain = CaloCondUtils::getDbCaloGain(caloGain);
+  return flt->getData(cellHash,dbGain,4);
+}
+
+//
+int 
+CaloNoiseToolDB::checkObjLength(unsigned int cellHash) const
+{
+ unsigned int subHash;
+ SYSTEM sysId = this->caloSystem(cellHash,subHash);
+ const CaloCondBlobFlt* const flt = m_noiseBlobMap.find(sysId)->second;
+ return flt->getObjSizeUint32();
+}
+
+//_______________________________________________________________________________________
+float 
+CaloNoiseToolDB::getDBNoise(SYSTEM sysId, 
+                             unsigned int cellHash, 
+                             CaloGain::CaloGain caloGain, 
+                             float lumi) const
+{
+  const CaloCondBlobFlt* const flt = m_noiseBlobMap.find(sysId)->second;
+  unsigned int dbGain = CaloCondUtils::getDbCaloGain(caloGain);
+  return flt->getCalib(cellHash, dbGain, lumi);
+}
+
+
+
+
+
+//////////////////////////////////////////////////
+// functions for the getNoise interface
+float
+CaloNoiseToolDB::getNoise(const CaloDetDescrElement* caloDDE, CalorimeterNoiseType type)
+{
+  float Nminbias=-1;
+  if( m_Nminbias>0 )
+    Nminbias=m_Nminbias;
+  
+  CaloGain::CaloGain igain = m_highestGain[caloDDE->getSubCalo()];
+  if( m_gain_from_joboption>=0 &&
+      (type == ICalorimeterNoiseTool::ELECTRONICNOISE ||
+       type == ICalorimeterNoiseTool::PILEUPNOISE ||
+       type == ICalorimeterNoiseTool::TOTALNOISE ))
+    igain = static_cast<CaloGain::CaloGain>(m_gain_from_joboption);
+  
+  switch(type) {
+  case ICalorimeterNoiseTool::JOBOPTION:
+    return (this->*m_CachedGetNoiseCDDE)(caloDDE,igain,Nminbias,
+					 ICaloNoiseToolStep::CELLS);
+    break;
+  case ICalorimeterNoiseTool::ELECTRONICNOISE_HIGHESTGAIN:
+  case ICalorimeterNoiseTool::ELECTRONICNOISE:
+    return elecNoiseRMS(caloDDE,igain,Nminbias,
+			ICaloNoiseToolStep::CELLS);
+    break;
+  case ICalorimeterNoiseTool::PILEUPNOISE_HIGHESTGAIN:
+  case ICalorimeterNoiseTool::PILEUPNOISE:
+    return pileupNoiseRMS(caloDDE,igain,Nminbias,
+			  ICaloNoiseToolStep::CELLS);
+    break;
+  case ICalorimeterNoiseTool::TOTALNOISE_HIGHESTGAIN:
+  case ICalorimeterNoiseTool::TOTALNOISE:
+    return totalNoiseRMS(caloDDE,igain,Nminbias,
+			 ICaloNoiseToolStep::CELLS);
+    break;
+    
+  default:
+    return 0.;
+    break;
+  }
+}
+
+float
+CaloNoiseToolDB::getNoise(const CaloCell* caloCell, CalorimeterNoiseType type)
+{
+  const CaloDetDescrElement* caloDDE = caloCell->caloDDE();
+  float Nminbias=-1;
+  if( m_Nminbias>0 )
+    Nminbias=m_Nminbias;
+  
+  CaloGain::CaloGain igain = caloCell->gain();
+  
+  if( m_gain_from_joboption>=0 &&
+      (type == ICalorimeterNoiseTool::ELECTRONICNOISE ||
+       type == ICalorimeterNoiseTool::PILEUPNOISE ||
+       type == ICalorimeterNoiseTool::TOTALNOISE ))
+    igain = static_cast<CaloGain::CaloGain>(m_gain_from_joboption);
+  
+  switch(type) {
+  case ICalorimeterNoiseTool::JOBOPTION:
+    return (this->*m_CachedGetNoiseCELL)(caloCell,igain,Nminbias,
+					 ICaloNoiseToolStep::CELLS);
+    break;
+  case ICalorimeterNoiseTool::ELECTRONICNOISE_HIGHESTGAIN:
+    // overwrite iGain with highest gain for that detector and
+    // continue into normal code (NO break !!)
+    igain=m_highestGain[caloDDE->getSubCalo()];
+  case ICalorimeterNoiseTool::ELECTRONICNOISE:
+    return elecNoiseRMS(caloDDE,igain,Nminbias,
+			ICaloNoiseToolStep::CELLS);
+    break;
+    
+  case ICalorimeterNoiseTool::PILEUPNOISE_HIGHESTGAIN:
+    // overwrite iGain with highest gain for that detector and
+    // continue into normal code (NO break !!)
+    igain=m_highestGain[caloDDE->getSubCalo()];
+    //  NOTE: igain is not used at the moment for pileupnoise
+  case ICalorimeterNoiseTool::PILEUPNOISE:
+    return pileupNoiseRMS(caloDDE,igain,Nminbias,
+			  ICaloNoiseToolStep::CELLS);
+    break;
+    
+  case ICalorimeterNoiseTool::TOTALNOISE_HIGHESTGAIN:
+    // overwrite iGain with highest gain for that detector and
+    // continue into normal code (NO break !!)
+    igain=m_highestGain[caloDDE->getSubCalo()];
+    //  NOTE: igain is only used for the electronics noise at the moment
+  case ICalorimeterNoiseTool::TOTALNOISE:
+    return totalNoiseRMS(caloDDE,igain,Nminbias,
+			 ICaloNoiseToolStep::CELLS);
+    break;
+    
+  default:
+    return 0.;
+    break;
+  }
+}
+
+float
+CaloNoiseToolDB::getNoise(const CaloCell* caloCell, float energy, CalorimeterNoiseType type)
+{
+  const CaloDetDescrElement* caloDDE = caloCell->caloDDE();
+  float Nminbias=-1;
+  if( m_Nminbias>0 )
+    Nminbias=m_Nminbias;
+  
+  CaloGain::CaloGain igain = caloCell->gain();
+  
+  if( m_gain_from_joboption>=0 &&
+      (type == ICalorimeterNoiseTool::ELECTRONICNOISE ||
+       type == ICalorimeterNoiseTool::PILEUPNOISE ||
+       type == ICalorimeterNoiseTool::TOTALNOISE ))
+    igain = static_cast<CaloGain::CaloGain>(m_gain_from_joboption);
+  
+  switch(type) {
+  case ICalorimeterNoiseTool::JOBOPTION:
+    return (this->*m_CachedGetNoiseCELL)(caloCell,igain,Nminbias,
+					 ICaloNoiseToolStep::CELLS);
+    break;
+  case ICalorimeterNoiseTool::ELECTRONICNOISE_HIGHESTGAIN:
+    // overwrite iGain with highest gain for that detector and
+    // continue into normal code (NO break !!)
+    igain=m_highestGain[caloDDE->getSubCalo()];
+  case ICalorimeterNoiseTool::ELECTRONICNOISE:
+    return elecNoiseRMS(caloDDE,igain,Nminbias,energy,
+			ICaloNoiseToolStep::CELLS);
+    break;
+    
+  case ICalorimeterNoiseTool::PILEUPNOISE_HIGHESTGAIN:
+    // overwrite iGain with highest gain for that detector and
+    // continue into normal code (NO break !!)
+    igain=m_highestGain[caloDDE->getSubCalo()];
+    //  NOTE: igain is not used at the moment for pileupnoise
+  case ICalorimeterNoiseTool::PILEUPNOISE:
+    return pileupNoiseRMS(caloDDE,igain,Nminbias,
+			  ICaloNoiseToolStep::CELLS);
+    break;
+    
+  case ICalorimeterNoiseTool::TOTALNOISE_HIGHESTGAIN:
+    // overwrite iGain with highest gain for that detector and
+    // continue into normal code (NO break !!)
+    igain=m_highestGain[caloDDE->getSubCalo()];
+    //  NOTE: igain is only used for the electronics noise at the moment
+  case ICalorimeterNoiseTool::TOTALNOISE:
+    return totalNoiseRMS(caloDDE,igain,Nminbias,energy,
+			 ICaloNoiseToolStep::CELLS);
+    break;
+    
+  default:
+    return 0.;
+    break;
+  }
+}
+
+float 
+CaloNoiseToolDB::calcSig(double e, double sigma1, double ratio, double sigma2) {
+//Luca: code to return the C.L. of the double gaussian with
+//3 parameters.
+//sigma1, sigma2 and ratio are the 3 noise parameters
+// e is the input energy of which you want to calculated the
+//significance
+  float valid_range[2]={0.9,7.5};
+  
+  if((sigma1 == 0. && sigma2 == 0.) || e == 0.) return 0.;
+  if(sigma1 == 0.) return e/sigma2;
+  if((ratio  == 0.) || sigma2 == 0.) return e/sigma1;
+  double x1 = e/sigma1;
+  double x2 = e/sigma2;
+
+  if (m_speedTwoGauss) {
+    float wide_gauss_sigma = std::min(fabs(x1),fabs(x2));
+    if(wide_gauss_sigma > valid_range[1]) return wide_gauss_sigma;
+    float narrow_gauss_sigma= std::max(fabs(x1),fabs(x2));
+    if(narrow_gauss_sigma < valid_range[0]) return narrow_gauss_sigma;
+  }
+
+  double y1= TMath::Erf(invsqrt2*x1);
+  double y2= TMath::Erf(invsqrt2*x2);
+
+  double z = ( y1*sigma1 + ratio*y2*sigma2 )/( sigma1 + ratio*sigma2);
+
+  //return the C.L. probability (with sign!)
+  //  return z;
+ 
+  // if instead you want to return the sigma-equivalent C.L.
+  // (with sign!) use the following line
+  return sqrt2*TMath::ErfInverse(z);
+
+}
+
+//========================  USER INTERFACES ===================================
+
+
+//////////////////////////////////////////////////
+
+float 
+CaloNoiseToolDB::elecNoiseRMS(const CaloCell* caloCell, 
+		 	    const int /* step */)
+{
+  if (!m_cacheValid) this->updateCache();
+  Identifier id = caloCell->ID();
+  int i = (int)(m_calo_id->calo_cell_hash(id));
+  if (i>m_ncell) return -1;
+  CaloGain::CaloGain calogain = caloCell->gain();
+  if (m_cached==ICalorimeterNoiseTool::ELECTRONICNOISE && m_cacheValid) {
+    int igain = CaloCondUtils::getDbCaloGain(calogain);
+    return m_noise[igain][i];
+  }
+  else 
+    return this->getA(i,calogain);
+}
+
+//////////////////////////////////////////////////
+
+float 
+CaloNoiseToolDB::elecNoiseRMS(const CaloCell* caloCell, 
+			    const float /* Nminbias */, const int step)
+{
+  return this->elecNoiseRMS(caloCell,step);
+}
+
+//////////////////////////////////////////////////
+
+float
+CaloNoiseToolDB::elecNoiseRMSHighestGain(const CaloCell* caloCell, 
+				       const int /* step */)
+{    
+ Identifier id = caloCell->ID();
+ int i = (int)(m_calo_id->calo_cell_hash(id));
+ if (i>m_ncell) return -1;
+ const CaloDetDescrElement* caloDDE = caloCell->caloDDE();
+ CaloGain::CaloGain highestgain=m_highestGain[caloDDE->getSubCalo()];
+ return this->getA(i,highestgain);
+}
+
+//////////////////////////////////////////////////
+
+float
+CaloNoiseToolDB::elecNoiseRMSHighestGain(const CaloCell* caloCell, 
+				         const float /* Nminbias */, const int step)
+{   
+ return this->elecNoiseRMSHighestGain(caloCell,step);
+ 
+}
+
+//////////////////////////////////////////////////
+
+float
+CaloNoiseToolDB::elecNoiseRMSHighestGain(const CaloDetDescrElement* caloDDE, 
+				       const int step)
+{    
+  CaloGain::CaloGain highestGain=m_highestGain[caloDDE->getSubCalo()];
+  return this->elecNoiseRMS(caloDDE,highestGain,-1,step);    
+}
+
+//////////////////////////////////////////////////
+
+float
+CaloNoiseToolDB::elecNoiseRMSHighestGain(const CaloDetDescrElement* caloDDE, 
+				       const float Nminbias, const int step)
+{    
+  CaloGain::CaloGain highestGain=m_highestGain[caloDDE->getSubCalo()];
+  return this->elecNoiseRMS(caloDDE,highestGain,Nminbias,step);    
+}
+
+//////////////////////////////////////////////////
+
+float 
+CaloNoiseToolDB::elecNoiseRMS(const CaloDetDescrElement* caloDDE, 
+			    const CaloGain::CaloGain gain,
+			    const float /* Nminbias */, 
+			    const int /* step */)
+{  
+  if (!m_cacheValid) this->updateCache();
+  int i = (int)(caloDDE->calo_hash());
+  if (i>m_ncell) return -1;
+  if (m_cached==ICalorimeterNoiseTool::ELECTRONICNOISE && m_cacheValid) {
+    int igain = CaloCondUtils::getDbCaloGain(gain);
+    return m_noise[igain][i];
+  }
+  else
+    return this->getA(i,gain);
+}
+
+//////////////////////////////////////////////////
+
+float 
+CaloNoiseToolDB::elecNoiseRMS(const CaloDetDescrElement* caloDDE, 
+			    const CaloGain::CaloGain gain,
+			    const float /* Nminbias */, 
+			    const float energy, 
+			    const int /* step */)
+{  
+  if (!m_cacheValid) this->updateCache();
+  int i = (int)(caloDDE->calo_hash());
+  if (i>m_ncell) return -1;
+  unsigned int subHash;
+  SYSTEM sysId = this->caloSystem(i,subHash);
+  const CaloCondBlobFlt* const flt = m_noiseBlobMap.find(sysId)->second;
+  unsigned int dbGain = CaloCondUtils::getDbCaloGain(gain);
+  if (flt->getObjSizeUint32() > 4) { // need at least 5 elements in a vector for 2G noise
+    double sigma1 = flt->getData(subHash,dbGain,2);
+    double sigma2 = flt->getData(subHash,dbGain,3);
+    double ratio  = flt->getData(subHash,dbGain,4);
+    float n_sigma = this->calcSig(energy, sigma1, ratio, sigma2);
+    float equiv_noise = (n_sigma != 0.) ? fabs(energy/n_sigma) : 0.0;
+    return equiv_noise;
+  } else {
+    if (m_cached==ICalorimeterNoiseTool::ELECTRONICNOISE && m_cacheValid) {
+      return m_noise[dbGain][i];
+    }
+    else {
+      return flt->getData(subHash,dbGain,0);
+    }
+  }
+}
+
+//////////////////////////////////////////////////
+
+std::vector<float> 
+CaloNoiseToolDB::elecNoiseRMS3gains(const CaloDetDescrElement* caloDDE, 
+				  const int step)
+{  
+  std::vector<float> sigma;
+  for(int igain=0;igain<CaloGain::LARNGAIN;++igain)
+    sigma.push_back(this->elecNoiseRMS(caloDDE,static_cast<CaloGain::CaloGain>(igain),-1,step));
+  return sigma;
+
+}
+
+//////////////////////////////////////////////////
+
+std::vector<float> 
+CaloNoiseToolDB::elecNoiseRMS3gains(const CaloDetDescrElement* caloDDE, 
+				  const float /* NMinBias */,const int step)
+{  
+  return this->elecNoiseRMS3gains(caloDDE,step);
+}
+
+//////////////////////////////////////////////////
+
+VectorContainer* 
+CaloNoiseToolDB::elecNoiseRMSContainer(const int &iCalo) 
+{
+  msg(MSG::WARNING) << " elecNoiseRMSContainer not implemented " << iCalo << endreq ;
+  return 0;
+}
+
+//////////////////////////////////////////////////
+// new interfaces to enable caching of the pointer to member
+
+float 
+CaloNoiseToolDB::elecNoiseRMS(const CaloCell* theCell,
+			    const CaloGain::CaloGain /*gain*/,
+			    const float Nminbias, 
+			    const int step) {
+  return this->elecNoiseRMS(theCell,Nminbias,step);
+}
+
+float 
+CaloNoiseToolDB::pileupNoiseRMS(const CaloCell* theCell,
+			      const CaloGain::CaloGain /*gain*/,
+			      const float Nminbias, 
+			      const int /*step*/) {
+  return this->pileupNoiseRMS(theCell,Nminbias);
+}
+
+float 
+CaloNoiseToolDB::totalNoiseRMS(const CaloCell* theCell,
+			     const CaloGain::CaloGain /*gain*/,
+			     const float Nminbias, 
+			     const int /* step */) {
+   return this->totalNoiseRMS(theCell,Nminbias);
+}
+
+float 
+CaloNoiseToolDB::pileupNoiseRMS(const CaloDetDescrElement* caloDDE, 
+			      const CaloGain::CaloGain gain,
+			      const float Nminbias, 
+			      const int /*step*/) {
+  if (!m_cacheValid) this->updateCache();
+  int i = (int)(caloDDE->calo_hash());
+  if (i>m_ncell) return -1;
+  if (m_cached==ICalorimeterNoiseTool::PILEUPNOISE && (Nminbias == m_Nminbias || Nminbias<0) && m_cacheValid) {
+    int igain = CaloCondUtils::getDbCaloGain(gain);
+    return m_noise[igain][i];
+  }
+  else {
+    float lumi;
+    if (Nminbias>0) {
+     lumi=Nminbias/2.3;
+    }
+    else {
+      lumi=m_lumi0;
+    }
+    return (this->getB(i,gain)*sqrt(lumi));
+  }
+
+}
+
+float 
+CaloNoiseToolDB::totalNoiseRMS(const CaloDetDescrElement* caloDDE, 
+			     const CaloGain::CaloGain gain,
+			     const float Nminbias, 
+			     const int /*step*/) {
+  if (!m_cacheValid) this->updateCache();
+  int i = (int)(caloDDE->calo_hash());
+  if (i>m_ncell) return -1;
+  if (m_cached==ICalorimeterNoiseTool::TOTALNOISE && (Nminbias == m_Nminbias || Nminbias<0) && m_cacheValid) {
+    int igain = CaloCondUtils::getDbCaloGain(gain);
+    return m_noise[igain][i];
+  } else {
+    float lumi = (Nminbias>0) ? Nminbias/2.3 : m_lumi0;
+    return this->getDBNoise(i,gain,lumi);
+  }
+}
+
+float 
+CaloNoiseToolDB::totalNoiseRMS(const CaloDetDescrElement* caloDDE, 
+			     const CaloGain::CaloGain gain,
+			     const float Nminbias, 
+			     const float energy, 
+			     const int /*step*/) {
+  //  std::cout << "totalNoiseRMS e " << energy << " gain " << gain << std::endl;
+  int i = (int)(caloDDE->calo_hash());
+  if (i>m_ncell) return -1;
+  float lumi = (Nminbias>0) ? Nminbias/2.3 : m_lumi0;
+  float x;
+  float a = elecNoiseRMS(caloDDE,gain,Nminbias,energy,
+			 ICaloNoiseToolStep::CELLS);
+  float b = this->getB(i,gain);
+
+  int objver = m_noiseBlobMap[TILE]->getObjVersion();
+  if(objver==1){
+    //=== Total noise parameterized as
+    //=== Sigma**2 = a**2 + b**2 * Lumi
+    x = std::sqrt( a*a + b*b*lumi );
+  }
+  else if (objver==2) {
+    //== parameterization for pedestal = a + b*Lumi
+    x = a+b*lumi;
+  }
+  else{
+    throw CaloCond::VersionConflict("CaloNoiseToolDB::totalNoiseRMS ",objver);
+  }
+  return x;
+}
+//////////////////////////////////////////////////
+
+float 
+CaloNoiseToolDB::pileupNoiseRMS(const CaloCell* caloCell, const float Nminbias)
+{
+  if (!m_cacheValid) this->updateCache();
+  Identifier id = caloCell->ID();
+  int i = (int)(m_calo_id->calo_cell_hash(id));
+  if (i>m_ncell) return -1;
+  CaloGain::CaloGain calogain = caloCell->gain();
+  if (m_cached==ICalorimeterNoiseTool::PILEUPNOISE && (Nminbias == m_Nminbias || Nminbias<0) && m_cacheValid) {
+    int igain = CaloCondUtils::getDbCaloGain(calogain);
+    return m_noise[igain][i];
+  }
+  else {
+    float lumi;
+    if (Nminbias>0) {
+      lumi=Nminbias/2.3;
+    }
+    else {
+       lumi=m_lumi0;
+    }
+    return (this->getB(i,calogain)*sqrt(lumi));
+  }
+}
+
+//////////////////////////////////////////////////
+
+float 
+CaloNoiseToolDB::pileupNoiseRMS(const CaloDetDescrElement* caloDDE, 
+			      const float Nminbias)
+{
+  if (!m_cacheValid) this->updateCache();
+  int subcalo = caloDDE->getSubCalo();
+  if (subcalo < 0 || subcalo >= m_nCalos) return -1;
+  CaloGain::CaloGain highestGain=m_highestGain[subcalo];
+  int i = (int)(caloDDE->calo_hash());
+  if (i>m_ncell) return -1;
+  if (m_cached==ICalorimeterNoiseTool::PILEUPNOISE && (Nminbias == m_Nminbias || Nminbias<0) && m_cacheValid) {
+    int igain = CaloCondUtils::getDbCaloGain(highestGain);
+    return m_noise[igain][i];
+  }
+  else {
+    float lumi;
+    if (Nminbias>0) {
+     lumi=Nminbias/2.3;
+    }
+    else {
+     lumi=m_lumi0;
+    }
+    return (this->getB(i,highestGain)*sqrt(lumi));
+  }
+
+}
+
+//////////////////////////////////////////////////
+
+float 
+CaloNoiseToolDB::totalNoiseRMS(const CaloCell* caloCell, const float Nminbias) 
+{
+  if (!m_cacheValid) this->updateCache();
+  Identifier id = caloCell->ID();
+  int i = (int)(m_calo_id->calo_cell_hash(id));
+  if (i>m_ncell) return -1;
+  CaloGain::CaloGain calogain = caloCell->gain();
+  if (m_cached==ICalorimeterNoiseTool::TOTALNOISE && (Nminbias == m_Nminbias || Nminbias<0) && m_cacheValid) {
+    int igain=CaloCondUtils::getDbCaloGain(calogain);
+    return m_noise[igain][i];
+  } else {
+    float lumi = (Nminbias>0) ? Nminbias/2.3 : m_lumi0;
+    return this->getDBNoise(i,calogain,lumi);
+  }
+
+
+}
+
+//////////////////////////////////////////////////
+
+float 
+CaloNoiseToolDB::totalNoiseRMS(const CaloDetDescrElement* caloDDE, 
+			     const CaloGain::CaloGain gain, 
+			     const float Nminbias)
+{
+  if (!m_cacheValid) this->updateCache();
+  int i = (int)(caloDDE->calo_hash());
+  if (i>m_ncell) return -1;
+  if (m_cached==ICalorimeterNoiseTool::TOTALNOISE && (Nminbias == m_Nminbias || Nminbias<0) && m_cacheValid) {
+    int igain = CaloCondUtils::getDbCaloGain(gain);
+    return m_noise[igain][i];
+  } else {
+    float lumi = (Nminbias>0) ? Nminbias/2.3 : m_lumi0;
+    return this->getDBNoise(i,gain,lumi);
+  }
+
+}
+
+//////////////////////////////////////////////////
+
+float 
+CaloNoiseToolDB::totalNoiseRMSHighestGain(const CaloCell* caloCell, 
+					const float Nminbias)
+{
+  return this->totalNoiseRMSHighestGain(caloCell->caloDDE(),Nminbias);
+}
+
+//////////////////////////////////////////////////
+
+float 
+CaloNoiseToolDB::totalNoiseRMSHighestGain(const CaloDetDescrElement* caloDDE, 
+					const float Nminbias)
+{
+  CaloGain::CaloGain highestGain=m_highestGain[caloDDE->getSubCalo()];
+  return this->totalNoiseRMS(caloDDE,highestGain,Nminbias);
+}
+
+
+CaloGain::CaloGain CaloNoiseToolDB::estimatedGain(const CaloCell* /* caloCell */,
+                                 const int & /*step */) {
+ msg(MSG::WARNING) << "  CaloNoiseToolDB::estimatedGain returns INVALIDGAIN " << endreq;
+ return CaloGain::INVALIDGAIN;
+}
+CaloGain::CaloGain CaloNoiseToolDB::estimatedGain(const CaloCell* /* caloCell */,
+                                 const CaloDetDescrElement* /* caloDDE */,
+                                 const int & /*step */){
+ msg(MSG::WARNING) << "  CaloNoiseToolDB::estimatedGain returns INVALIDGAIN " << endreq;
+ return CaloGain::INVALIDGAIN;
+}
+CaloGain::CaloGain CaloNoiseToolDB::estimatedGain(const CaloDetDescrElement* /* caloDDE */,
+                                 const float& /* energy */,
+                                 const int & /* step */) {
+ msg(MSG::WARNING) << "  CaloNoiseToolDB::estimatedGain returns INVALIDGAIN " << endreq;
+ return CaloGain::INVALIDGAIN;
+}
+
+StatusCode CaloNoiseToolDB::LoadCalibration(IOVSVC_CALLBACK_ARGS) {
+ msg(MSG::WARNING) << "  CaloNoiseToolDB::LoadCalibration dummy method " << endreq;
+ return StatusCode::SUCCESS;
+}
+
+
+// GU: below are temporary implementations, waiting for non-gaussian noise description in DB (at least for Tiles)
+
+/////////////////////////////////////////////////////////////////////////
+
+bool CaloNoiseToolDB::isEOverNSigma(const CaloCell* caloCell, float sigmaCut ,
+                     CalorimeterNoiseSymmetryHandling /* symmetryHandling */,
+                     CalorimeterNoiseType type)
+{
+  float noise_cut;
+  const CaloDetDescrElement* caloDDE = caloCell->caloDDE();
+  if(caloDDE->getSubCalo()==CaloCell_ID::TILE) {
+    noise_cut = fabs(sigmaCut*this->getNoise(caloCell, (float) caloCell->e(), type));
+  } else {
+    noise_cut = fabs(sigmaCut*this->getNoise(caloCell, type));
+  }
+  float energy = fabs(caloCell->e());
+  return (energy>noise_cut);
+}
+
+////////////////////////////////////////////////////////////////////
+
+float CaloNoiseToolDB::getRandomisedE(const CaloCell* caloCell , CLHEP::HepRandomEngine* engine, CalorimeterNoiseType type)
+{
+  double rms = this->getNoise(caloCell,type);
+  return RandGauss::shoot(engine,0.,rms);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////
+
+float CaloNoiseToolDB::getEffectiveSigma(const CaloCell* caloCell,
+                     CalorimeterNoiseSymmetryHandling /*symmetryHandling*/,
+                     CalorimeterNoiseType type )
+{
+  const CaloDetDescrElement* caloDDE = caloCell->caloDDE();
+  float eqnoise;
+  if(caloDDE->getSubCalo()==CaloCell_ID::TILE) {
+    eqnoise = this->getNoise(caloCell, (float) caloCell->e(), type);
+  } else {
+    eqnoise = this->getNoise(caloCell, type);
+  }
+  return eqnoise;
+     // simple implementation for gaussian noise
+  //     return this->getNoise(caloCell,type);
+}
diff --git a/Calorimeter/CaloTools/src/SimpleNoiseTool.cxx b/Calorimeter/CaloTools/src/SimpleNoiseTool.cxx
new file mode 100755
index 0000000000000000000000000000000000000000..c0ed4d62b76a570d39d424ff0414c1202ef5203f
--- /dev/null
+++ b/Calorimeter/CaloTools/src/SimpleNoiseTool.cxx
@@ -0,0 +1,94 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+
+#include "GaudiKernel/Service.h"
+#include "GaudiKernel/MsgStream.h"
+
+#include "StoreGate/StoreGateSvc.h"
+
+#include "CLHEP/Units/SystemOfUnits.h"
+#include "CLHEP/Random/RandomEngine.h"
+#include "CLHEP/Random/RandGauss.h"
+
+
+#include "CaloTools/SimpleNoiseTool.h"
+
+#include "CaloEvent/CaloCell.h"
+
+std::map<float, CaloDetDescrElement> NoiseMap;
+
+SimpleNoiseTool::SimpleNoiseTool(const std::string& type,
+				 const std::string& name,
+				 const IInterface* parent)
+  : AthAlgTool(type,name,parent)
+{
+
+  declareInterface<ICalorimeterNoiseTool>(this);
+
+  MsgStream report(msgSvc(),name);
+  report << MSG::INFO << " SimpleNoiseTool start" << endreq;
+}
+
+SimpleNoiseTool::~SimpleNoiseTool()
+{ }
+
+StatusCode SimpleNoiseTool::initialize()
+{
+  MsgStream report(msgSvc(),name());
+  report << MSG::INFO << " SimpleNoiseTool initialize()" << endreq;
+
+  
+  return StatusCode::SUCCESS;
+}
+
+float SimpleNoiseTool::getNoise(const CaloCell* /*aCell*/, CalorimeterNoiseType /*type*/)
+{
+  float noise=10.0;
+  
+  MsgStream report(msgSvc(),name());
+  // report << MSG::INFO
+  // << "::getNoise::" << aCell->caloDDE() << " : " << noise << "\n";
+  return noise;
+}
+
+float SimpleNoiseTool::getNoise(const CaloDetDescrElement* /*caloDDE*/, CalorimeterNoiseType /*type*/)
+{
+  float noise=10.0;
+  
+  MsgStream report(msgSvc(),name());
+  // report << MSG::INFO
+  // << "::getNoise::" << caloDDE << " : " << noise << "\n";
+  return noise;
+}
+
+/////////////////////////////////////////////////////////////////////////
+
+bool SimpleNoiseTool::isEOverNSigma(const CaloCell* caloCell, float sigmaCut ,
+                     CalorimeterNoiseSymmetryHandling symmetryHandling,
+                     CalorimeterNoiseType type)
+{
+  float noise_cut = fabs(sigmaCut*this->getEffectiveSigma(caloCell,  symmetryHandling, type));
+  float energy = fabs(caloCell->e());
+  return (energy>noise_cut);
+
+}
+
+////////////////////////////////////////////////////////////////////
+
+float SimpleNoiseTool::getRandomisedE(const CaloCell* caloCell , CLHEP::HepRandomEngine* engine, CalorimeterNoiseType type)
+{
+  double rms = this->getNoise(caloCell,type);
+  return CLHEP::RandGauss::shoot(engine,0.,rms);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////
+
+float SimpleNoiseTool::getEffectiveSigma(const CaloCell* caloCell,
+                     CalorimeterNoiseSymmetryHandling /*symmetryHandling*/,
+                     CalorimeterNoiseType type )
+{
+     // simple implementation for gaussian noise
+     return this->getNoise(caloCell,type);
+}
diff --git a/Calorimeter/CaloTools/src/SimpleNoiseToolFromTextFile.cxx b/Calorimeter/CaloTools/src/SimpleNoiseToolFromTextFile.cxx
new file mode 100755
index 0000000000000000000000000000000000000000..e648ea90032c58f3f2f4b760fe2c708fc380fda2
--- /dev/null
+++ b/Calorimeter/CaloTools/src/SimpleNoiseToolFromTextFile.cxx
@@ -0,0 +1,223 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+
+#include "GaudiKernel/Service.h"
+#include "GaudiKernel/MsgStream.h"
+#include "StoreGate/StoreGateSvc.h"
+#include "CLHEP/Units/SystemOfUnits.h"
+#include "CLHEP/Random/RandomEngine.h"
+#include "CLHEP/Random/RandGauss.h"
+#include "CaloTools/SimpleNoiseToolFromTextFile.h"
+#include "CaloEvent/CaloCell.h"
+#include "CaloDetDescr/CaloDetDescrElement.h"
+#include "GeoModelInterfaces/IGeoModelSvc.h"
+
+#include <iomanip>
+#include <iostream>
+#include <fstream>
+#include <string>
+
+using CLHEP::MeV;
+using CLHEP::RandGauss;
+
+SimpleNoiseToolFromTextFile::SimpleNoiseToolFromTextFile(const std::string& type,
+							 const std::string& name,
+							 const IInterface* parent)
+  : AthAlgTool(type,name,parent)
+    , m_cellNoiseFileName("")
+    , m_cellNoiseUnits(MeV)
+    , m_cellNoiseDefault(100.*MeV)
+    , m_cellNoiseDefaultWarning(true)
+{ 
+  declareInterface<ICalorimeterNoiseTool>(this);
+
+  declareProperty("CellNoiseFileName",       m_cellNoiseFileName="/afs/cern.ch/user/h/hectbmon/public/tb/aug02/noise/H6_2002NoiseMuons.dat");
+  declareProperty("CellNoiseUnits",          m_cellNoiseUnits=MeV);
+  declareProperty("CellNoiseDefault",        m_cellNoiseDefault=100*MeV);
+  declareProperty("CellNoiseDefaultWarning", m_cellNoiseDefaultWarning=true);
+}
+
+SimpleNoiseToolFromTextFile::~SimpleNoiseToolFromTextFile()
+{ }
+
+StatusCode SimpleNoiseToolFromTextFile::initialize()
+{
+  MsgStream report(msgSvc(),name());
+
+  StoreGateSvc* detStore;
+  if (service("DetectorStore", detStore).isFailure()) {
+    report << MSG::ERROR   << "Unable to access DetectoreStore" << endreq ;
+    return StatusCode::FAILURE;
+  }
+
+  const IGeoModelSvc *geoModel=0;
+  StatusCode sc = service("GeoModelSvc", geoModel);
+  if(sc.isFailure())
+  {
+    report << MSG::ERROR << "Could not locate GeoModelSvc" << endreq;
+    return sc;
+  }
+
+  // dummy parameters for the callback:
+  int dummyInt=0;
+  std::list<std::string> dummyList;
+
+  if (geoModel->geoInitialized())
+  {
+    return geoInit(dummyInt,dummyList);
+  }
+  else
+  {
+    sc = detStore->regFcn(&IGeoModelSvc::geoInit,
+			  geoModel,
+			  &SimpleNoiseToolFromTextFile::geoInit,this);
+    if(sc.isFailure())
+    {
+      report << MSG::ERROR << "Could not register geoInit callback" << endreq;
+      return sc;
+    }
+  }
+  return sc;
+}
+
+StatusCode
+SimpleNoiseToolFromTextFile::geoInit(IOVSVC_CALLBACK_ARGS)
+{
+  MsgStream report(msgSvc(),name());
+  
+  report << MSG::INFO 
+         << "SimpleNoiseToolFromTextFile initialize()" 
+         << endreq;
+  
+  // access calo detector managers
+  m_caloDDM = CaloDetDescrManager::instance(); 
+
+  // access calo identifier helper
+  m_caloIDH = m_caloDDM->getCaloCell_ID();
+  
+  // open noise file
+  std::ifstream fStream(m_cellNoiseFileName.c_str());
+  
+  // exit if the file cannot be opened
+  if (!fStream.is_open()) {
+    report << MSG::ERROR 
+           << "Failed to open file: " << m_cellNoiseFileName 
+           << endreq;
+    return StatusCode::FAILURE;
+  }
+  
+  // read the cell noise from file
+  std::string line;
+  std::istringstream inStream; 
+  while (getline(fStream, line)) {  // read line into line
+    if (line[0] != '#') {  // skip line if starting with #
+      inStream.clear();
+      inStream.str(line);  // use line as input stream
+      int offlineID;       // this is theID.get_compact()
+      float cellNoise;     // noise units are specified by a the jobOption CellNoiseUnits
+      if (inStream >> offlineID >> cellNoise) {  // read in offlineID and cellNoise
+        // sync noise units
+        cellNoise *= m_cellNoiseUnits;
+        // make the Identifier
+        Identifier theID(offlineID);
+        // fill the noise map
+        m_cellNoise[theID] = cellNoise;
+	
+        report << MSG::DEBUG
+               << "Cell " << theID.get_compact()
+               << std::setbase(16) << std::setiosflags(std::ios_base::showbase) 
+               << " : "    << theID.get_compact()  << std::setbase(10)
+               << " : "    << std::setw(17) << m_caloIDH->show_to_string(theID)
+               << " : noise = " << cellNoise/MeV << " MeV" 
+               << endreq;
+      } else {
+        report << MSG::ERROR 
+               << "bad format in cell noise file " << m_cellNoiseFileName 
+               << endreq;
+        return StatusCode::FAILURE;
+      }
+    }
+  }
+  
+  fStream.close();
+  
+  report << MSG::INFO 
+         << "SimpleNoiseToolFromTextFile: cell noise values read from file " 
+         << m_cellNoiseFileName 
+         << endreq;
+  
+  return StatusCode::SUCCESS;
+}
+
+float SimpleNoiseToolFromTextFile::getNoise(const CaloCell* aCell, CalorimeterNoiseType /*type*/)
+{  
+  Identifier tmp=aCell->ID();
+  return getNoiseHelper(tmp);
+}
+
+float SimpleNoiseToolFromTextFile::getNoise(const CaloDetDescrElement* caloDDE, CalorimeterNoiseType /*type*/)
+{
+  Identifier tmp=caloDDE->identify();
+  return getNoiseHelper(tmp);
+}
+
+float SimpleNoiseToolFromTextFile::getNoiseHelper(Identifier id)
+{
+  MsgStream report( msgSvc(), name() );
+  
+  std::map<Identifier, float>::iterator itr = m_cellNoise.find(id);
+  if (itr != m_cellNoise.end()) {
+    // cell is in the map
+    // return the noise
+    return itr->second;
+  } else {
+    // cell not in the map
+    // report this if requested
+    if (m_cellNoiseDefaultWarning) 
+      report << MSG::WARNING 
+             << "SimpleNoiseToolFromTextFile: default noise " 
+             << m_cellNoiseDefault/MeV
+             << " MeV for cell " 
+             << id.get_compact()
+             << std::setbase(16) << std::setiosflags(std::ios_base::showbase) 
+             << " : "    << id.get_compact()  << std::setbase(10)
+             << " : "    << std::setw(17) << m_caloIDH->show_to_string(id)
+             << endreq;
+    // return the default noise value set by jobOption
+    return m_cellNoiseDefault;
+  }
+}
+
+
+/////////////////////////////////////////////////////////////////////////
+
+bool SimpleNoiseToolFromTextFile::isEOverNSigma(const CaloCell* caloCell, float sigmaCut ,
+                     CalorimeterNoiseSymmetryHandling symmetryHandling,
+                     CalorimeterNoiseType type)
+{
+  float noise_cut = fabs(sigmaCut*this->getEffectiveSigma(caloCell,  symmetryHandling,type));
+  float energy = fabs(caloCell->e());
+  return (energy>noise_cut);
+
+}
+
+////////////////////////////////////////////////////////////////////
+
+float SimpleNoiseToolFromTextFile::getRandomisedE(const CaloCell* caloCell , CLHEP::HepRandomEngine* engine, CalorimeterNoiseType type)
+{
+  double rms = this->getNoise(caloCell,type);
+  return RandGauss::shoot(engine,0.,rms);
+}
+
+////////////////////////////////////////////////////////////////////
+
+float SimpleNoiseToolFromTextFile::getEffectiveSigma(const CaloCell* caloCell,
+                     CalorimeterNoiseSymmetryHandling /*symmetryHandling*/,
+                     CalorimeterNoiseType type )
+{
+     // simple implementation for gaussian noise
+     return this->getNoise(caloCell,type);
+}
+
diff --git a/Calorimeter/CaloTools/src/components/CaloTools_entries.cxx b/Calorimeter/CaloTools/src/components/CaloTools_entries.cxx
new file mode 100755
index 0000000000000000000000000000000000000000..9b1b3ce0ff23c4406fd8c6813243a644a5f95536
--- /dev/null
+++ b/Calorimeter/CaloTools/src/components/CaloTools_entries.cxx
@@ -0,0 +1,29 @@
+#include "CaloTools/CaloCompactCellTool.h"
+#include "CaloTools/CaloNoiseTool.h"
+#include "CaloTools/CaloMBAverageTool.h"
+#include "CaloTools/CaloNoiseToolDB.h"
+#include "CaloTools/SimpleNoiseTool.h"
+#include "CaloTools/SimpleNoiseToolFromTextFile.h"
+#include "CaloTools/CaloAffectedTool.h"
+#include "CaloTools/CaloLumiBCIDTool.h"
+#include "GaudiKernel/DeclareFactoryEntries.h"
+
+DECLARE_TOOL_FACTORY( CaloCompactCellTool )
+DECLARE_TOOL_FACTORY( CaloNoiseTool )
+DECLARE_TOOL_FACTORY( CaloMBAverageTool )
+DECLARE_TOOL_FACTORY( CaloNoiseToolDB )
+DECLARE_TOOL_FACTORY( SimpleNoiseTool )
+DECLARE_TOOL_FACTORY( SimpleNoiseToolFromTextFile )
+DECLARE_TOOL_FACTORY( CaloAffectedTool )
+DECLARE_TOOL_FACTORY( CaloLumiBCIDTool )
+
+DECLARE_FACTORY_ENTRIES(CaloTools) {
+    DECLARE_TOOL( CaloCompactCellTool )
+    DECLARE_TOOL( CaloNoiseTool )
+    DECLARE_TOOL( CaloMBAverageTool )
+    DECLARE_TOOL( CaloNoiseToolDB )
+    DECLARE_TOOL( SimpleNoiseTool )
+    DECLARE_TOOL( SimpleNoiseToolFromTextFile )
+    DECLARE_TOOL( CaloAffectedTool )
+    DECLARE_TOOL( CaloLumiBCIDTool )
+}
diff --git a/Calorimeter/CaloTools/src/components/CaloTools_load.cxx b/Calorimeter/CaloTools/src/components/CaloTools_load.cxx
new file mode 100755
index 0000000000000000000000000000000000000000..6daa57fe1e8c1036d6c99f329c5b1de02b0c8101
--- /dev/null
+++ b/Calorimeter/CaloTools/src/components/CaloTools_load.cxx
@@ -0,0 +1,3 @@
+#include "GaudiKernel/LoadFactoryEntries.h"
+
+LOAD_FACTORY_ENTRIES(CaloTools)
diff --git a/Calorimeter/CaloTools/test/CaloCellPackerUtils_test.cxx b/Calorimeter/CaloTools/test/CaloCellPackerUtils_test.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..1b5d3fc4e28f1d81441f9a2a71ae9f4f06a79ded
--- /dev/null
+++ b/Calorimeter/CaloTools/test/CaloCellPackerUtils_test.cxx
@@ -0,0 +1,72 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+// $Id: CaloCellPackerUtils_test.cxx,v 1.1 2007-11-08 18:14:23 ssnyder Exp $
+/**
+ * @file  CaloCellPackerUtils_test.cxx
+ * @author scott snyder <snyder@bnl.gov>
+ * @date Nov, 2007
+ * @brief Component test for CaloCellPackerUtils.
+ */
+
+#undef NDEBUG
+
+
+#include "CaloTools/CaloCellPackerUtils.h"
+#include <cassert>
+#include <cmath>
+#include <cstdio>
+#include <cstdlib>
+
+
+void compare_float (float x1, float x2, float thresh=1e-9)
+{
+  float den = std::abs(x1) + std::abs(x2);
+  if (den == 0) den = 1;
+  if (std::abs(x1-x2) / den > thresh) {
+    printf ("Float miscompare: %f %f\n", x1, x2);
+    std::abort();
+  }
+}
+
+
+void test1()
+{
+  CaloCellPackerUtils::Bitfield bf (0x00f0);
+  assert (bf.in (5) == 0x0050);
+  assert (bf.in (0x123) == 0x0030);
+  assert (bf.out (0x1234) == 3);
+
+  int underflow;
+  CaloCellPackerUtils::Floatfield ff (0x00f0, 2, 4);
+  assert (ff.in (2.5) == 0x0040);
+  compare_float (ff.out (0x0040, underflow), 2.5625);
+  assert (underflow == 0);
+  assert (ff.in (0) == 0);
+  compare_float (ff.out (0, underflow), 2);
+  assert (underflow == 1);
+  assert (ff.in (10) == 0x00f0);
+  compare_float (ff.out (0x00f0, underflow), 3.9375);
+  assert (underflow == 0);
+
+  CaloCellPackerUtils::Floatfield2 ff2 (0x00f0, 4);
+  assert (ff2.in (2.5) == 0x00a0);
+  compare_float (ff2.out (0x00a0), 2.625);
+  assert (ff2.in (0) == 0);
+  compare_float (ff2.out (0), 0);
+  assert (ff2.in (10) == 0x00f0);
+  compare_float (ff2.out (0x00f0), 3.875);
+}
+
+
+int main()
+{
+  test1();
+  return 0;
+}
+
+
+// This package builds a component library, so we don't normally
+// link against the library.  So just include this here.
+#include "../src/CaloCellPackerUtils.cxx"
diff --git a/Calorimeter/CaloTools/test/CaloCompactCellTool_test.cxx b/Calorimeter/CaloTools/test/CaloCompactCellTool_test.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..eec816dae89e0133ec13156245f11d5908791bb5
--- /dev/null
+++ b/Calorimeter/CaloTools/test/CaloCompactCellTool_test.cxx
@@ -0,0 +1,1274 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+// $Id: CaloCompactCellTool_test.cxx,v 1.12 2009-03-31 19:04:04 ssnyder Exp $
+/**
+ * @file  CaloCompactCellTool_test.cxx
+ * @author scott snyder <snyder@bnl.gov>
+ * @date Nov, 2007
+ * @brief Component test for CaloCompactCellTool.
+ */
+
+#undef NDEBUG
+
+#include "CaloTools/CaloCompactCellTool.h"
+#include "CaloTools/CaloCellPacker_400_500.h"
+#include "CaloTriggerTool/ICaloSuperCellIDTool.h"
+#include "CaloEvent/CaloCellContainer.h"
+#include "CaloEvent/CaloCell.h"
+#include "TileEvent/TileCell.h"
+#include "LArRecEvent/LArCell.h"
+#include "CaloDetDescr/CaloDetectorElements.h"
+#include "CaloDetDescr/CaloDetDescriptor.h"
+#include "CaloDetDescr/CaloDetDescrManager.h"
+#include "CaloIdentifier/CaloCell_ID.h"
+#include "CaloIdentifier/CaloCell_SuperCell_ID.h"
+#include "CaloIdentifier/LArEM_ID.h"
+#include "CaloIdentifier/LArHEC_ID.h"
+#include "CaloIdentifier/LArFCAL_ID.h"
+#include "CaloIdentifier/LArMiniFCAL_ID.h"
+#include "CaloIdentifier/TileID.h"
+#include "CaloIdentifier/CaloIdManager.h"
+#include "StoreGate/StoreGateSvc.h"
+#include "AthAllocators/Arena.h"
+#include "AthAllocators/ArenaHeaderGaudiClear.h"
+#include "IdDictParser/IdDictParser.h"
+#include "GaudiKernel/Bootstrap.h"
+#include "TestTools/initGaudi.h"
+#include "AthenaKernel/errorcheck.h"
+#include "boost/foreach.hpp"
+#include <vector>
+#include <map>
+#include <algorithm>
+#include <sstream>
+#include <iostream>
+#include <cmath>
+#include <sys/resource.h>
+#include <sys/time.h>
+
+using CLHEP::MeV;
+using CLHEP::GeV;
+using CLHEP::TeV;
+
+
+typedef long double efloat_t;
+
+
+SG::Arena* arena = 0;
+
+CaloDetDescrManager* g_mgr = 0;
+IToolSvc* g_toolsvc = 0;
+ISvcLocator* g_svcloc = 0;
+
+
+#undef CHECK
+#define CHECK(s) do { if (!(s).isSuccess()) {printf("error: %s\n", #s);exit(1);}} while(0)
+
+
+// Dufus-quality RNG, using LCG.  Constants from numerical recipies.
+// I don't particularly care about RNG quality here, just about
+// getting something that's reproducible.
+
+#include <stdint.h>
+uint32_t seed = 1;
+uint32_t rngmax = static_cast<uint32_t> (-1);
+uint32_t rng()
+{
+  seed = (1664525*seed + 1013904223);
+  return seed;
+}
+
+efloat_t randf (float rmax)
+{
+  return static_cast<efloat_t>(rng()) / rngmax * rmax;
+}
+int randi (int rmax)
+{
+  return static_cast<int> (randf(rmax));
+}
+
+
+
+
+CaloCell_ID* make_helper ()
+{
+  TileID*     tile_id = new TileID;
+  LArEM_ID*   em_id   = new LArEM_ID;
+  LArHEC_ID*  hec_id  = new LArHEC_ID;
+  LArFCAL_ID* fcal_id = new LArFCAL_ID;
+  LArMiniFCAL_ID* minifcal_id = new LArMiniFCAL_ID;
+
+  IdDictParser* parser = new IdDictParser;
+  parser->register_external_entity ("LArCalorimeter",
+                                    "IdDictLArCalorimeter.xml");
+  IdDictMgr& idd = parser->parse ("IdDictParser/ATLAS_IDS.xml");
+  em_id->set_do_neighbours (false);
+  em_id->initialize_from_dictionary (idd);
+  hec_id->initialize_from_dictionary (idd);
+  fcal_id->set_do_neighbours (false);
+  fcal_id->initialize_from_dictionary (idd);
+  minifcal_id->set_do_neighbours (false);
+  minifcal_id->initialize_from_dictionary (idd);
+  tile_id->set_do_neighbours (false);
+  tile_id->initialize_from_dictionary (idd);
+
+  CaloCell_ID* calo_helper = new CaloCell_ID (em_id,
+                                              hec_id,
+                                              fcal_id,
+                                              minifcal_id,
+                                              tile_id);
+  calo_helper->initialize_from_dictionary (idd);
+  return calo_helper;
+}
+
+
+CaloCell_SuperCell_ID* make_sc_helper ()
+{
+  Tile_SuperCell_ID*    tile_id = new Tile_SuperCell_ID;
+  LArEM_SuperCell_ID*   em_id   = new LArEM_SuperCell_ID;
+  LArHEC_SuperCell_ID*  hec_id  = new LArHEC_SuperCell_ID;
+  LArFCAL_SuperCell_ID* fcal_id = new LArFCAL_SuperCell_ID;
+  LArMiniFCAL_ID*       minifcal_id = new LArMiniFCAL_ID;
+
+  IdDictParser* parser = new IdDictParser;
+  parser->register_external_entity ("LArCalorimeter",
+                                    "IdDictLArCalorimeter.xml");
+  IdDictMgr& idd = parser->parse ("IdDictParser/ATLAS_IDS.xml");
+  em_id->set_do_neighbours (false);
+  em_id->initialize_from_dictionary (idd);
+  hec_id->initialize_from_dictionary (idd);
+  fcal_id->set_do_neighbours (false);
+  fcal_id->initialize_from_dictionary (idd);
+  minifcal_id->set_do_neighbours (false);
+  minifcal_id->initialize_from_dictionary (idd);
+  tile_id->set_do_neighbours (false);
+  tile_id->initialize_from_dictionary (idd);
+
+  CaloCell_SuperCell_ID* calo_helper =
+    new CaloCell_SuperCell_ID (em_id,
+                               hec_id,
+                               fcal_id,
+                               minifcal_id,
+                               tile_id);
+  calo_helper->initialize_from_dictionary (idd);
+  return calo_helper;
+}
+
+
+CaloIdManager* make_idmgr (const CaloCell_ID* cellhelper,
+                           const CaloCell_SuperCell_ID* schelper)
+{
+  CaloIdManager* idmgr = new CaloIdManager;
+  idmgr->set_helper (cellhelper);
+  idmgr->set_helper (cellhelper->em_idHelper());
+  idmgr->set_helper (cellhelper->hec_idHelper());
+  idmgr->set_helper (cellhelper->fcal_idHelper());
+  idmgr->set_helper (cellhelper->tile_idHelper());
+
+  idmgr->set_helper (schelper);
+  idmgr->set_helper (schelper->em_idHelper());
+  idmgr->set_helper (schelper->hec_idHelper());
+  idmgr->set_helper (schelper->fcal_idHelper());
+  idmgr->set_helper (schelper->tile_idHelper());
+
+  return idmgr;
+}
+
+
+typedef std::map<Identifier, CaloDetDescriptor*> ddmap_t;
+ddmap_t ddmap_ol;
+ddmap_t ddmap_sc;
+CaloDetDescriptor* find_dd (int hashid,
+                            const CaloDetDescrManager_Base* mgr)
+{
+  const CaloCell_Base_ID* helper = mgr->getCaloCell_ID();
+  Identifier id = helper->cell_id (hashid);
+  Identifier reg_id;
+  int subcalo = helper->sub_calo (id);
+  if (subcalo == CaloCell_ID::TILE) {
+    int section = helper->section (id);
+    int side = helper->side (id);
+    reg_id = helper->region_id (subcalo, section, side, 0);
+  }
+  else {
+    int sampling = helper->sampling (id);
+    int posneg = helper->pos_neg (id);
+    int region = helper->region (id);
+    reg_id = helper->region_id (subcalo, posneg, sampling, region);
+  }
+  ddmap_t& ddmap = helper->is_supercell(id) ? ddmap_sc : ddmap_ol;
+  CaloDetDescriptor* dd = ddmap[reg_id];
+  if (!dd) {
+    dd = new CaloDetDescriptor (reg_id, helper->tile_idHelper(), helper);
+    ddmap[reg_id] = dd;
+  }
+  return dd;
+}
+
+
+CaloCell* make_cell (int hashid,
+                     CaloDetDescrManager* mgr)
+{
+  CaloDetDescriptor* descr = find_dd (hashid, mgr);
+  CaloDetDescrElement* dde = new DummyDetDescrElement (hashid -
+                                                        descr->caloCellMin(),
+                                                       0,
+                                                       0,
+                                                       descr);
+  mgr->add (dde);
+
+  if (descr->is_tile()) {
+    int gain1;
+    efloat_t ene1;
+    switch (randi(2)) {
+    case 0:
+      gain1 = TileID::LOWGAIN;
+      ene1 = randf(3200*GeV)-20*GeV;
+      break;
+    case 1:
+    default:
+      gain1 = TileID::HIGHGAIN;
+      ene1 = randf(50*GeV)-20*GeV;
+      break;
+    }
+    int qbit1 = randi(32);
+    int qual1 = ((qbit1 & TileCell::MASK_BADCH) != 0) ? 255 : randi(256);
+    int time1 = 0;
+    if (randi(2)>0) {
+      qbit1 |= TileCell::KEEP_TIME;
+      time1 = (randi(2000)-1000);
+    }  
+
+    int gain2;
+    efloat_t ene2;
+    switch (randi(3)) {
+    case 0:
+      gain2 = TileID::LOWGAIN;
+      ene2 = randf(3200*GeV)-20*GeV;
+      break;
+    case 1:
+      gain2 = TileID::HIGHGAIN;
+      ene2 = randf(50*GeV)-20*GeV;
+      break;
+    default:
+      gain2 = CaloGain::INVALIDGAIN;
+      ene2 = 0;
+      break;
+    }
+    int qbit2 = randi(32);
+    int qual2 = ((qbit2 & TileCell::MASK_BADCH) != 0) ? 255 : randi(256);
+    int time2 = 0;
+    if (randi(2)>0) {
+      qbit2 |= TileCell::KEEP_TIME;
+      time2 = (randi(2000)-1000);
+    }
+    
+    if (((gain1 == TileID::LOWGAIN && gain2 == TileID::HIGHGAIN) ||
+         (gain1 == TileID::HIGHGAIN && gain2 == TileID::LOWGAIN)) &&
+        ene1 + ene2 > 400*GeV)
+    {
+      float scale = 399*GeV / (ene1 + ene2);
+      ene1 *= scale;
+      ene2 *= scale;
+    }
+
+    if (gain1 == TileID::HIGHGAIN && gain2 == TileID::HIGHGAIN &&
+        ene1 + ene2 > 50*GeV)
+    {
+      efloat_t scale = 49*GeV / (ene1 + ene2);
+      ene1 *= scale;
+      ene2 *= scale;
+    }
+
+    if ( ((qbit1 & qbit2) & TileCell::MASK_BADCH) != 0 ) { // both channels masked
+      time1 = time2 = 0;
+      ene1  = ene2  = 0.512932 * MeV;
+      gain1 = gain2 = TileID::LOWGAIN;
+    }
+    
+    return new TileCell (dde,
+                         ene1, ene2,
+                         time1, time2,
+                         qual1, qual2,
+                         qbit1, qbit2,
+                         gain1, gain2);
+  }
+  else {
+    CaloGain::CaloGain gain = CaloGain::INVALIDGAIN;
+    efloat_t energy = 0;
+    int quality = randi(65536);
+    int provenance = randi(0x2000);
+    float time = 0;
+    // Good quality?  Take 10% to be bad.
+    if (randi(10) != 0) {
+      provenance |= 0x2000;
+      switch (randi(3)) {
+      case 0:
+        gain = CaloGain::LARHIGHGAIN;
+        energy = randf(60*GeV) - 16*GeV;
+        break;
+      case 1:
+        gain = CaloGain::LARMEDIUMGAIN;
+        energy = randf(360*GeV) + 40*GeV;
+        break;
+      case 2:
+      default:
+        gain = CaloGain::LARLOWGAIN;
+        energy = randf(3000*GeV) + 40*GeV;
+        break;
+      }
+      time = randf(2000) - 1000;
+    }
+    return new CaloCell (dde, energy, time, quality, provenance, gain);
+  }
+}
+
+
+std::vector<CaloCell*> make_cells (CaloDetDescrManager* mgr)
+{
+  size_t hashmax = mgr->getCaloCell_ID()->calo_cell_hash_max(); 
+ std::vector<CaloCell*> v;
+  v.reserve (hashmax);
+  for (size_t i = 0; i < hashmax; i++)
+    v.push_back (make_cell (i, mgr));
+
+  // Give a few cells off-scale energies, to test saturation.
+  IdentifierHash tilemin, tilemax;
+  mgr->getCaloCell_ID()->calo_cell_hash_range (CaloCell_ID::TILE,
+                                               tilemin, tilemax);
+  assert (tilemax <= v.size());
+  assert (tilemin <= tilemax);
+  for (size_t i = 0; i < 10; i++) {
+    CaloCell* cell = v[randi(tilemin)];
+    assert ( ! cell->caloDDE()->is_tile());
+    cell->setGain ((i&2) ? CaloGain::LARLOWGAIN : CaloGain::LARHIGHGAIN);
+    cell->setEnergy ((((int)i&1)*2-1) * 4000*GeV);
+  }
+  for (size_t i = 0; i < 8; i++) {
+    TileCell* cell =
+      dynamic_cast<TileCell*>(v[tilemin + randi(tilemax-tilemin)]);
+    assert (cell != 0);
+    assert (cell->caloDDE()->is_tile());
+    int pmt = (i&2)>>1;
+    cell->addEnergy ((((int)i&1)*2-1) * 8000*GeV, pmt,
+                     (i&4) ? TileID::LOWGAIN : TileID::HIGHGAIN);
+  }
+  return v;
+}
+
+
+void fill_cells_rand (int n,
+                      const std::vector<CaloCell*>& cells,
+                      CaloCellContainer& cont)
+{
+  std::vector<CaloCell*> tmp = cells;
+  std::random_shuffle (tmp.begin(), tmp.end(), randi);
+  for (int i = 0; i < n; i++)
+    cont.push_back (tmp[i]);
+}
+
+
+void fill_cells_clustery (int n,
+                          const std::vector<CaloCell*>& cells,
+                          CaloCellContainer& cont)
+{
+  std::vector<CaloCell*> tmp = cells;
+  while (n > 0) {
+    int idx = randi (tmp.size());
+    int nmax = std::min ((unsigned int)n, (unsigned int)tmp.size() - idx);
+    assert (nmax > 0);
+    int thisn = randi (nmax) + 1;
+    for (int i = idx; i < idx + thisn; i++)
+      cont.push_back (tmp[i]);
+    tmp.erase (tmp.begin()+idx, tmp.begin()+idx+thisn);
+    n -= thisn;
+  }
+}
+
+
+CaloCellContainer* fill_cells (int n,
+                               const std::vector<CaloCell*>& cells,
+                               bool clustery,
+                               bool ordered)
+{
+  CaloCellContainer* cont = new CaloCellContainer (SG::VIEW_ELEMENTS);
+  if (clustery)
+    fill_cells_clustery (n, cells, *cont);
+  else
+    fill_cells_rand (n, cells, *cont);
+
+  if (ordered) {
+    cont->order();
+    cont->updateCaloIterators();
+  }
+  return cont;
+}
+
+
+CaloCellContainer* fill_supercells (const std::vector<CaloCell*>& cells)
+{
+  CaloCellContainer* cont = new CaloCellContainer;
+
+  ICaloSuperCellIDTool* sctool = 0;
+  CHECK( g_toolsvc->retrieveTool ("CaloSuperCellIDTool", sctool) );
+
+  StoreGateSvc* detstore = 0;
+  CHECK( g_svcloc->service ("DetectorStore", detstore) );
+  const CaloIdManager* idmgr = 0;
+  CHECK( detstore->retrieve (idmgr, "CaloIdManager") );
+  const CaloCell_SuperCell_ID* schelper =
+    idmgr->getCaloCell_SuperCell_ID();
+
+  CaloSuperCellDetDescrManager* scmgr = 0;
+  CHECK( detstore->retrieve (scmgr, "CaloSuperCellMgr") );
+
+  std::vector<CaloCell*> scells (schelper->calo_cell_hash_max());
+  BOOST_FOREACH (const CaloCell* cell, cells) {
+    Identifier scid = sctool->offlineToSuperCellID (cell->ID());
+    if (!scid.is_valid()) continue;
+    IdentifierHash hash = schelper->calo_cell_hash (scid);
+    assert (hash < scells.size());
+    if (scells[hash] == 0) {
+      const CaloDetDescrElement* dde = scmgr->get_element (hash);
+      if (!dde) {
+        CaloDetDescriptor* descr = find_dd (hash, scmgr);
+        CaloDetDescrElement* dde_nc =
+          new DummyDetDescrElement (hash -
+                                      descr->caloCellMin(),
+                                    0,
+                                    0,
+                                    descr);
+        scmgr->add (dde_nc);
+        dde = dde_nc;
+      }
+      CaloGain::CaloGain gain = cell->gain();
+      switch (gain)
+      {
+      case CaloGain::TILELOWLOW:
+      case CaloGain::TILELOWHIGH:
+      case CaloGain::TILEONELOW:
+        gain = CaloGain::LARLOWGAIN;
+        break;
+      case CaloGain::TILEHIGHHIGH:
+      case CaloGain::TILEHIGHLOW:
+      case CaloGain::TILEONEHIGH:
+        gain = CaloGain::LARHIGHGAIN;
+        break;
+      default:
+        break;
+      }
+      scells[hash] = new CaloCell (dde,
+                                   cell->energy(),
+                                   cell->provenance() & 0x2000 ? 
+                                     cell->time() : 0,
+                                   cell->quality(),
+                                   cell->provenance() & 0x3fff,
+                                   gain);
+    }
+    else if (scells[hash]->gain() != CaloGain::INVALIDGAIN) {
+      scells[hash]->setEnergy (scells[hash]->energy() + cell->energy());
+    }
+  }
+
+  BOOST_FOREACH (CaloCell* cell, scells) {
+    cont->push_back (cell);
+  }
+
+  cont->order();
+  cont->updateCaloIterators();
+  return cont;
+}
+
+
+void compare_float (float x1, float x2,
+                    const std::string& what,
+                    float thresh=0.01)
+{
+  float den = std::abs(x1) + std::abs(x2);
+  if (den == 0) den = 1;
+  if (den < 1e-3) den = 1e-3;
+  if (std::abs(x1-x2) / den > thresh) {
+    printf ("Float %s miscompare: %f %f\n", what.c_str(), x1, x2);
+    std::abort();
+  }
+}
+
+
+void compare_lar_energy (int hash, float e1, float e2, float prec)
+{
+  std::ostringstream ss;
+  ss << "energy " << hash;
+  if (e1 > 3.2*TeV)
+    compare_float (3.2*TeV, e2, ss.str(), prec);
+  else if (e1 < -3.2*TeV)
+    compare_float (-3.2*TeV, e2, ss.str(), prec);
+  else
+    compare_float (e1, e2, ss.str(), prec);
+}
+
+
+float tile_ele (const TileCell* c, int pmt)
+{
+  if (pmt)
+    return c->ene2();
+  return c->ene1();
+}
+
+
+int tile_gain (const TileCell* c, int pmt)
+{
+  if (pmt)
+    return c->gain2();
+  return c->gain1();
+}
+
+
+void compare_tile_energy (const TileCell* c1, const TileCell* c2,
+                          int pmt,
+                          const char* what)
+{
+  float max = 3.2*TeV;
+  if (tile_gain (c2, pmt) == TileID::HIGHGAIN)
+    max = 50*GeV;
+
+  float prec = 0.01;
+  if (fabs (c2->ene1() - c2->ene2()) > 30*GeV) prec = 0.02;
+
+  float e1 = tile_ele (c1, pmt);
+  float e2 = tile_ele (c2, pmt);
+
+  if (e1 > max)
+    compare_float (max, e2, what, prec);
+  else if (e1 < -max)
+    compare_float (-max, e2, what, prec);
+  else
+    compare_float (e1, e2, what, prec);
+}
+
+
+void compare_lar (const CaloCell* cell1, const CaloCell* cell2,
+                  int version)
+{
+  const CaloDetDescrElement* dde = cell1->caloDDE();
+  
+  float prec = 0.01;
+  if (fabs(cell1->energy()) < 0.1)
+    prec = 0.1;
+  else if (fabs(cell1->energy()) < 10) {
+    if (dde->getSubCalo() == CaloCell_ID::LARHEC)
+      prec = 0.02;
+    else
+      prec = 0.015;
+  }
+
+  if (dde->getSubCalo() == CaloCell_ID::TILE)
+    prec = 0.03;  // supercell
+
+  compare_lar_energy (dde->calo_hash(),
+                      cell1->energy(), cell2->energy(), prec);
+
+  std::ostringstream twhat;
+  twhat << "time " << dde->calo_hash();
+  compare_float (cell1->time(), cell2->time(), twhat.str());
+  assert (cell1->gain() == cell2->gain());
+
+  // Test quality flag.
+  assert ((cell1->provenance()&0x2000) == (cell2->provenance()&0x2000));
+
+  if (version <= ICaloCompactCellTool::VERSION_400) {
+    // Quality not saved.
+    assert (cell2->quality() == 0);
+  }
+  else {
+    assert (cell1->provenance() == cell2->provenance());
+
+    // Quality saved if good flag is set.
+    if ((cell1->provenance() & 0x2000) != 0) {
+      assert (cell1->quality() == cell2->quality());
+    }
+    else {
+      assert (cell2->quality() == 0);
+    }
+  }
+}
+
+
+void compare_tile (const TileCell* cell1, const TileCell* cell2,
+                   int version)
+{
+  assert (cell1->gain1() == cell2->gain1());
+  assert (cell1->gain2() == cell2->gain2());
+  compare_tile_energy (cell1, cell2, 0, "ene1");
+  compare_float (cell1->time1(), cell2->time1(), "time1", 0.1);
+
+  assert ((cell1->qbit1() >= TileCell::KEEP_TIME) == 
+          (cell2->qbit1() >= TileCell::KEEP_TIME));
+
+  if (version < ICaloCompactCellTool::VERSION_502 ) {
+    assert ((cell2->qbit1() & 0x1F) == 0); // Provenance not saved.
+  }
+  else {
+    assert ((cell1->qbit1() & 0x1F) == (cell2->qbit1() & 0x1F));
+  }
+
+  if (version < ICaloCompactCellTool::VERSION_502 ) {
+    assert (cell2->qual1() == 0); // Quality not saved.
+  } else {
+      if (cell1->qbit1() < TileCell::KEEP_TIME && 
+          (cell1->qbit2() < TileCell::KEEP_TIME || cell1->gain2() == CaloGain::INVALIDGAIN)) {
+      if ((cell1->qbit1() & TileCell::MASK_BADCH) != 0)
+        assert (cell2->qual1() == 255); // Quality is bad.
+      else 
+        assert (cell2->qual1() == 0); // Quality is good.
+    } else {
+      assert (cell1->qual1() == cell2->qual1());
+    }
+  }
+
+  if (cell1->gain2() != CaloGain::INVALIDGAIN) {
+    compare_tile_energy (cell1, cell2, 1, "ene2");
+    compare_float (cell1->time2(), cell2->time2(), "time2", 0.1);
+    assert ((cell1->qbit2() >= TileCell::KEEP_TIME) == 
+            (cell2->qbit2() >= TileCell::KEEP_TIME));
+
+    if (version < ICaloCompactCellTool::VERSION_502 ) {
+      assert ((cell2->qbit2() & 0x1F) == 0); // Provenance not saved.
+    }
+    else {
+      assert ((cell1->qbit2() & 0x1F) == (cell2->qbit2() & 0x1F));
+    }
+
+    if (version < ICaloCompactCellTool::VERSION_502 ) {
+      assert (cell2->qual2() == 0); // Quality not saved.
+    } else {
+      if (cell1->qbit1() < TileCell::KEEP_TIME && cell1->qbit2() < TileCell::KEEP_TIME) {
+        if ((cell1->qbit2() & TileCell::MASK_BADCH) != 0)
+          assert (cell2->qual2() == 255); // Quality is bad.
+        else 
+          assert (cell2->qual2() == 0); // Quality is good.
+      } else {
+        assert (cell1->qual2() == cell2->qual2());
+      }
+    }
+  }
+}
+
+
+void dump_packed (const CaloCompactCellContainer& packed)
+{
+  const std::vector<CaloCompactCellContainer::value_type>& data =
+    packed.getData();
+
+  int ccount = 0;
+  for (size_t i = 0; i < data.size(); i++) {
+    if (ccount == 0)
+      printf ("\n%08x ", (unsigned int)i*4);
+    printf (" %08x", data[i]);
+    ++ccount;
+    if (ccount == 4) ccount = 0;
+  }
+  printf ("\n");
+}
+
+
+void dump_e (double e)
+{
+  if (e > 1000*GeV)
+    e = round (e / 20) * 20;
+  else
+    e = round (e / 10) * 10;
+  printf ("%8.0f ", e);
+}
+
+
+void dump_cells (const CaloCellContainer& cont)
+{
+  for (size_t i = 0; i < cont.size(); i++) {
+    const CaloCell* cell = cont[i];
+    printf ("%8d ", (unsigned int)cell->caloDDE()->calo_hash());
+    if (const TileCell* tcell = dynamic_cast<const TileCell*> (cell)) {
+      dump_e (tcell->ene1());
+      dump_e (tcell->ene2());
+      printf ("%8.2f %8.2f %d %d 0x%02x 0x%02x %d %d\n",
+              tcell->time1(), tcell->time2(),
+              tcell->qual1(), tcell->qual2(),
+              tcell->qbit1(), tcell->qbit2(),
+              (int)tcell->gain1(), (int)tcell->gain2());
+    }
+    else {
+      printf ("%8.1f %8.2f %d %d %d\n",
+              cell->energy(), cell->time(),
+              cell->quality(), cell->provenance(),
+              (int)cell->gain());
+    }
+  }
+}
+
+
+void compare_containers (const CaloCellContainer* cont,
+                         const CaloCellContainer* cont2,
+                         bool ordered,
+                         int version)
+{
+  assert (cont->size() == cont2->size());
+
+  CaloCell_ID::SUBCALO subcalos[4] = {CaloCell_ID::LAREM,
+                                      CaloCell_ID::LARHEC,
+                                      CaloCell_ID::LARFCAL,
+                                      CaloCell_ID::TILE};
+  for (int i = 0; i < 4; i++) {
+    assert (cont->hasCalo(subcalos[i]) ==
+            cont2->hasCalo(subcalos[i]));
+    if (ordered) {
+      assert (cont->indexFirstCellCalo(subcalos[i]) ==
+              cont2->indexFirstCellCalo(subcalos[i]));
+      assert (cont->indexLastCellCalo(subcalos[i]) ==
+              cont2->indexLastCellCalo(subcalos[i]));
+      assert (cont->nCellsCalo(subcalos[i]) ==
+              cont2->nCellsCalo(subcalos[i]));
+    }
+  }
+
+  for (size_t i = 0; i < cont->size(); i++) {
+    const CaloCell* cell1 = (*cont)[i];
+    const CaloCell* cell2 = (*cont2)[i];
+    assert (cell1->caloDDE() == cell2->caloDDE());
+    if (dynamic_cast<const LArCell*> (cell2) != 0) {
+      assert (dynamic_cast<const TileCell*> (cell1) == 0);
+      compare_lar (cell1, cell2, version);
+    }
+    else if (const TileCell* tcell2 =
+             dynamic_cast<const TileCell*> (cell2)) {
+      const TileCell* tcell1 = dynamic_cast<const TileCell*> (cell1);
+      assert (tcell1 != 0);
+      compare_tile (tcell1, tcell2, version);
+    }
+    else
+      std::abort();
+  }
+}
+
+
+void test_one (int n,
+               int version,
+               const std::vector<CaloCell*>& cells,
+               ICaloCompactCellTool* tool,
+               bool clustery = false,
+               bool dump = false,
+               bool ordered = true)
+{
+  printf ("*** test %d %d %d %d\n", version, n, clustery, ordered);
+  CaloCellContainer* cont = fill_cells (n, cells, clustery, ordered);
+
+  if (dump)
+    dump_cells (*cont);
+
+  CaloCompactCellContainer ccc;
+  tool->getPersistent (*cont, &ccc, version);
+
+  if (dump)
+    dump_packed (ccc);
+
+  CaloCellContainer* cont2 = new CaloCellContainer (SG::VIEW_ELEMENTS);
+  SG::Arena::Push push (*arena);
+  tool->getTransient (ccc, cont2);
+
+  if (dump)
+    dump_cells (*cont2);
+
+  compare_containers (cont, cont2, ordered, version);
+
+  delete cont;
+  delete cont2;
+
+  arena->reset();
+}
+
+
+void test_supercells (int version,
+                      const std::vector<CaloCell*>& cells,
+                      ICaloCompactCellTool* tool)
+{
+  printf ("*** test SC %d\n", version);
+  CaloCellContainer* cont = fill_supercells (cells);
+  //dump_cells (*cont);
+
+  CaloCompactCellContainer ccc;
+  tool->getPersistent (*cont, &ccc, version);
+
+  CaloCellContainer* cont2 = new CaloCellContainer (SG::VIEW_ELEMENTS);
+  SG::Arena::Push push (*arena);
+  tool->getTransient (ccc, cont2);
+  //dump_cells (*cont2);
+
+  compare_containers (cont, cont2, true, version);
+
+  delete cont;
+  delete cont2;
+  arena->reset();
+}
+
+
+//============================================================================
+
+
+struct CaloCellPacker_400_500_test
+{
+  typedef CaloCellPacker_400_500::header500 header_t;
+  typedef CaloCompactCellContainer::value_type value_type;
+  typedef std::vector<value_type> vec_t;
+
+  static
+  void test_fin (const CaloCompactCellContainer& ccc,
+                 ICaloCompactCellTool* tool);
+
+  static
+  void test_err1 (const CaloCompactCellContainer& ccc,
+                  ICaloCompactCellTool* tool);
+  static
+  void test_err2 (const CaloCompactCellContainer& ccc,
+                  ICaloCompactCellTool* tool);
+
+  static
+  void test_err3 (const CaloCompactCellContainer& ccc,
+                  ICaloCompactCellTool* tool);
+
+  static
+  void test_err4 (const CaloCompactCellContainer& ccc,
+                  ICaloCompactCellTool* tool);
+
+  static
+  void test_err5 (const CaloCompactCellContainer& ccc,
+                  ICaloCompactCellTool* tool);
+
+  static
+  void test_err6 (const CaloCompactCellContainer& ccc,
+                  ICaloCompactCellTool* tool);
+
+  static
+  void test_err7 (const CaloCompactCellContainer& ccc,
+                  ICaloCompactCellTool* tool);
+
+  static
+  void test_err8 (const CaloCompactCellContainer& ccc,
+                  ICaloCompactCellTool* tool);
+
+  static
+  void test_err9 (const CaloCompactCellContainer& ccc,
+                  ICaloCompactCellTool* tool);
+
+  static
+  void test_err10 (const CaloCompactCellContainer& ccc,
+                   ICaloCompactCellTool* tool);
+
+  static
+  void test_err11 (const CaloCompactCellContainer& ccc,
+                   ICaloCompactCellTool* tool);
+};
+
+
+void
+CaloCellPacker_400_500_test::test_fin (const CaloCompactCellContainer&
+                                       ccc2,
+                                       ICaloCompactCellTool* tool)
+{
+  CaloCellContainer cont2 (SG::VIEW_ELEMENTS);
+  SG::Arena::Push push (*arena);
+  tool->getTransient (ccc2, &cont2);
+}
+
+
+void
+CaloCellPacker_400_500_test::test_err1 (const CaloCompactCellContainer&
+                                        ccc,
+                                        ICaloCompactCellTool* tool)
+{
+  printf (" --- err1\n");
+  CaloCompactCellContainer ccc2 = ccc;
+  vec_t& vec = const_cast<vec_t&>(ccc2.getData());
+  header_t& header = *reinterpret_cast<header_t*> (&*vec.begin());
+  header.m_ncells_larhec = 1000000;
+  test_fin (ccc2, tool);
+}
+
+
+void
+CaloCellPacker_400_500_test::test_err2 (const CaloCompactCellContainer& 
+                                        ccc,
+                                        ICaloCompactCellTool* tool)
+{
+  printf (" --- err2\n");
+  CaloCompactCellContainer ccc2 = ccc;
+  vec_t& vec = const_cast<vec_t&>(ccc2.getData());
+  header_t& header = *reinterpret_cast<header_t*> (&*vec.begin());
+  header.m_seq_larem = 1000000;
+  test_fin (ccc2, tool);
+}
+
+
+void
+CaloCellPacker_400_500_test::test_err3 (const CaloCompactCellContainer& 
+                                        ccc,
+                                        ICaloCompactCellTool* tool)
+{
+  printf (" --- err3\n");
+  CaloCompactCellContainer ccc2 = ccc;
+  vec_t& vec = const_cast<vec_t&>(ccc2.getData());
+  header_t& header = *reinterpret_cast<header_t*> (&*vec.begin());
+  header.m_seq_larem = 10000;
+  test_fin (ccc2, tool);
+}
+
+
+void
+CaloCellPacker_400_500_test::test_err4 (const CaloCompactCellContainer&
+                                        ccc,
+                                        ICaloCompactCellTool* tool)
+{
+  printf (" --- err4\n");
+  CaloCompactCellContainer ccc2 = ccc;
+  vec_t& vec = const_cast<vec_t&>(ccc2.getData());
+  vec.resize (vec.size() + 100);
+  test_fin (ccc2, tool);
+}
+
+
+void
+CaloCellPacker_400_500_test::test_err5 (const CaloCompactCellContainer& 
+                                        ccc,
+                                        ICaloCompactCellTool* tool)
+{
+  printf (" --- err5\n");
+  CaloCompactCellContainer ccc2 = ccc;
+  vec_t& vec = const_cast<vec_t&>(ccc2.getData());
+  vec.resize (vec.size() - 100);
+  test_fin (ccc2, tool);
+}
+
+
+void
+CaloCellPacker_400_500_test::test_err6 (const CaloCompactCellContainer& 
+                                        ccc,
+                                        ICaloCompactCellTool* tool)
+{
+  printf (" --- err6\n");
+  CaloCompactCellContainer ccc2 = ccc;
+  vec_t& vec = const_cast<vec_t&>(ccc2.getData());
+  vec.resize (vec.size() - 100);
+  header_t& header = *reinterpret_cast<header_t*> (&*vec.begin());
+  value_type val = vec[header.m_length];
+  vec[header.m_length] = (10000<<2) | (val & 0xffff0003);
+  test_fin (ccc2, tool);
+}
+
+
+void
+CaloCellPacker_400_500_test::test_err7 (const CaloCompactCellContainer& 
+                                        ccc,
+                                        ICaloCompactCellTool* tool)
+{
+  printf (" --- err7\n");
+  CaloCompactCellContainer ccc2 = ccc;
+  vec_t& vec = const_cast<vec_t&>(ccc2.getData());
+  vec.resize (vec.size() - 100);
+  header_t& header = *reinterpret_cast<header_t*> (&*vec.begin());
+  value_type val = vec[header.m_length];
+  int newhash = 200000;
+  vec[header.m_length] = (newhash>>16) | ((newhash&0xffff)<<16) | (val&0xfffc);
+  test_fin (ccc2, tool);
+}
+
+
+void
+CaloCellPacker_400_500_test::test_err8 (const CaloCompactCellContainer& 
+                                        ccc,
+                                        ICaloCompactCellTool* tool)
+{
+  printf (" --- err8\n");
+  CaloCompactCellContainer ccc2 = ccc;
+  vec_t& vec = const_cast<vec_t&>(ccc2.getData());
+  header_t* header = reinterpret_cast<header_t*> (&*vec.begin());
+  vec.insert (vec.begin() + header->m_length, 10, 0);
+  header = reinterpret_cast<header_t*> (&*vec.begin());
+  header->m_length += 10;
+  test_fin (ccc2, tool);
+}
+
+
+// Deletes the last word of the header.
+void
+CaloCellPacker_400_500_test::test_err9 (const CaloCompactCellContainer& 
+                                        ccc,
+                                        ICaloCompactCellTool* tool)
+{
+  printf (" --- err9\n");
+  CaloCompactCellContainer ccc2 = ccc;
+  vec_t& vec = const_cast<vec_t&>(ccc2.getData());
+  header_t* header = reinterpret_cast<header_t*> (&*vec.begin());
+  vec.erase (vec.begin() + header->m_length-1);
+  header = reinterpret_cast<header_t*> (&*vec.begin());
+  --header->m_length;
+  test_fin (ccc2, tool);
+}
+
+
+void
+CaloCellPacker_400_500_test::test_err10(const CaloCompactCellContainer&
+                                        ccc,
+                                        ICaloCompactCellTool* tool)
+{
+  printf (" --- err10\n");
+  CaloCompactCellContainer ccc2 = ccc;
+  vec_t& vec = const_cast<vec_t&>(ccc2.getData());
+  header_t& header = *reinterpret_cast<header_t*> (&*vec.begin());
+  value_type val = vec[header.m_length];
+  int nseq = (val & 0xfffc) >> 2;
+  int hash = (val & 3) << 16 | ((val & 0xffff0000)>>16);
+  int target = hash + std::min (10, nseq);
+
+  CaloDetDescrManager::calo_element_const_iterator cbeg =
+    g_mgr->element_begin();
+  CaloDetDescrElement * const & rcbeg = *cbeg;
+  CaloDetDescrElement** beg = const_cast<CaloDetDescrElement**> (&rcbeg);
+  CaloDetDescrElement* dde = beg[target];
+  beg[target] = 0;
+  test_fin (ccc2, tool);
+  beg[target] = dde;
+}
+
+
+void
+CaloCellPacker_400_500_test::test_err11(const CaloCompactCellContainer&
+                                        ccc,
+                                        ICaloCompactCellTool* tool)
+{
+  printf (" --- err11\n");
+  CaloCompactCellContainer ccc2 = ccc;
+  vec_t& vec = const_cast<vec_t&>(ccc2.getData());
+  header_t& header = *reinterpret_cast<header_t*> (&*vec.begin());
+  header.m_lengthProvenance = 9999999;
+  test_fin (ccc2, tool);
+}
+
+
+// Test handling of corrupt data.
+void test_errs (const std::vector<CaloCell*>& cells,
+                ICaloCompactCellTool* tool)
+{
+  printf ("*** test_errs\n");
+  CaloCellContainer* cont = fill_cells (10000, cells, true, true);
+  CaloCompactCellContainer ccc;
+  tool->getPersistent (*cont, &ccc, ICaloCompactCellTool::VERSION_501);
+
+  typedef CaloCellPacker_400_500_test T;
+
+  T::test_err1  (ccc, tool);
+  T::test_err2  (ccc, tool);
+  T::test_err3  (ccc, tool);
+  T::test_err4  (ccc, tool);
+  T::test_err5  (ccc, tool);
+  T::test_err6  (ccc, tool);
+  T::test_err7  (ccc, tool);
+  T::test_err8  (ccc, tool);
+  T::test_err9  (ccc, tool);
+  T::test_err10 (ccc, tool);
+  T::test_err11 (ccc, tool);
+
+  // Unordered
+  printf (" --- err unordered\n");
+  seed = 101;
+  CaloCellContainer* cont2 = fill_cells (10000, cells, true, false);
+  CaloCompactCellContainer ccc2;
+  tool->getPersistent (*cont2, &ccc2, ICaloCompactCellTool::VERSION_500);
+  T::test_fin (ccc2, tool);
+
+  delete cont;
+}
+
+
+//============================================================================
+
+
+std::vector<CaloCell*> init (ICaloCompactCellTool* & tool)
+{
+  ISvcLocator* svcloc;
+  if (!Athena_test::initGaudi("CaloCompactCellTool_test.txt", svcloc)) {
+    std::cerr << "This test can not be run" << std::endl;
+    exit(0);
+  }  
+  g_svcloc = svcloc;
+
+  CaloCell_ID* helper = make_helper ();
+  CaloCell_SuperCell_ID* schelper = make_sc_helper ();
+  CaloIdManager* idmgr = make_idmgr (helper, schelper);
+  CaloDetDescrManager* mgr = new CaloDetDescrManager;
+  mgr->set_helper (helper);
+  mgr->initialize();
+
+  CaloSuperCellDetDescrManager* scmgr = new CaloSuperCellDetDescrManager;
+  scmgr->set_helper (schelper);
+  scmgr->initialize();
+
+  std::vector<CaloCell*> cells = make_cells (mgr);
+
+  IToolSvc* toolsvc = 0;
+  CHECK( svcloc->service ("ToolSvc", toolsvc, true) );
+  g_toolsvc = toolsvc;
+
+  tool = 0;
+  CHECK( toolsvc->retrieveTool ("CaloCompactCellTool", tool) );
+
+  StoreGateSvc* detstore = 0;
+  CHECK( svcloc->service ("DetectorStore", detstore) );
+
+  CHECK( detstore->record (mgr, "CaloMgr") );
+  CHECK( detstore->record (scmgr, "CaloSuperCellMgr") );
+  CHECK( detstore->record (idmgr, "CaloIdManager") );
+
+  arena = new SG::Arena ("arena");
+  SG::ArenaHeaderGaudiClear::disable();
+
+  g_mgr = mgr;
+
+  return cells;
+}
+
+
+void runtests ()
+{
+  ICaloCompactCellTool* tool = 0;
+  std::vector<CaloCell*> cells = init (tool);
+
+  seed = 10;
+  test_one (400, ICaloCompactCellTool::VERSION_400, cells, tool, false, true);
+  test_one (400, ICaloCompactCellTool::VERSION_400, cells, tool,  true, true);
+  test_one (10000, ICaloCompactCellTool::VERSION_400, cells, tool);
+  test_one (10000, ICaloCompactCellTool::VERSION_400, cells, tool, true);
+
+  test_one (100000, ICaloCompactCellTool::VERSION_400, cells, tool);
+  test_one (100000, ICaloCompactCellTool::VERSION_400, cells, tool, true);
+
+  test_one (cells.size(), ICaloCompactCellTool::VERSION_400, cells, tool);
+
+  seed = 20;
+  test_one (400, ICaloCompactCellTool::VERSION_500, cells, tool, false, true);
+  test_one (400, ICaloCompactCellTool::VERSION_500, cells, tool,  true, true);
+
+  test_one (10000, ICaloCompactCellTool::VERSION_500, cells, tool);
+  test_one (10000, ICaloCompactCellTool::VERSION_500, cells, tool, true);
+
+  test_one (100000, ICaloCompactCellTool::VERSION_500, cells, tool);
+  test_one (100000, ICaloCompactCellTool::VERSION_500, cells, tool, true);
+
+  test_one (cells.size(), ICaloCompactCellTool::VERSION_500, cells, tool);
+
+  seed = 40;
+  test_one (400, ICaloCompactCellTool::VERSION_501, cells, tool, false);
+  test_one (400, ICaloCompactCellTool::VERSION_501, cells, tool,  true);
+
+  test_one (10000, ICaloCompactCellTool::VERSION_501, cells, tool);
+  test_one (10000, ICaloCompactCellTool::VERSION_501, cells, tool, true);
+
+  test_one (100000, ICaloCompactCellTool::VERSION_501, cells, tool);
+  test_one (100000, ICaloCompactCellTool::VERSION_501, cells, tool, true);
+
+  test_one (cells.size(), ICaloCompactCellTool::VERSION_501, cells, tool);
+
+  // Unordered
+  test_one (400, ICaloCompactCellTool::VERSION_501, cells, tool,  false,
+            true, false);
+
+  seed = 50;
+  test_one (400, ICaloCompactCellTool::VERSION_502, cells, tool, false);
+  test_one (400, ICaloCompactCellTool::VERSION_502, cells, tool,  true);
+
+  test_one (10000, ICaloCompactCellTool::VERSION_502, cells, tool);
+  test_one (10000, ICaloCompactCellTool::VERSION_502, cells, tool, true);
+
+  test_one (100000, ICaloCompactCellTool::VERSION_502, cells, tool);
+  test_one (100000, ICaloCompactCellTool::VERSION_502, cells, tool, true);
+
+  test_one (cells.size(), ICaloCompactCellTool::VERSION_502, cells, tool);
+
+  seed = 60;
+  test_one (400, ICaloCompactCellTool::VERSION_503, cells, tool, false);
+  test_one (400, ICaloCompactCellTool::VERSION_503, cells, tool,  true);
+
+  test_one (10000, ICaloCompactCellTool::VERSION_503, cells, tool);
+  test_one (10000, ICaloCompactCellTool::VERSION_503, cells, tool, true);
+
+  test_one (100000, ICaloCompactCellTool::VERSION_503, cells, tool);
+  test_one (100000, ICaloCompactCellTool::VERSION_503, cells, tool, true);
+
+  test_one (cells.size(), ICaloCompactCellTool::VERSION_503, cells, tool);
+
+  seed = 70;
+  test_one (400, ICaloCompactCellTool::VERSION_504, cells, tool, false);
+  test_one (400, ICaloCompactCellTool::VERSION_504, cells, tool,  true);
+
+  test_one (10000, ICaloCompactCellTool::VERSION_504, cells, tool);
+  test_one (10000, ICaloCompactCellTool::VERSION_504, cells, tool, true);
+
+  test_one (100000, ICaloCompactCellTool::VERSION_504, cells, tool);
+  test_one (100000, ICaloCompactCellTool::VERSION_504, cells, tool, true);
+
+  test_one (cells.size(), ICaloCompactCellTool::VERSION_504, cells, tool);
+
+  seed = 80;
+  test_supercells (ICaloCompactCellTool::VERSION_504, cells, tool);
+
+  seed = 30;
+  test_errs (cells, tool);
+}
+
+
+float tv_diff (const timeval& tv1, const timeval& tv2)
+{
+  return tv2.tv_sec - tv1.tv_sec + (tv2.tv_usec - tv1.tv_usec) / 1000000.;
+}
+
+
+void timetests (int nrep)
+{
+  ICaloCompactCellTool* tool = 0;
+  std::vector<CaloCell*> cells = init (tool);
+
+  CaloCellContainer* cont = fill_cells (10000, cells, true, true);
+
+  rusage ru0, ru1, ru2, ru3;
+
+  CaloCompactCellContainer ccc;
+  getrusage (RUSAGE_SELF, &ru0);
+  for (int i=0; i < nrep; i++)
+    tool->getPersistent (*cont, &ccc);
+  getrusage (RUSAGE_SELF, &ru1);
+
+  SG::Arena::Push push (*arena);
+  CaloCellContainer* cont2 = new CaloCellContainer (SG::VIEW_ELEMENTS);
+  getrusage (RUSAGE_SELF, &ru2);
+  for (int i = 0; i < nrep; i++) {
+    tool->getTransient (ccc, cont2);
+    cont2->clear();
+    arena->reset();
+  }
+  getrusage (RUSAGE_SELF, &ru3);
+
+  printf ("pack: %f  ", tv_diff (ru0.ru_utime, ru1.ru_utime));
+  printf ("unpack: %f\n", tv_diff (ru2.ru_utime, ru3.ru_utime));
+}
+
+
+int main (int argc, char** argv)
+{
+  errorcheck::ReportMessage::hideErrorLocus (true);
+
+  if (argc >= 3 && strcmp (argv[1], "-t") == 0) {
+    timetests (atoi (argv[2]));
+    return 0;
+  }
+
+  runtests ();
+
+  return 0;
+}
diff --git a/Calorimeter/CaloTools/test/CaloTools.xml b/Calorimeter/CaloTools/test/CaloTools.xml
new file mode 100755
index 0000000000000000000000000000000000000000..bb9ddb7422141b6de7f1f2726a0dd46023d3fd34
--- /dev/null
+++ b/Calorimeter/CaloTools/test/CaloTools.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0"?>
+<atn>
+   <TEST name="CaloToolsTests" type="makecheck">
+      <package>Calorimeter/CaloTools</package>
+      <author> scott snyder </author>
+      <mailto> snyder@bnl.gov </mailto>
+      <expectations>
+         <errorMessage>Athena exited abnormally</errorMessage>
+         <errorMessage>differ</errorMessage>
+         <warningMessage> # WARNING_MESSAGE : post.sh> ERROR</warningMessage>
+         <successMessage>check ok</successMessage>
+         <returnValue>0</returnValue>
+      </expectations>
+   </TEST>
+</atn>