From 3aaf35b4c50186cd5fe0763b27e1df963792931d Mon Sep 17 00:00:00 2001
From: Patrick Robbe <robbe@lal.in2p3.fr>
Date: Sat, 15 Sep 2018 13:52:19 +0200
Subject: [PATCH 1/2] Port L0 Calo 2016 fix to 2017-branches

---
 L0/L0Calo/CMakeLists.txt                      |   8 ++
 L0/L0Calo/python/L0Calo/Configuration.py      | 127 ++++++++++++++++++
 L0/L0Calo/python/L0Calo/__init__.py           |   0
 L0/L0Calo/src/CaloTriggerAdcsFromCaloRaw.cpp  |  34 +++++
 L0/L0Calo/src/CaloTriggerAdcsFromCaloRaw.h    |  10 +-
 L0/L0Calo/src/L0CaloAlg.cpp                   |  14 +-
 L0/L0Calo/src/L0CaloCandidatesFromRawBank.cpp |  26 +++-
 L0/L0Calo/src/L0CaloCandidatesFromRawBank.h   |   4 +
 L0/L0Calo/src/L0Candidate.h                   |  12 +-
 .../qmtest/l0calo.qms/testL0CaloFix2016.qmt   |   9 ++
 L0/L0Calo/tests/scripts/testL0CaloFix2016.py  |  24 ++++
 11 files changed, 259 insertions(+), 9 deletions(-)
 create mode 100644 L0/L0Calo/python/L0Calo/Configuration.py
 create mode 100644 L0/L0Calo/python/L0Calo/__init__.py
 create mode 100644 L0/L0Calo/tests/qmtest/l0calo.qms/testL0CaloFix2016.qmt
 create mode 100644 L0/L0Calo/tests/scripts/testL0CaloFix2016.py

diff --git a/L0/L0Calo/CMakeLists.txt b/L0/L0Calo/CMakeLists.txt
index 732572119cf..8f951b0802f 100644
--- a/L0/L0Calo/CMakeLists.txt
+++ b/L0/L0Calo/CMakeLists.txt
@@ -3,6 +3,11 @@
 ################################################################################
 gaudi_subdir(L0Calo v11r16)
 
+# hide warnings from some external projects
+find_package(Boost)
+find_package(ROOT)
+include_directories(SYSTEM ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS})
+
 gaudi_depends_on_subdirs(Calo/CaloDAQ
                          Calo/CaloUtils
                          Event/LinkerEvent
@@ -16,5 +21,8 @@ gaudi_add_module(L0Calo
                  INCLUDE_DIRS AIDA Calo/CaloDAQ
                  LINK_LIBRARIES CaloUtils LinkerEvent L0Base DAQKernelLib)
 
+gaudi_install_python_modules()
+
 gaudi_env(SET L0CALOOPTS \${L0CALOROOT}/options)
 
+gaudi_add_test(QMTest QMTEST)
diff --git a/L0/L0Calo/python/L0Calo/Configuration.py b/L0/L0Calo/python/L0Calo/Configuration.py
new file mode 100644
index 00000000000..47b10ac8ea1
--- /dev/null
+++ b/L0/L0Calo/python/L0Calo/Configuration.py
@@ -0,0 +1,127 @@
+"""
+Configuration tools for L0Calo
+"""
+
+from Configurables import LHCbConfigurableUser
+from Configurables import L0CaloAlg, DataOnDemandSvc, L0CaloCandidatesFromRaw
+from Configurables import L0CaloCandidatesFromRawBank, ToolSvc
+from Gaudi.Configuration import appendPostConfigAction, log
+
+## @class L0CaloFix2016
+# Configurable to configure L0Calo to handle 2016 electron bug
+# Definitions:
+#   GOOD = the expected correct constants, depend on cell position
+#   BAD = the wrong constants loaded in the CALO electronics in 2016,
+#         equal to 127 everywhere
+# Use cases:
+#
+# #1 Simulation was done with GOOD constants (eg Sim09b) and the DST contains
+#    the CALO RAW banks: in order to represent 2016 data taken with BAD
+#    constants, use L0CaloFix2016 with options ApproximateMethod = False
+#    and Simulation = True. Set the TCK property to the one you want to
+#    simulate (best to use the one that was used for the simulation,
+#    ie '0x160F' for most cases. In the DaVinci options, set the DB tags to
+#    these used for the simulation.
+#
+# #2 Simulation was done with GOOD constants (Sim09b) and the DST do not contain
+#    the CALO RAW banks: in order to represent 2016 data taken with BAD
+#    constants, use L0CaloFix2016 with options ApproximateMethod = True
+#    and Simulation = True. Set the TCK property to the one you want to
+#    simulate (best to use the one that was used for the simulation,
+#    ie '0x160F' for most cases.In the DaVinci options, set the DB tags to
+#    these used for the simulation.
+#
+# #3 Data was recorded in 2016 with BAD constants and you want to re-run
+#    L0 with the GOOD constants in order to reject the extra events that
+#    were triggered because of the BAD constants, in order to obtain a
+#    coherent sample with 2015, 2017 or 2018. Use ApproximateMethod = False
+#    and Simulation = False.
+#
+# NB: Check for messages when running: if there are error messages due
+#     to missing CALO banks, do not trust the results. Use the approximate
+#     method instead.
+# NB: Only L0 is redone, not HLT. If the HLT depends on L0, it has to be
+#     ran again.
+#
+# @author Patrick Robbe <robbe@lal.in2p3.fr>
+# @date   2018/03/12
+
+class L0CaloFix2016(LHCbConfigurableUser):
+
+    __slots__ = {
+        # Properties
+        "ApproximateMethod" : False,
+        "Simulation" : True ,
+        "TCK" : '0x160F'
+        }
+
+    __propertyDocDct = {
+        # Properties
+        "ApproximateMethod" : """Use approximation on L0Calo to correct energy, otherwise use full method on Calo banks. Useful when Calo banks are not available.""" ,
+        "Simulation" : """True for MC, False for data.""",
+        "TCK": """The TCK number to emulate"""
+        }
+    
+    def __apply_configuration__(self):
+        def fixL0Calo( approximate , simulation , tck ):
+            dod = DataOnDemandSvc()
+            if not approximate:
+                l0calo = L0CaloAlg()
+                l0calo.WriteBanks = False
+                l0calo.WriteOnTES = True
+                l0calo.L0CaloADCTool = "CaloTriggerAdcsFromCaloRaw"
+                from Configurables import CaloTriggerAdcsFromCaloRaw 
+                l0calo.addTool( CaloTriggerAdcsFromCaloRaw ,
+                                "EcalTriggerAdcTool" )
+                if simulation:
+                    l0calo.EcalTriggerAdcTool.FixFor2016 = True
+                else:
+                    # for data, take what is in database for the constants
+                    l0calo.EcalTriggerAdcTool.FixFor2016 = False
+                    
+                dod.AlgMap[ 'Trig/L0/FullCalo' ] = l0calo
+                dod.AlgMap[ 'Trig/L0/Calo' ] = l0calo
+            else:
+                l0calo = L0CaloCandidatesFromRaw("L0CaloFromRaw")
+                ToolSvc().addTool( L0CaloCandidatesFromRawBank )
+                ToolSvc().L0CaloCandidatesFromRawBank.FixFor2016 = True
+                if simulation:
+                    ToolSvc().L0CaloCandidatesFromRawBank.Simulation = True
+                else:
+                    # assumes that the correct database tag is given
+                    ToolSvc().L0CaloCandidatesFromRawBank.Simulation = False                    
+                l0calo.WriteProcData = True
+                dod.AlgMap[ 'Trig/L0/FullCalo' ] = l0calo
+                dod.AlgMap[ 'Trig/L0/Calo' ] = l0calo
+            
+            from Configurables import L0DUAlg, L0DUFromRawAlg, GaudiSequencer, L0DUFromRawTool
+            l0du = L0DUAlg()
+            l0du.WriteBanks = False
+            l0du.WriteOnTES = True
+            if not approximate:
+                dod.AlgMap[ 'Trig/L0/L0DUCaloData' ] = l0calo
+                l0du.ProcessorDataLocations = [ 'Trig/L0/L0DUCaloData' , 'Trig/L0/L0DUData' ]
+            else:
+                dod.AlgMap[ 'Trig/L0/L0DUL0CaloData' ] = l0calo
+                l0du.ProcessorDataLocations = [ 'Trig/L0/L0DUL0CaloData' , 'Trig/L0/L0DUData' ]
+                
+            l0du.TCK = tck
+            # CALO
+            l0seq = GaudiSequencer("L0Seq")
+            l0raw = L0DUFromRawAlg(  WriteProcData = True , WriteOnTES = False )
+            l0raw.addTool( L0DUFromRawTool )
+            l0raw.L0DUFromRawTool.Emulate = False
+            l0seq.Members = [ l0raw , l0du ]
+            dod.AlgMap[ 'Trig/L0/L0DUReport' ] = l0seq
+ 
+        log.warning( "Apply 2016 L0Calo fix" )
+        if self.getProp( "ApproximateMethod" ):
+            if self.getProp( "Simulation" ):
+                appendPostConfigAction( lambda tck = self.getProp( "TCK" ): fixL0Calo(True,True,tck) )
+            else:
+                appendPostConfigAction( lambda tck = self.getProp( "TCK" ): fixL0Calo(True,False,tck) )
+        else:
+            if self.getProp( "Simulation" ):
+                appendPostConfigAction( lambda tck = self.getProp( "TCK" ): fixL0Calo(False,True,tck) )
+            else:
+                appendPostConfigAction( lambda tck = self.getProp( "TCK" ): fixL0Calo(False,False,tck) )
diff --git a/L0/L0Calo/python/L0Calo/__init__.py b/L0/L0Calo/python/L0Calo/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/L0/L0Calo/src/CaloTriggerAdcsFromCaloRaw.cpp b/L0/L0Calo/src/CaloTriggerAdcsFromCaloRaw.cpp
index 2d8c59605a4..abde51adbaf 100644
--- a/L0/L0Calo/src/CaloTriggerAdcsFromCaloRaw.cpp
+++ b/L0/L0Calo/src/CaloTriggerAdcsFromCaloRaw.cpp
@@ -26,8 +26,16 @@ CaloTriggerAdcsFromCaloRaw::CaloTriggerAdcsFromCaloRaw( const std::string& type,
 {
   declareInterface<ICaloTriggerAdcsFromRaw>(this);
   declareProperty( "DoubleScale" , m_doubleScale = false ) ;
+  // fix L0Calo to reproduce 2016 bug
+  declareProperty( "FixFor2016" , m_fixFor2016 = false ) ;
+  declareProperty( "RawEventLocations" , m_rawEventLocations ) ;
   int index = name.find_first_of(".",0) +1 ;
   m_detectorName = name.substr( index, 4 );
+  if( "Ecal" == m_detectorName ){
+    m_bank = LHCb::RawBank::EcalPacked;
+  } else if( "Hcal" == m_detectorName ){
+    m_bank = LHCb::RawBank::HcalPacked;
+  }
   m_data.clear() ;
 }
 
@@ -53,6 +61,15 @@ StatusCode CaloTriggerAdcsFromCaloRaw::initialize() {
     return StatusCode::FAILURE ;
   }
 
+  // Initialise the RawEvent locations
+  if (std::find(m_rawEventLocations.begin(), m_rawEventLocations.end(), 
+                LHCb::RawEventLocation::Default)
+      == m_rawEventLocations.end()) {
+    // append the defaults to the search path
+    m_rawEventLocations.push_back(LHCb::RawEventLocation::Calo);
+    m_rawEventLocations.push_back(LHCb::RawEventLocation::Default);
+  }
+
   long nCells = m_calo -> numberOfCells() ;
   m_data.reserve( nCells ) ;
   m_data.clear() ;
@@ -62,6 +79,20 @@ StatusCode CaloTriggerAdcsFromCaloRaw::initialize() {
 //=============================================================================
 const std::vector< LHCb::L0CaloAdc > & CaloTriggerAdcsFromCaloRaw::adcs( ) 
 {
+  // Retrieve the RawEvent:
+  LHCb::RawEvent* rawEvt = nullptr ;
+  for (auto p = m_rawEventLocations.begin(); p != m_rawEventLocations.end() && 
+         ! rawEvt; ++p) {
+    rawEvt = getIfExists<LHCb::RawEvent>(*p);
+  }
+  
+  if( rawEvt == nullptr )
+    Exception( "No CALO Raw bank in the event" ) ;
+  
+  bool bank = ( 0 == (rawEvt->banks( m_bank )).size() ) ?  false : true ;
+  if ( ! bank ) 
+    Exception( "No Calo packed bank in the event" ) ;
+
   m_data.clear() ;
   const CaloVector< LHCb::CaloAdc >& adcs = m_adcs -> adcs( -1 ) ;
   std::transform( adcs.begin(), adcs.end(), std::back_inserter(m_data),
@@ -96,6 +127,9 @@ int CaloTriggerAdcsFromCaloRaw::l0adcFromAdc( const int adc ,
   unsigned long calibCte = m_calo -> cellParam( id ).l0Constant() ;
   if ( m_doubleScale ) calibCte = calibCte / 2 ;
 
+  // for 2016, all constants were set to 127 in ECAL
+  if ( ( m_fixFor2016 ) && ( id.calo() == 2 ) ) calibCte = 127 ;
+  
   int theAdc = adc ;
 
   if ( calibCte > 255 ) { 
diff --git a/L0/L0Calo/src/CaloTriggerAdcsFromCaloRaw.h b/L0/L0Calo/src/CaloTriggerAdcsFromCaloRaw.h
index 49d1cbc2a0b..cfcfdf7cbd7 100644
--- a/L0/L0Calo/src/CaloTriggerAdcsFromCaloRaw.h
+++ b/L0/L0Calo/src/CaloTriggerAdcsFromCaloRaw.h
@@ -26,10 +26,12 @@ public:
 
   const std::vector<LHCb::L0CaloAdc>&    adcs( )  override;
   const std::vector<LHCb::L0CaloAdc>&    adcs( int source )  override;
-  const std::vector<LHCb::L0CaloAdc>&    adcs( const LHCb::RawBank& bank )  override;
+  const std::vector<LHCb::L0CaloAdc>&    adcs( const LHCb::RawBank& bank )  
+    override;
   const std::vector<LHCb::L0CaloAdc>&    pinAdcs( )  override;
 
-  StatusCode  _setProperty(const std::string& ,const std::string& ) override { return StatusCode::SUCCESS ; }
+  StatusCode  _setProperty(const std::string& ,const std::string& )
+    override { return StatusCode::SUCCESS ; }
   bool getBanks() override { return true ; }
   void setBanks(const std::vector<LHCb::RawBank*>& ) override { return ; }
   void clear() override { m_data.clear() ; }
@@ -50,6 +52,10 @@ private:
   DeCalorimeter     * m_calo = nullptr ;
 
   bool m_doubleScale ;
+  bool m_fixFor2016 ;
+  LHCb::RawBank::BankType m_bank;
+  /// List of locations in the transient store to search the RawEvent object.
+  std::vector<std::string> m_rawEventLocations;
 
   int l0adcFromAdc( const int adc , const LHCb::CaloCellID & id ) const ;
 };
diff --git a/L0/L0Calo/src/L0CaloAlg.cpp b/L0/L0Calo/src/L0CaloAlg.cpp
index c73fe42d9e2..2bd54315526 100755
--- a/L0/L0Calo/src/L0CaloAlg.cpp
+++ b/L0/L0Calo/src/L0CaloAlg.cpp
@@ -324,7 +324,11 @@ StatusCode L0CaloAlg::initialize() {
 //=============================================================================
 StatusCode L0CaloAlg::execute() {
   // Get the ECAL data, store them in the Front-End card
-  sumEcalData( );
+  try { sumEcalData( ); }
+  catch ( const GaudiException & exc ) {
+    fatal() << "The L0Calo trigger will be wrong, dont rely on it" << endmsg ;
+    return StatusCode::FAILURE ;
+  }
 
   // Get Spd+Prs data
   m_PrsSpdIds = m_bitsFromRaw -> prsSpdCells( ) ;
@@ -414,8 +418,12 @@ StatusCode L0CaloAlg::execute() {
   } // eCard
 
   //  Do a similar processing for HCAL Data
-  sumHcalData( );
-  
+  try { sumHcalData( ); }
+  catch ( const GaudiException & exc ) {
+    fatal() << "The L0Calo trigger will be wrong, dont rely on it" << endmsg ;
+    return StatusCode::FAILURE ;
+  }
+   
   // Add the highest ECAL energy in matching cards and store
   // the candidates (one per Selection Board input, in 3 vectors
   // one vector per SB: (0 - master, 1 - slave1, 2 - slave2)
diff --git a/L0/L0Calo/src/L0CaloCandidatesFromRawBank.cpp b/L0/L0Calo/src/L0CaloCandidatesFromRawBank.cpp
index ddda0d0b65a..445fe4c4824 100755
--- a/L0/L0Calo/src/L0CaloCandidatesFromRawBank.cpp
+++ b/L0/L0Calo/src/L0CaloCandidatesFromRawBank.cpp
@@ -36,6 +36,10 @@ L0CaloCandidatesFromRawBank::L0CaloCandidatesFromRawBank
   // Store also the intermediate informations for debugging the Selection boards
   // such as the partial results of the hadron Selection Boards
   declareProperty( "DebugDecoding" , m_doDebugDecoding = false ) ;
+  // Correct the L0electron and photon energies to reflect 2016 bug
+  declareProperty( "FixFor2016" , m_fixFor2016 = false ) ;
+  // Data or simulation (relevant for FixFor2016 only !)
+  declareProperty( "Simulation" , m_simulation = false ) ;
 }
 
 //=============================================================================
@@ -84,7 +88,7 @@ void L0CaloCandidatesFromRawBank::convertRawBankToTES
   if ( msgLevel( MSG::DEBUG ) ) 
     debug() << "L0CaloCandidatesFromRawBank ... entering conversion" 
             << " for version " << version << endmsg ;
-  
+
   Gaudi::XYZPoint dummy( 0. , 0. , 0. ) , center( 0. , 0. , 0. ) ;
   LHCb::L0CaloCandidate * myL0Cand( 0 ) ;
   std::vector< LHCb::L0CaloCandidate * > bestCand ;
@@ -311,6 +315,14 @@ void L0CaloCandidatesFromRawBank::convertRawBankToTES
             }
           }   
         } else {
+          // ECAL trigger
+          // Apply 2016 correction here if requested
+          if ( m_fixFor2016 ) {
+            et = correctedEnergy( et , id ) ;
+            if ( et > 255 ) et = 255 ;
+          }
+          
+          
           myL0Cand = new LHCb::L0CaloCandidate ( type, id, et, 
                                                  et * m_etScale, center, 
                                                  tol );
@@ -389,3 +401,15 @@ void L0CaloCandidatesFromRawBank::convertRawBankToTES
     outFull -> add( *it ) ;
 }
 //=============================================================================
+// Function to correct ECAL energy (approximatively) for 2016 bug
+//=============================================================================
+int L0CaloCandidatesFromRawBank::correctedEnergy( const int oldEnergy ,
+                                                  const LHCb::CaloCellID & id ) 
+  const 
+{
+  // Get correct calib constant
+  unsigned long calibCte = m_ecal -> cellParam( id ).l0Constant() ;
+  // compute energy with wrong calib constant (127)
+  if ( m_simulation ) return (int) ( (double) oldEnergy * 127. / ( (double) calibCte ) ) ;
+  return (int) ( (double) oldEnergy * ( (double) calibCte ) / 127. ) ;
+}
diff --git a/L0/L0Calo/src/L0CaloCandidatesFromRawBank.h b/L0/L0Calo/src/L0CaloCandidatesFromRawBank.h
index d66e60313b6..ec5825426ce 100755
--- a/L0/L0Calo/src/L0CaloCandidatesFromRawBank.h
+++ b/L0/L0Calo/src/L0CaloCandidatesFromRawBank.h
@@ -53,5 +53,9 @@ private:
   DeCalorimeter* m_hcal;         ///< HCAL detector element
   double         m_etScale;      ///< Conversion int -> Et.
   bool           m_doDebugDecoding ; ///< Store intermediate information for debug
+  bool           m_fixFor2016 ;  ///< Fix energy to correspond to 2016 conditions
+  bool           m_simulation ;  ///< Data or MC, relevant only for fixFor2016
+
+  int correctedEnergy( const int oldEnergy , const LHCb::CaloCellID & id ) const ;
 };
 #endif // L0CALO_L0CALOCANDIDATESFROMRAWBANK_H
diff --git a/L0/L0Calo/src/L0Candidate.h b/L0/L0Calo/src/L0Candidate.h
index 24232c16d6f..1f1426e617d 100644
--- a/L0/L0Calo/src/L0Candidate.h
+++ b/L0/L0Calo/src/L0Candidate.h
@@ -49,9 +49,15 @@ public:
    */
   void saveCandidate( L0DUBase::Fiber::Type type , 
                       LHCb::L0ProcessorDatas* L0Calo ) {
-    unsigned int word = 0x10000 |
-			( m_ID.index() << L0DUBase::Calo::Address::Shift) | 
-			( m_et << L0DUBase::Calo::Et::Shift ) ;
+    unsigned int word = 0 ;
+    if ( L0DUBase::Fiber::CaloSumEt == type ) 
+      word = 0x10000 + ( m_et << L0DUBase::Calo::Sum::Shift ) ;
+    else if ( L0DUBase::Fiber::CaloSpdMult == type ) 
+      word = 0x10000 + ( m_et << L0DUBase::Calo::Sum::Shift ) ;
+    else
+      word = 0x10000 |
+        ( m_ID.index() << L0DUBase::Calo::Address::Shift) | 
+        ( m_et << L0DUBase::Calo::Et::Shift ) ;
     LHCb::L0ProcessorData * temp = new LHCb::L0ProcessorData ( type , word ) ;
     L0Calo -> add( temp );
   }
diff --git a/L0/L0Calo/tests/qmtest/l0calo.qms/testL0CaloFix2016.qmt b/L0/L0Calo/tests/qmtest/l0calo.qms/testL0CaloFix2016.qmt
new file mode 100644
index 00000000000..9245d5387ea
--- /dev/null
+++ b/L0/L0Calo/tests/qmtest/l0calo.qms/testL0CaloFix2016.qmt
@@ -0,0 +1,9 @@
+<?xml version="1.0" ?><!DOCTYPE extension  PUBLIC '-//QM/2.3/Extension//EN'  'http://www.codesourcery.com/qm/dtds/2.3/-//qm/2.3/extension//en.dtd'>
+<extension class="GaudiTest.GaudiExeTest" kind="test">
+<argument name="program"><text>../scripts/testL0CaloFix2016.py</text></argument>
+<argument name="validator"><text>
+findReferenceBlock("""
+Number of L0 electron decisions =  515
+""")
+</text></argument>
+</extension>
diff --git a/L0/L0Calo/tests/scripts/testL0CaloFix2016.py b/L0/L0Calo/tests/scripts/testL0CaloFix2016.py
new file mode 100644
index 00000000000..d3b62644e61
--- /dev/null
+++ b/L0/L0Calo/tests/scripts/testL0CaloFix2016.py
@@ -0,0 +1,24 @@
+from Configurables import LHCbApp
+from PRConfig import TestFileDB
+TestFileDB.test_file_db['2016-lb2l0gamma.strip.dst'].run(configurable=LHCbApp())
+
+from Configurables import L0Conf, DataOnDemandSvc, ApplicationMgr
+ApplicationMgr().ExtSvc += [ DataOnDemandSvc() ]
+L0Conf( FullL0MuonDecoding = True , EnableL0DecodingOnDemand = True )
+
+from Configurables import L0CaloFix2016
+L0CaloFix2016( ApproximateMethod = False , Simulation = True , TCK = '0x160F' )
+
+import GaudiPython
+appMgr = GaudiPython.AppMgr()
+evt = appMgr.evtsvc()
+
+counter_electron = 0
+
+for i in xrange( 1000 ) :
+    appMgr.run(1)
+    l0du = evt['Trig/L0/L0DUReport']
+    if l0du.channelDecisionByName( "Electron" ):
+        counter_electron += 1
+
+print "Number of L0 electron decisions = ", counter_electron
-- 
GitLab


From 6ec6b5463246f266b6b0a5d905e8fb998cd8f99a Mon Sep 17 00:00:00 2001
From: Patrick Robbe <robbe@lal.in2p3.fr>
Date: Sat, 15 Sep 2018 14:55:58 +0200
Subject: [PATCH 2/2] Port L0DU modifications mandatory for L0 Calo fix 2016

---
 L0/L0DU/CMakeLists.txt                 |  4 ++++
 L0/L0DU/src/L0ProcessorDataDecoder.cpp | 17 +++++++++++++++--
 L0/L0DU/src/L0ProcessorDataDecoder.h   |  1 +
 3 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/L0/L0DU/CMakeLists.txt b/L0/L0DU/CMakeLists.txt
index d4eee7a21e2..e18468555ca 100644
--- a/L0/L0DU/CMakeLists.txt
+++ b/L0/L0DU/CMakeLists.txt
@@ -13,6 +13,10 @@ gaudi_depends_on_subdirs(Calo/CaloUtils
                          L0/L0Interfaces)
 
 find_package(AIDA)
+find_package(Boost)
+find_package(ROOT)
+# hide warnings from some external projects
+include_directories(SYSTEM ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS})
 
 gaudi_add_module(L0DU
                  src/*.cpp
diff --git a/L0/L0DU/src/L0ProcessorDataDecoder.cpp b/L0/L0DU/src/L0ProcessorDataDecoder.cpp
index 7ea34d51aff..a830539356c 100644
--- a/L0/L0DU/src/L0ProcessorDataDecoder.cpp
+++ b/L0/L0DU/src/L0ProcessorDataDecoder.cpp
@@ -44,6 +44,11 @@ StatusCode L0ProcessorDataDecoder::finalize ()
 {
   if ( msgLevel(MSG::DEBUG) ) debug() << "release L0ProcessoDataDecoder" << endmsg;
   delete m_dataContainer;
+  if( msgLevel(MSG::DEBUG) ){
+    for(std::map<int,std::string>::iterator it=m_fiberSource.begin();m_fiberSource.end()!=it;++it){
+      debug() << "Fiber "<< it->first << " data is provided by : " << it->second <<endmsg;
+    }
+  }
   return GaudiTool::finalize();
 }
 
@@ -111,10 +116,18 @@ bool L0ProcessorDataDecoder::setL0ProcessorData(std::vector<std::string> dataLoc
           ( (*itt)->key() == L0DUBase::Fiber::CaloPi0Global ||  (*itt)->key() == L0DUBase::Fiber::CaloPi0Local) ){
         if( msgLevel(MSG::VERBOSE) ) verbose() << "CaloPI0 fibers to be replaced by HC fibers " << loc << endmsg;
       }else{
+        if( !m_dataContainer->object( (*itt)->key() ) ){
+          m_fiberSource[(*itt)->key()]=loc;
           m_dataContainer->insert(*itt);
-      }      
+        } else {
+          std::ostringstream ss;
+          ss << "L0ProcessorData for fiber " << (*itt)->key() << " already exists. Ignoring data from " << loc;
+          Warning(ss.str(), StatusCode::SUCCESS).ignore();
+        }      
+      } 
     } 
-  } 
+  }
+  
   if( msgLevel(MSG::VERBOSE) ) verbose() << "DATA INSERTED" << endmsg;
   return m_ok;
 } 
diff --git a/L0/L0DU/src/L0ProcessorDataDecoder.h b/L0/L0DU/src/L0ProcessorDataDecoder.h
index ea186e75b99..ab9f9064c05 100644
--- a/L0/L0DU/src/L0ProcessorDataDecoder.h
+++ b/L0/L0DU/src/L0ProcessorDataDecoder.h
@@ -33,6 +33,7 @@ private:
   IL0CondDBProvider* m_condDB;
   bool   m_ok;
   bool   m_hasHC;
+  std::map<int,std::string> m_fiberSource;
 };
 
 #endif // L0DU_L0PROCESSORDATADECODER_H
-- 
GitLab