From 7f7e3bba59d4c33559ccbdf8a67f4c5d1fc393ca Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Fri, 11 Feb 2022 09:24:01 +0000
Subject: [PATCH] Natively read dd4hep RICH decoding conditions

---
 .../include/RichDetectors/Condition.h         | 48 +++++++++++++
 .../include/RichDetectors/Handle.h            |  3 +-
 .../include/RichDetectors/RichPDInfo.h        | 67 ++++++-------------
 .../include/RichDetectors/RichPDPanel.h       | 23 ++++---
 .../RichFutureDAQ/RichPDMDBDecodeMapping.h    | 45 +++++++++----
 .../RichFutureDAQ/RichPDMDBEncodeMapping.h    | 44 ++++++++----
 .../RichFutureDAQ/RichTel40CableMapping.h     | 45 +++++++++----
 .../src/lib/RichPDMDBDecodeMapping.cpp        | 38 ++++++-----
 .../src/lib/RichPDMDBEncodeMapping.cpp        | 34 ++++++----
 .../src/lib/RichTel40CableMapping.cpp         | 27 ++++----
 10 files changed, 237 insertions(+), 137 deletions(-)
 create mode 100644 Rich/RichDetectors/include/RichDetectors/Condition.h

diff --git a/Rich/RichDetectors/include/RichDetectors/Condition.h b/Rich/RichDetectors/include/RichDetectors/Condition.h
new file mode 100644
index 00000000000..59e1dd46e1f
--- /dev/null
+++ b/Rich/RichDetectors/include/RichDetectors/Condition.h
@@ -0,0 +1,48 @@
+/*****************************************************************************\
+* (c) Copyright 2000-2020 CERN for the benefit of the LHCb Collaboration      *
+*                                                                             *
+* This software is distributed under the terms of the GNU General Public      *
+* Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING".   *
+*                                                                             *
+* In applying this licence, CERN does not waive the privileges and immunities *
+* granted to it by virtue of its status as an Intergovernmental Organization  *
+* or submit itself to any jurisdiction.                                       *
+\*****************************************************************************/
+
+#pragma once
+
+#ifdef USE_DD4HEP
+#  include <yaml-cpp/yaml.h>
+#else
+#  include "DetDesc/ParamValidDataObject.h"
+#endif
+
+#include <cassert>
+#include <utility>
+
+namespace Rich::Detector {
+
+#ifdef USE_DD4HEP
+  using Condition = YAML::Node;
+#else
+  using Condition = ParamValidDataObject;
+#endif
+
+  template <typename T>
+  inline auto condition_param( const Condition& cond, std::string paramName ) {
+#ifdef USE_DD4HEP
+    // tutorial on how to use yaml-cpp can be found at
+    // https://github.com/jbeder/yaml-cpp/wiki/Tutorial
+    return cond[std::move( paramName )].as<T>();
+#else
+    return cond.param<T>( std::move( paramName ) );
+#endif
+  }
+
+  template <typename T>
+  inline auto condition_param( const Condition* cond, std::string paramName ) {
+    assert( cond );
+    return condition_param<T>( *cond, std::move( paramName ) );
+  }
+
+} // namespace Rich::Detector
diff --git a/Rich/RichDetectors/include/RichDetectors/Handle.h b/Rich/RichDetectors/include/RichDetectors/Handle.h
index e1992fbe021..2b0642f922e 100644
--- a/Rich/RichDetectors/include/RichDetectors/Handle.h
+++ b/Rich/RichDetectors/include/RichDetectors/Handle.h
@@ -16,6 +16,7 @@
 #include <type_traits>
 
 class DetectorElement;
+class ParamValidDataObject;
 
 namespace Rich::Detector {
 
@@ -34,7 +35,7 @@ namespace Rich::Detector {
 
   private:
     // Test of object type (DD4HEP or DetDesc)
-    using B = std::is_base_of<DetectorElement, T>;
+    using B = std::disjunction<std::is_base_of<DetectorElement, T>, std::is_base_of<ParamValidDataObject, T>>;
     // internal handle type
     using H = std::conditional_t<B::value, const T*, std::optional<T>>;
     // the handle
diff --git a/Rich/RichDetectors/include/RichDetectors/RichPDInfo.h b/Rich/RichDetectors/include/RichDetectors/RichPDInfo.h
index 13f59253fd6..393e75f152d 100644
--- a/Rich/RichDetectors/include/RichDetectors/RichPDInfo.h
+++ b/Rich/RichDetectors/include/RichDetectors/RichPDInfo.h
@@ -19,6 +19,7 @@
 #include "RichDetectors/RichPD.h"
 
 // RichDetector
+#include "RichDetectors/Condition.h"
 #include "RichDetectors/Rich1.h"
 #include "RichDetectors/Rich2.h"
 #include "RichDetectors/RichPD.h"
@@ -84,10 +85,10 @@ namespace Rich::Detector {
       PDInfo() = default;
 
       /// Constructor from Rich Detectors
-      PDInfo( const ParamValidDataObject& r1Nums, //
-              const ParamValidDataObject& r2Nums, //
-              const Detector::Rich1&      rich1,  //
-              const Detector::Rich2&      rich2 ) {
+      PDInfo( const Rich::Detector::Condition& r1Nums, //
+              const Rich::Detector::Condition& r2Nums, //
+              const Detector::Rich1&           rich1,  //
+              const Detector::Rich2&           rich2 ) {
 
         // Cache pointers to detectors
         m_riches[Rich::Rich1] = &rich1;
@@ -100,7 +101,7 @@ namespace Rich::Detector {
         for ( const auto numbers : {&r1Nums, &r2Nums} ) {
 
           // PD RichSmartIDs
-          for ( const auto softID : numbers->paramVect<int>( "PMTSmartIDs" ) ) {
+          for ( const auto softID : condition_param<std::vector<int>>( numbers, "PMTSmartIDs" ) ) {
 
             // get PD ID
             const LHCb::RichSmartID32 pdID32( softID ); // needed for 32->64 bit support
@@ -145,20 +146,22 @@ namespace Rich::Detector {
     public:
       // conditions handling
 
-      // Note - With DD4HEP these will be different
-      /// RICH1 Detector numbers
+#ifdef USE_DD4HEP
+      inline static const std::string R1_Nums = "/world/BeforeMagnetRegion/Rich1:PMTDetectorNumbers";
+      inline static const std::string R2_Nums = "/world/AfterMagnetRegion/Rich2:PMTDetectorNumbers";
+#else
       inline static const std::string R1_Nums = "/dd/Conditions/ReadoutConf/Rich1/PMTDetectorNumbers";
-      /// RICH2 Detector numbers
       inline static const std::string R2_Nums = "/dd/Conditions/ReadoutConf/Rich2/PMTDetectorNumbers";
+#endif
 
       /// Default conditions name
       inline static const std::string DefaultConditionKey = DeRichLocations::derivedCondition( "RichPDInfo" );
 
       /// Static generator function
-      static auto generate( const ParamValidDataObject& r1Nums, //
-                            const ParamValidDataObject& r2Nums, //
-                            const Detector::Rich1&      r1,     //
-                            const Detector::Rich2&      r2 ) {
+      static auto generate( const Rich::Detector::Condition& r1Nums, //
+                            const Rich::Detector::Condition& r2Nums, //
+                            const Detector::Rich1&           r1,     //
+                            const Detector::Rich2&           r2 ) {
         auto msgSvc = Gaudi::svcLocator()->service<IMessageSvc>( "MessageSvc" );
         assert( msgSvc );
         MsgStream log( msgSvc, Name );
@@ -166,25 +169,6 @@ namespace Rich::Detector {
         return PDInfo{r1Nums, r2Nums, r1, r2};
       }
 
-      /// Static generator function (temporary for dd4hep until conditions can be natively accessed)
-      static auto generate_dd4hep( const Detector::Rich1& r1, //
-                                   const Detector::Rich2& r2 ) {
-        auto msgSvc = Gaudi::svcLocator()->service<IMessageSvc>( "MessageSvc" );
-        assert( msgSvc );
-        MsgStream log( msgSvc, Name );
-        log << MSG::DEBUG << "Creating instance" << endmsg;
-        // load conditions from DetDesc
-        log << MSG::WARNING << "Loading '" << R1_Nums << "' via DetDesc until available natively to dd4hep" << endmsg;
-        log << MSG::WARNING << "Loading '" << R2_Nums << "' via DetDesc until available natively to dd4hep" << endmsg;
-        auto detSvc = Gaudi::svcLocator()->service<IDataProviderSvc>( "DetectorDataSvc" );
-        assert( detSvc );
-        const auto r1Nums = Gaudi::Utils::getFromTS<ParamValidDataObject>( detSvc, R1_Nums );
-        const auto r2Nums = Gaudi::Utils::getFromTS<ParamValidDataObject>( detSvc, R2_Nums );
-        assert( r1Nums && r2Nums );
-        // return object
-        return PDInfo{*r1Nums, *r2Nums, r1, r2};
-      }
-
       /// Creates a condition derivation for the given key
       template <typename PARENT>
       static auto addConditionDerivation( PARENT* parent, LHCb::DetDesc::ConditionKey key = DefaultConditionKey ) {
@@ -195,21 +179,12 @@ namespace Rich::Detector {
         if ( parent->msgLevel( MSG::DEBUG ) ) {
           parent->debug() << "RichPDInfo::addConditionDerivation : Key=" << key << endmsg;
         }
-        // Until we have the conditions available 'natively' to dd4hep avoid dependencies on
-        // them directly and side-load from DetDesc
-        if constexpr ( std::is_base_of_v<DetectorElement, Detector::Rich1::DetElem> ) {
-          return parent->addSharedConditionDerivation( {R1_Nums, // input condition locations
-                                                        R2_Nums, //
-                                                        Detector::Rich1::DefaultConditionKey,  //
-                                                        Detector::Rich2::DefaultConditionKey}, //
-                                                       std::move( key ), // output condition location
-                                                       &generate );
-        } else {
-          return parent->addSharedConditionDerivation( {Detector::Rich1::DefaultConditionKey,  // input conditions
-                                                        Detector::Rich2::DefaultConditionKey}, //
-                                                       std::move( key ), // output condition location
-                                                       &generate_dd4hep );
-        }
+        return parent->addSharedConditionDerivation( {R1_Nums,                              // input condition locations
+                                                      R2_Nums,                              //
+                                                      Detector::Rich1::DefaultConditionKey, //
+                                                      Detector::Rich2::DefaultConditionKey}, //
+                                                     std::move( key ), // output condition location
+                                                     &generate );
       }
     };
 
diff --git a/Rich/RichDetectors/include/RichDetectors/RichPDPanel.h b/Rich/RichDetectors/include/RichDetectors/RichPDPanel.h
index 63dbf07a8c5..836591ead92 100644
--- a/Rich/RichDetectors/include/RichDetectors/RichPDPanel.h
+++ b/Rich/RichDetectors/include/RichDetectors/RichPDPanel.h
@@ -119,14 +119,21 @@ namespace Rich::Detector {
       const PD* dePD = nullptr;
       if ( pdID.pdIsSet() ) {
         const auto localModNum = panelLocalModNum( pdID );
-        assert( localModNum < m_PDs.size() );
-        const auto& mod = m_PDs[localModNum];
-        assert( pdID.pdNumInMod() < mod.size() );
-        const auto& pd = mod[pdID.pdNumInMod()];
-        /** As long as we need to support 'classic' PMTs cannot apply this assert.
-         *  @todo put assert back once old DetDesc is dropped. */
-        // assert( pd.get() ); // should always have an object
-        dePD = pd.get();
+        // Note, whilst comissioning dd4hep, but still using old DetDesc MC samples with
+        // different PMTs, we cannot apply assers here by instead must using runtime size checks.
+        // to be reverted once dd4hep is fully comissioned and DetDesc completely dropped.
+        // assert( localModNum < m_PDs.size() );
+        if ( localModNum < m_PDs.size() ) {
+          const auto& mod = m_PDs[localModNum];
+          // assert( pdID.pdNumInMod() < mod.size() );
+          if ( pdID.pdNumInMod() < mod.size() ) {
+            const auto& pd = mod[pdID.pdNumInMod()];
+            /** As long as we need to support 'classic' PMTs cannot apply this assert.
+             *  @todo put assert back once old DetDesc is dropped. */
+            // assert( pd.get() ); // should always have an object
+            dePD = pd.get();
+          }
+        }
       }
       return dePD;
     }
diff --git a/Rich/RichFutureDAQ/include/RichFutureDAQ/RichPDMDBDecodeMapping.h b/Rich/RichFutureDAQ/include/RichFutureDAQ/RichPDMDBDecodeMapping.h
index 7349dd8323a..b1c6b57903c 100644
--- a/Rich/RichFutureDAQ/include/RichFutureDAQ/RichPDMDBDecodeMapping.h
+++ b/Rich/RichFutureDAQ/include/RichFutureDAQ/RichPDMDBDecodeMapping.h
@@ -27,7 +27,12 @@
 #include "GaudiAlg/GetData.h"
 #include "RichDetectors/Rich1.h"
 
+// RICH Utils
+#include "RichUtils/RichDAQDefinitions.h"
+
 // Detectors
+#include "RichDet/DeRichLocations.h"
+#include "RichDetectors/Condition.h"
 #include "RichDetectors/Utilities.h"
 
 // STL
@@ -56,8 +61,8 @@ namespace Rich::Future::DAQ {
 
     /// Local struct to hold conditions
     struct DecodingConds {
-      DetectorArray<const ParamValidDataObject*> rTypeConds;
-      const ParamValidDataObject*                hTypeCond;
+      DetectorArray<const Rich::Detector::Condition*> rTypeConds{{}};
+      const Rich::Detector::Condition*                hTypeCond{nullptr};
     };
 
   public:
@@ -196,23 +201,35 @@ namespace Rich::Future::DAQ {
       if ( parent->msgLevel( MSG::DEBUG ) ) {
         parent->debug() << "PDMDBDecodeMapping::addConditionDerivation : Key=" << key << endmsg;
       }
-      // Note - With DD4HEP these will be different
-      std::array<std::string, 3> //
-          cond_paths{"/dd/Conditions/ReadoutConf/Rich1/PDMDB_R_DecodePixelMap",
-                     "/dd/Conditions/ReadoutConf/Rich2/PDMDB_R_DecodePixelMap",
-                     "/dd/Conditions/ReadoutConf/Rich2/PDMDB_H_DecodePixelMap"};
+      std::array<std::string, 3> cond_paths{
+#ifdef USE_DD4HEP
+          "/world/BeforeMagnetRegion/Rich1:PDMDB_R_DecodePixelMap",
+          "/world/AfterMagnetRegion/Rich2:PDMDB_R_DecodePixelMap",
+          "/world/AfterMagnetRegion/Rich2:PDMDB_H_DecodePixelMap"
+#else
+          "/dd/Conditions/ReadoutConf/Rich1/PDMDB_R_DecodePixelMap",
+          "/dd/Conditions/ReadoutConf/Rich2/PDMDB_R_DecodePixelMap",
+          "/dd/Conditions/ReadoutConf/Rich2/PDMDB_H_DecodePixelMap"
+#endif
+      };
       // NOTE: CheckData test only needed here to deal with fact
       // not all DB tags currently in use have the required mapping conditions.
       // We detect this here and just return a default uninitialised object.
       // downstream users always check if the object is initialised before using
       // the object, which is only done when the DB tags require it.
       // Once support for the old DB tags is no longer required the test can be removed.
-      if ( Gaudi::Utils::CheckData<ParamValidDataObject>()( parent->detSvc(), cond_paths[0] ) ) {
-        return parent->addConditionDerivation( std::move( cond_paths ),                        // input
-                                               std::move( key ),                               // output
-                                               [p = parent]( const ParamValidDataObject& r1Cr, //
-                                                             const ParamValidDataObject& r2Cr, //
-                                                             const ParamValidDataObject& r2Ch ) {
+#ifdef USE_DD4HEP
+      // dd4hep will always have the tag, so skip the test
+      const bool hasCond = true;
+#else
+      const bool hasCond = Gaudi::Utils::CheckData<Rich::Detector::Condition>()( parent->detSvc(), cond_paths[0] );
+#endif
+      if ( hasCond ) {
+        return parent->addConditionDerivation( std::move( cond_paths ),                             // input
+                                               std::move( key ),                                    // output
+                                               [p = parent]( const Rich::Detector::Condition& r1Cr, //
+                                                             const Rich::Detector::Condition& r2Cr, //
+                                                             const Rich::Detector::Condition& r2Ch ) {
                                                  return PDMDBDecodeMapping{DecodingConds{{&r1Cr, &r2Cr}, &r2Ch}, p};
                                                } );
       } else {
@@ -246,6 +263,6 @@ namespace Rich::Future::DAQ {
 
     /// Pointer back to parent algorithm (for messaging)
     const Gaudi::Algorithm* m_parent{nullptr};
-  };
+  }; // namespace Rich::Future::DAQ
 
 } // namespace Rich::Future::DAQ
diff --git a/Rich/RichFutureDAQ/include/RichFutureDAQ/RichPDMDBEncodeMapping.h b/Rich/RichFutureDAQ/include/RichFutureDAQ/RichPDMDBEncodeMapping.h
index b6760aebb7a..e9bc4f6cbee 100644
--- a/Rich/RichFutureDAQ/include/RichFutureDAQ/RichPDMDBEncodeMapping.h
+++ b/Rich/RichFutureDAQ/include/RichFutureDAQ/RichPDMDBEncodeMapping.h
@@ -25,8 +25,13 @@
 #include "RichDetectors/Rich1.h"
 
 // Rich Detector
+#include "RichDet/DeRichLocations.h"
+#include "RichDetectors/Condition.h"
 #include "RichDetectors/Utilities.h"
 
+// RICH Utils
+#include "RichUtils/RichDAQDefinitions.h"
+
 // STL
 #include <array>
 #include <cassert>
@@ -53,8 +58,8 @@ namespace Rich::Future::DAQ {
 
     /// Local struct to hold conditions
     struct EncodingConds {
-      DetectorArray<const ParamValidDataObject*> rTypeConds;
-      const ParamValidDataObject*                hTypeCond;
+      DetectorArray<const Rich::Detector::Condition*> rTypeConds{{}};
+      const Rich::Detector::Condition*                hTypeCond{nullptr};
     };
 
   public:
@@ -196,24 +201,35 @@ namespace Rich::Future::DAQ {
         parent->debug() << "PDMDBEncodeMapping::addConditionDerivation : Key=" << key << endmsg;
       }
       // Note - Will need to be different paths for DD4HEP
-      std::array<std::string, 3> //
-          cond_paths{"/dd/Conditions/ReadoutConf/Rich1/PDMDB_R_EncodePixelMap",
-                     "/dd/Conditions/ReadoutConf/Rich2/PDMDB_R_EncodePixelMap",
-                     "/dd/Conditions/ReadoutConf/Rich2/PDMDB_H_EncodePixelMap"};
+      std::array<std::string, 3> cond_paths{
+#ifdef USE_DD4HEP
+          "/world/BeforeMagnetRegion/Rich1:PDMDB_R_EncodePixelMap",
+          "/world/AfterMagnetRegion/Rich2:PDMDB_R_EncodePixelMap",
+          "/world/AfterMagnetRegion/Rich2:PDMDB_H_EncodePixelMap"
+#else
+          "/dd/Conditions/ReadoutConf/Rich1/PDMDB_R_EncodePixelMap",
+          "/dd/Conditions/ReadoutConf/Rich2/PDMDB_R_EncodePixelMap",
+          "/dd/Conditions/ReadoutConf/Rich2/PDMDB_H_EncodePixelMap"
+#endif
+      };
       // NOTE: CheckData test only needed here to deal with fact
       // not all DB tags currently in use have the required mapping conditions.
       // We detect this here and just return a default uninitialised object.
       // downstream users always check if the object is initialised before using
       // the object, which is only done when the DB tags require it.
       // Once support for the old DB tags is no longer required the test can be removed.
-      // Gerhard/Seb/Ben - If when you see this, if you can think of a better
-      //                   way to handle this pleae let me know ;)
-      if ( Gaudi::Utils::CheckData<ParamValidDataObject>()( parent->detSvc(), cond_paths[0] ) ) {
-        return parent->addConditionDerivation( std::move( cond_paths ),                        // input
-                                               std::move( key ),                               // output
-                                               [p = parent]( const ParamValidDataObject& r1Cr, //
-                                                             const ParamValidDataObject& r2Cr, //
-                                                             const ParamValidDataObject& r2Ch ) {
+#ifdef USE_DD4HEP
+      // dd4hep will always have the tag, so skip the test
+      const bool hasCond = true;
+#else
+      const bool hasCond = Gaudi::Utils::CheckData<Rich::Detector::Condition>()( parent->detSvc(), cond_paths[0] );
+#endif
+      if ( hasCond ) {
+        return parent->addConditionDerivation( std::move( cond_paths ),                             // input
+                                               std::move( key ),                                    // output
+                                               [p = parent]( const Rich::Detector::Condition& r1Cr, //
+                                                             const Rich::Detector::Condition& r2Cr, //
+                                                             const Rich::Detector::Condition& r2Ch ) {
                                                  return PDMDBEncodeMapping{EncodingConds{{&r1Cr, &r2Cr}, &r2Ch}, p};
                                                } );
       } else {
diff --git a/Rich/RichFutureDAQ/include/RichFutureDAQ/RichTel40CableMapping.h b/Rich/RichFutureDAQ/include/RichFutureDAQ/RichTel40CableMapping.h
index fe3ffb59aa5..cd9b0bf2524 100644
--- a/Rich/RichFutureDAQ/include/RichFutureDAQ/RichTel40CableMapping.h
+++ b/Rich/RichFutureDAQ/include/RichFutureDAQ/RichTel40CableMapping.h
@@ -32,6 +32,8 @@
 #include "RichDetectors/Rich1.h"
 
 // Rich Detector
+#include "RichDet/DeRichLocations.h"
+#include "RichDetectors/Condition.h"
 #include "RichDetectors/Utilities.h"
 
 namespace Gaudi {
@@ -58,7 +60,7 @@ namespace Rich::Future::DAQ {
 
   public:
     /// Local struct to hold conditions
-    using Conds = std::array<const ParamValidDataObject*, Rich::NTotalPDPanels>;
+    using Conds = std::array<const Rich::Detector::Condition*, Rich::NTotalPDPanels>;
 
   public:
     /// Default constructor
@@ -233,6 +235,21 @@ namespace Rich::Future::DAQ {
     inline static const std::string DefaultConditionKey =
         DeRichLocations::derivedCondition( "Tel40CableMapping-Handler" );
 
+    /// paths to the various mapping conditions for each RICH/panel
+    inline static const std::array<std::string, Rich::NTotalPDPanels> ConditionPaths{
+#ifdef USE_DD4HEP
+        "/world/BeforeMagnetRegion/Rich1:R1U_Tel40CablingMap", //
+        "/world/BeforeMagnetRegion/Rich1:R1D_Tel40CablingMap", //
+        "/world/AfterMagnetRegion/Rich2:R2A_Tel40CablingMap",  //
+        "/world/AfterMagnetRegion/Rich2:R2C_Tel40CablingMap"
+#else
+        "/dd/Conditions/ReadoutConf/Rich1/R1U_Tel40CablingMap", //
+        "/dd/Conditions/ReadoutConf/Rich1/R1D_Tel40CablingMap", //
+        "/dd/Conditions/ReadoutConf/Rich2/R2A_Tel40CablingMap", //
+        "/dd/Conditions/ReadoutConf/Rich2/R2C_Tel40CablingMap"
+#endif
+    };
+
     /// Creates a condition derivation
     template <typename PARENT>
     static auto addConditionDerivation( PARENT* parent ) {
@@ -246,25 +263,25 @@ namespace Rich::Future::DAQ {
       if ( parent->msgLevel( MSG::DEBUG ) ) {
         parent->debug() << "Tel40CableMapping::addConditionDerivation : Key=" << key << endmsg;
       }
-      // Note - Will need to be different paths for DD4HEP
-      std::array<std::string, Rich::NTotalPDPanels> //
-          cond_paths{"/dd/Conditions/ReadoutConf/Rich1/R1U_Tel40CablingMap",
-                     "/dd/Conditions/ReadoutConf/Rich1/R1D_Tel40CablingMap",
-                     "/dd/Conditions/ReadoutConf/Rich2/R2A_Tel40CablingMap",
-                     "/dd/Conditions/ReadoutConf/Rich2/R2C_Tel40CablingMap"};
       // NOTE: CheckData test only needed here to deal with fact
       // not all DB tags currently in use have the required mapping conditions.
       // We detect this here and just return a default uninitialised object.
       // downstream users always check if the object is initialised before using
       // the object, which is only done when the DB tags require it.
       // Once support for the old DB tags is no longer required the test can be removed.
-      if ( Gaudi::Utils::CheckData<ParamValidDataObject>()( parent->detSvc(), cond_paths[0] ) ) {
-        return parent->addConditionDerivation( std::move( cond_paths ),                       //
-                                               std::move( key ),                              // output
-                                               [p = parent]( const ParamValidDataObject& r1U, //
-                                                             const ParamValidDataObject& r1D, //
-                                                             const ParamValidDataObject& r2A, //
-                                                             const ParamValidDataObject& r2C ) {
+#ifdef USE_DD4HEP
+      // dd4hep will always have the tag, so skip the test
+      const bool hasCond = true;
+#else
+      const bool hasCond = Gaudi::Utils::CheckData<Rich::Detector::Condition>()( parent->detSvc(), ConditionPaths[0] );
+#endif
+      if ( hasCond ) {
+        return parent->addConditionDerivation( ConditionPaths,                                     //
+                                               std::move( key ),                                   // output
+                                               [p = parent]( const Rich::Detector::Condition& r1U, //
+                                                             const Rich::Detector::Condition& r1D, //
+                                                             const Rich::Detector::Condition& r2A, //
+                                                             const Rich::Detector::Condition& r2C ) {
                                                  return Tel40CableMapping{Conds{&r1U, &r1D, &r2A, &r2C}, p};
                                                } );
       } else {
diff --git a/Rich/RichFutureDAQ/src/lib/RichPDMDBDecodeMapping.cpp b/Rich/RichFutureDAQ/src/lib/RichPDMDBDecodeMapping.cpp
index 79efc2c62a0..9a4567c2c33 100644
--- a/Rich/RichFutureDAQ/src/lib/RichPDMDBDecodeMapping.cpp
+++ b/Rich/RichFutureDAQ/src/lib/RichPDMDBDecodeMapping.cpp
@@ -27,13 +27,15 @@
 #define verbo( ... )                                                                                                   \
   if ( messenger() ) { ri_verbo( __VA_ARGS__ ); }
 
+// STL
+#include <vector>
+
 using namespace Rich::Future::DAQ;
 using namespace Rich::DAQ;
+using namespace Rich::Detector;
 
 bool PDMDBDecodeMapping::fillRType( const DecodingConds& C ) {
 
-  using namespace Rich::DAQ;
-
   bool OK = true;
 
   // Loop over RICHes
@@ -43,15 +45,15 @@ bool PDMDBDecodeMapping::fillRType( const DecodingConds& C ) {
     const auto cond = C.rTypeConds[rich];
 
     // load the active PDBDBs
-    const auto activePDMDBs = cond->paramVect<int>( "ActivePDMDBs" );
+    const auto activePDMDBs = condition_param<std::vector<int>>( cond, "ActivePDMDBs" );
     debug( " -> Found ", activePDMDBs.size(), " active R-type PDMDBs for ", rich, endmsg );
-
+ 
     // Loop over active PDMDBs
     for ( const auto pdmdb : activePDMDBs ) {
       const auto pdmdbS = "PDMDB" + std::to_string( pdmdb ) + "R";
 
       // load the active Frames
-      const auto activeFrames = cond->paramVect<int>( pdmdbS + "_ActiveFrames" );
+      const auto activeFrames = condition_param<std::vector<int>>( cond, pdmdbS + "_ActiveFrames" );
       verbo( "  -> ", pdmdbS, " active frames ", activeFrames, endmsg );
 
       // loop over active frames
@@ -60,9 +62,12 @@ bool PDMDBDecodeMapping::fillRType( const DecodingConds& C ) {
 
         // load ECs, PMTs and Anodes data
         const std::string pA = pdmdbS + "_" + frameS;
-        const auto ECs       = Rich::toArray<ElementaryCell::Type, BitsPerFrame>( cond->paramVect<int>( pA + "_ECs" ) );
-        const auto PMTs      = Rich::toArray<PMTInEC::Type, BitsPerFrame>( cond->paramVect<int>( pA + "_PMTs" ) );
-        const auto Anodes    = Rich::toArray<AnodeIndex::Type, BitsPerFrame>( cond->paramVect<int>( pA + "_Anodes" ) );
+        const auto        ECs =
+            Rich::toArray<ElementaryCell::Type, BitsPerFrame>( condition_param<std::vector<int>>( cond, pA + "_ECs" ) );
+        const auto PMTs =
+            Rich::toArray<PMTInEC::Type, BitsPerFrame>( condition_param<std::vector<int>>( cond, pA + "_PMTs" ) );
+        const auto Anodes =
+            Rich::toArray<AnodeIndex::Type, BitsPerFrame>( condition_param<std::vector<int>>( cond, pA + "_Anodes" ) );
 
         verbo( "   -> ", frameS, endmsg );
 
@@ -94,15 +99,13 @@ bool PDMDBDecodeMapping::fillRType( const DecodingConds& C ) {
 
 bool PDMDBDecodeMapping::fillHType( const DecodingConds& C ) {
 
-  using namespace Rich::DAQ;
-
   bool OK = true;
 
   // load condition
   const auto cond = C.hTypeCond;
 
   // load the active PDBDBs
-  const auto activePDMDBs = cond->paramVect<int>( "ActivePDMDBs" );
+  const auto activePDMDBs = condition_param<std::vector<int>>( cond, "ActivePDMDBs" );
   debug( " -> Found ", activePDMDBs.size(), " active H-type PDMDBs", endmsg );
 
   // Loop over active PDMDBs
@@ -110,7 +113,7 @@ bool PDMDBDecodeMapping::fillHType( const DecodingConds& C ) {
     const auto pdmdbS = "PDMDB" + std::to_string( pdmdb ) + "H";
 
     // load the active Frames
-    const auto activeFrames = cond->paramVect<int>( pdmdbS + "_ActiveFrames" );
+    const auto activeFrames = condition_param<std::vector<int>>( cond, pdmdbS + "_ActiveFrames" );
     verbo( "  -> ", pdmdbS, " active frames ", activeFrames, endmsg );
 
     // loop over active frames
@@ -118,10 +121,13 @@ bool PDMDBDecodeMapping::fillHType( const DecodingConds& C ) {
       const auto frameS = "Frame" + std::to_string( frame );
 
       // load ECs, PMTs and Anodes data
-      const std::string pA   = pdmdbS + "_" + frameS;
-      const auto        ECs  = Rich::toArray<ElementaryCell::Type, BitsPerFrame>( cond->paramVect<int>( pA + "_ECs" ) );
-      const auto        PMTs = Rich::toArray<PMTInEC::Type, BitsPerFrame>( cond->paramVect<int>( pA + "_PMTs" ) );
-      const auto Anodes      = Rich::toArray<AnodeIndex::Type, BitsPerFrame>( cond->paramVect<int>( pA + "_Anodes" ) );
+      const std::string pA = pdmdbS + "_" + frameS;
+      const auto        ECs =
+          Rich::toArray<ElementaryCell::Type, BitsPerFrame>( condition_param<std::vector<int>>( cond, pA + "_ECs" ) );
+      const auto PMTs =
+          Rich::toArray<PMTInEC::Type, BitsPerFrame>( condition_param<std::vector<int>>( cond, pA + "_PMTs" ) );
+      const auto Anodes =
+          Rich::toArray<AnodeIndex::Type, BitsPerFrame>( condition_param<std::vector<int>>( cond, pA + "_Anodes" ) );
 
       verbo( "   -> ", frameS, endmsg );
 
diff --git a/Rich/RichFutureDAQ/src/lib/RichPDMDBEncodeMapping.cpp b/Rich/RichFutureDAQ/src/lib/RichPDMDBEncodeMapping.cpp
index 875a05a9192..5c42229ed1e 100644
--- a/Rich/RichFutureDAQ/src/lib/RichPDMDBEncodeMapping.cpp
+++ b/Rich/RichFutureDAQ/src/lib/RichPDMDBEncodeMapping.cpp
@@ -27,7 +27,11 @@
 #define verbo( ... )                                                                                                   \
   if ( messenger() ) { ri_verbo( __VA_ARGS__ ); }
 
+// STL
+#include <vector>
+
 using namespace Rich::Future::DAQ;
+using namespace Rich::Detector;
 
 bool PDMDBEncodeMapping::fillRType( const EncodingConds& C ) {
 
@@ -42,7 +46,7 @@ bool PDMDBEncodeMapping::fillRType( const EncodingConds& C ) {
     const auto cond = C.rTypeConds[rich];
 
     // get the active ECs
-    const auto active_ecs = cond->paramVect<int>( "ActiveECs" );
+    const auto active_ecs = condition_param<std::vector<int>>( cond, "ActiveECs" );
     debug( " -> Found ", active_ecs.size(), " active ECs", endmsg );
 
     // Loop over active ECs
@@ -50,7 +54,7 @@ bool PDMDBEncodeMapping::fillRType( const EncodingConds& C ) {
 
       // Load the active PMTs for this EC
       const auto ecS         = "EC" + std::to_string( ec ) + "_";
-      const auto active_pmts = cond->paramVect<int>( ecS + "ActivePMTs" );
+      const auto active_pmts = condition_param<std::vector<int>>( cond, ecS + "ActivePMTs" );
       debug( "  -> Loading ", active_pmts.size(), "ActivePMTs ", endmsg );
 
       // data shortcuts
@@ -64,10 +68,13 @@ bool PDMDBEncodeMapping::fillRType( const EncodingConds& C ) {
         verbo( "   -> PMT ", pmt, endmsg );
 
         // Load the PMT data
-        const std::string pmtS   = ecS + "PMT" + std::to_string( pmt ) + "_";
-        const auto        pdmdbs = Rich::toArray<PDMDBID::Type, NumAnodes>( cond->paramVect<int>( pmtS + "PDMDB" ) );
-        const auto        frames = Rich::toArray<PDMDBFrame::Type, NumAnodes>( cond->paramVect<int>( pmtS + "Frame" ) );
-        const auto        bits = Rich::toArray<FrameBitIndex::Type, NumAnodes>( cond->paramVect<int>( pmtS + "Bit" ) );
+        const std::string pmtS = ecS + "PMT" + std::to_string( pmt ) + "_";
+        const auto        pdmdbs =
+            Rich::toArray<PDMDBID::Type, NumAnodes>( condition_param<std::vector<int>>( cond, pmtS + "PDMDB" ) );
+        const auto frames =
+            Rich::toArray<PDMDBFrame::Type, NumAnodes>( condition_param<std::vector<int>>( cond, pmtS + "Frame" ) );
+        const auto bits =
+            Rich::toArray<FrameBitIndex::Type, NumAnodes>( condition_param<std::vector<int>>( cond, pmtS + "Bit" ) );
 
         // Fill data structure for each anode
         assert( (std::size_t)pmt < ec_data.size() );
@@ -100,7 +107,7 @@ bool PDMDBEncodeMapping::fillHType( const EncodingConds& C ) {
   const auto cond = C.hTypeCond;
 
   // get the active ECs
-  const auto active_ecs = cond->paramVect<int>( "ActiveECs" );
+  const auto active_ecs = condition_param<std::vector<int>>( cond, "ActiveECs" );
   debug( " -> Found ", active_ecs.size(), " active ECs", endmsg );
 
   // Loop over active ECs
@@ -108,7 +115,7 @@ bool PDMDBEncodeMapping::fillHType( const EncodingConds& C ) {
 
     // Load the active PMTs for this EC
     const auto ecS         = "EC" + std::to_string( ec ) + "_";
-    const auto active_pmts = cond->paramVect<int>( ecS + "ActivePMTs" );
+    const auto active_pmts = condition_param<std::vector<int>>( cond, ecS + "ActivePMTs" );
     debug( "  -> Loading ", active_pmts.size(), "ActivePMTs ", endmsg );
 
     // data shortcuts
@@ -120,10 +127,13 @@ bool PDMDBEncodeMapping::fillHType( const EncodingConds& C ) {
       verbo( "   -> PMT ", pmt, endmsg );
 
       // Load the PMT data
-      const std::string pmtS   = ecS + "PMT" + std::to_string( pmt ) + "_";
-      const auto        pdmdbs = Rich::toArray<PDMDBID::Type, NumAnodes>( cond->paramVect<int>( pmtS + "PDMDB" ) );
-      const auto        frames = Rich::toArray<PDMDBFrame::Type, NumAnodes>( cond->paramVect<int>( pmtS + "Frame" ) );
-      const auto        bits   = Rich::toArray<FrameBitIndex::Type, NumAnodes>( cond->paramVect<int>( pmtS + "Bit" ) );
+      const std::string pmtS = ecS + "PMT" + std::to_string( pmt ) + "_";
+      const auto        pdmdbs =
+          Rich::toArray<PDMDBID::Type, NumAnodes>( condition_param<std::vector<int>>( cond, pmtS + "PDMDB" ) );
+      const auto frames =
+          Rich::toArray<PDMDBFrame::Type, NumAnodes>( condition_param<std::vector<int>>( cond, pmtS + "Frame" ) );
+      const auto bits =
+          Rich::toArray<FrameBitIndex::Type, NumAnodes>( condition_param<std::vector<int>>( cond, pmtS + "Bit" ) );
 
       // Fill data structure for each anode
       assert( (std::size_t)pmt < ec_data.size() );
diff --git a/Rich/RichFutureDAQ/src/lib/RichTel40CableMapping.cpp b/Rich/RichFutureDAQ/src/lib/RichTel40CableMapping.cpp
index 422ce70371b..c5a2c82b8c3 100644
--- a/Rich/RichFutureDAQ/src/lib/RichTel40CableMapping.cpp
+++ b/Rich/RichFutureDAQ/src/lib/RichTel40CableMapping.cpp
@@ -23,6 +23,8 @@
 // STL
 #include <algorithm>
 #include <limits>
+#include <string>
+#include <vector>
 
 // Messaging
 #include "RichFutureUtils/RichMessaging.h"
@@ -32,6 +34,7 @@
   if ( messenger() ) { ri_verbo( __VA_ARGS__ ); }
 
 using namespace Rich::Future::DAQ;
+using namespace Rich::Detector;
 
 bool Tel40CableMapping::fillCableMaps( const Conds& C ) {
 
@@ -42,23 +45,23 @@ bool Tel40CableMapping::fillCableMaps( const Conds& C ) {
 
   const auto rich_types  = std::array{Rich::Rich1, Rich::Rich1, Rich::Rich2, Rich::Rich2};
   const auto panel_types = std::array{Rich::top, Rich::bottom, Rich::aside, Rich::cside};
-  for ( const auto&& [cond, rich, panel] : Ranges::ConstZip( C, rich_types, panel_types ) ) {
+  for ( const auto&& [cond, rich, panel, name] : Ranges::ConstZip( C, rich_types, panel_types, ConditionPaths ) ) {
 
     // Number of links for this RICH panel
-    const std::size_t nLinks = cond->param<int>( "NumberOfLinks" );
+    const std::size_t nLinks = condition_param<int>( cond, "NumberOfLinks" );
     if ( nLinks > 0 ) {
       debug( " -> Found ", nLinks, " links for ", rich, " ", Rich::text( rich, panel ), endmsg );
 
       // Load links data
-      const auto pmtTypes   = cond->paramVect<std::string>( "PMTTypes" );
-      const auto modNames   = cond->paramVect<std::string>( "ModuleNames" );
-      const auto modNums    = cond->paramVect<int>( "ModuleNumbers" );
-      const auto pdmdbs     = cond->paramVect<int>( "PDMDBNumbers" );
-      const auto pdmdbLinks = cond->paramVect<int>( "PDMDBLinks" );
-      const auto sourceIDs  = cond->paramVect<int>( "Tel40SourceIDs" );
-      const auto connectors = cond->paramVect<int>( "Tel40SConnectors" );
-      const auto mpos       = cond->paramVect<int>( "Tel40MPOs" );
-      const auto statuses   = cond->paramVect<int>( "Tel40LinkIsActive" );
+      const auto pmtTypes   = condition_param<std::vector<std::string>>( cond, "PMTTypes" );
+      const auto modNames   = condition_param<std::vector<std::string>>( cond, "ModuleNames" );
+      const auto modNums    = condition_param<std::vector<int>>( cond, "ModuleNumbers" );
+      const auto pdmdbs     = condition_param<std::vector<int>>( cond, "PDMDBNumbers" );
+      const auto pdmdbLinks = condition_param<std::vector<int>>( cond, "PDMDBLinks" );
+      const auto sourceIDs  = condition_param<std::vector<int>>( cond, "Tel40SourceIDs" );
+      const auto connectors = condition_param<std::vector<int>>( cond, "Tel40SConnectors" );
+      const auto mpos       = condition_param<std::vector<int>>( cond, "Tel40MPOs" );
+      const auto statuses   = condition_param<std::vector<int>>( cond, "Tel40LinkIsActive" );
       // sanity size check
       if ( nLinks != pmtTypes.size() ||   //
            nLinks != modNames.size() ||   //
@@ -70,7 +73,7 @@ bool Tel40CableMapping::fillCableMaps( const Conds& C ) {
            nLinks != mpos.size() ||       //
            nLinks != statuses.size() ) {
         ok = false;
-        throw Rich::Exception( "Inconsistent data sizes for " + cond->name() );
+        throw Rich::Exception( "Inconsistent data sizes for '" + name + "'" );
       }
 
       // Find Max SourceID for this RICH/Side
-- 
GitLab