diff --git a/Det/RichDet/include/RichDet/DeRichPDPanel.h b/Det/RichDet/include/RichDet/DeRichPDPanel.h
index 1875601a79edf471020fa8976ce2f77f46ed3c63..e6aa3087721a0d1a62761baabd51ef95ac6b9dd8 100644
--- a/Det/RichDet/include/RichDet/DeRichPDPanel.h
+++ b/Det/RichDet/include/RichDet/DeRichPDPanel.h
@@ -165,6 +165,9 @@ public:
    */
   virtual const DeRichPD* dePD( const LHCb::RichSmartID pdID ) const = 0;
 
+  /// Access the PDs in the panel
+  inline decltype( auto ) dePDs() const { return m_allPDs; }
+
   /** @brief Returns the intersection point with an HPD window given a vector
    *  and a point (scalar)
    *
@@ -316,6 +319,9 @@ protected:
 
   Rich::SIMD::Transform3D<Rich::SIMD::DefaultScalarFP> m_globalToPDPanelTransformSIMD;
 
+  /// All the PDs in thi panel
+  std::vector<DeRichPD*> m_allPDs;
+
 private:
   // data
 
diff --git a/Det/RichDet/src/Lib/DeRichHPDPanel.cpp b/Det/RichDet/src/Lib/DeRichHPDPanel.cpp
index 4e3d41040c2022170e9452326285ba77cdbc131c..6a0222dda5dbdf0933932d3a6a72f3f9bd6a23c3 100644
--- a/Det/RichDet/src/Lib/DeRichHPDPanel.cpp
+++ b/Det/RichDet/src/Lib/DeRichHPDPanel.cpp
@@ -76,6 +76,7 @@ StatusCode DeRichHPDPanel::initialize() {
 
   // get the HPD and SiSensor detector elements
   m_DeHPDs.clear();
+  m_allPDs.clear();
   m_DeSiSensors.clear();
   for ( const auto* detelem : childIDetectorElements() ) {
     if ( std::string::npos != detelem->name().find( "HPD:" ) ) {
@@ -89,6 +90,7 @@ StatusCode DeRichHPDPanel::initialize() {
 
       // save to list of HPDs
       m_DeHPDs.push_back( deHPD );
+      m_allPDs.push_back( deHPD );
 
       // register UMS dependency
       updMgrSvc()->registerCondition( this, deHPD->geometry(), &DeRichHPDPanel::geometryUpdate );
diff --git a/Det/RichDet/src/Lib/DeRichPMTPanel.cpp b/Det/RichDet/src/Lib/DeRichPMTPanel.cpp
index 43ddfa7c219d29da2544bbd69261346ee0cc547b..fbfd416b0644f6716ad09f5d59392ee4f6319510 100644
--- a/Det/RichDet/src/Lib/DeRichPMTPanel.cpp
+++ b/Det/RichDet/src/Lib/DeRichPMTPanel.cpp
@@ -105,6 +105,7 @@ StatusCode DeRichPMTPanel::geometryUpdate() {
 
   // get the pmtmodule and pmt detector elements
   m_DePMTs.clear();
+  m_allPDs.clear();
   m_DePMTModules.clear();
   m_DePMTAnodes.clear();
   m_DePMTModulesZeroPtn.clear();
@@ -345,6 +346,8 @@ StatusCode DeRichPMTPanel::geometryUpdate() {
   for ( const auto& m : m_DePMTs ) {
     for ( const auto& pd : m ) {
       if ( pd ) {
+        // save pointer to all flat vector
+        m_allPDs.push_back( pd );
         // smartID for this PD
         const auto pdID = pd->pdSmartID();
         // test method to get dePD from smartID
diff --git a/Det/RichDet/src/Lib/DeRichPMTPanelClassic.cpp b/Det/RichDet/src/Lib/DeRichPMTPanelClassic.cpp
index fc6cd0cea1633b79d3499725be43e11b0be4396e..47bb2d131e1f9af3ae580a8f1c6c5e60e8dbca0d 100644
--- a/Det/RichDet/src/Lib/DeRichPMTPanelClassic.cpp
+++ b/Det/RichDet/src/Lib/DeRichPMTPanelClassic.cpp
@@ -106,6 +106,7 @@ StatusCode DeRichPMTPanelClassic::geometryUpdate() {
 
   // get the pmtmodule and pmt detector elements
   m_DePMTs.clear();
+  m_allPDs.clear();
   m_DePMTModules.clear();
   m_DePMTAnodes.clear();
   m_DePMTModulesZeroPtn.clear();
@@ -197,6 +198,7 @@ StatusCode DeRichPMTPanelClassic::geometryUpdate() {
               }
 
               DePmtsInCurModule[curPmtNum] = dePMT;
+              m_allPDs.push_back( dePMT );
 
               if ( !dePMT->childIDetectorElements().empty() ) {
                 for ( auto det_it_pm_an = dePMT->childIDetectorElements().begin();
diff --git a/Kernel/LHCbKernel/include/Kernel/RichRadIntersection.h b/Kernel/LHCbKernel/include/Kernel/RichRadIntersection.h
index fece0703614999f3f27ede8a1fe26087abc5acc3..8e897c7aeeabed8dd2e7b25b1c4ae9f78bbacec0 100644
--- a/Kernel/LHCbKernel/include/Kernel/RichRadIntersection.h
+++ b/Kernel/LHCbKernel/include/Kernel/RichRadIntersection.h
@@ -23,6 +23,7 @@
 
 // STL
 #include <algorithm>
+#include <any>
 #include <cmath>
 #include <functional>
 #include <utility>
@@ -35,9 +36,6 @@
 #include <boost/container/small_vector.hpp>
 #include <boost/version.hpp>
 
-// DetDesc
-class DeRichRadiator;
-
 namespace Rich {
 
   /** @class RadIntersection RichRadIntersection.h Kernel/RichRadIntersection.h
@@ -87,12 +85,13 @@ namespace Rich {
 
   public:
     /// Constructor from (copied) entry and exit points and momentum vectors, and a pointer to a
-    /// DeRichRadiator
-    RadIntersection( Gaudi::XYZPoint       entryPoint, ///< The radiator entry point
-                     Gaudi::XYZVector      entryVect,  ///< The direction vector at the entry point
-                     Gaudi::XYZPoint       exitPoint,  ///< The radiator exit point
-                     Gaudi::XYZVector      exitVect,   ///< The direction vector at the exit point
-                     const DeRichRadiator* rad         ///< Pointer to the intersected radiator volume
+    /// radiator object
+    template <typename RADIATOR>
+    RadIntersection( Gaudi::XYZPoint  entryPoint, ///< The radiator entry point
+                     Gaudi::XYZVector entryVect,  ///< The direction vector at the entry point
+                     Gaudi::XYZPoint  exitPoint,  ///< The radiator exit point
+                     Gaudi::XYZVector exitVect,   ///< The direction vector at the exit point
+                     const RADIATOR*  rad         ///< Pointer to the intersected radiator volume
                      )
         : m_entryPoint( std::move( entryPoint ) )
         , m_entryVect( std::move( entryVect ) )
@@ -101,12 +100,13 @@ namespace Rich {
         , m_radiator( rad ) {}
 
     /// Constructor from (moved) entry and exit points and momentum vectors, and a pointer to a
-    /// DeRichRadiator
-    RadIntersection( Gaudi::XYZPoint&&     entryPoint, ///< The radiator entry point
-                     Gaudi::XYZVector&&    entryVect,  ///< The direction vector at the entry point
-                     Gaudi::XYZPoint&&     exitPoint,  ///< The radiator exit point
-                     Gaudi::XYZVector&&    exitVect,   ///< The direction vector at the exit point
-                     const DeRichRadiator* rad         ///< Pointer to the intersected radiator volume
+    /// radiator object
+    template <typename RADIATOR>
+    RadIntersection( Gaudi::XYZPoint&&  entryPoint, ///< The radiator entry point
+                     Gaudi::XYZVector&& entryVect,  ///< The direction vector at the entry point
+                     Gaudi::XYZPoint&&  exitPoint,  ///< The radiator exit point
+                     Gaudi::XYZVector&& exitVect,   ///< The direction vector at the exit point
+                     const RADIATOR*    rad         ///< Pointer to the intersected radiator volume
                      )
         : m_entryPoint( std::move( entryPoint ) )
         , m_entryVect( std::move( entryVect ) )
@@ -140,10 +140,16 @@ namespace Rich {
     [[nodiscard]] inline const Gaudi::XYZVector& exitMomentum() const noexcept { return m_exitVect; }
 
     /// Set pointer to associated radiator detector element
-    inline void setRadiator( const DeRichRadiator* radiator ) noexcept { m_radiator = radiator; }
+    template <typename RADIATOR>
+    inline void setRadiator( const RADIATOR* radiator ) noexcept {
+      m_radiator = radiator;
+    }
 
-    /// Get pointer to associated radiator detector element
-    [[nodiscard]] inline const DeRichRadiator* radiator() const noexcept { return m_radiator; }
+    /// Get pointer to associated radiator detector element as given type
+    template <typename RADIATOR>
+    [[nodiscard]] inline decltype( auto ) radiator() const noexcept {
+      return std::any_cast<const RADIATOR*>( m_radiator );
+    }
 
     /// Returns the path length (squared) in the given radiator
     [[nodiscard]] inline double pathLength2() const { return ( exitPoint() - entryPoint() ).Mag2(); }
@@ -154,7 +160,6 @@ namespace Rich {
     /// Overload output to ostream
     friend inline std::ostream& operator<<( std::ostream& os, const Rich::RadIntersection& intersect ) {
       os << "["
-         //<< " " << intersect.radiator()->radiatorID()
          << " Entry: Point=" << intersect.entryPoint() << " Dir=" << intersect.entryMomentum()
          << " Exit: Point=" << intersect.exitPoint() << " Dir=" << intersect.exitMomentum() << " ]";
       return os;
@@ -173,8 +178,11 @@ namespace Rich {
     /// Momentum (direction) vector at the entry point
     Gaudi::XYZVector m_exitVect;
 
-    /// pointer to DeRichRadiator for this radiator
-    const DeRichRadiator* m_radiator = nullptr;
+    /** pointer to radiator detector
+     *  NOTE: As long as we need to support DD4Hep and the old RichDet
+     *        use void* here to allow storing either type.
+     *        to be replaced with Detectors::Radiator once RichDet is fully dropped */
+    std::any m_radiator;
 
   public:
     /** @class Sorter RichRadIntersection.h Kernel/RichRadIntersection.h
diff --git a/Kernel/LHCbKernel/include/Kernel/RichSmartID.h b/Kernel/LHCbKernel/include/Kernel/RichSmartID.h
index 203ce79f2ffe239b0e3c5c0ad51999519ef4a6f9..3e99d80590f24aadb4ea2f5c5cf6c0103ae01067 100644
--- a/Kernel/LHCbKernel/include/Kernel/RichSmartID.h
+++ b/Kernel/LHCbKernel/include/Kernel/RichSmartID.h
@@ -1,5 +1,5 @@
 /*****************************************************************************\
-* (c) Copyright 2000-2018 CERN for the benefit of the LHCb Collaboration      *
+* (c) Copyright 2000-2022 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".   *
@@ -261,6 +261,11 @@ namespace LHCb {
       static constexpr const DataType MaxModuleColumnsAnyPanel = 13;
       /// Number of modules per panel, in each RICH
       static constexpr const Rich::DetectorArray<DataType> ModulesPerPanel = {{66, 72}};
+      /** Maximum number of modules in any panel
+       *  @todo Should be 72 (as above), but to retain support for 'classic' PMTs need to
+       *  set to 92 to cover fact the old numbering scheme had more modules.
+       *  To be changed back once support for the 'classic' PMTs is no longer required. */
+      static constexpr const DataType MaxModulesPerPanel = 92;
       /// Module 'global' number offsets for each RICH and Panel
       static constexpr const Rich::DetectorArray<Rich::PanelArray<DataType>> PanelModuleOffsets = {
           {{0, 66}, {132, 204}}};
diff --git a/Kernel/MCInterfaces/dict/MCInterfacesDict.h b/Kernel/MCInterfaces/dict/MCInterfacesDict.h
index e480d9ed7952b2f708cb0bfda0c0ffd8501b4e61..83f5116664d4ddab281c0480bfda482078517b95 100755
--- a/Kernel/MCInterfaces/dict/MCInterfacesDict.h
+++ b/Kernel/MCInterfaces/dict/MCInterfacesDict.h
@@ -12,7 +12,6 @@
 #define DICT_MCINTERFACESDICT_H 1
 
 // Previously in RichKernel
-#include "MCInterfaces/IRichMCTrackInfoTool.h"
 #include "MCInterfaces/IRichMCTruthTool.h"
 
 // Previously in TrackMCInterfaces
diff --git a/Kernel/MCInterfaces/dict/MCInterfacesDict.xml b/Kernel/MCInterfaces/dict/MCInterfacesDict.xml
index 7a0f9d3e24b6d6aed381770515ea7966a3663dda..59f33bf6b4c5b645076f37b4cf7f14ad927ee91e 100755
--- a/Kernel/MCInterfaces/dict/MCInterfacesDict.xml
+++ b/Kernel/MCInterfaces/dict/MCInterfacesDict.xml
@@ -21,7 +21,6 @@
   <class name = "IMCReconstructible"          />
   <class name = "IMuonPad2MCTool"             />
   <class name = "IPrintMCDecayTreeTool"       />
-  <class name = "Rich::MC::IMCTrackInfoTool"  />
   <class name = "Rich::MC::IMCTruthTool"      />
   <class name = "ISiDepositedCharge"          />
   <class name = "ITrackGhostClassification"   />
diff --git a/Kernel/MCInterfaces/include/MCInterfaces/IRichMCTrackInfoTool.h b/Kernel/MCInterfaces/include/MCInterfaces/IRichMCTrackInfoTool.h
deleted file mode 100644
index 8715b6f269b9ad2e534b515e853797986abd9f95..0000000000000000000000000000000000000000
--- a/Kernel/MCInterfaces/include/MCInterfaces/IRichMCTrackInfoTool.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*****************************************************************************\
-* (c) Copyright 2000-2018 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.                                       *
-\*****************************************************************************/
-/** @file IRichMCTrackInfoTool.h
- *
- *  Header file for tool interface : Rich::IMCTrackInfoTool
- *
- *  CVS Log :-
- *
- *  @author Chris Jones   Christopher.Rob.Jones@cern.ch
- *  @date   15/03/2002
- */
-
-#ifndef RICHKERNEL_IRICHMCTRACKINFOTOOL_H
-#define RICHKERNEL_IRICHMCTRACKINFOTOOL_H 1
-
-// from Gaudi
-#include "GaudiKernel/IAlgTool.h"
-#include "GaudiKernel/Point3DTypes.h"
-
-// Event Model
-namespace LHCb {
-  class MCRichSegment;
-}
-
-namespace Rich {
-  namespace MC {
-
-    /** @class IMCTrackInfoTool IRichMCTrackInfoTool.h
-     *
-     *  Interface to tool providing tracking extrapolation information from
-     *  RICH Monte Carlo data objects
-     *
-     *  @author Chris Jones   Christopher.Rob.Jones@cern.ch
-     *  @date   15/03/2002
-     */
-
-    struct IMCTrackInfoTool : extend_interfaces<IAlgTool> {
-
-      /** static interface identification
-       *  @return unique interface identifier
-       */
-      DeclareInterfaceID( IMCTrackInfoTool, 2, 0 );
-
-      /** Takes the direction information from a MCRichSegment and ray traces it through the
-       *  appropriate RICH optical system and computes the intersect points with the HPD
-       *  panel in LHCb global coordinates.
-       *
-       *  @param segment  Pointer to an MCRichSegment
-       *  @param hitPoint Ray traced hit position on HPD panel in global LHCb coordinates
-       *
-       *  @return boolean indicating if the intersection was successful
-       *  @retval true   intersection was successful, returned hitPoint is valid
-       *  @retval false  intersection was unsuccessful, returned hitPoint is not valid
-       */
-      virtual bool panelIntersectGlobal( const LHCb::MCRichSegment* segment, Gaudi::XYZPoint& hitPoint ) const = 0;
-
-      /** Takes the direction information from a MCRichSegment and ray traces it through the
-       *  appropriate RICH optical system and computes the intersect points with the HPD
-       *  panel in local HPD panel coordinates.
-       *
-       *  @param segment  Pointer to an MCRichSegment
-       *  @param hitPoint Ray traced hit position on HPD panel in local HPD panel coordinates
-       *
-       *  @return boolean indicating if the intersection was successful
-       *  @retval true   intersection was successful, returned hitPoint is valid
-       *  @retval false  intersection was unsuccessful, returned hitPoint is not valid
-       */
-      virtual bool panelIntersectLocal( const LHCb::MCRichSegment* segment, Gaudi::XYZPoint& hitPoint ) const = 0;
-    };
-
-  } // namespace MC
-} // namespace Rich
-
-#endif // RICHKERNEL_IRICHMCTRACKINFOTOOL_H
diff --git a/Rich/RichDetectors/CMakeLists.txt b/Rich/RichDetectors/CMakeLists.txt
index 8f10a3c3e1aee45229e6a5600b9225a58cd46ca9..b2d84ec13e86282580ff9926f18e0e12e0d98708 100644
--- a/Rich/RichDetectors/CMakeLists.txt
+++ b/Rich/RichDetectors/CMakeLists.txt
@@ -18,6 +18,8 @@ gaudi_add_library(RichDetectors
         src/Rich1.cpp
         src/Rich2.cpp
         src/RichX.cpp
+        src/RichPDInfo.cpp
+        src/RichPDPanel.cpp
     LINK
         PUBLIC
             LHCb::DetDescLib
diff --git a/Rich/RichDetectors/include/RichDetectors/Rich1.h b/Rich/RichDetectors/include/RichDetectors/Rich1.h
index bf753b847d561e9dfa955b7bbe36d86a31f6c4ea..0b13c9952658b88249e8555cdadfc32f1ee0ed76 100644
--- a/Rich/RichDetectors/include/RichDetectors/Rich1.h
+++ b/Rich/RichDetectors/include/RichDetectors/Rich1.h
@@ -29,13 +29,17 @@ namespace Rich::Detector {
    */
   //-----------------------------------------------------------------------------
 
-  class Rich1 final : public Rich::Detector::RichX {
+  class Rich1 final : public RichX {
 
   public:
     // types
 
     /// The underlying detector description object (DetDesc or DD4HEP)
+#ifdef USE_DD4HEP
+    using DetElem = DeRich1; // TODO: Change for equivalent DD4HEP class
+#else
     using DetElem = DeRich1;
+#endif
 
   public:
     /// Constructor from DetDesc Rich1
diff --git a/Rich/RichDetectors/include/RichDetectors/Rich1Gas.h b/Rich/RichDetectors/include/RichDetectors/Rich1Gas.h
new file mode 100644
index 0000000000000000000000000000000000000000..4417abe2733e91275bf7c97af9af2af179b7fac0
--- /dev/null
+++ b/Rich/RichDetectors/include/RichDetectors/Rich1Gas.h
@@ -0,0 +1,64 @@
+/*****************************************************************************\
+* (c) Copyright 2000-2022 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
+
+// Detectors
+#include "RichDetectors/RichRadiator.h"
+
+namespace Rich::Detector {
+
+  //-----------------------------------------------------------------------------
+  /** @class Rich1Gas.h
+   *
+   *  RICH1 Radiator
+   *
+   *  @author Chris Jones
+   *  @date   2021-12-07
+   */
+  //-----------------------------------------------------------------------------
+
+  class Rich1Gas : public Radiator {
+
+  public:
+    // constructors
+
+    /// Default Constructor
+    Rich1Gas() = default;
+
+    /// Constructor from Det Elem
+    Rich1Gas( const Radiator::DetElem& rad ) : Radiator( rad ) {}
+
+  public:
+    // conditions handling
+
+    /// Default conditions name
+    static constexpr const char* DefaultConditionKey = "Rich1Gas";
+
+    /// Creates a condition derivation for the given key
+    template <typename PARENT>
+    static decltype( auto )                                                       //
+    addConditionDerivation( PARENT*                     parent,                   ///< Pointer to parent algorithm
+                            LHCb::DetDesc::ConditionKey key = DefaultConditionKey ///< Derived object name
+    ) {
+      if ( parent->msgLevel( MSG::DEBUG ) ) {
+        parent->debug() << "Rich1Gas::addConditionDerivation : Key=" << key << endmsg;
+      }
+      return LHCb::DetDesc::                                           //
+          addConditionDerivation<Rich1Gas( const Radiator::DetElem& )> //
+          ( parent->conditionDerivationMgr(),                          // manager
+            {DeRichLocations::Rich1Gas},                               // input condition locations
+            std::move( key )                                           // output derived condition location
+          );
+    }
+  };
+
+} // namespace Rich::Detector
diff --git a/Rich/RichDetectors/include/RichDetectors/Rich2.h b/Rich/RichDetectors/include/RichDetectors/Rich2.h
index d651455b816e887f81be89557ac5f51397af6484..ed978af3859e51715fb68364565fd754ed01f1db 100644
--- a/Rich/RichDetectors/include/RichDetectors/Rich2.h
+++ b/Rich/RichDetectors/include/RichDetectors/Rich2.h
@@ -34,8 +34,12 @@ namespace Rich::Detector {
   public:
     // types
 
-    /// The underlying detector description object (DetDesc or DD4HEP)
+    /// The underlying detector description object
+#ifdef USE_DD4HEP
+    using DetElem = DeRich2; // TODO: Change for equivalent DD4HEP class
+#else
     using DetElem = DeRich2;
+#endif
 
   public:
     /// Constructor from DetDesc Rich2
diff --git a/Rich/RichDetectors/include/RichDetectors/Rich2Gas.h b/Rich/RichDetectors/include/RichDetectors/Rich2Gas.h
new file mode 100644
index 0000000000000000000000000000000000000000..bc3255ef89ba5ed8d7f5f6bb81ac4216ef4c4c80
--- /dev/null
+++ b/Rich/RichDetectors/include/RichDetectors/Rich2Gas.h
@@ -0,0 +1,64 @@
+/*****************************************************************************\
+* (c) Copyright 2000-2022 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
+
+// Detectors
+#include "RichDetectors/RichRadiator.h"
+
+namespace Rich::Detector {
+
+  //-----------------------------------------------------------------------------
+  /** @class Rich2Gas.h
+   *
+   *  RICH2 Radiator
+   *
+   *  @author Chris Jones
+   *  @date   2021-12-07
+   */
+  //-----------------------------------------------------------------------------
+
+  class Rich2Gas : public Radiator {
+
+  public:
+    // constructors
+
+    /// Default Constructor
+    Rich2Gas() = default;
+
+    /// Constructor from Det Elem
+    Rich2Gas( const Radiator::DetElem& rad ) : Radiator( rad ) {}
+
+  public:
+    // conditions handling
+
+    /// Default conditions name
+    static constexpr const char* DefaultConditionKey = "Rich2Gas";
+
+    /// Creates a condition derivation for the given key
+    template <typename PARENT>
+    static decltype( auto )                                                       //
+    addConditionDerivation( PARENT*                     parent,                   ///< Pointer to parent algorithm
+                            LHCb::DetDesc::ConditionKey key = DefaultConditionKey ///< Derived object name
+    ) {
+      if ( parent->msgLevel( MSG::DEBUG ) ) {
+        parent->debug() << "Rich2Gas::addConditionDerivation : Key=" << key << endmsg;
+      }
+      return LHCb::DetDesc::                                           //
+          addConditionDerivation<Rich2Gas( const Radiator::DetElem& )> //
+          ( parent->conditionDerivationMgr(),                          // manager
+            {DeRichLocations::Rich2Gas},                               // input condition locations
+            std::move( key )                                           // output derived condition location
+          );
+    }
+  };
+
+} // namespace Rich::Detector
diff --git a/Rich/RichDetectors/include/RichDetectors/RichMirror.h b/Rich/RichDetectors/include/RichDetectors/RichMirror.h
index bb4e2cd4ae852afb62bf29fbf4870a8d004c5528..4ae36e27193cf2106d11fe587a26bfa2569d904d 100644
--- a/Rich/RichDetectors/include/RichDetectors/RichMirror.h
+++ b/Rich/RichDetectors/include/RichDetectors/RichMirror.h
@@ -14,6 +14,9 @@
 // RichDet
 #include "RichDet/DeRichSphMirror.h"
 
+// local
+#include "RichDetectors/Utilities.h"
+
 namespace Rich::Detector {
 
   //-----------------------------------------------------------------------------
@@ -32,7 +35,11 @@ namespace Rich::Detector {
     // types
 
     /// The underlying detector description object (DetDesc or DD4HEP)
+#ifdef USE_DD4HEP
+    using DetElem = DeRichSphMirror; // TODO: Change for equivalent DD4HEP class
+#else
     using DetElem = DeRichSphMirror;
+#endif
 
   public:
     /// Constructor from DetDesc
@@ -46,35 +53,19 @@ namespace Rich::Detector {
     // Note for now just forward to DetDesc implementations but eventually
     // aim is to port (some?) functionality here, in preparation for (simplier) DD4HEP objects.
 
-    /// Access cached SIMD mirror data
-    inline decltype( auto ) mirrorData() const noexcept { return m_mirr->mirrorData(); }
-
-    /// Intersection method forwarding
-    template <typename... ARGS>
-    inline decltype( auto ) intersects( ARGS&&... args ) const {
-      return m_mirr->intersects( std::forward<ARGS>( args )... );
-    }
-
-    /// Mirror number
-    inline decltype( auto ) mirrorNumber() const noexcept { return m_mirr->mirrorNumber(); }
-
-    /// Retrieves the centre of curvarute of this mirror
-    inline decltype( auto ) centreOfCurvature() const noexcept { return m_mirr->centreOfCurvature(); }
-
-    /// Retrieves the centre this mirror on the reflective surface.
-    inline decltype( auto ) mirrorCentre() const noexcept { return m_mirr->mirrorCentre(); }
+    FORWARD_TO_DET_OBJ( mirrorData )
+    FORWARD_TO_DET_OBJ( intersects )
+    FORWARD_TO_DET_OBJ( mirrorNumber )
+    FORWARD_TO_DET_OBJ( centreOfCurvature )
+    FORWARD_TO_DET_OBJ( mirrorCentre )
+    FORWARD_TO_DET_OBJ( radius )
+    FORWARD_TO_DET_OBJ( centreNormal )
+    FORWARD_TO_DET_OBJ( centreNormalPlane )
+    FORWARD_TO_DET_OBJ( reflectivity )
 
-    /// Retrieves the radius of this spherical mirror
-    inline decltype( auto ) radius() const noexcept { return m_mirr->radius(); }
-
-    /// Retrieves the normal vector at the centre of the mirror
-    inline decltype( auto ) centreNormal() const noexcept { return m_mirr->centreNormal(); }
-
-    /// Retrieves the plane defined by the centre normal and the centre
-    inline decltype( auto ) centreNormalPlane() const noexcept { return m_mirr->centreNormalPlane(); }
-
-    /// Returns a pointer to the tabulated property that holds the reflectivity
-    inline decltype( auto ) reflectivity() const noexcept { return m_mirr->reflectivity(); }
+  private:
+    /// Get access to the underlying object
+    inline const DetElem* get() const noexcept { return m_mirr; }
 
   private:
     // data
diff --git a/Rich/RichDetectors/include/RichDetectors/RichPD.h b/Rich/RichDetectors/include/RichDetectors/RichPD.h
index a5ccfc92318d12a8f08baa521e05e67909b7c48e..eb16f350d2e5bef187bef6766751f14dd52334b3 100644
--- a/Rich/RichDetectors/include/RichDetectors/RichPD.h
+++ b/Rich/RichDetectors/include/RichDetectors/RichPD.h
@@ -1,5 +1,5 @@
 /*****************************************************************************\
-* (c) Copyright 2000-2020 CERN for the benefit of the LHCb Collaboration      *
+* (c) Copyright 2000-2021 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".   *
@@ -14,6 +14,9 @@
 // RichDet
 #include "RichDet/DeRichPD.h"
 
+// local
+#include "RichDetectors/Utilities.h"
+
 namespace Rich::Detector {
 
   //-----------------------------------------------------------------------------
@@ -32,7 +35,11 @@ namespace Rich::Detector {
     // types
 
     /// The underlying detector description object (DetDesc or DD4HEP)
+#ifdef USE_DD4HEP
+    using DetElem = DeRichPD; // TODO: Change for equivalent DD4HEP class
+#else
     using DetElem = DeRichPD;
+#endif
 
   public:
     /// Constructor from DetDesc
@@ -43,11 +50,15 @@ namespace Rich::Detector {
     // Note for now just forward to DetDesc implementations but eventually
     // aim is to port (some?) functionality here, in preparation for (simplier) DD4HEP objects.
 
-    /// Forward ray tracing methods to DetDesc. To be moved here...
-    template <typename... ARGS>
-    inline decltype( auto ) detectionPoint( ARGS&&... args ) const {
-      return m_pd->detectionPoint( std::forward<ARGS>( args )... );
-    }
+    FORWARD_TO_DET_OBJ( detectionPoint )
+    FORWARD_TO_DET_OBJ( effectivePixelArea )
+    FORWARD_TO_DET_OBJ( pdQuantumEff )
+    FORWARD_TO_DET_OBJ( pdSmartID )
+    FORWARD_TO_DET_OBJ( effectiveNumActivePixels )
+
+  public:
+    /// Get access to the underlying object
+    inline const DetElem* get() const noexcept { return m_pd; }
 
   private:
     // data
diff --git a/Rich/RichDetectors/include/RichDetectors/RichPDInfo.h b/Rich/RichDetectors/include/RichDetectors/RichPDInfo.h
new file mode 100644
index 0000000000000000000000000000000000000000..408d1e007aebc7447376708d2d8a38331b63811c
--- /dev/null
+++ b/Rich/RichDetectors/include/RichDetectors/RichPDInfo.h
@@ -0,0 +1,125 @@
+/*****************************************************************************\
+* (c) Copyright 2000-2021 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
+
+// Det Desc
+#include "DetDesc/ConditionKey.h"
+#include "DetDesc/IConditionDerivationMgr.h"
+
+// local
+#include "RichDetectors/RichPD.h"
+
+// RichDetector
+#include "RichDetectors/Rich1.h"
+#include "RichDetectors/Rich2.h"
+#include "RichDetectors/RichPD.h"
+
+// STL
+#include <array>
+
+namespace Rich::Detector {
+
+  //-----------------------------------------------------------------------------
+  /** @class PDInfo RichPDInfo.h
+   *
+   *  Helper class for accessing rich PD information
+   *
+   *  @author Chris Jones
+   *  @date   2021-11-30
+   */
+  //-----------------------------------------------------------------------------
+
+  class PDInfo final {
+
+  public:
+    /// Constructor from Rich Detectors
+    PDInfo( const ParamValidDataObject& r1Nums, //
+            const ParamValidDataObject& r2Nums, //
+            const Detector::Rich1&      rich1,  //
+            const Detector::Rich2&      rich2 );
+
+  public:
+    // accessors
+
+    /// Access the PD panel for a given Smart ID
+    decltype( auto ) pdPanel( const LHCb::RichSmartID pdID ) const noexcept {
+      return m_riches[pdID.rich()]->pdPanel( pdID.panel() );
+    }
+
+    /// Access the PD object for a given Smart ID
+    decltype( auto ) dePD( const LHCb::RichSmartID pdID ) const noexcept { return pdPanel( pdID )->dePD( pdID ); }
+
+    /// Is a given PD active ?
+    bool pdIsActive( const LHCb::RichSmartID ) const noexcept {
+      // TO DO: Implement this if/when required.
+      return true;
+    }
+
+    /// Is a 'large' (H Type) PD
+    inline bool isLargePD( const LHCb::RichSmartID pdID ) const noexcept {
+      return m_riches[pdID.rich()]->pdPanel( pdID.panel() )->isLargePD( pdID );
+    }
+
+    /// Returns a list of all (active and inactive) PDs identified by their RichSmartID
+    inline const LHCb::RichSmartID::Vector& allPDRichSmartIDs() const noexcept { return m_allPDSmartIDs; }
+
+  private:
+    // data
+
+    /// cache the Rich1 and Rich2 objects
+    Rich::DetectorArray<const RichX*> m_riches;
+
+    /// List of all PD RichSmartIDs
+    LHCb::RichSmartID::Vector m_allPDSmartIDs;
+
+  public:
+    // conditions handling
+
+    // Note - With DD4HEP these will be different
+    /// RICH1 Detector numbers
+    static constexpr const char* R1_Nums = "/dd/Conditions/ReadoutConf/Rich1/PMTDetectorNumbers";
+    /// RICH2 Detector numbers
+    static constexpr const char* R2_Nums = "/dd/Conditions/ReadoutConf/Rich2/PMTDetectorNumbers";
+
+    /// Default conditions name
+    static constexpr const char* DefaultConditionKey = "RichPDInfo";
+
+    /// Creates a condition derivation for the given key
+    template <typename PARENT>
+    static decltype( auto )                                                       //
+    addConditionDerivation( PARENT*                     parent,                   ///< Pointer to parent algorithm
+                            LHCb::DetDesc::ConditionKey key = DefaultConditionKey ///< Derived object name
+    ) {
+      // Need to first add the required RICH detectors
+      Detector::Rich1::addConditionDerivation( parent );
+      Detector::Rich2::addConditionDerivation( parent );
+
+      // Now instanciate the helper derived condition
+      if ( parent->msgLevel( MSG::DEBUG ) ) {
+        parent->debug() << "RichPDInfo::addConditionDerivation : Key=" << key << endmsg;
+      }
+      return LHCb::DetDesc::                                                 //
+          addConditionDerivation<PDInfo( const ParamValidDataObject& r1Nums, //
+                                         const ParamValidDataObject& r2Nums, //
+                                         const Detector::Rich1&,             //
+                                         const Detector::Rich2& )>           //
+          ( parent->conditionDerivationMgr(),                                // manager
+            {R1_Nums,                                                        // input condition locations
+             R2_Nums,                                                        //
+             Detector::Rich1::DefaultConditionKey,                           //
+             Detector::Rich2::DefaultConditionKey},                          //
+            std::move( key )                                                 // output condition location
+          );
+    }
+  };
+
+} // namespace Rich::Detector
diff --git a/Rich/RichDetectors/include/RichDetectors/RichPDPanel.h b/Rich/RichDetectors/include/RichDetectors/RichPDPanel.h
index 6a2d2f128616704aa4f705af58dd5ba1f02e4d9a..63dbf07a8c516c4bf86df88f16faa9a3ac4ed15b 100644
--- a/Rich/RichDetectors/include/RichDetectors/RichPDPanel.h
+++ b/Rich/RichDetectors/include/RichDetectors/RichPDPanel.h
@@ -11,9 +11,6 @@
 
 #pragma once
 
-// STL
-#include <memory>
-
 // LHCbKernel
 #include "Kernel/RichSide.h"
 #include "Kernel/RichSmartID.h"
@@ -24,16 +21,26 @@
 
 // Local
 #include "RichDetectors/RichPD.h"
+#include "RichDetectors/Utilities.h"
 
 // RichDet
 #include "RichDet/DeRichPDPanel.h"
 
+// RichUtils
+#include "RichUtils/RichDAQDefinitions.h"
+#include "RichUtils/RichSIMDRayTracing.h"
+
+// STL
+#include <array>
+#include <memory>
+#include <tuple>
+
 namespace Rich::Detector {
 
   //-----------------------------------------------------------------------------
-  /** @class Rich Rich1.h
+  /** @class RichPDPanel.h
    *
-   *  Rich Detector base class
+   *  RICH PD panel class
    *
    *  @author Chris Jones
    *  @date   2020-10-05
@@ -46,7 +53,39 @@ namespace Rich::Detector {
     // types
 
     /// The underlying detector description object (DetDesc or DD4HEP)
+#ifdef USE_DD4HEP
+    using DetElem = DeRichPDPanel; // TODO: Change for equivalent DD4HEP class
+#else
     using DetElem = DeRichPDPanel;
+#endif
+
+    /// type for SIMD ray tracing result
+    using SIMDRayTResult = Rich::RayTracingUtils::SIMDResult;
+    /// scalar FP type for SIMD objects
+    using FP = Rich::SIMD::DefaultScalarFP;
+    /// SIMD float type
+    using SIMDFP = Rich::SIMD::FP<FP>;
+    /// SIMD Int32 type
+    using SIMDINT32 = Rich::SIMD::Int32;
+    /// SIMD Point
+    using SIMDPoint = Rich::SIMD::Point<FP>;
+    /// SIMD Vector
+    using SIMDVector = Rich::SIMD::Vector<FP>;
+    /// Array of PD pointers
+    using SIMDPDs = Rich::SIMD::STDArray<const PD*>;
+    /// Array of SmartIDs
+    using SIMDSmartIDs = SIMDRayTResult::SmartIDs;
+
+    /// Return types for ray-tracing methods
+    using RayTStruct = std::tuple<Gaudi::XYZPoint, LHCb::RichSmartID, const PD*, LHCb::RichTraceMode::RayTraceResult>;
+    using RayTStructSIMD = std::tuple<SIMDPoint, SIMDSmartIDs, SIMDPDs, SIMDRayTResult::Results>;
+
+  private:
+    // types
+
+    // types for PD lookup storage
+    using PDsArray    = std::array<std::unique_ptr<const PD>, LHCb::RichSmartID::MaPMT::MaxPDsPerModule>;
+    using ModuleArray = std::array<PDsArray, LHCb::RichSmartID::MaPMT::MaxModulesPerPanel>;
 
   public:
     // constructors
@@ -55,42 +94,150 @@ namespace Rich::Detector {
     PDPanel() = default;
 
     /// Constructor from det elem
-    PDPanel( const DetElem& panel ) : m_panel( &panel ) {}
+    PDPanel( const DetElem& panel );
 
-  public:
-    // Accesssors
-    // Note for now just forward to DetDesc implementations but eventually
-    // aim is to port functionality here, in preparation for (simplier) DD4HEP objects.
-
-    /// Intersect PD panel (scalar)
-    template <typename... ARGS>
-    inline decltype( auto ) detPlanePoint( ARGS&&... args ) const {
-      return m_panel->detPlanePoint( std::forward<ARGS>( args )... );
+  private:
+    /// Get access to the underlying object
+    inline const DetElem* get() const noexcept { return m_panel; }
+
+    /// Panel local module number
+    inline auto panelLocalModNum( const LHCb::RichSmartID pdID ) const noexcept {
+      // for now retain our own offset to support classic PMTs
+      // in future can just use RichSmartID::panelLocalModuleNum()
+      return ( pdID.pdMod() - m_modNumOffset );
     }
 
-    /// Intersect PD window (scalar)
-    template <typename... ARGS>
-    inline decltype( auto ) PDWindowPoint( ARGS&&... args ) const {
-      return m_panel->PDWindowPoint( std::forward<ARGS>( args )... );
+  public:
+    // accessors
+
+    /// Get the PD for given ID
+    decltype( auto ) dePD( const LHCb::RichSmartID pdID ) const
+#ifdef NDEBUG
+        noexcept
+#endif
+    {
+      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();
+      }
+      return dePD;
     }
 
+  public:
+    // ray tracing methods
+
     /// Intersect PD panel (SIMD)
-    template <typename... ARGS>
-    inline decltype( auto ) detPlanePointSIMD( ARGS&&... args ) const {
-      return m_panel->detPlanePointSIMD( std::forward<ARGS>( args )... );
+    inline decltype( auto ) detPlanePointSIMD( const SIMDPoint&          pGlobal, //
+                                               const SIMDVector&         vGlobal, //
+                                               const LHCb::RichTraceMode mode ) const {
+      auto data = RayTStructSIMD{};
+      // work arounds to deal with old DetElems
+      // To Be done better with DD4Hep
+      auto&                  ids = std::get<SIMDSmartIDs>( data );
+      auto&                  pds = std::get<SIMDPDs>( data );
+      DeRichPDPanel::SIMDPDs oldPDs;
+      std::get<SIMDRayTResult::Results>( data ) =                //
+          get()->detPlanePointSIMD( pGlobal, vGlobal,            //
+                                    std::get<SIMDPoint>( data ), //
+                                    ids, oldPDs, mode );
+      for ( std::size_t i = 0; i < oldPDs.size(); ++i ) {
+        pds[i] = dePD( ids[i] );
+        assert( !pds[i] || oldPDs[i] == pds[i]->get() );
+      }
+      return data;
     }
 
     /// Intersect PD window (SIMD)
-    template <typename... ARGS>
-    inline decltype( auto ) PDWindowPointSIMD( ARGS&&... args ) const {
-      return m_panel->PDWindowPointSIMD( std::forward<ARGS>( args )... );
+    inline decltype( auto ) PDWindowPointSIMD( const SIMDPoint&          pGlobal, //
+                                               const SIMDVector&         vGlobal, //
+                                               const LHCb::RichTraceMode mode ) const {
+      auto data = RayTStructSIMD{};
+      // work arounds to deal with old DetElems
+      // To Be done better with DD4Hep
+      auto&                  ids = std::get<SIMDSmartIDs>( data );
+      auto&                  pds = std::get<SIMDPDs>( data );
+      DeRichPDPanel::SIMDPDs oldPDs;
+      std::get<SIMDRayTResult::Results>( data ) =                //
+          get()->PDWindowPointSIMD( pGlobal, vGlobal,            //
+                                    std::get<SIMDPoint>( data ), //
+                                    ids, oldPDs, mode );
+      for ( std::size_t i = 0; i < oldPDs.size(); ++i ) {
+        pds[i] = dePD( ids[i] );
+        assert( !pds[i] || oldPDs[i] == pds[i]->get() );
+      }
+      return data;
+    }
+
+    /// Intersect PD panel (scalar)
+    inline decltype( auto ) detPlanePoint( const Gaudi::XYZPoint&    pGlobal, //
+                                           const Gaudi::XYZVector&   vGlobal, //
+                                           const LHCb::RichTraceMode mode ) const {
+      auto data = RayTStruct{};
+      // work arounds to deal with old DetElems
+      // To Be done better with DD4Hep
+      auto&           id = std::get<LHCb::RichSmartID>( data );
+      auto&           pd = std::get<const PD*>( data );
+      const DeRichPD* oldPD{nullptr};
+      std::get<LHCb::RichTraceMode::RayTraceResult>( data ) =      //
+          get()->detPlanePoint( pGlobal, vGlobal,                  //
+                                std::get<Gaudi::XYZPoint>( data ), //
+                                id, oldPD, mode );
+      pd = dePD( id );
+      assert( !pd || pd->get() == oldPD );
+      return data;
     }
 
+    /// Intersect PD window (scalar)
+    inline decltype( auto ) PDWindowPoint( const Gaudi::XYZPoint&    pGlobal, //
+                                           const Gaudi::XYZVector&   vGlobal, //
+                                           const LHCb::RichTraceMode mode ) const {
+      auto data = RayTStruct{};
+      // work arounds to deal with old DetElems
+      // To Be done better with DD4Hep
+      auto&           id = std::get<LHCb::RichSmartID>( data );
+      auto&           pd = std::get<const PD*>( data );
+      const DeRichPD* oldPD{nullptr};
+      std::get<LHCb::RichTraceMode::RayTraceResult>( data ) =      //
+          get()->PDWindowPoint( pGlobal, vGlobal,                  //
+                                std::get<Gaudi::XYZPoint>( data ), //
+                                id, oldPD, mode );
+      pd = dePD( id );
+      assert( !pd || pd->get() == oldPD );
+      return data;
+    }
+
+  public:
+    // Methods that just forward to underlying detector object
+    // With DD4Hep will need to implement here or in those classes
+
+    FORWARD_TO_DET_OBJ( detectionPoint )
+    FORWARD_TO_DET_OBJ( PDPanelToGlobalMatrix )
+    FORWARD_TO_DET_OBJ( globalToPDPanelMatrixSIMD )
+    FORWARD_TO_DET_OBJ( smartID )
+    FORWARD_TO_DET_OBJ( globalToPDPanelMatrix )
+    FORWARD_TO_DET_OBJ( readoutChannelList )
+    FORWARD_TO_DET_OBJ( isLargePD )
+    FORWARD_TO_DET_OBJ( pdNumber )
+
   private:
     // data
 
+    /// Owned PD objects
+    ModuleArray m_PDs;
+
     /// DetDesc panel object
     const DetElem* m_panel{nullptr};
+
+    /// Panel local module number offset
+    LHCb::RichSmartID::DataType m_modNumOffset{0};
   };
 
 } // namespace Rich::Detector
diff --git a/Rich/RichDetectors/include/RichDetectors/RichRadiator.h b/Rich/RichDetectors/include/RichDetectors/RichRadiator.h
new file mode 100644
index 0000000000000000000000000000000000000000..7a39d41cf485dfde5b911ed14255f3f38afa649a
--- /dev/null
+++ b/Rich/RichDetectors/include/RichDetectors/RichRadiator.h
@@ -0,0 +1,74 @@
+/*****************************************************************************\
+* (c) Copyright 2000-2022 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
+
+// RichDet
+#include "RichDet/DeRichRadiator.h"
+
+// local
+#include "RichDetectors/Utilities.h"
+
+namespace Rich::Detector {
+
+  //-----------------------------------------------------------------------------
+  /** @class RichRadiator.h
+   *
+   *  RICH Radiator
+   *
+   *  @author Chris Jones
+   *  @date   2021-12-07
+   */
+  //-----------------------------------------------------------------------------
+
+  class Radiator {
+
+  public:
+    // types
+
+    /// The underlying detector description object (DetDesc or DD4HEP)
+#ifdef USE_DD4HEP
+    using DetElem = DeRichRadiator; // TODO: Change for equivalent DD4HEP class
+#else
+    using DetElem = DeRichRadiator;
+#endif
+
+  public:
+    // constructors
+
+    /// Default Constructor
+    Radiator() = default;
+
+    /// Constructor from Det Elem
+    Radiator( const DetElem& rad ) : m_radiator( &rad ) {}
+
+  private:
+    /// Get access to the underlying object
+    inline const DetElem* get() const noexcept { return m_radiator; }
+
+  public:
+    // methods forwarded to Det Elem
+
+    FORWARD_TO_DET_OBJ( radiatorID )
+    FORWARD_TO_DET_OBJ( intersectionPoints )
+    FORWARD_TO_DET_OBJ( refractiveIndex )
+    FORWARD_TO_DET_OBJ( rich )
+    FORWARD_TO_DET_OBJ( isInside )
+    FORWARD_TO_DET_OBJ( refIndex )
+
+  private:
+    // data
+
+    /// DetDesc panel object
+    const DetElem* m_radiator{nullptr};
+  };
+
+} // namespace Rich::Detector
diff --git a/Rich/RichDetectors/include/RichDetectors/RichX.h b/Rich/RichDetectors/include/RichDetectors/RichX.h
index 999e2c10dc1069014c58532704da53fb994c9726..6aab57c13fc891a24fdbfbd261971a871cf0e038 100644
--- a/Rich/RichDetectors/include/RichDetectors/RichX.h
+++ b/Rich/RichDetectors/include/RichDetectors/RichX.h
@@ -11,10 +11,6 @@
 
 #pragma once
 
-// STL
-#include <memory>
-#include <vector>
-
 // Det Desc
 #include "DetDesc/ConditionKey.h"
 #include "DetDesc/IConditionDerivationMgr.h"
@@ -38,6 +34,11 @@
 #include "RichDetectors/RichMirror.h"
 #include "RichDetectors/RichPD.h"
 #include "RichDetectors/RichPDPanel.h"
+#include "RichDetectors/Utilities.h"
+
+// STL
+#include <memory>
+#include <vector>
 
 namespace Rich::Detector {
 
@@ -56,19 +57,20 @@ namespace Rich::Detector {
   public:
     // types
 
-    /// The underlying detector description object (DetDesc or DD4HEP)
+    /// The underlying detector description object(s)
+#ifdef USE_DD4HEP
+    using BaseDetElem = DeRich; // TODO: Change for equivalent DD4HEP class
+    using BeamPipe    = DeRichBeamPipe;
+#else
     using BaseDetElem = DeRich;
+    using BeamPipe    = DeRichBeamPipe;
+#endif
 
     /// Type for container of allocated mirror objects
     using Mirrors = std::vector<std::shared_ptr<const Mirror>>;
 
     /// The PD type to use in public API
-#ifdef USE_DD4HEP
-    // For now use RichDet here as well. To Do migrate to DDD4HEP classes...
-    using PD = DeRichPD;
-#else
-    using PD = DeRichPD;
-#endif
+    using PD = Rich::Detector::PD;
 
   public:
     // constructors
@@ -83,6 +85,9 @@ namespace Rich::Detector {
   private:
     // methods
 
+    /// Get access to the underlying object
+    inline const BaseDetElem* get() const noexcept { return m_rich; }
+
     template <typename MIRRORS>
     inline Mirrors convertMirrors( MIRRORS&& in_mirrs ) const {
       Mirrors out_mirrs;
@@ -96,149 +101,128 @@ namespace Rich::Detector {
     // Note for now just forward to DetDesc implementations but eventually
     // aim is to port functionality here, in preparation for (simplier) DD4HEP objects.
 
+    // Conditions
+    FORWARD_TO_DET_OBJ( hasCondition )
+    FORWARD_TO_DET_OBJ( condition )
+
     /// Check a parameter exists
-    inline decltype( auto ) exists( const std::string& name ) const { return m_rich->exists( name ); }
+    FORWARD_TO_DET_OBJ( exists )
 
     /// Access a parameter
     template <typename TYPE>
     inline decltype( auto ) param( const std::string& name ) const {
-      return m_rich->param<TYPE>( name );
+      return get()->param<TYPE>( name );
     }
 
     /// Access a parameter vector
     template <typename TYPE>
     inline decltype( auto ) paramVect( const std::string& name ) const {
-      return m_rich->paramVect<TYPE>( name );
+      return get()->paramVect<TYPE>( name );
     }
 
     /// The RICH type
     inline Rich::DetectorType rich() const noexcept { return m_type; }
 
     /// primary mirrors
-    inline decltype( auto ) primaryMirrors() const { return convertMirrors( m_rich->primaryMirrors() ); }
+    inline decltype( auto ) primaryMirrors() const { return convertMirrors( get()->primaryMirrors() ); }
 
     /// secondary mirrors
-    inline decltype( auto ) secondaryMirrors() const { return convertMirrors( m_rich->secondaryMirrors() ); }
+    inline decltype( auto ) secondaryMirrors() const { return convertMirrors( get()->secondaryMirrors() ); }
 
     /// Spherical mirror radius
-    inline decltype( auto ) sphMirrorRadius() const noexcept { return m_rich->sphMirrorRadius(); }
+    FORWARD_TO_DET_OBJ( sphMirrorRadius )
 
     /// Spherical mirror radius (SIMD)
-    inline decltype( auto ) sphMirrorRadiusSIMD() const noexcept { return m_rich->sphMirrorRadiusSIMD(); }
+    FORWARD_TO_DET_OBJ( sphMirrorRadiusSIMD )
 
     /// Access CoC for given side(s)
-    template <typename SIDE>
-    inline decltype( auto ) nominalCentreOfCurvature( const SIDE& side ) const noexcept {
-      return m_rich->nominalCentreOfCurvature( side );
-    }
+    FORWARD_TO_DET_OBJ( nominalCentreOfCurvature )
 
     /// Access CoC (SIMD) for given side
-    inline decltype( auto ) nominalCentreOfCurvatureSIMD( const Rich::Side side ) const noexcept {
-      return m_rich->nominalCentreOfCurvatureSIMD( side );
-    }
+    FORWARD_TO_DET_OBJ( nominalCentreOfCurvatureSIMD )
 
     /// Access nominal plane for given side(s)
-    template <typename SIDE>
-    inline decltype( auto ) nominalPlane( const SIDE& side ) const noexcept {
-      return m_rich->nominalPlane( side );
-    }
+    FORWARD_TO_DET_OBJ( nominalPlane )
 
     /// Access nominal plane (SIMD)
-    inline decltype( auto ) nominalPlaneSIMD( const Rich::Side side ) const { return m_rich->nominalPlaneSIMD( side ); }
+    FORWARD_TO_DET_OBJ( nominalPlaneSIMD )
 
     /// Returns the nominal normal vector of the flat mirror plane for this Rich
-    inline decltype( auto ) nominalNormal( const Rich::Side side ) const noexcept {
-      return m_rich->nominalNormal( side );
-    }
+    FORWARD_TO_DET_OBJ( nominalNormal )
 
     /// Returns the SIMD nominal normal vector of the flat mirror plane for this Rich
-    inline decltype( auto ) nominalNormalSIMD( const Rich::Side side ) const noexcept {
-      return m_rich->nominalNormalSIMD( side );
-    }
+    FORWARD_TO_DET_OBJ( nominalNormalSIMD )
 
     /// Access which detector side given point is on
-    template <typename POINT>
-    inline decltype( auto ) side( const POINT& point ) const noexcept {
-      return m_rich->side( point );
-    }
+    FORWARD_TO_DET_OBJ( side )
 
     /// Access RICH Beampipe object. To be seen if this is reallty used and needed with DD4HEP ?
-    inline decltype( auto ) beampipe() const noexcept { return m_rich->beampipe(); }
+    FORWARD_TO_DET_OBJ( beampipe )
 
     /// Access PD Panels
-    inline decltype( auto ) pdPanel( const Rich::Side panel ) const noexcept {
-      return m_rich->pdPanel( panel );
-      // return &m_panels[panel];
-    }
+    inline decltype( auto ) pdPanel( const Rich::Side panel ) const noexcept { return &m_panels[panel]; }
 
     /// Method to find the row/column of a spherical mirror segment.
-    inline decltype( auto ) sphMirrorSegPos( const int mirrNum ) const { return m_rich->sphMirrorSegPos( mirrNum ); }
+    FORWARD_TO_DET_OBJ( sphMirrorSegPos )
 
     /// Method to find the row/column of a flat mirror segment. It can be used to
-    inline decltype( auto ) secMirrorSegPos( const int mirrNum ) const { return m_rich->secMirrorSegPos( mirrNum ); }
+    FORWARD_TO_DET_OBJ( secMirrorSegPos )
 
     /// Returns a pointer to the tabulated property that holds the nominal quantum efficiency of a PD
-    inline decltype( auto ) nominalPDQuantumEff() const noexcept { return m_rich->nominalPDQuantumEff(); }
+    FORWARD_TO_DET_OBJ( nominalPDQuantumEff )
 
     /// Returns a pointer to the tabulated property that holds the nominal reflectivity of primary mirrors
-    inline decltype( auto ) nominalSphMirrorRefl() const noexcept { return m_rich->nominalSphMirrorRefl(); }
+    FORWARD_TO_DET_OBJ( nominalSphMirrorRefl )
 
     /// Returns a pointer to the tabulated property that holds the nominal reflectivity of secondary mirrors
-    inline decltype( auto ) nominalSecMirrorRefl() const noexcept { return m_rich->nominalSecMirrorRefl(); }
+    FORWARD_TO_DET_OBJ( nominalSecMirrorRefl )
 
     /** Returns a pointer to the tabulated property that holds the absorption
      *  length of the gas window for this Rich */
-    inline decltype( auto ) gasWinAbsLength() const noexcept { return m_rich->gasWinAbsLength(); }
+    FORWARD_TO_DET_OBJ( gasWinAbsLength )
 
   public:
     // ray tracing
 
     /// Ray trace a given direction with the given PD panel (scalar)
-    LHCb::RichTraceMode::RayTraceResult rayTrace( const Rich::Side          side,        //
-                                                  const Gaudi::XYZPoint&    pGlobal,     //
-                                                  const Gaudi::XYZVector&   vGlobal,     //
-                                                  Gaudi::XYZPoint&          hitPosition, //
-                                                  LHCb::RichSmartID&        smartID,     //
-                                                  const PD*&                dePD,        //
-                                                  const LHCb::RichTraceMode mode ) const {
+    decltype( auto ) rayTrace( const Rich::Side          side,    //
+                               const Gaudi::XYZPoint&    pGlobal, //
+                               const Gaudi::XYZVector&   vGlobal, //
+                               const LHCb::RichTraceMode mode ) const {
       // are we configured to test individual PD acceptance or just interset the plane ?
       return ( mode.detPlaneBound() == LHCb::RichTraceMode::DetectorPlaneBoundary::RespectPDTubes
-                   ? m_panels[side].PDWindowPoint( pGlobal, vGlobal, hitPosition, smartID, dePD, mode )
-                   : m_panels[side].detPlanePoint( pGlobal, vGlobal, hitPosition, smartID, dePD, mode ) );
+                   ? m_panels[side].PDWindowPoint( pGlobal, vGlobal, mode )
+                   : m_panels[side].detPlanePoint( pGlobal, vGlobal, mode ) );
     }
 
     /// type for SIMD ray tracing result
-    using SIMDRayTResult = Rich::RayTracingUtils::SIMDResult;
+    using SIMDRayTResult = PDPanel::SIMDRayTResult;
     /// scalar FP type for SIMD objects
-    using FP = Rich::SIMD::DefaultScalarFP;
+    using FP = PDPanel::FP;
     /// SIMD float type
-    using SIMDFP = Rich::SIMD::FP<FP>;
+    using SIMDFP = PDPanel::SIMDFP;
     /// Array of PD pointers
-    using SIMDPDs = Rich::SIMD::STDArray<const PD*>;
+    using SIMDPDs = PDPanel::SIMDPDs;
     /// Array of SmartIDs
-    using SIMDSmartIDs = SIMDRayTResult::SmartIDs;
+    using SIMDSmartIDs = PDPanel::SIMDSmartIDs;
+    /// SIMD Point
+    using SIMDPoint = PDPanel::SIMDPoint;
 
     /// Ray trace a given direction with the given PD panel (SIMD)
-    SIMDRayTResult::Results rayTrace( const Rich::Side              side,        //
-                                      const Rich::SIMD::Point<FP>&  pGlobal,     //
-                                      const Rich::SIMD::Vector<FP>& vGlobal,     //
-                                      Rich::SIMD::Point<FP>&        hitPosition, //
-                                      SIMDSmartIDs&                 smartID,     //
-                                      SIMDPDs&                      PDs,         //
-                                      const LHCb::RichTraceMode     mode ) const {
+    decltype( auto ) rayTrace( const Rich::Side              side,    //
+                               const Rich::SIMD::Point<FP>&  pGlobal, //
+                               const Rich::SIMD::Vector<FP>& vGlobal, //
+                               const LHCb::RichTraceMode     mode ) const {
       // are we configured to test individual PD acceptance or just interset the plane ?
       return ( mode.detPlaneBound() == LHCb::RichTraceMode::DetectorPlaneBoundary::RespectPDTubes
-                   ? m_panels[side].PDWindowPointSIMD( pGlobal, vGlobal, hitPosition, smartID, PDs, mode )
-                   : m_panels[side].detPlanePointSIMD( pGlobal, vGlobal, hitPosition, smartID, PDs, mode ) );
+                   ? m_panels[side].PDWindowPointSIMD( pGlobal, vGlobal, mode )
+                   : m_panels[side].detPlanePointSIMD( pGlobal, vGlobal, mode ) );
     }
 
     /// Ray trace a given direction with the correct PD panel (SIMD)
-    SIMDRayTResult::Results rayTrace( const Rich::SIMD::Sides&      sides,       //
-                                      const Rich::SIMD::Point<FP>&  pGlobal,     //
-                                      const Rich::SIMD::Vector<FP>& vGlobal,     //
-                                      Rich::SIMD::Point<FP>&        hitPosition, //
-                                      SIMDSmartIDs&                 smartID,     //
-                                      SIMDPDs&                      PDs,         //
+    PDPanel::RayTStructSIMD rayTrace( const Rich::SIMD::Sides&      sides,   //
+                                      const Rich::SIMD::Point<FP>&  pGlobal, //
+                                      const Rich::SIMD::Vector<FP>& vGlobal, //
                                       const LHCb::RichTraceMode     mode ) const;
 
   private:
diff --git a/Rich/RichDetectors/include/RichDetectors/Utilities.h b/Rich/RichDetectors/include/RichDetectors/Utilities.h
new file mode 100644
index 0000000000000000000000000000000000000000..a5ed2a9bf749d4af087bb07497aa6b6eba2f5854
--- /dev/null
+++ b/Rich/RichDetectors/include/RichDetectors/Utilities.h
@@ -0,0 +1,20 @@
+/*****************************************************************************\
+* (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
+
+#ifndef FORWARD_TO_DET_OBJ
+#  define FORWARD_TO_DET_OBJ( method )                                                                                 \
+    template <typename... ARGS>                                                                                        \
+    inline decltype( auto ) method( ARGS&&... args ) const {                                                           \
+      return get()->method( std::forward<ARGS>( args )... );                                                           \
+    }
+#endif
diff --git a/Rich/RichDetectors/src/RichPDInfo.cpp b/Rich/RichDetectors/src/RichPDInfo.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..aa23a4876a64b973d29a06401ce54130586dd354
--- /dev/null
+++ b/Rich/RichDetectors/src/RichPDInfo.cpp
@@ -0,0 +1,61 @@
+/*****************************************************************************\
+* (c) Copyright 2000-2021 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.                                       *
+\*****************************************************************************/
+
+// local
+#include "RichDetectors/RichPDInfo.h"
+
+// LHCbKernel
+#include "Kernel/RichSmartID32.h"
+
+using namespace Rich::Detector;
+
+PDInfo::PDInfo( const ParamValidDataObject& r1Nums, //
+                const ParamValidDataObject& r2Nums, //
+                const Detector::Rich1&      rich1,  //
+                const Detector::Rich2&      rich2 ) {
+
+  // Cache pointers to detectors
+  m_riches[Rich::Rich1] = &rich1;
+  m_riches[Rich::Rich2] = &rich2;
+
+  // clear current storage
+  m_allPDSmartIDs.clear();
+
+  // loop over RICH1 and RICH2 conditions
+  for ( const auto numbers : {&r1Nums, &r2Nums} ) {
+
+    // PD RichSmartIDs
+    for ( const auto softID : numbers->paramVect<int>( "PMTSmartIDs" ) ) {
+
+      // get PD ID
+      const LHCb::RichSmartID32 pdID32( softID ); // needed for 32->64 bit support
+      LHCb::RichSmartID         pdID( pdID32 );   // handles correct format conversion
+
+      // check large PMT flag
+      const auto check_isLarge = isLargePD( pdID );
+      if ( pdID.isLargePMT() != check_isLarge ) {
+        // should make this a warning/error/fatal when 'classic' PMT support is not required any longer.
+        pdID.setLargePMT( check_isLarge );
+      }
+      // check if this PD ID has a valid DePD object, if not skip.
+      if ( !dePD( pdID ) ) {
+        // should make this a warning/error/fatal when 'classic' PMT support is not required any longer.
+        continue;
+      }
+      // sanity checks
+      assert( std::find( m_allPDSmartIDs.begin(), m_allPDSmartIDs.end(), pdID ) == m_allPDSmartIDs.end() );
+
+      // fill containers
+      m_allPDSmartIDs.push_back( pdID );
+
+    } // loop over PDs
+  }   // loop over conditions
+}
diff --git a/Rich/RichDetectors/src/RichPDPanel.cpp b/Rich/RichDetectors/src/RichPDPanel.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4f0e63c0a6b916b184d6b42ba7bccae9b4804acd
--- /dev/null
+++ b/Rich/RichDetectors/src/RichPDPanel.cpp
@@ -0,0 +1,49 @@
+/*****************************************************************************\
+* (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.                                       *
+\*****************************************************************************/
+
+#include "RichDetectors/RichPDPanel.h"
+
+#include <limits>
+
+using namespace Rich::Detector;
+
+PDPanel::PDPanel( const DetElem& panel ) : m_panel( &panel ) {
+
+  // pre-loop over IDs to determine min/max module numbers for this panel
+  // note, doing this here rather than relying on RichSmartID::panelLocalModuleNum()
+  // as that does not work correctly for 'classic' PMTs. Once support for this
+  // older scheme is no londer needed we remove the local offsets here.
+  using UINT = decltype( m_modNumOffset );
+  UINT maxlocalModNum{0}, maxPDNumInMod{0};
+  m_modNumOffset = std::numeric_limits<UINT>::max();
+  for ( const auto dePD : panel.dePDs() ) {
+    const auto id     = dePD->pdSmartID();
+    const auto modNum = id.pdMod();
+    const auto pdNum  = id.pdNumInMod();
+    if ( modNum > maxlocalModNum ) { maxlocalModNum = modNum; }
+    if ( modNum < m_modNumOffset ) { m_modNumOffset = modNum; }
+    if ( pdNum > maxPDNumInMod ) { maxPDNumInMod = pdNum; }
+  }
+  assert( ( maxlocalModNum - m_modNumOffset ) < m_PDs.size() );
+  assert( maxPDNumInMod < m_PDs[0].size() );
+
+  // access the PDs and make owned wrapped objects
+  for ( const auto dePD : panel.dePDs() ) {
+    const auto id          = dePD->pdSmartID();
+    const auto localModNum = panelLocalModNum( id );
+    assert( localModNum < m_PDs.size() );
+    auto& mod = m_PDs[localModNum];
+    assert( id.pdNumInMod() < mod.size() );
+    auto& pd = mod[id.pdNumInMod()];
+    assert( nullptr == pd.get() ); // should not be set yet
+    pd = std::make_unique<PD>( *dePD );
+  }
+}
diff --git a/Rich/RichDetectors/src/RichX.cpp b/Rich/RichDetectors/src/RichX.cpp
index a1926797aff9c3a529d646c22af7699f4ba604ec..8a22e76381ceb30915deaf3a5bd1f86e50ced5cb 100644
--- a/Rich/RichDetectors/src/RichX.cpp
+++ b/Rich/RichDetectors/src/RichX.cpp
@@ -16,13 +16,10 @@ using namespace Rich::Detector;
 //=============================================================================
 // Ray trace a given direction with the correct PD panel (SIMD)
 //=============================================================================
-RichX::SIMDRayTResult::Results RichX::rayTrace( const Rich::SIMD::Sides&      sides,       //
-                                                const Rich::SIMD::Point<FP>&  pGlobal,     //
-                                                const Rich::SIMD::Vector<FP>& vGlobal,     //
-                                                Rich::SIMD::Point<FP>&        hitPosition, //
-                                                SIMDSmartIDs&                 smartID,     //
-                                                SIMDPDs&                      PDs,         //
-                                                const LHCb::RichTraceMode     mode ) const {
+PDPanel::RayTStructSIMD RichX::rayTrace( const Rich::SIMD::Sides&      sides,   //
+                                         const Rich::SIMD::Point<FP>&  pGlobal, //
+                                         const Rich::SIMD::Vector<FP>& vGlobal, //
+                                         const LHCb::RichTraceMode     mode ) const {
   using namespace LHCb::SIMD;
 
   // If all sides are the same, shortcut to a single call
@@ -30,28 +27,25 @@ RichX::SIMDRayTResult::Results RichX::rayTrace( const Rich::SIMD::Sides&      si
 
   // side 1 mask
   const auto m1 = ( sides == Rich::SIMD::Sides( (int)Rich::firstSide ) );
-  if ( all_of( m1 ) ) { return rayTrace( Rich::firstSide, pGlobal, vGlobal, hitPosition, smartID, PDs, mode ); }
+  if ( all_of( m1 ) ) { return rayTrace( Rich::firstSide, pGlobal, vGlobal, mode ); }
 
   // side 2 mask
   const auto m2 = ( sides == Rich::SIMD::Sides( (int)Rich::secondSide ) );
-  if ( all_of( m2 ) ) { return rayTrace( Rich::secondSide, pGlobal, vGlobal, hitPosition, smartID, PDs, mode ); }
+  if ( all_of( m2 ) ) { return rayTrace( Rich::secondSide, pGlobal, vGlobal, mode ); }
 
   // we have a mixture... So must run both and merge..
   // Is there a better way to handle this ... ?
 
-  // copy input objects for second call
-  auto hitPosition2 = hitPosition;
-  auto smartID2     = smartID;
-  auto PDs2         = PDs;
-
   // call for the first side
-  auto res1 = rayTrace( Rich::firstSide, pGlobal, vGlobal, hitPosition, smartID, PDs, mode );
+  auto res1 = rayTrace( Rich::firstSide, pGlobal, vGlobal, mode );
   // call for the second side
-  auto res2 = rayTrace( Rich::secondSide, pGlobal, vGlobal, hitPosition2, smartID2, PDs2, mode );
+  auto res2 = rayTrace( Rich::secondSide, pGlobal, vGlobal, mode );
 
   // merge results2 into the returned results
 
-  const auto fm2 = LHCb::SIMD::simd_cast<SIMDFP::mask_type>( m2 );
+  auto&      hitPosition  = std::get<SIMDPoint>( res1 );
+  auto&      hitPosition2 = std::get<SIMDPoint>( res2 );
+  const auto fm2          = LHCb::SIMD::simd_cast<SIMDFP::mask_type>( m2 );
   SIMDFP     hx( hitPosition.x() ), hy( hitPosition.y() ), hz( hitPosition.z() );
   hx( fm2 )   = hitPosition2.x();
   hy( fm2 )   = hitPosition2.y();
@@ -59,12 +53,15 @@ RichX::SIMDRayTResult::Results RichX::rayTrace( const Rich::SIMD::Sides&      si
   hitPosition = {hx, hy, hz};
 
   // copy m2 values from res2 to res1
-  res1( m2 ) = res2;
+  std::get<SIMDRayTResult::Results>( res1 )( m2 ) = std::get<SIMDRayTResult::Results>( res2 );
 
   // scalar loop for non-Vc types
+  auto& smartID  = std::get<SIMDSmartIDs>( res1 );
+  auto& smartID2 = std::get<SIMDSmartIDs>( res2 );
+  auto& PDs      = std::get<SIMDPDs>( res1 );
+  auto& PDs2     = std::get<SIMDPDs>( res2 );
   for ( std::size_t i = 0; i < SIMDFP::Size; ++i ) {
     if ( m2[i] ) {
-      // res1[i]    = res2[i];
       smartID[i] = smartID2[i];
       PDs[i]     = PDs2[i];
     }
diff --git a/Rich/RichFutureDAQ/include/RichFutureDAQ/RichPDMDBDecodeMapping.h b/Rich/RichFutureDAQ/include/RichFutureDAQ/RichPDMDBDecodeMapping.h
index 0b26c88cccdad01755a10443542b8a4051725b6f..457748c4a37c0d5282f4bfd11090229405de9b14 100644
--- a/Rich/RichFutureDAQ/include/RichFutureDAQ/RichPDMDBDecodeMapping.h
+++ b/Rich/RichFutureDAQ/include/RichFutureDAQ/RichPDMDBDecodeMapping.h
@@ -14,9 +14,6 @@
 // Kernel
 #include "Kernel/RichSmartID.h"
 
-// RichDet
-#include "RichDet/DeRichSystem.h"
-
 // Gaudi
 #include "GaudiKernel/SerializeSTL.h"
 
@@ -27,6 +24,10 @@
 // RICH DAQ
 #include "RichFutureDAQ/RichTel40CableMapping.h"
 
+// Temporary. To check if conditions exist (see below)
+#include "GaudiAlg/GetData.h"
+#include "RichDetectors/Rich1.h"
+
 // STL
 #include <array>
 #include <cassert>
@@ -48,13 +49,28 @@ namespace Rich::Future::DAQ {
   /// Helper class for RICH PDMDB readout mapping
   class PDMDBDecodeMapping final {
 
+  private:
+    // types
+
+    /// Local struct to hold conditions
+    struct DecodingConds {
+      DetectorArray<const ParamValidDataObject*> rTypeConds;
+      const ParamValidDataObject*                hTypeCond;
+    };
+
   public:
-    /// Constructor from RICH detector elements
-    PDMDBDecodeMapping( const DeRichSystem&     richSys, //
+    /// No default constructor
+    PDMDBDecodeMapping() = delete;
+
+    /// Null constructor
+    explicit PDMDBDecodeMapping( const Gaudi::Algorithm* parent ) : m_parent( parent ) {}
+
+    /// Constructor from decoding map conditions
+    PDMDBDecodeMapping( const DecodingConds     C, //
                         const Gaudi::Algorithm* parent = nullptr )
         : m_parent( parent ) {
       // load the mapping conditions needed for encoding
-      m_isInitialised = fillRType( richSys ) && fillHType( richSys );
+      m_isInitialised = fillRType( C ) && fillHType( C );
     }
 
   public:
@@ -124,10 +140,10 @@ namespace Rich::Future::DAQ {
     // methods
 
     /// fill R Type PMT anode map data
-    bool fillRType( const DeRichSystem& richSys );
+    bool fillRType( const DecodingConds& C );
 
     /// fill H Type PMT anode map data
-    bool fillHType( const DeRichSystem& richSys );
+    bool fillHType( const DecodingConds& C );
 
   public:
     // accessors
@@ -161,6 +177,17 @@ namespace Rich::Future::DAQ {
   public:
     // conditions handling
 
+    // Note - With DD4HEP these will be different
+    /// RICH1 R-Type decoding conditions map path
+    static constexpr const char* R1_RTypePath = "/dd/Conditions/ReadoutConf/Rich1/PDMDB_R_DecodePixelMap";
+    /// RICH2 R-Type decoding conditions map path
+    static constexpr const char* R2_RTypePath = "/dd/Conditions/ReadoutConf/Rich2/PDMDB_R_DecodePixelMap";
+    /// RICH2 H-Type decoding conditions map path
+    static constexpr const char* R2_HTypePath = "/dd/Conditions/ReadoutConf/Rich2/PDMDB_H_DecodePixelMap";
+
+    /// Default conditions name
+    static constexpr const char* DefaultConditionKey = "PDMDBDecodeMapping-Handler";
+
     /// Creates a condition derivation
     template <typename PARENT>
     static decltype( auto ) addConditionDerivation( PARENT* parent ) {
@@ -177,18 +204,34 @@ namespace Rich::Future::DAQ {
       if ( parent->msgLevel( MSG::DEBUG ) ) {
         parent->debug() << "PDMDBDecodeMapping::addConditionDerivation : Key=" << key << endmsg;
       }
-      return LHCb::DetDesc::                                        //
-          addConditionDerivation( parent->conditionDerivationMgr(), //
-                                  {DeRichLocations::RichSystem},    // input
-                                  std::move( key ),                 // output
-                                  [p = parent]( const DeRichSystem& deSys ) {
-                                    return PDMDBDecodeMapping{deSys, p};
-                                  } );
+      // 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(), R2_HTypePath ) ) {
+        return LHCb::DetDesc::                                                      //
+            addConditionDerivation( parent->conditionDerivationMgr(),               //
+                                    {R1_RTypePath, R2_RTypePath, R2_HTypePath},     // input
+                                    std::move( key ),                               // output
+                                    [p = parent]( const ParamValidDataObject& r1Cr, //
+                                                  const ParamValidDataObject& r2Cr, //
+                                                  const ParamValidDataObject& r2Ch ) {
+                                      return PDMDBDecodeMapping{DecodingConds{&r1Cr, &r2Cr, &r2Ch}, p};
+                                    } );
+      } else {
+        // needs to depend on 'something' so fake a dependency on Rich1
+        Detector::Rich1::addConditionDerivation( parent );
+        // return an unintialised object
+        return LHCb::DetDesc::addConditionDerivation(
+            parent->conditionDerivationMgr(), {Detector::Rich1::DefaultConditionKey}, std::move( key ),
+            [p = parent]( const Detector::Rich1& ) { return PDMDBDecodeMapping{p}; } );
+      }
     }
 
-    /// Default conditions name
-    static constexpr const char* DefaultConditionKey = "PDMDBDecodeMapping-Handler";
-
   private:
     /// Define the messenger entity
     inline auto messenger() const noexcept {
diff --git a/Rich/RichFutureDAQ/include/RichFutureDAQ/RichPDMDBEncodeMapping.h b/Rich/RichFutureDAQ/include/RichFutureDAQ/RichPDMDBEncodeMapping.h
index a47ff395b9eeb91eb5807c5cc491b30b55ad626b..5ed0b74deb66b7a1f4b46e3074234622077f8c50 100644
--- a/Rich/RichFutureDAQ/include/RichFutureDAQ/RichPDMDBEncodeMapping.h
+++ b/Rich/RichFutureDAQ/include/RichFutureDAQ/RichPDMDBEncodeMapping.h
@@ -14,9 +14,6 @@
 // Kernel
 #include "Kernel/RichSmartID.h"
 
-// RichDet
-#include "RichDet/DeRichSystem.h"
-
 // Gaudi
 #include "GaudiKernel/SerializeSTL.h"
 
@@ -24,6 +21,10 @@
 #include "DetDesc/ConditionKey.h"
 #include "DetDesc/IConditionDerivationMgr.h"
 
+// Temporary. To check if conditions exist (see below)
+#include "GaudiAlg/GetData.h"
+#include "RichDetectors/Rich1.h"
+
 // STL
 #include <array>
 #include <cassert>
@@ -46,12 +47,27 @@ namespace Rich::Future::DAQ {
   class PDMDBEncodeMapping final {
 
   public:
-    /// Constructor from RICH detector elements
-    PDMDBEncodeMapping( const DeRichSystem&     richSys, //
+    // types
+
+    /// Local struct to hold conditions
+    struct EncodingConds {
+      DetectorArray<const ParamValidDataObject*> rTypeConds;
+      const ParamValidDataObject*                hTypeCond;
+    };
+
+  public:
+    /// Default constructor
+    PDMDBEncodeMapping() = delete;
+
+    /// Null constructor
+    explicit PDMDBEncodeMapping( const Gaudi::Algorithm* parent ) : m_parent( parent ) {}
+
+    /// Constructor from mapping conditions
+    PDMDBEncodeMapping( const EncodingConds     C, //
                         const Gaudi::Algorithm* parent = nullptr )
         : m_parent( parent ) {
       // load the mapping conditions needed for encoding
-      m_isInitialised = fillRType( richSys ) && fillHType( richSys );
+      m_isInitialised = fillRType( C ) && fillHType( C );
     }
 
   public:
@@ -116,10 +132,10 @@ namespace Rich::Future::DAQ {
     // methods
 
     /// fill R Type PMT anode map data
-    bool fillRType( const DeRichSystem& richSys );
+    bool fillRType( const EncodingConds& C );
 
     /// fill H Type PMT anode map data
-    bool fillHType( const DeRichSystem& richSys );
+    bool fillHType( const EncodingConds& C );
 
   public:
     // accessors
@@ -160,6 +176,17 @@ namespace Rich::Future::DAQ {
   public:
     // conditions handling
 
+    // Note - With DD4HEP these will be different
+    /// RICH1 R-Type encoding conditions map path
+    static constexpr const char* R1_RTypePath = "/dd/Conditions/ReadoutConf/Rich1/PDMDB_R_EncodePixelMap";
+    /// RICH2 R-Type encoding conditions map path
+    static constexpr const char* R2_RTypePath = "/dd/Conditions/ReadoutConf/Rich2/PDMDB_R_EncodePixelMap";
+    /// RICH2 H-Type encoding conditions map path
+    static constexpr const char* R2_HTypePath = "/dd/Conditions/ReadoutConf/Rich2/PDMDB_H_EncodePixelMap";
+
+    /// Default conditions name
+    static constexpr const char* DefaultConditionKey = "PDMDBEncodeMapping-Handler";
+
     /// Creates a condition derivation
     template <typename PARENT>
     static decltype( auto ) addConditionDerivation( PARENT* parent ) {
@@ -176,18 +203,34 @@ namespace Rich::Future::DAQ {
       if ( parent->msgLevel( MSG::DEBUG ) ) {
         parent->debug() << "PDMDBEncodeMapping::addConditionDerivation : Key=" << key << endmsg;
       }
-      return LHCb::DetDesc::                                        //
-          addConditionDerivation( parent->conditionDerivationMgr(), //
-                                  {DeRichLocations::RichSystem},    // input
-                                  std::move( key ),                 // output
-                                  [p = parent]( const DeRichSystem& deSys ) {
-                                    return PDMDBEncodeMapping{deSys, p};
-                                  } );
+      // 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(), R2_HTypePath ) ) {
+        return LHCb::DetDesc::                                                      //
+            addConditionDerivation( parent->conditionDerivationMgr(),               //
+                                    {R1_RTypePath, R2_RTypePath, R2_HTypePath},     // input
+                                    std::move( key ),                               // output
+                                    [p = parent]( const ParamValidDataObject& r1Cr, //
+                                                  const ParamValidDataObject& r2Cr, //
+                                                  const ParamValidDataObject& r2Ch ) {
+                                      return PDMDBEncodeMapping{EncodingConds{&r1Cr, &r2Cr, &r2Ch}, p};
+                                    } );
+      } else {
+        // needs to depend on 'something' so fake a dependency on Rich1
+        Detector::Rich1::addConditionDerivation( parent );
+        // return an unintialised object
+        return LHCb::DetDesc::addConditionDerivation(
+            parent->conditionDerivationMgr(), {Detector::Rich1::DefaultConditionKey}, std::move( key ),
+            [p = parent]( const Detector::Rich1& ) { return PDMDBEncodeMapping{p}; } );
+      }
     }
 
-    /// Default conditions name
-    static constexpr const char* DefaultConditionKey = "PDMDBEncodeMapping-Handler";
-
   private:
     /// Define the messenger entity
     inline auto messenger() const noexcept {
diff --git a/Rich/RichFutureDAQ/include/RichFutureDAQ/RichTel40CableMapping.h b/Rich/RichFutureDAQ/include/RichFutureDAQ/RichTel40CableMapping.h
index 609449483dbdd234f36928a8cf8ec60851eb278e..8435fd54b8046dfb8918043dc9a0d234ff5f3917 100644
--- a/Rich/RichFutureDAQ/include/RichFutureDAQ/RichTel40CableMapping.h
+++ b/Rich/RichFutureDAQ/include/RichFutureDAQ/RichTel40CableMapping.h
@@ -14,9 +14,6 @@
 // Kernel
 #include "Kernel/RichSmartID.h"
 
-// RichDet
-#include "RichDet/DeRichSystem.h"
-
 // Gaudi
 #include "GaudiKernel/SerializeSTL.h"
 
@@ -28,8 +25,13 @@
 #include "boost/container/static_vector.hpp"
 
 // RICH Utils
+#include "RichUtils/RichDAQDefinitions.h"
 #include "RichUtils/RichException.h"
 
+// Temporary. To check if conditions exist (see below)
+#include "GaudiAlg/GetData.h"
+#include "RichDetectors/Rich1.h"
+
 namespace Gaudi {
   class Algorithm;
 }
@@ -53,12 +55,22 @@ namespace Rich::Future::DAQ {
   class Tel40CableMapping final {
 
   public:
+    /// Local struct to hold conditions
+    using Conds = std::array<const ParamValidDataObject*, Rich::NTotalPDPanels>;
+
+  public:
+    /// No default constructor
+    Tel40CableMapping() = delete;
+
+    /// Null constructor
+    explicit Tel40CableMapping( const Gaudi::Algorithm* parent ) : m_parent( parent ) {}
+
     /// Constructor from RICH detector elements
-    Tel40CableMapping( const DeRichSystem&     richSys, //
+    Tel40CableMapping( const Conds&            C, //
                        const Gaudi::Algorithm* parent = nullptr )
         : m_parent( parent ) {
       // load the mapping conditions needed for encoding
-      m_isInitialised = fillCableMaps( richSys );
+      m_isInitialised = fillCableMaps( C );
     }
 
   public:
@@ -168,7 +180,7 @@ namespace Rich::Future::DAQ {
     // methods
 
     /// fill Tel40 cable map data
-    bool fillCableMaps( const DeRichSystem& richSys );
+    bool fillCableMaps( const Conds& C );
 
   public:
     // accessors
@@ -231,18 +243,38 @@ namespace Rich::Future::DAQ {
       if ( parent->msgLevel( MSG::DEBUG ) ) {
         parent->debug() << "Tel40CableMapping::addConditionDerivation : Key=" << key << endmsg;
       }
-      // return LHCb::DetDesc::                                                //
-      //    addConditionDerivation<Tel40CableMapping( const DeRichSystem& )>( //
-      //       parent->conditionDerivationMgr(),                             //
-      //        std::array{DeRichLocations::RichSystem},                      //
-      //        std::move( key ) );
-      return LHCb::DetDesc::                                        //
-          addConditionDerivation( parent->conditionDerivationMgr(), //
-                                  {DeRichLocations::RichSystem},    // input
-                                  std::move( key ),                 // output
-                                  [p = parent]( const DeRichSystem& deSys ) {
-                                    return Tel40CableMapping{deSys, p};
-                                  } );
+      const 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.
+      // 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 LHCb::DetDesc::                                                     //
+            addConditionDerivation( parent->conditionDerivationMgr(),              //
+                                    cond_paths,                                    //
+                                    std::move( key ),                              // output
+                                    [p = parent]( const ParamValidDataObject& r1U, //
+                                                  const ParamValidDataObject& r1D, //
+                                                  const ParamValidDataObject& r2A, //
+                                                  const ParamValidDataObject& r2C ) {
+                                      return Tel40CableMapping{Conds{&r1U, &r1D, &r2A, &r2C}, p};
+                                    } );
+      } else {
+        // needs to depend on 'something' so fake a dependency on Rich1
+        Detector::Rich1::addConditionDerivation( parent );
+        // return an unintialised object
+        return LHCb::DetDesc::addConditionDerivation(
+            parent->conditionDerivationMgr(), {Detector::Rich1::DefaultConditionKey}, std::move( key ),
+            [p = parent]( const Detector::Rich1& ) { return Tel40CableMapping{p}; } );
+      }
     }
 
     /// Default conditions name
@@ -272,6 +304,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/src/component/RichRawBankDecoder.cpp b/Rich/RichFutureDAQ/src/component/RichRawBankDecoder.cpp
index 1c128d3dea059a3bb474e1b7c773797215151073..3f843a1e4c2d51a389d8a056dd18a80128fee52f 100644
--- a/Rich/RichFutureDAQ/src/component/RichRawBankDecoder.cpp
+++ b/Rich/RichFutureDAQ/src/component/RichRawBankDecoder.cpp
@@ -9,24 +9,11 @@
 * or submit itself to any jurisdiction.                                       *
 \*****************************************************************************/
 
-// STD
-#include <algorithm>
-#include <array>
-#include <bitset>
-#include <cstdint>
-#include <limits>
-#include <memory>
-#include <numeric>
-#include <set>
-#include <sstream>
-#include <string>
-#include <type_traits>
-
 // Gaudi Array properties ( must be first ...)
 #include "GaudiKernel/ParsersFactory.h"
 #include "GaudiKernel/StdArrayAsProperty.h"
 
-// Rich (Future) Kernel
+// Rich Kernel
 #include "RichFutureKernel/RichAlgBase.h"
 
 // DetDesc
@@ -49,8 +36,8 @@
 // Event model
 #include "Event/RawEvent.h"
 
-// RichDet
-#include "RichDet/DeRichSystem.h"
+// Detectors
+#include "RichDetectors/RichPDInfo.h"
 
 // Boost
 #include "boost/format.hpp"
@@ -58,6 +45,19 @@
 // Old 32 bit SmartID
 #include "Kernel/RichSmartID32.h"
 
+// STD
+#include <algorithm>
+#include <array>
+#include <bitset>
+#include <cstdint>
+#include <limits>
+#include <memory>
+#include <numeric>
+#include <set>
+#include <sstream>
+#include <string>
+#include <type_traits>
+
 using namespace Rich::Future::DAQ;
 using namespace Rich::DAQ;
 
@@ -111,11 +111,11 @@ namespace Rich::Future {
    *  @date   2016-09-21
    */
   class RawBankDecoder final : public Transformer<OutData( const LHCb::RawEvent&,    //
-                                                           const DeRichSystem&,      //
+                                                           const Detector::PDInfo&,  //
                                                            const Tel40CableMapping&, //
                                                            const PDMDBDecodeMapping& ),
                                                   LHCb::DetDesc::usesBaseAndConditions<AlgBase<>,         //
-                                                                                       DeRichSystem,      //
+                                                                                       Detector::PDInfo,  //
                                                                                        Tel40CableMapping, //
                                                                                        PDMDBDecodeMapping>> {
 
@@ -129,7 +129,7 @@ namespace Rich::Future {
                        {KeyValue{"RawEventLocation", concat_alternatives( {LHCb::RawEventLocation::Rich,
                                                                            LHCb::RawEventLocation::Default} )},
                         // conditions input
-                        KeyValue{"DeRichSystem", DeRichLocations::RichSystem},
+                        KeyValue{"RichPDInfo", Detector::PDInfo::DefaultConditionKey},
                         KeyValue{"Tel40CableMapping", name + "-" + Tel40CableMapping::DefaultConditionKey},
                         KeyValue{"PDMDBDecodeMapping", name + "-" + PDMDBDecodeMapping::DefaultConditionKey}},
                        // output data
@@ -147,6 +147,7 @@ namespace Rich::Future {
       // derived conditions
       Tel40CableMapping::addConditionDerivation( this );
       PDMDBDecodeMapping::addConditionDerivation( this );
+      Detector::PDInfo::addConditionDerivation( this );
 
       // report inactive RICHes
       if ( !m_richIsActive[Rich::Rich1] ) { info() << "Decoding for RICH1 disabled" << endmsg; }
@@ -157,7 +158,7 @@ namespace Rich::Future {
 
     /// Algorithm execution via transform
     OutData operator()( const LHCb::RawEvent&     rawEvent,  //
-                        const DeRichSystem&       deRichSys, //
+                        const Detector::PDInfo&   pdInfo,    //
                         const Tel40CableMapping&  tel40Maps, //
                         const PDMDBDecodeMapping& pdmdbMaps ) const override;
 
@@ -169,9 +170,9 @@ namespace Rich::Future {
                                   DecodedIDs&               decodedIDs ) const;
 
     /// Decoding for streamed RichSmartIDs version
-    void decodeToSmartIDs_StreamIDs( const LHCb::RawBank& bank,      //
-                                     const DeRichSystem&  deRichSys, //
-                                     DecodedIDs&          decodedIDs ) const;
+    void decodeToSmartIDs_StreamIDs( const LHCb::RawBank&    bank,   //
+                                     const Detector::PDInfo& pdInfo, //
+                                     DecodedIDs&             decodedIDs ) const;
 
     /// Fill the output decoded data from a list of Smart IDs
     void fillDecodedData( const DecodedIDs& decodedIDs, //
@@ -237,7 +238,7 @@ using namespace Rich::Future;
 //=============================================================================
 
 OutData RawBankDecoder::operator()( const LHCb::RawEvent&     rawEvent,  //
-                                    const DeRichSystem&       deRichSys, //
+                                    const Detector::PDInfo&   pdInfo,    //
                                     const Tel40CableMapping&  tel40Maps, //
                                     const PDMDBDecodeMapping& pdmdbMaps ) const {
 
@@ -297,7 +298,7 @@ OutData RawBankDecoder::operator()( const LHCb::RawEvent&     rawEvent,  //
             decodeToSmartIDs_MaPMT1( *bank, tel40Maps, pdmdbMaps, decodedIDs );
           } else if ( StreamSmartIDs == version ) {
             // simple 'streamed RichSmartID' version (MC only)
-            decodeToSmartIDs_StreamIDs( *bank, deRichSys, decodedIDs );
+            decodeToSmartIDs_StreamIDs( *bank, pdInfo, decodedIDs );
           } else {
             throw Rich::Exception( "Unknown RICH Tel40 version number " + std::to_string( version ) );
           }
@@ -563,9 +564,9 @@ void RawBankDecoder::decodeToSmartIDs_MaPMT1( const LHCb::RawBank&      bank,
 
 //=============================================================================
 
-void RawBankDecoder::decodeToSmartIDs_StreamIDs( const LHCb::RawBank& bank,      //
-                                                 const DeRichSystem&  deRichSys, //
-                                                 DecodedIDs&          decodedIDs ) const {
+void RawBankDecoder::decodeToSmartIDs_StreamIDs( const LHCb::RawBank&    bank,   //
+                                                 const Detector::PDInfo& pdInfo, //
+                                                 DecodedIDs&             decodedIDs ) const {
 
   // Get Tel40 Source ID
   const auto Tel40ID( bank.sourceID() );
@@ -585,7 +586,7 @@ void RawBankDecoder::decodeToSmartIDs_StreamIDs( const LHCb::RawBank& bank,
     LHCb::RichSmartID id( LHCb::RichSmartID32( bank.data()[lineC++] ) );
 
     // work around for some persistent data without 'large' PMT flag set.
-    const bool isLarge = deRichSys.isLargePD( id );
+    const bool isLarge = pdInfo.isLargePD( id );
     if ( id.isLargePMT() != isLarge ) {
       ++m_pmtSLFlagMismatch;
       // hack to fix up large PMT flag
diff --git a/Rich/RichFutureDAQ/src/lib/RichPDMDBDecodeMapping.cpp b/Rich/RichFutureDAQ/src/lib/RichPDMDBDecodeMapping.cpp
index 53d437fa9e5bbb71a09bb47c87da8b303b6f8451..c73c353d473ba2aaeff23a14b01bcb08a5f666f6 100644
--- a/Rich/RichFutureDAQ/src/lib/RichPDMDBDecodeMapping.cpp
+++ b/Rich/RichFutureDAQ/src/lib/RichPDMDBDecodeMapping.cpp
@@ -30,7 +30,7 @@
 using namespace Rich::Future::DAQ;
 using namespace Rich::DAQ;
 
-bool PDMDBDecodeMapping::fillRType( const DeRichSystem& richSys ) {
+bool PDMDBDecodeMapping::fillRType( const DecodingConds& C ) {
 
   using namespace Rich::DAQ;
 
@@ -39,84 +39,8 @@ bool PDMDBDecodeMapping::fillRType( const DeRichSystem& richSys ) {
   // Loop over RICHes
   for ( const auto rich : Rich::detectors() ) {
 
-    // Load the R Type encoding condition for this RICH
-    const std::string richS = ( rich == Rich::Rich1 ? "R1" : "R2" );
-    const std::string condS = richS + "_PDMDB_R_DecodePixelMap";
-    if ( !richSys.hasCondition( condS ) ) {
-      OK = false;
-    } else {
-      debug( "Reading Condition '", condS, "'", endmsg );
-
-      // load the condition
-      const auto cond = richSys.condition( condS );
-
-      // load the active PDBDBs
-      const auto activePDMDBs = cond->paramVect<int>( "ActivePDMDBs" );
-      debug( " -> Found ", activePDMDBs, " active PDMDBs", 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" );
-        verbo( "  -> ", pdmdbS, " active frames ", activeFrames, endmsg );
-
-        // loop over active frames
-        for ( const auto frame : activeFrames ) {
-          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" ) );
-
-          verbo( "   -> ", frameS, endmsg );
-
-          // fill the data cache
-          assert( (std::size_t)rich < m_pdmDataR.size() );
-          auto& richD = m_pdmDataR[rich];
-          assert( (std::size_t)pdmdb < richD.size() );
-          auto& pdmdbD = richD[pdmdb];
-          assert( (std::size_t)frame < pdmdbD.size() );
-          auto& frameD = pdmdbD[frame];
-
-          // loop over bit data and fill
-          std::uint16_t bit{0};
-          for ( const auto&& [ec, pmt, anode] : Ranges::ConstZip( ECs, PMTs, Anodes ) ) {
-            assert( (std::size_t)bit < frameD.size() ); // check bit index in range
-            assert( !frameD[bit].isValid() );           // should not be initialised yet
-            frameD[bit] = BitData( ElementaryCell( ec ), PMTInEC( pmt ), AnodeIndex( anode ) );
-            verbo( "    -> Bit ", bit, frameD[bit], endmsg );
-            ++bit;
-          } // bit loop
-
-        } // frame loop
-      }   // PDMDB loop
-
-    } // condition exists
-
-  } // RICH loop
-
-  return OK;
-}
-
-bool PDMDBDecodeMapping::fillHType( const DeRichSystem& richSys ) {
-
-  using namespace Rich::DAQ;
-
-  bool OK = true;
-
-  // Load the H Type encoding condition for this RICH
-  const std::string condS = "R2_PDMDB_H_DecodePixelMap";
-  if ( !richSys.hasCondition( condS ) ) {
-    OK = false;
-  } else {
-    debug( "Reading Condition '", condS, "'", endmsg );
-
-    // load condition
-    const auto cond = richSys.condition( condS );
+    // load the condition
+    const auto cond = C.rTypeConds[rich];
 
     // load the active PDBDBs
     const auto activePDMDBs = cond->paramVect<int>( "ActivePDMDBs" );
@@ -124,7 +48,7 @@ bool PDMDBDecodeMapping::fillHType( const DeRichSystem& richSys ) {
 
     // Loop over active PDMDBs
     for ( const auto pdmdb : activePDMDBs ) {
-      const auto pdmdbS = "PDMDB" + std::to_string( pdmdb ) + "H";
+      const auto pdmdbS = "PDMDB" + std::to_string( pdmdb ) + "R";
 
       // load the active Frames
       const auto activeFrames = cond->paramVect<int>( pdmdbS + "_ActiveFrames" );
@@ -143,8 +67,10 @@ bool PDMDBDecodeMapping::fillHType( const DeRichSystem& richSys ) {
         verbo( "   -> ", frameS, endmsg );
 
         // fill the data cache
-        assert( (std::size_t)pdmdb < m_pdmDataH.size() );
-        auto& pdmdbD = m_pdmDataH[pdmdb];
+        assert( (std::size_t)rich < m_pdmDataR.size() );
+        auto& richD = m_pdmDataR[rich];
+        assert( (std::size_t)pdmdb < richD.size() );
+        auto& pdmdbD = richD[pdmdb];
         assert( (std::size_t)frame < pdmdbD.size() );
         auto& frameD = pdmdbD[frame];
 
@@ -157,10 +83,65 @@ bool PDMDBDecodeMapping::fillHType( const DeRichSystem& richSys ) {
           verbo( "    -> Bit ", bit, frameD[bit], endmsg );
           ++bit;
         } // bit loop
-      }
-    }
 
-  } // condition exists
+      } // frame loop
+    }   // PDMDB loop
+
+  } // RICH loop
+
+  return OK;
+}
+
+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" );
+  debug( " -> Found ", activePDMDBs, " active PDMDBs", endmsg );
+
+  // Loop over active PDMDBs
+  for ( const auto pdmdb : activePDMDBs ) {
+    const auto pdmdbS = "PDMDB" + std::to_string( pdmdb ) + "H";
+
+    // load the active Frames
+    const auto activeFrames = cond->paramVect<int>( pdmdbS + "_ActiveFrames" );
+    verbo( "  -> ", pdmdbS, " active frames ", activeFrames, endmsg );
+
+    // loop over active frames
+    for ( const auto frame : activeFrames ) {
+      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" ) );
+
+      verbo( "   -> ", frameS, endmsg );
+
+      // fill the data cache
+      assert( (std::size_t)pdmdb < m_pdmDataH.size() );
+      auto& pdmdbD = m_pdmDataH[pdmdb];
+      assert( (std::size_t)frame < pdmdbD.size() );
+      auto& frameD = pdmdbD[frame];
+
+      // loop over bit data and fill
+      std::uint16_t bit{0};
+      for ( const auto&& [ec, pmt, anode] : Ranges::ConstZip( ECs, PMTs, Anodes ) ) {
+        assert( (std::size_t)bit < frameD.size() ); // check bit index in range
+        assert( !frameD[bit].isValid() );           // should not be initialised yet
+        frameD[bit] = BitData( ElementaryCell( ec ), PMTInEC( pmt ), AnodeIndex( anode ) );
+        verbo( "    -> Bit ", bit, frameD[bit], endmsg );
+        ++bit;
+      } // bit loop
+    }
+  }
 
   return OK;
 }
diff --git a/Rich/RichFutureDAQ/src/lib/RichPDMDBEncodeMapping.cpp b/Rich/RichFutureDAQ/src/lib/RichPDMDBEncodeMapping.cpp
index c419245e958b6343922b45427856ff346b27a558..875a05a91927592a8825d6d467a6f1919f74095d 100644
--- a/Rich/RichFutureDAQ/src/lib/RichPDMDBEncodeMapping.cpp
+++ b/Rich/RichFutureDAQ/src/lib/RichPDMDBEncodeMapping.cpp
@@ -29,7 +29,7 @@
 
 using namespace Rich::Future::DAQ;
 
-bool PDMDBEncodeMapping::fillRType( const DeRichSystem& richSys ) {
+bool PDMDBEncodeMapping::fillRType( const EncodingConds& C ) {
 
   using namespace Rich::DAQ;
 
@@ -38,83 +38,8 @@ bool PDMDBEncodeMapping::fillRType( const DeRichSystem& richSys ) {
   // Loop over RICHes
   for ( const auto rich : Rich::detectors() ) {
 
-    // Load the R Type encoding condition for this RICH
-    const std::string richS = ( rich == Rich::Rich1 ? "R1" : "R2" );
-    const std::string condS = richS + "_PDMDB_R_EncodePixelMap";
-    if ( !richSys.hasCondition( condS ) ) {
-      OK = false;
-    } else {
-      debug( "Reading Condition '", condS, "'", endmsg );
-
-      // load the condition
-      const auto cond = richSys.condition( condS );
-
-      // get the active ECs
-      const auto active_ecs = cond->paramVect<int>( "ActiveECs" );
-      debug( " -> Found ", active_ecs.size(), " active ECs", endmsg );
-
-      // Loop over active ECs
-      for ( const auto ec : active_ecs ) {
-
-        // Load the active PMTs for this EC
-        const auto ecS         = "EC" + std::to_string( ec ) + "_";
-        const auto active_pmts = cond->paramVect<int>( ecS + "ActivePMTs" );
-        debug( "  -> Loading ", active_pmts.size(), "ActivePMTs ", endmsg );
-
-        // data shortcuts
-        assert( rich < Rich::NRiches );
-        auto& rich_data = m_rTypeData[rich];
-        assert( (std::size_t)ec < rich_data.size() );
-        auto& ec_data = rich_data[ec];
-
-        // loop over PMTs ..
-        for ( const auto pmt : active_pmts ) {
-          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" ) );
-
-          // Fill data structure for each anode
-          assert( (std::size_t)pmt < ec_data.size() );
-          auto&         pmt_data = ec_data[pmt];
-          std::uint16_t anode{0};
-          for ( const auto&& [pdmdb, frame, bit] : Ranges::ConstZip( pdmdbs, frames, bits ) ) {
-            assert( (std::size_t)anode < pmt_data.size() ); // check anode in range
-            assert( !pmt_data[anode].isValid() );           // check not yet initialised
-            pmt_data[anode] = AnodeData( PDMDBID( pdmdb ), PDMDBFrame( frame ), FrameBitIndex( bit ) );
-            verbo( "    -> Anode ", anode, " ", pmt_data[anode], endmsg );
-            ++anode;
-          } // conditions data loop
-
-        } // active PMT loop
-
-      } // ECs loop
-
-    } // condition exists
-
-  } // RICH loop
-
-  return OK;
-}
-
-bool PDMDBEncodeMapping::fillHType( const DeRichSystem& richSys ) {
-
-  using namespace Rich::DAQ;
-
-  bool OK = true;
-
-  // Load the H Type encoding condition for this RICH
-  const std::string condS = "R2_PDMDB_H_EncodePixelMap";
-  if ( !richSys.hasCondition( condS ) ) {
-    OK = false;
-  } else {
-    debug( "Reading Condition '", condS, "'", endmsg );
-
-    // load condition
-    const auto cond = richSys.condition( condS );
+    // load the condition
+    const auto cond = C.rTypeConds[rich];
 
     // get the active ECs
     const auto active_ecs = cond->paramVect<int>( "ActiveECs" );
@@ -129,8 +54,10 @@ bool PDMDBEncodeMapping::fillHType( const DeRichSystem& richSys ) {
       debug( "  -> Loading ", active_pmts.size(), "ActivePMTs ", endmsg );
 
       // data shortcuts
-      assert( (std::size_t)ec < m_hTypeData.size() );
-      auto& ec_data = m_hTypeData[ec];
+      assert( rich < Rich::NRiches );
+      auto& rich_data = m_rTypeData[rich];
+      assert( (std::size_t)ec < rich_data.size() );
+      auto& ec_data = rich_data[ec];
 
       // loop over PMTs ..
       for ( const auto pmt : active_pmts ) {
@@ -158,7 +85,61 @@ bool PDMDBEncodeMapping::fillHType( const DeRichSystem& richSys ) {
 
     } // ECs loop
 
-  } // condition exists
+  } // RICH loop
+
+  return OK;
+}
+
+bool PDMDBEncodeMapping::fillHType( const EncodingConds& C ) {
+
+  using namespace Rich::DAQ;
+
+  bool OK = true;
+
+  // Load the H Type encoding condition for this RICH
+  const auto cond = C.hTypeCond;
+
+  // get the active ECs
+  const auto active_ecs = cond->paramVect<int>( "ActiveECs" );
+  debug( " -> Found ", active_ecs.size(), " active ECs", endmsg );
+
+  // Loop over active ECs
+  for ( const auto ec : active_ecs ) {
+
+    // Load the active PMTs for this EC
+    const auto ecS         = "EC" + std::to_string( ec ) + "_";
+    const auto active_pmts = cond->paramVect<int>( ecS + "ActivePMTs" );
+    debug( "  -> Loading ", active_pmts.size(), "ActivePMTs ", endmsg );
+
+    // data shortcuts
+    assert( (std::size_t)ec < m_hTypeData.size() );
+    auto& ec_data = m_hTypeData[ec];
+
+    // loop over PMTs ..
+    for ( const auto pmt : active_pmts ) {
+      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" ) );
+
+      // Fill data structure for each anode
+      assert( (std::size_t)pmt < ec_data.size() );
+      auto&         pmt_data = ec_data[pmt];
+      std::uint16_t anode{0};
+      for ( const auto&& [pdmdb, frame, bit] : Ranges::ConstZip( pdmdbs, frames, bits ) ) {
+        assert( (std::size_t)anode < pmt_data.size() ); // check anode in range
+        assert( !pmt_data[anode].isValid() );           // check not yet initialised
+        pmt_data[anode] = AnodeData( PDMDBID( pdmdb ), PDMDBFrame( frame ), FrameBitIndex( bit ) );
+        verbo( "    -> Anode ", anode, " ", pmt_data[anode], endmsg );
+        ++anode;
+      } // conditions data loop
+
+    } // active PMT loop
+
+  } // ECs loop
 
   return OK;
 }
diff --git a/Rich/RichFutureDAQ/src/lib/RichTel40CableMapping.cpp b/Rich/RichFutureDAQ/src/lib/RichTel40CableMapping.cpp
index 36efec8ef54a83affe00cbe789f1840e6bf9f84f..3ed993e9ecf7c996d144d8d1acf19898bf44ccf0 100644
--- a/Rich/RichFutureDAQ/src/lib/RichTel40CableMapping.cpp
+++ b/Rich/RichFutureDAQ/src/lib/RichTel40CableMapping.cpp
@@ -33,155 +33,143 @@
 
 using namespace Rich::Future::DAQ;
 
-bool Tel40CableMapping::fillCableMaps( const DeRichSystem& richSys ) {
+bool Tel40CableMapping::fillCableMaps( const Conds& C ) {
 
   using namespace Rich::DAQ;
 
-  const auto cable_conds = std::array{"R1U_Tel40CablingMap", "R1D_Tel40CablingMap", //
-                                      "R2A_Tel40CablingMap", "R2C_Tel40CablingMap"};
   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};
 
   // default to properly initialised
   bool ok = true;
 
-  for ( const auto&& [cable_cond, rich, panel] : Ranges::ConstZip( cable_conds, rich_types, panel_types ) ) {
-
-    // load the condition, if available
-    if ( richSys.hasCondition( cable_cond ) ) {
-
-      debug( "Reading Condition '", cable_cond, "'", endmsg );
-      const auto cond = richSys.condition( cable_cond );
-
-      // Number of links for this RICH panel
-      const std::size_t nLinks = cond->param<int>( "NumberOfLinks" );
-      if ( nLinks > 0 ) {
-        debug( " -> Found ", nLinks, " links", 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" );
-        // sanity size check
-        if ( nLinks != pmtTypes.size() ||   //
-             nLinks != modNames.size() ||   //
-             nLinks != modNums.size() ||    //
-             nLinks != pdmdbs.size() ||     //
-             nLinks != pdmdbLinks.size() || //
-             nLinks != sourceIDs.size() ||  //
-             nLinks != connectors.size() || //
-             nLinks != mpos.size() ||       //
-             nLinks != statuses.size() ) {
-          ok = false;
-          throw Rich::Exception( "Inconsistent data sizes for " + std::string{cable_cond} );
-        }
-
-        // Find Max SourceID for this RICH/Side
-        assert( !sourceIDs.empty() );
-        const SourceID maxSID( *std::max_element( sourceIDs.begin(), sourceIDs.end() ) );
-        // handle this silently to work around issues with older DB tags.
-        if ( rich != maxSID.rich() || panel != maxSID.side() ) {
-          ok = false;
-          continue;
-        }
-
-        // initialise the data storage
-        auto& tel40CD = m_tel40ConnData[rich][panel];
-        tel40CD.resize( 1 + maxSID.payload() );
-        debug( " -> Reserved space for ", tel40CD.size(), " sourceIDs", endmsg );
-
-        // loop over data and fill lookup structures
-        for ( const auto&& [type, name, modN, pdmdb, pdmdbLink, sID, conn, mpo, status] : //
-              Ranges::ConstZip( pmtTypes, modNames, modNums, pdmdbs, pdmdbLinks,          //
-                                sourceIDs, connectors, mpos, statuses ) ) {
-          // data
-          assert( (std::size_t)conn <= ConnectionsPerTel40MPO );
-          assert( sID >= 0 && sID < std::numeric_limits<SourceID::Type>::max() );
-          const SourceID sourceID( sID );
-          assert( rich == sourceID.rich() && panel == sourceID.side() );
-          // connections in DB are numbered [1-12] so subtract one to convert to [0-11]
-          // In first (unrealistic) implementation MPO was just [1,2] for the two groups
-          // of 12 connections per sourceID. In the real DB they are [1,3] for the first
-          // SourceID per Tel40, [5,7] for the second SourceID. As we just need to know
-          // which of the two groups we have, map back to [1,2]
-          assert( 1 == mpo || 2 == mpo || 3 == mpo || 5 == mpo || 7 == mpo );
-          auto norm_mpo = []( const auto mpo ) {
-            switch ( mpo ) {
-            case 1:
-              return 1;
-            case 2:
-              return 2;
-            case 3:
-              return 2;
-            case 5:
-              return 1;
-            case 7:
-              return 2;
-            }
-            return std::numeric_limits<int>::signaling_NaN();
-          };
-          const Tel40Connector link( ( ConnectionsPerTel40MPO * ( norm_mpo( mpo ) - 1 ) ) + ( conn - 1 ) );
-
-          // PMT type
-          const bool isLargePMT = ( "H" == type );
-
-          // The cached RichSmartID for this entry
-          LHCb::RichSmartID smartID( rich, panel, LHCb::RichSmartID::MaPMTID );
-          smartID.setLargePMT( isLargePMT );
-
-          // link data struct
-          const Tel40LinkData linkD( name,                   //
-                                     smartID,                //
-                                     sourceID,               //
-                                     link,                   //
-                                     isLargePMT,             //
-                                     bool( status ),         //
-                                     PDModuleNumber( modN ), //
-                                     PDMDBID( pdmdb ),       //
-                                     PDMDBFrame( pdmdbLink ) );
-
-          // fill the Tel40 connection data structure
-          const std::size_t idx = sourceID.payload();
-          if ( idx >= tel40CD.size() ) {
-            throw Rich::Exception( "Tel40 Source ID '" + std::to_string( idx ) + "' exceeds expected range" );
-          }
-          auto& conData = tel40CD[idx];
-          assert( (std::size_t)link.data() < Tel40CableMapping::MaxConnectionsPerTel40 );
-          if ( conData.size() <= (std::size_t)link.data() ) { conData.resize( link.data() + 1 ); }
-          conData[link.data()] = linkD;
-          if ( status ) {
-            ++conData.nActiveLinks;
-          } else {
-            conData.hasInactiveLinks = true;
+  for ( const auto&& [cond, rich, panel] : Ranges::ConstZip( C, rich_types, panel_types ) ) {
+
+    // Number of links for this RICH panel
+    const std::size_t nLinks = cond->param<int>( "NumberOfLinks" );
+    if ( nLinks > 0 ) {
+      debug( " -> Found ", nLinks, " links", 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" );
+      // sanity size check
+      if ( nLinks != pmtTypes.size() ||   //
+           nLinks != modNames.size() ||   //
+           nLinks != modNums.size() ||    //
+           nLinks != pdmdbs.size() ||     //
+           nLinks != pdmdbLinks.size() || //
+           nLinks != sourceIDs.size() ||  //
+           nLinks != connectors.size() || //
+           nLinks != mpos.size() ||       //
+           nLinks != statuses.size() ) {
+        ok = false;
+        throw Rich::Exception( "Inconsistent data sizes for " + cond->name() );
+      }
+
+      // Find Max SourceID for this RICH/Side
+      assert( !sourceIDs.empty() );
+      const SourceID maxSID( *std::max_element( sourceIDs.begin(), sourceIDs.end() ) );
+      // handle this silently to work around issues with older DB tags.
+      if ( rich != maxSID.rich() || panel != maxSID.side() ) {
+        ok = false;
+        continue;
+      }
+
+      // initialise the data storage
+      auto& tel40CD = m_tel40ConnData[rich][panel];
+      tel40CD.resize( 1 + maxSID.payload() );
+      debug( " -> Reserved space for ", tel40CD.size(), " sourceIDs", endmsg );
+
+      // loop over data and fill lookup structures
+      for ( const auto&& [type, name, modN, pdmdb, pdmdbLink, sID, conn, mpo, status] : //
+            Ranges::ConstZip( pmtTypes, modNames, modNums, pdmdbs, pdmdbLinks,          //
+                              sourceIDs, connectors, mpos, statuses ) ) {
+        // data
+        assert( (std::size_t)conn <= ConnectionsPerTel40MPO );
+        assert( sID >= 0 && sID < std::numeric_limits<SourceID::Type>::max() );
+        const SourceID sourceID( sID );
+        assert( rich == sourceID.rich() && panel == sourceID.side() );
+        // connections in DB are numbered [1-12] so subtract one to convert to [0-11]
+        // In first (unrealistic) implementation MPO was just [1,2] for the two groups
+        // of 12 connections per sourceID. In the real DB they are [1,3] for the first
+        // SourceID per Tel40, [5,7] for the second SourceID. As we just need to know
+        // which of the two groups we have, map back to [1,2]
+        assert( 1 == mpo || 2 == mpo || 3 == mpo || 5 == mpo || 7 == mpo );
+        auto norm_mpo = []( const auto mpo ) {
+          switch ( mpo ) {
+          case 1:
+            return 1;
+          case 2:
+            return 2;
+          case 3:
+            return 2;
+          case 5:
+            return 1;
+          case 7:
+            return 2;
           }
-          verbo( "  -> ", linkD, endmsg );
-
-          // fill Tel40 module data structure
-          assert( (std::size_t)modN < m_tel40ModuleData.size() ); // in range
-          auto& mData = m_tel40ModuleData[modN];
-          assert( (std::size_t)pdmdb < mData.size() ); // in range
-          auto& pData = mData[pdmdb];
-          assert( (std::size_t)pdmdbLink < pData.size() ); // in range
-          assert( !pData[pdmdbLink].isValid() );           // not yet initialised
-          pData[pdmdbLink] = linkD;
-
-          // fill the active links per source ID map
-          auto& links = m_linksPerSourceID[sourceID];
-          assert( std::find( links.begin(), links.end(), link ) == links.end() );
-          links.insert( link );
+          return std::numeric_limits<int>::signaling_NaN();
+        };
+        const Tel40Connector link( ( ConnectionsPerTel40MPO * ( norm_mpo( mpo ) - 1 ) ) + ( conn - 1 ) );
+
+        // PMT type
+        const bool isLargePMT = ( "H" == type );
+
+        // The cached RichSmartID for this entry
+        LHCb::RichSmartID smartID( rich, panel, LHCb::RichSmartID::MaPMTID );
+        smartID.setLargePMT( isLargePMT );
+
+        // link data struct
+        const Tel40LinkData linkD( name,                   //
+                                   smartID,                //
+                                   sourceID,               //
+                                   link,                   //
+                                   isLargePMT,             //
+                                   bool( status ),         //
+                                   PDModuleNumber( modN ), //
+                                   PDMDBID( pdmdb ),       //
+                                   PDMDBFrame( pdmdbLink ) );
+
+        // fill the Tel40 connection data structure
+        const std::size_t idx = sourceID.payload();
+        if ( idx >= tel40CD.size() ) {
+          throw Rich::Exception( "Tel40 Source ID '" + std::to_string( idx ) + "' exceeds expected range" );
+        }
+        auto& conData = tel40CD[idx];
+        assert( (std::size_t)link.data() < Tel40CableMapping::MaxConnectionsPerTel40 );
+        if ( conData.size() <= (std::size_t)link.data() ) { conData.resize( link.data() + 1 ); }
+        conData[link.data()] = linkD;
+        if ( status ) {
+          ++conData.nActiveLinks;
+        } else {
+          conData.hasInactiveLinks = true;
         }
-      } // nLinks > 0
+        verbo( "  -> ", linkD, endmsg );
+
+        // fill Tel40 module data structure
+        assert( (std::size_t)modN < m_tel40ModuleData.size() ); // in range
+        auto& mData = m_tel40ModuleData[modN];
+        assert( (std::size_t)pdmdb < mData.size() ); // in range
+        auto& pData = mData[pdmdb];
+        assert( (std::size_t)pdmdbLink < pData.size() ); // in range
+        assert( !pData[pdmdbLink].isValid() );           // not yet initialised
+        pData[pdmdbLink] = linkD;
+
+        // fill the active links per source ID map
+        auto& links = m_linksPerSourceID[sourceID];
+        assert( std::find( links.begin(), links.end(), link ) == links.end() );
+        links.insert( link );
+      }
+    } // nLinks > 0
 
-    } else {
-      // indicate initialisation failed.
-      ok = false;
-    }
   } // conditions loop
 
   // return final status
diff --git a/Rich/RichFutureKernel/include/RichFutureKernel/RichCommonBase.h b/Rich/RichFutureKernel/include/RichFutureKernel/RichCommonBase.h
index 65363273a57ce2a68496f6f908772e25e6db9212..c701bba38fe3039e3e42d2cd05727f1e4989879e 100644
--- a/Rich/RichFutureKernel/include/RichFutureKernel/RichCommonBase.h
+++ b/Rich/RichFutureKernel/include/RichFutureKernel/RichCommonBase.h
@@ -35,9 +35,6 @@
 // STL
 #include <utility>
 
-// Forward declarations
-class DeRich;
-
 namespace Rich {
   using GaudiUtils::operator<<;
 
diff --git a/Rich/RichFutureUtils/include/RichFutureUtils/RichGeomPhoton.h b/Rich/RichFutureUtils/include/RichFutureUtils/RichGeomPhoton.h
index 7af9979fd433c2b4dcc62e3957bd08d1ddff13f2..0461df09624fa005d3f037c571d8cd1cda188ccc 100644
--- a/Rich/RichFutureUtils/include/RichFutureUtils/RichGeomPhoton.h
+++ b/Rich/RichFutureUtils/include/RichFutureUtils/RichGeomPhoton.h
@@ -22,10 +22,6 @@
 
 #pragma once
 
-// STL
-#include <iostream>
-#include <utility>
-
 // geometry
 #include "GaudiKernel/Point3DTypes.h"
 #include "GaudiKernel/Vector3DTypes.h"
@@ -37,6 +33,10 @@
 // Rich Detector
 #include "RichDetectors/RichX.h"
 
+// STL
+#include <iostream>
+#include <utility>
+
 namespace Rich::Future {
 
   /** @class RecoPhoton RichFutureUtils/RichGeomPhoton.h
@@ -153,7 +153,7 @@ namespace Rich::Future {
     Scalar m_activeSegmentFraction{1};
   };
 
-  /** @class GeomPhoton RichGeomPhoton.h RichUtils/RichGeomPhoton.h
+  /** @class GeomPhoton RichGeomPhoton.h RichFutureUtils/RichGeomPhoton.h
    *
    *  A geometrical representation of a reconstructed Cherenkov photon.
    *  Contains full information on the photon trajectory.
diff --git a/Rich/RichFutureUtils/include/RichFutureUtils/RichRadIntersects.h b/Rich/RichFutureUtils/include/RichFutureUtils/RichRadIntersects.h
index db5679e14f2bab5d1221bf384ab3d87091ecc69e..63c3ecff6571761f380d376d2d0b62485ec417be 100644
--- a/Rich/RichFutureUtils/include/RichFutureUtils/RichRadIntersects.h
+++ b/Rich/RichFutureUtils/include/RichFutureUtils/RichRadIntersects.h
@@ -1,5 +1,5 @@
 /*****************************************************************************\
-* (c) Copyright 2000-2020 CERN for the benefit of the LHCb Collaboration      *
+* (c) Copyright 2000-2022 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".   *
@@ -11,11 +11,6 @@
 
 #pragma once
 
-// STL
-#include <algorithm>
-#include <array>
-#include <vector>
-
 // LHCbKernel
 #include "Kernel/RichRadIntersection.h"
 #include "Kernel/RichRadiatorType.h"
@@ -23,13 +18,19 @@
 // Math
 #include "GaudiKernel/Transform3DTypes.h"
 
-// RichDet
-#include "RichDet/DeRichRadiator.h"
-
 // Det Desc
 #include "DetDesc/ConditionKey.h"
 #include "DetDesc/IConditionDerivationMgr.h"
 
+// Detectors
+#include "RichDetectors/Rich1Gas.h"
+#include "RichDetectors/Rich2Gas.h"
+
+// STL
+#include <algorithm>
+#include <array>
+#include <vector>
+
 namespace Rich::Utils {
 
   //-----------------------------------------------------------------------------
@@ -48,9 +49,9 @@ namespace Rich::Utils {
     // construtors
 
     // From radiators
-    RadIntersects( const DeRichRadiator& r1gas,  // RICH1 gas volume
-                   const DeRichRadiator& r2gas ) // RICH2 gas volume
-        : m_radiators{nullptr, &r1gas, &r2gas}   // Aero hardcoded to off...
+    RadIntersects( const Detector::Rich1Gas& r1gas,  // RICH1 gas volume
+                   const Detector::Rich2Gas& r2gas ) // RICH2 gas volume
+        : m_radiators{nullptr, &r1gas, &r2gas}       // Aero hardcoded to off...
     {}
 
   public:
@@ -87,11 +88,14 @@ namespace Rich::Utils {
 
   private:
     /// Radiators for each RICH
-    RadiatorArray<const DeRichRadiator*> m_radiators = {{}};
+    RadiatorArray<const Detector::Radiator*> m_radiators = {{}};
 
   public:
     // conditions handling
 
+    /// Default conditions name
+    static constexpr const char* DefaultConditionKey = "RadiatorIntersects-Handler";
+
     /// Creates a condition derivation
     template <typename PARENT>
     static decltype( auto ) addConditionDerivation( PARENT* parent ) {
@@ -106,15 +110,15 @@ namespace Rich::Utils {
       if ( parent->msgLevel( MSG::DEBUG ) ) {
         parent->debug() << "RadIntersects::addConditionDerivation : Key=" << key << endmsg;
       }
+      Detector::Rich1Gas::addConditionDerivation( parent );
+      Detector::Rich2Gas::addConditionDerivation( parent );
       return LHCb::DetDesc:: //
-          addConditionDerivation<RadIntersects( const DeRichRadiator&, const DeRichRadiator& )>(
-              parent->conditionDerivationMgr(),                       // manager
-              {DeRichLocations::Rich1Gas, DeRichLocations::Rich2Gas}, // input conditions
-              std::move( key ) );                                     // output derived condition location
+          addConditionDerivation<RadIntersects( const Detector::Rich1Gas&, const Detector::Rich2Gas& )>(
+              parent->conditionDerivationMgr(),          // manager
+              {Detector::Rich1Gas::DefaultConditionKey,  //
+               Detector::Rich2Gas::DefaultConditionKey}, // input conditions
+              std::move( key ) );                        // output derived condition location
     }
-
-    /// Default conditions name
-    static constexpr const char* DefaultConditionKey = "RadiatorIntersects-Handler";
   };
 
 } // namespace Rich::Utils
diff --git a/Rich/RichFutureUtils/include/RichFutureUtils/RichSmartIDs.h b/Rich/RichFutureUtils/include/RichFutureUtils/RichSmartIDs.h
index 2e06a357a89557041b4395e7c3e457b9b81a69aa..3d7cb692875ebd2d1f2b6bbc2aba59aa67457eb2 100644
--- a/Rich/RichFutureUtils/include/RichFutureUtils/RichSmartIDs.h
+++ b/Rich/RichFutureUtils/include/RichFutureUtils/RichSmartIDs.h
@@ -16,10 +16,10 @@
 #include <memory>
 
 // RichDet
-#include "RichDet/DeRichSystem.h"
 #include "RichDetectors/Rich1.h"
 #include "RichDetectors/Rich2.h"
 #include "RichDetectors/RichPD.h"
+#include "RichDetectors/RichPDInfo.h"
 
 // Det Desc
 #include "DetDesc/ConditionKey.h"
@@ -55,10 +55,10 @@ namespace Rich::Utils {
     // constructors
 
     /// Constructor from RICH detector elements
-    RichSmartIDs( const DeRichSystem&    richSys, //
-                  const Detector::Rich1& rich1,   //
-                  const Detector::Rich2& rich2 )
-        : m_richS{&richSys} //
+    RichSmartIDs( const Detector::PDInfo& pdInfo, //
+                  const Detector::Rich1&  rich1,  //
+                  const Detector::Rich2&  rich2 )
+        : m_pdInfo{&pdInfo} //
         , m_riches{&rich1, &rich2} {}
 
   public:
@@ -163,6 +163,7 @@ namespace Rich::Utils {
     static decltype( auto ) //
     addConditionDerivation( PARENT* parent, LHCb::DetDesc::ConditionKey key ) {
       // The detector objects
+      Detector::PDInfo::addConditionDerivation( parent );
       Detector::Rich1::addConditionDerivation( parent );
       Detector::Rich2::addConditionDerivation( parent );
       // create derived object
@@ -170,11 +171,11 @@ namespace Rich::Utils {
         parent->debug() << "RichSmartIDs::addConditionDerivation : Key=" << key << endmsg;
       }
       return LHCb::DetDesc::                                              //
-          addConditionDerivation<RichSmartIDs( const DeRichSystem&,       //
+          addConditionDerivation<RichSmartIDs( const Detector::PDInfo&,   //
                                                const Detector::Rich1&,    //
                                                const Detector::Rich2& )>( //
               parent->conditionDerivationMgr(),                           // manager
-              {DeRichLocations::RichSystem,                               // input conditions
+              {Detector::PDInfo::DefaultConditionKey,                     // input conditions
                Detector::Rich1::DefaultConditionKey,                      // locations
                Detector::Rich2::DefaultConditionKey},                     //
               std::move( key ) );                                         // output location
@@ -186,8 +187,8 @@ namespace Rich::Utils {
   private:
     // data
 
-    /// RichSystem object
-    const DeRichSystem* m_richS = nullptr;
+    /// PD Info
+    const Detector::PDInfo* m_pdInfo = nullptr;
 
     /// Pointers to RICH1 and RICH2
     Rich::DetectorArray<const Detector::RichX*> m_riches = {{}};
diff --git a/Rich/RichFutureUtils/include/RichFutureUtils/RichTabulatedRefIndex.h b/Rich/RichFutureUtils/include/RichFutureUtils/RichTabulatedRefIndex.h
index f459675a7ad3837fd60f2384bd9f26ff84320322..a9cd0445d4264415da435602f43f0f979d86eaac 100644
--- a/Rich/RichFutureUtils/include/RichFutureUtils/RichTabulatedRefIndex.h
+++ b/Rich/RichFutureUtils/include/RichFutureUtils/RichTabulatedRefIndex.h
@@ -17,10 +17,10 @@
 #include <memory>
 
 // Rich Detector
-#include "RichDet/DeRichRadiator.h"
-#include "RichDet/Rich1DTabProperty.h"
 #include "RichDetectors/Rich1.h"
+#include "RichDetectors/Rich1Gas.h"
 #include "RichDetectors/Rich2.h"
+#include "RichDetectors/Rich2Gas.h"
 
 // Kernel
 #include "Kernel/RichParticleIDType.h"
@@ -58,8 +58,8 @@ namespace Rich::Utils {
     /// Constructor from detector info
     TabulatedRefIndex( const Detector::Rich1&      rich1,     //
                        const Detector::Rich2&      rich2,     //
-                       const DeRichRadiator&       r1gas,     //
-                       const DeRichRadiator&       r2gas,     //
+                       const Detector::Rich1Gas&   r1gas,     //
+                       const Detector::Rich2Gas&   r2gas,     //
                        const RadiatorArray<float>& minPhotEn, //
                        const RadiatorArray<float>& maxPhotEn, //
                        const ParticleArray<float>& masses )
@@ -144,7 +144,7 @@ namespace Rich::Utils {
     DetectorArray<const Detector::RichX*> m_riches = {{}};
 
     /// Pointers to RICH radiator detector elements
-    RadiatorArray<const DeRichRadiator*> m_radiators = {{}};
+    RadiatorArray<const Detector::Radiator*> m_radiators = {{}};
 
     /// The minimum photon energies
     RadiatorArray<float> m_minPhotEn{{std::numeric_limits<float>::signaling_NaN()}};
@@ -165,6 +165,9 @@ namespace Rich::Utils {
   public:
     // conditions handling
 
+    /// Default conditions name
+    static constexpr const char* DefaultConditionKey = "RichRefIndex-Handler";
+
     /// Creates a condition derivation
     template <typename PARENT>
     static decltype( auto ) addConditionDerivation( PARENT* parent ) {
@@ -180,21 +183,23 @@ namespace Rich::Utils {
       // The detector objects
       Detector::Rich1::addConditionDerivation( parent );
       Detector::Rich2::addConditionDerivation( parent );
+      Detector::Rich1Gas::addConditionDerivation( parent );
+      Detector::Rich2Gas::addConditionDerivation( parent );
 
       if ( parent->msgLevel( MSG::DEBUG ) ) {
         parent->debug() << "TabulatedRefIndex::addConditionDerivation : Key=" << key << endmsg;
       }
       return LHCb::DetDesc:: //
           addConditionDerivation( parent->conditionDerivationMgr(),
-                                  {Detector::Rich1::DefaultConditionKey,      // inputs
-                                   Detector::Rich2::DefaultConditionKey,      //
-                                   DeRichLocations::Rich1Gas,                 //
-                                   DeRichLocations::Rich2Gas},                //
-                                  std::move( key ),                           // output
-                                  [p = parent]( const Detector::Rich1& rich1, //
-                                                const Detector::Rich2& rich2, //
-                                                const DeRichRadiator&  r1gas, //
-                                                const DeRichRadiator&  r2gas ) {
+                                  {Detector::Rich1::DefaultConditionKey,         // inputs
+                                   Detector::Rich2::DefaultConditionKey,         //
+                                   Detector::Rich1Gas::DefaultConditionKey,      //
+                                   Detector::Rich2Gas::DefaultConditionKey},     //
+                                  std::move( key ),                              // output
+                                  [p = parent]( const Detector::Rich1&    rich1, //
+                                                const Detector::Rich2&    rich2, //
+                                                const Detector::Rich1Gas& r1gas, //
+                                                const Detector::Rich2Gas& r2gas ) {
                                     return TabulatedRefIndex{
                                         rich1,                                 // RICH1
                                         rich2,                                 // RICH2
@@ -205,9 +210,6 @@ namespace Rich::Utils {
                                         p->richPartProps()->masses()};         // particle masses
                                   } );
     }
-
-    /// Default conditions name
-    static constexpr const char* DefaultConditionKey = "RichRefIndex-Handler";
   };
 
 } // namespace Rich::Utils
diff --git a/Rich/RichFutureUtils/src/RichRayTracing.cpp b/Rich/RichFutureUtils/src/RichRayTracing.cpp
index 976244d8fd64a8b7bef48e15714d4f6b6a6772ae..d51b297f9b4724b95614c74daeca1f13bd689c56 100644
--- a/Rich/RichFutureUtils/src/RichRayTracing.cpp
+++ b/Rich/RichFutureUtils/src/RichRayTracing.cpp
@@ -14,6 +14,8 @@
 
 #include "RichDetectors/RichPD.h"
 
+#include <type_traits>
+
 using namespace Rich::Utils;
 
 namespace {
@@ -182,7 +184,7 @@ RayTracing::traceToDetector( SIMD::STDVector<SIMDPointVect>& startPointsDirs, //
     sides = m_rich[rich]->side( point );
 
     // do ray tracing to PD panels
-    result.result = m_rich[rich]->rayTrace( sides, point, dir, hitPosition, smartID, pds, mode );
+    std::tie( hitPosition, smartID, pds, result.result ) = m_rich[rich]->rayTrace( sides, point, dir, mode );
     mask &= LHCb::SIMD::simd_cast<SIMDFP::mask_type>( result.result >= testMask );
 
     // test for beam pipe intersections ?
@@ -324,7 +326,7 @@ RayTracing::traceToDetector( const Gaudi::XYZPoint&       startPoint, //
     sides = m_rich[rich]->side( point );
 
     // do ray tracing to PD panels
-    result.result = m_rich[rich]->rayTrace( sides, point, dir, hitPosition, smartID, pds, mode );
+    std::tie( hitPosition, smartID, pds, result.result ) = m_rich[rich]->rayTrace( sides, point, dir, mode );
     mask &= LHCb::SIMD::simd_cast<SIMDFP::mask_type>( result.result >= testMask );
 
     // test for beam pipe intersections ?
@@ -396,11 +398,11 @@ RayTracing::_traceToDetector( const Rich::DetectorType  rich,       //
     // LHCb::RichSmartID smartID( rich, side, pdPanel( rich, side )->pdType() );
     LHCb::RichSmartID smartID( rich, side, LHCb::RichSmartID::MaPMTID );
 
-    // pointer to the underlying detector PD object
-    const Detector::PD::DetElem* dePD{nullptr};
+    // pointer to detector PD object
+    const Detector::PD* dePD{nullptr};
 
     // do ray tracing, depending on mode
-    result = m_rich[rich]->rayTrace( side, tmpPos, tmpDir, hitPosition, smartID, dePD, mode );
+    std::tie( hitPosition, smartID, dePD, result ) = m_rich[rich]->rayTrace( side, tmpPos, tmpDir, mode );
 
     // Set remaining GeomPhoton data
     photon.setSmartID( smartID );
diff --git a/Rich/RichFutureUtils/src/RichSmartIDs.cpp b/Rich/RichFutureUtils/src/RichSmartIDs.cpp
index 27e7c4c87d7f758befff6f1d63479fa3a5bf83d0..079717acfa5b3df5053a2c3cfdbfba84280909f6 100644
--- a/Rich/RichFutureUtils/src/RichSmartIDs.cpp
+++ b/Rich/RichFutureUtils/src/RichSmartIDs.cpp
@@ -151,7 +151,7 @@ bool RichSmartIDs::pdPosition( const LHCb::RichSmartID& pdid, //
 bool RichSmartIDs::smartID( const Gaudi::XYZPoint& globalPoint, //
                             LHCb::RichSmartID&     smartid ) const {
   // check to see if the smartID is set, and if PD is active
-  if ( smartid.pdIsSet() && !m_richS->pdIsActive( smartid ) ) { return false; }
+  if ( smartid.pdIsSet() && !m_pdInfo->pdIsActive( smartid ) ) { return false; }
 
   try {
     if ( globalPoint.z() < 8000.0 ) {
diff --git a/Rich/RichFutureUtils/src/RichTabulatedRefIndex.cpp b/Rich/RichFutureUtils/src/RichTabulatedRefIndex.cpp
index d865f429e98788b07c8d6d217224cfab6b04f290..2f5f8c211cad2c1db7bb9c74cebb418ed61b6e11 100644
--- a/Rich/RichFutureUtils/src/RichTabulatedRefIndex.cpp
+++ b/Rich/RichFutureUtils/src/RichTabulatedRefIndex.cpp
@@ -15,8 +15,20 @@
 #include "boost/limits.hpp"
 #include "boost/numeric/conversion/bounds.hpp"
 
+// Detector
+#include "RichDetectors/RichRadiator.h"
+
 using namespace Rich::Utils;
 
+namespace {
+  // work around for fact radiator is stored as void*
+  // to be removed once RichDet is dropped
+  // here we can assume it must be a Detector::Radiator pointer
+  decltype( auto ) radiator( const Rich::RadIntersection& inter ) {
+    return inter.radiator<const Rich::Detector::Radiator>();
+  }
+} // namespace
+
 float TabulatedRefIndex::refractiveIndex( const Rich::RadIntersection::Vector& intersections,
                                           const float                          energy ) const {
   // loop over all radiator intersections and calculate the weighted average
@@ -24,7 +36,7 @@ float TabulatedRefIndex::refractiveIndex( const Rich::RadIntersection::Vector& i
   float refIndex( 0 ), totPathL( 0 );
   for ( const auto& R : intersections ) {
     const auto pLength = R.pathLength();
-    refIndex += pLength * R.radiator()->refractiveIndex( energy, m_hltMode );
+    refIndex += pLength * radiator( R )->refractiveIndex( energy, m_hltMode );
     totPathL += pLength;
   }
   return ( totPathL > 0 ? refIndex / totPathL : refIndex );
@@ -35,9 +47,10 @@ float TabulatedRefIndex::refractiveIndex( const Rich::RadIntersection::Vector& i
   // according to the path length in each radiator
   float refIndex( 0 ), totPathL( 0 );
   for ( const auto& R : intersections ) {
-    const auto energy  = meanPhotonEnergy( R.radiator()->radiatorID() );
+    auto       rad     = radiator( R );
+    const auto energy  = meanPhotonEnergy( rad->radiatorID() );
     const auto pLength = R.pathLength();
-    refIndex += pLength * R.radiator()->refractiveIndex( energy, m_hltMode );
+    refIndex += pLength * rad->refractiveIndex( energy, m_hltMode );
     totPathL += pLength;
   }
   return ( totPathL > 0 ? refIndex / totPathL : refIndex );
@@ -49,7 +62,7 @@ float TabulatedRefIndex::refractiveIndexRMS( const Rich::RadIntersection::Vector
   float refIndexRMS( 0 ), totPathL( 0 );
   for ( const auto& R : intersections ) {
     const auto  pLength = R.pathLength();
-    const auto* index   = R.radiator()->refIndex( m_hltMode );
+    const auto* index   = radiator( R )->refIndex( m_hltMode );
     refIndexRMS += pLength * index->rms( index->minX(), index->maxX(), 100 );
     totPathL += pLength;
   }
@@ -62,7 +75,7 @@ float TabulatedRefIndex::refractiveIndexSD( const Rich::RadIntersection::Vector&
   float refIndexSD( 0 ), totPathL( 0 );
   for ( const auto& R : intersections ) {
     const auto  pLength = R.pathLength();
-    const auto* index   = R.radiator()->refIndex( m_hltMode );
+    const auto* index   = radiator( R )->refIndex( m_hltMode );
     refIndexSD += pLength * index->standardDeviation( index->minX(), index->maxX(), 100 );
     totPathL += pLength;
   }
diff --git a/Rich/RichInterfaces/dict/RichInterfacesDict.h b/Rich/RichInterfaces/dict/RichInterfacesDict.h
index a47228e235448ef465ad33d7f601b914e8547fbc..42942495a6508090e2918d1138ad87f60ae33f25 100644
--- a/Rich/RichInterfaces/dict/RichInterfacesDict.h
+++ b/Rich/RichInterfaces/dict/RichInterfacesDict.h
@@ -12,25 +12,8 @@
 #define DICT_RICHKERNELDICT_H 1
 
 // Interfaces
-#include "RichInterfaces/IRichAddBackground.h"
-#include "RichInterfaces/IRichDetParameters.h"
-#include "RichInterfaces/IRichGenericHPDAnalysisTool.h"
 #include "RichInterfaces/IRichParticleProperties.h"
-#include "RichInterfaces/IRichPixelSuppressionTool.h"
-#include "RichInterfaces/IRichRadiatorTool.h"
-#include "RichInterfaces/IRichRayTracing.h"
-#include "RichInterfaces/IRichRefractiveIndex.h"
 #include "RichInterfaces/IRichSmartIDTool.h"
-#include "RichInterfaces/IRichSnellsLawRefraction.h"
 #include "RichInterfaces/IRichToolRegistry.h"
 
-// instanciate templated classes
-namespace {
-  struct RichInterfaces_Instantiations {
-    Rich::IAddBackground::HPDBackgrounds   obj_1;
-    Rich::IGenericHPDAnalysisTool::Result  obj_2;
-    Rich::IGenericHPDAnalysisTool::Results obj_3;
-  };
-} // namespace
-
 #endif // DICT_RICHKERNELDICT_H
diff --git a/Rich/RichInterfaces/dict/RichInterfacesDict.xml b/Rich/RichInterfaces/dict/RichInterfacesDict.xml
index a714be389c9c9a320a3de9977d50e3877362234d..50099c697c19dc90addf8ba0a40ee15d565bb973 100755
--- a/Rich/RichInterfaces/dict/RichInterfacesDict.xml
+++ b/Rich/RichInterfaces/dict/RichInterfacesDict.xml
@@ -10,20 +10,8 @@
 -->
 <lcgdict>
 
-  <class name  = "Rich::IDetParameters"                />
   <class name  = "Rich::IParticleProperties"           />
-  <class name  = "Rich::DAQ::IPixelSuppressionTool"    />
-  <class name  = "Rich::IRadiatorTool"                 />
-  <class name  = "Rich::IRayTracing"                   />
-  <class name  = "Rich::IRefractiveIndex"              />
   <class name  = "Rich::ISmartIDTool"                  />
   <class name  = "Rich::IToolRegistry"                 />
-  <class name  = "Rich::ISnellsLawRefraction"          />
-  <class name  = "Rich::IDetParameters::RadLimits"     />
-  <class name  = "Rich::IAddBackground"                />
-  <class name  = "Rich::IAddBackground::HPDBackgrounds"/>
-  <class name  = "Rich::IGenericHPDAnalysisTool"       />
-  <class name  = "Rich::IGenericHPDAnalysisTool::Result"  />
-  <class name  = "Rich::IGenericHPDAnalysisTool::Results" />
 
 </lcgdict>
diff --git a/Rich/RichInterfaces/include/RichInterfaces/IRichAddBackground.h b/Rich/RichInterfaces/include/RichInterfaces/IRichAddBackground.h
deleted file mode 100644
index a9550cae830c2c0c106cf6ab0bb20e1a02b6fc26..0000000000000000000000000000000000000000
--- a/Rich/RichInterfaces/include/RichInterfaces/IRichAddBackground.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*****************************************************************************\
-* (c) Copyright 2000-2018 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.                                       *
-\*****************************************************************************/
-
-//---------------------------------------------------------------------------------
-/** @file IRichAddBackground.h
- *
- * Header file for tool interface : Rich::IAddBackground
- *
- * @author Chris Jones   Christopher.Rob.Jones@cern.ch
- * @date   2008-10-10
- */
-//---------------------------------------------------------------------------------
-
-#pragma once
-
-// from STL
-#include <string>
-
-// from Gaudi
-#include "GaudiKernel/IAlgTool.h"
-
-// RICH Utils
-#include "RichUtils/RichHashMap.h"
-
-namespace Rich {
-
-  /** @class IAddBackground RichKernel/IRichAddBackground.h
-   *
-   *  Interface for tools that generate RICH backgrounds
-   *
-   *  @author Chris Jones
-   *  @date   2008-10-10
-   */
-
-  class IAddBackground : virtual public IAlgTool {
-
-  public:
-    /// Interface ID
-    DeclareInterfaceID( IAddBackground, 1, 0 );
-
-  public:
-    /// Data structure for returned additional backgrounds
-    using HPDBackgrounds = Rich::HashMap<LHCb::RichSmartID, LHCb::RichSmartID::Vector>;
-
-  public:
-    /// Compute a set of background hits
-    virtual StatusCode createBackgrounds( HPDBackgrounds& backgrounds, const bool aliceMode = false ) const = 0;
-  };
-
-} // namespace Rich
diff --git a/Rich/RichInterfaces/include/RichInterfaces/IRichDetParameters.h b/Rich/RichInterfaces/include/RichInterfaces/IRichDetParameters.h
deleted file mode 100644
index f3292ef88fed2407e510a6b8c6ce0b8d29187626..0000000000000000000000000000000000000000
--- a/Rich/RichInterfaces/include/RichInterfaces/IRichDetParameters.h
+++ /dev/null
@@ -1,138 +0,0 @@
-/*****************************************************************************\
-* (c) Copyright 2000-2018 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.                                       *
-\*****************************************************************************/
-
-//-----------------------------------------------------------------------------
-/** @file IRichDetParameters.h
- *
- *  Header file for tool interface : Rich::IDetParameters
- *
- *  @author Chris Jones    Christopher.Rob.Jones@cern.ch
- *  @date   2004-03-29
- */
-//-----------------------------------------------------------------------------
-
-#pragma once
-
-// Gaudi
-#include "GaudiKernel/IAlgTool.h"
-
-// LHCbKernel
-#include "Kernel/RichRadiatorType.h"
-
-namespace Rich {
-
-  //-----------------------------------------------------------------------------
-  /** @class IDetParameters IRichDetParameters.h RichKernel/IRichDetParameters.h
-   *
-   *  Interface for tools providing access to useful detector parameters, that
-   *  cannot be easily calculated on the fly. Some could eventually be moved to
-   *  either the LHCbCond or DDDB databases.
-   *
-   *  @author Chris Jones    Christopher.Rob.Jones@cern.ch
-   *  @date   2004-03-29
-   */
-  //-----------------------------------------------------------------------------
-
-  class IDetParameters : public virtual IAlgTool {
-
-  public:
-    /** @class RadLimits IRichDetParameters.h RichKernel/IRichDetParameters.h
-     *
-     *  Helper class for IRichDetParameters to contain HPD acceptance data
-     *
-     *  @author Chris Jones    Christopher.Rob.Jones@cern.ch
-     *  @date   2005-01-29
-     */
-    class RadLimits {
-
-    public:
-      /// Default Constructor
-      RadLimits() = default;
-
-      /** Constructor from limit data
-       *
-       *  Limits are unsigned, and correspond to a single HPD panel.
-       *
-       *  @param minX The minimum x edge of acceptance
-       *  @param maxX The maximum x edge of acceptance
-       *  @param minY The minimum y edge of acceptance
-       *  @param maxY The maximum y edge of acceptance
-       */
-      RadLimits( const double minX, const double maxX, const double minY, const double maxY )
-          : m_maxX( maxX ), m_minX( minX ), m_maxY( maxY ), m_minY( minY ) {}
-
-    public:
-      /// Access the minimum x limit
-      inline double minX() const noexcept { return m_minX; }
-      /// Access the maximum x limit
-      inline double maxX() const noexcept { return m_maxX; }
-      /// Access the minimum y limit
-      inline double minY() const noexcept { return m_minY; }
-      /// Access the maximum y limit
-      inline double maxY() const noexcept { return m_maxY; }
-
-    private:
-      double m_maxX{0}; ///< Maximum X limit
-      double m_minX{0}; ///< Minimum X limit
-      double m_maxY{0}; ///< Maximum Y limit
-      double m_minY{0}; ///< Minimum Y limit
-    };
-
-  public:
-    /// Interface ID
-    DeclareInterfaceID( IDetParameters, 1, 0 );
-
-    /** Calculates the maximum observable photon energy for a given radiator medium
-     *
-     *  @param rad  The radiator type
-     *
-     *  @return The value of the maximum photon energy for the given radiator
-     */
-    virtual double maxPhotonEnergy( const Rich::RadiatorType rad ) const = 0;
-
-    /** Calculates the minimum observable photon energy for a given radiator medium
-     *
-     *  @param rad  The radiator type
-     *
-     *  @return The value of the minimum photon energy for the given radiator
-     */
-    virtual double minPhotonEnergy( const Rich::RadiatorType rad ) const = 0;
-
-    /** Calculate the mean observable photon energy for a given radiator medium
-     *
-     *  @param rad  The radiator type
-     *
-     * @return The value of the mean photon energy for the given radiator
-     */
-    virtual double meanPhotonEnergy( const Rich::RadiatorType rad ) const = 0;
-
-    /** Calculate the standard deviation of n-1 distribution for observed photons
-     *
-     *  @param rad  The radiator type
-     *
-     * @return The standard deviation of n-1 distribution for observed photons for the given
-     * radiator
-     */
-    virtual double refIndexSD( const Rich::RadiatorType rad ) const = 0;
-
-    /** Returns the average acceptance outer limits in local HPD coordinates
-     *  for the given radiator type
-     *
-     *  @param rad The radiator type
-     *
-     *  @return The average (x,y) outer acceptance limits
-     *          .first  Gives the x limit
-     *          .second Gives the y limit
-     */
-    virtual const IDetParameters::RadLimits& AvAcceptOuterLimitsLocal( const Rich::RadiatorType rad ) const = 0;
-  };
-
-} // namespace Rich
diff --git a/Rich/RichInterfaces/include/RichInterfaces/IRichGenericHPDAnalysisTool.h b/Rich/RichInterfaces/include/RichInterfaces/IRichGenericHPDAnalysisTool.h
deleted file mode 100644
index 12c83738f379e88b4a2678e6e3150d73a88ac5e5..0000000000000000000000000000000000000000
--- a/Rich/RichInterfaces/include/RichInterfaces/IRichGenericHPDAnalysisTool.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*****************************************************************************\
-* (c) Copyright 2000-2018 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.                                       *
-\*****************************************************************************/
-
-//-----------------------------------------------------------------------------
-/** @file IRichGenericHPDAnalysisTool.h
- *
- *  Header file for tool interface : Rich::IGenericHPDAnalysisTool
- *
- *  @author Chris Jones   Christopher.Rob.Jones@cern.ch
- *  @date   10/10/2009
- */
-//-----------------------------------------------------------------------------
-
-#pragma once
-
-// STL
-#include <vector>
-
-// from Gaudi
-#include "GaudiKernel/IAlgTool.h"
-
-// Kernel
-#include "Kernel/RichSmartID.h"
-
-namespace Rich {
-  //-----------------------------------------------------------------------------
-  /** @class IGenericHPDAnalysisTool RichKernel/IRichGenericHPDAnalysisTool.h
-   *
-   *  Interface for tools that perform any data anlysis on a single HPD data block
-   *
-   *  @author Chris Jones   Christopher.Rob.Jones@cern.ch
-   *  @date   10/10/2009
-   */
-  //-----------------------------------------------------------------------------
-
-  class IGenericHPDAnalysisTool : public virtual IAlgTool {
-
-  public:
-    /// Interface ID
-    DeclareInterfaceID( IGenericHPDAnalysisTool, 1, 0 );
-
-  public:
-    /** @class Result RichKernel/IRichGenericHPDAnalysisTool.h
-     *
-     *  Results of the HPD analysis
-     *
-     *  @author Chris Jones   Christopher.Rob.Jones@cern.ch
-     *  @date   10/10/2009
-     */
-    class Result {
-    public:
-      LHCb::RichSmartID id;      ///< Detector component the result refers to
-      std::string       message; ///< Message associated with the result
-      StatusCode        status;  ///< StatusCode indicating the severity of the report
-    };
-
-    /// Type for a list of results
-    using Results = std::vector<Result>;
-
-  public:
-    /** Applies HPD data analysis to given HPD data
-     *
-     *  @param hpdID    HPD identifier
-     *  @param smartIDs Reference to vector of pixel RichSmartIDs for the given HPD
-     *
-     *  @return StatusCode indicating if the analysis was successfully run or not
-     */
-    virtual StatusCode analyse( const LHCb::RichSmartID hpdID, const LHCb::RichSmartID::Vector& smartIDs,
-                                IGenericHPDAnalysisTool::Results& results ) const = 0;
-  };
-
-} // namespace Rich
diff --git a/Rich/RichInterfaces/include/RichInterfaces/IRichPixelSuppressionTool.h b/Rich/RichInterfaces/include/RichInterfaces/IRichPixelSuppressionTool.h
deleted file mode 100644
index 0f3ddc8d2c03b38b200f7237b8184dee6a1a7819..0000000000000000000000000000000000000000
--- a/Rich/RichInterfaces/include/RichInterfaces/IRichPixelSuppressionTool.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*****************************************************************************\
-* (c) Copyright 2000-2018 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.                                       *
-\*****************************************************************************/
-
-//-----------------------------------------------------------------------------
-/** @file IRichPixelSuppressionTool.h
- *
- *  Header file for tool interface : Rich::DAQ::IPixelSuppressionTool
- *
- *  @author Chris Jones   Christopher.Rob.Jones@cern.ch
- *  @date   2003-07-31
- */
-//-----------------------------------------------------------------------------
-
-#pragma once
-
-// STL
-#include <vector>
-
-// from Gaudi
-#include "GaudiKernel/IAlgTool.h"
-
-// Kernel
-#include "Kernel/RichSmartID.h"
-
-namespace Rich::DAQ {
-
-  //-----------------------------------------------------------------------------
-  /** @class IPixelSuppressionTool IRichPixelSuppressionTool.h
-   * RichKernel/IRichPixelSuppressionTool.h
-   *
-   *  Interface for tool for apply suppression to HPD pixels
-   *
-   *  @author Chris Jones   Christopher.Rob.Jones@cern.ch
-   *  @date   15/03/2002
-   */
-  //-----------------------------------------------------------------------------
-
-  class IPixelSuppressionTool : public virtual IAlgTool {
-
-  public:
-    /// Interface ID
-    DeclareInterfaceID( IPixelSuppressionTool, 1, 0 );
-
-    /** Applies pixel suppression to the given HPD
-     *
-     *  @param hpdID    HPD identifier
-     *  @param smartIDs Reference to vector of pixel RichSmartIDs for the given HPD
-     *
-     *  @return Boolean indicating if pixels have been suppressed or not
-     *  @retval true Some (or all) pixels have been suppressed. In the case the vector of
-     *               pixel RichSmartIDs is changed
-     *  @retval false No pixels are suppressed
-     */
-    virtual bool applyPixelSuppression( const LHCb::RichSmartID hpdID, LHCb::RichSmartID::Vector& smartIDs ) const = 0;
-  };
-
-} // namespace Rich::DAQ
diff --git a/Rich/RichInterfaces/include/RichInterfaces/IRichRadiatorTool.h b/Rich/RichInterfaces/include/RichInterfaces/IRichRadiatorTool.h
deleted file mode 100644
index 4f07f7ecc61fb8063b0e7144580b481a7cf558ec..0000000000000000000000000000000000000000
--- a/Rich/RichInterfaces/include/RichInterfaces/IRichRadiatorTool.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*****************************************************************************\
-* (c) Copyright 2000-2018 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.                                       *
-\*****************************************************************************/
-
-//---------------------------------------------------------------------------------
-/** @file IRichRadiatorTool.h
- *
- *  Header file for RICH tool interface : Rich::IRadiatorTool
- *
- *  @author Antonis Papanestis
- *  @date   2006-03-01
- */
-//---------------------------------------------------------------------------------
-
-#pragma once
-
-// from STL
-#include <string>
-
-// from Gaudi
-#include "GaudiKernel/IAlgTool.h"
-
-// from MathCore
-#include "GaudiKernel/Point3DTypes.h"
-#include "GaudiKernel/Vector3DTypes.h"
-
-// from LHCbKernel
-#include "Kernel/RichRadIntersection.h"
-#include "Kernel/RichRadiatorType.h"
-
-namespace Rich {
-
-  /** @class IRadiatorTool IRichRadiatorTool.h RichKernel/IRichRadiatorTool.h
-   *
-   *  Interface to RICH radiator tool
-   *
-   *  @author Antonis Papanestis
-   *  @date   2006-03-01
-   */
-
-  class IRadiatorTool : virtual public IAlgTool {
-
-  public:
-    /// Interface ID
-    DeclareInterfaceID( IRadiatorTool, 1, 0 );
-
-    /** @brief Finds the intersections (entry/exit) with radiator.
-     *
-     * For multiple radiators (e.g. the aerogel tiles) there can be more than one intersections
-     *
-     * The intersections are sorted into order of increasing z
-     *
-     * @param globalPoint   The start point for the intersection extraplotion
-     * @param globalVector  The direction vector for the intersection extraplotion
-     * @param radiator      The radiator to find the intersections in
-     * @param intersections The found intersections
-     *
-     * @return The number of intersections
-     */
-    virtual unsigned int intersections( const Gaudi::XYZPoint& globalPoint, const Gaudi::XYZVector& globalVector,
-                                        const Rich::RadiatorType       radiator,
-                                        Rich::RadIntersection::Vector& intersections ) const = 0;
-  };
-
-} // namespace Rich
diff --git a/Rich/RichInterfaces/include/RichInterfaces/IRichRayTracing.h b/Rich/RichInterfaces/include/RichInterfaces/IRichRayTracing.h
deleted file mode 100644
index b011e909485484e78aec6554e91fdaa25d4cd1aa..0000000000000000000000000000000000000000
--- a/Rich/RichInterfaces/include/RichInterfaces/IRichRayTracing.h
+++ /dev/null
@@ -1,158 +0,0 @@
-/*****************************************************************************\
-* (c) Copyright 2000-2018 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.                                       *
-\*****************************************************************************/
-
-//-----------------------------------------------------------------------------
-/** @file IRichRayTracing.h
- *
- *  Header file for tool interface : Rich::IRayTracing
- *
- *  @author Antonis Papanestis
- *  @date   2003-10-28
- */
-//-----------------------------------------------------------------------------
-
-#pragma once
-
-// from Gaudi
-#include "GaudiKernel/IAlgTool.h"
-
-// LHCbKernel
-#include "Kernel/RichDetectorType.h"
-#include "Kernel/RichSide.h"
-#include "Kernel/RichTraceMode.h"
-
-// MathCore
-#include "GaudiKernel/Plane3DTypes.h"
-#include "GaudiKernel/Point3DTypes.h"
-#include "GaudiKernel/Vector3DTypes.h"
-
-// forward decs
-namespace LHCb {
-  class RichGeomPhoton;
-  class RichTrackSegment;
-} // namespace LHCb
-
-namespace Rich {
-
-  //-----------------------------------------------------------------------------
-  /** @class IRayTracing IRichRayTracing.h RichKernel/IRichRayTracing.h
-   *
-   *  A tool to trace photons (or similar) from a point all the way to
-   *  the photo detectors.
-   *
-   *  @author Antonis Papanestis
-   *  @author Chris Jones   Christopher.Rob.Jones@cern.ch
-   *  @date   2003-10-28
-   */
-  //-----------------------------------------------------------------------------
-
-  class IRayTracing : public virtual IAlgTool {
-
-  public:
-    /// Interface ID
-    DeclareInterfaceID( IRayTracing, 1, 0 );
-
-    /** For a given detector, ray-traces a given direction from a given point to
-     *  the photo detectors. Returns the result in the form of a RichGeomPhoton
-     *  which contains the full ray tracing information.
-     *
-     *  @param[in]  rich       The RICH detector
-     *  @param[in]  startPoint The start point to use for the ray tracing
-     *  @param[in]  startDir   The direction to ray trace from the start point
-     *  @param[out] photon     The result of the raytracing, encapsulated as a RichGeomPhoton
-     *  @param[in]  trSeg      The track segment associated to the photon direction to update
-     *  @param[in]  mode       The ray tracing mode configuration
-     *  @param[in]  forcedSide If configured to do so, the forced side to use
-     *
-     *  @return Status of the ray tracing
-     */
-    virtual LHCb::RichTraceMode::RayTraceResult
-    traceToDetector( const Rich::DetectorType rich, const Gaudi::XYZPoint& startPoint, const Gaudi::XYZVector& startDir,
-                     LHCb::RichGeomPhoton& photon, const LHCb::RichTrackSegment& trSeg,
-                     const LHCb::RichTraceMode mode       = LHCb::RichTraceMode(),
-                     const Rich::Side          forcedSide = Rich::top ) const = 0;
-
-    /** For a given detector, raytraces a given direction from a given point to
-     *  the photo detectors. Returns the result in the form of a RichGeomPhoton.
-     *
-     *  @param[in]  rich        The RICH detector
-     *  @param[in]  startPoint  The start point to use for the ray tracing
-     *  @param[in]  startDir    The direction to ray trace from the start point
-     *  @param[out] hitPosition The result of the tracing, the hit point on the HPD panel
-     *  @param[in]  trSeg       The track segment associated to the photon direction to update
-     *  @param[in]  mode        The ray tracing mode configuration
-     *  @param[in]  forcedSide  If configured to do so, the forced side to use
-     *
-     *  @return Status of the ray tracing
-     */
-    virtual LHCb::RichTraceMode::RayTraceResult
-    traceToDetector( const Rich::DetectorType rich, const Gaudi::XYZPoint& startPoint, const Gaudi::XYZVector& startDir,
-                     Gaudi::XYZPoint& hitPosition, const LHCb::RichTrackSegment& trSeg,
-                     const LHCb::RichTraceMode mode       = LHCb::RichTraceMode(),
-                     const Rich::Side          forcedSide = Rich::top ) const = 0;
-
-    /** For a given detector, ray-traces a given direction from a given point to
-     *  the photo detectors. Returns the result in the form of a RichGeomPhoton
-     *  which contains the full ray tracing information.
-     *
-     *  @param[in]  rich       The RICH detector
-     *  @param[in]  startPoint The start point to use for the ray tracing
-     *  @param[in]  startDir   The direction to ray trace from the start point
-     *  @param[out] photon     The result of the raytracing, encapsulated as a RichGeomPhoton
-     *  @param[in]  mode       The ray tracing mode configuration
-     *  @param[in]  forcedSide If configured to do so, the forced side to use
-     *  @param[in]  photonEnergy If needed (for instance for refraction corrections) the photon
-     *                           energy to assume.
-     *
-     *  @return Status of the ray tracing
-     */
-    virtual LHCb::RichTraceMode::RayTraceResult
-    traceToDetector( const Rich::DetectorType rich, const Gaudi::XYZPoint& startPoint, const Gaudi::XYZVector& startDir,
-                     LHCb::RichGeomPhoton& photon, const LHCb::RichTraceMode mode = LHCb::RichTraceMode(),
-                     const Rich::Side forcedSide = Rich::top, const double photonEnergy = 0 ) const = 0;
-
-    /** For a given detector, raytraces a given direction from a given point to
-     *  the photo detectors. Returns the result in the form of a RichGeomPhoton.
-     *
-     *  @param[in]  rich        The RICH detector
-     *  @param[in]  startPoint  The start point to use for the ray tracing
-     *  @param[in]  startDir    The direction to ray trace from the start point
-     *  @param[out] hitPosition The result of the tracing, the hit point on the HPD panel
-     *  @param[in]  mode        The ray tracing mode configuration
-     *  @param[in]  forcedSide  If configured to do so, the forced side to use
-     *  @param[in]  photonEnergy If needed (for instance for refraction corrections) the photon
-     *                           energy to assume.
-     *
-     *  @return Status of the ray tracing
-     */
-    virtual LHCb::RichTraceMode::RayTraceResult
-    traceToDetector( const Rich::DetectorType rich, const Gaudi::XYZPoint& startPoint, const Gaudi::XYZVector& startDir,
-                     Gaudi::XYZPoint& hitPosition, const LHCb::RichTraceMode mode = LHCb::RichTraceMode(),
-                     const Rich::Side forcedSide = Rich::top, const double photonEnergy = 0 ) const = 0;
-
-    /** Raytraces from a point in the detector panel back to the spherical mirror
-     *  returning the mirror intersection point and the direction a track would have
-     *  in order to hit that point in the detector panel.
-     *
-     *  @param[in]  startPoint The start point to use for the ray tracing
-     *  @param[in]  startDir   The direction to ray trace from the start point
-     *  @param[out] endPoint   The required mirror intersection point
-     *  @param[out] endDir     The required track direction
-     *
-     *  @return Boolean indicating the status of the ray tracing
-     *  @retval true  Ray tracing was successful
-     *  @retval false Ray tracing was unsuccessful
-     */
-    virtual bool traceBackFromDetector( const Gaudi::XYZPoint& startPoint, const Gaudi::XYZVector& startDir,
-                                        Gaudi::XYZPoint& endPoint, Gaudi::XYZVector& endDir ) const = 0;
-  };
-
-} // namespace Rich
diff --git a/Rich/RichInterfaces/include/RichInterfaces/IRichRefractiveIndex.h b/Rich/RichInterfaces/include/RichInterfaces/IRichRefractiveIndex.h
deleted file mode 100644
index 165a712871c738b05c5f55e3fd8007bb72a3850d..0000000000000000000000000000000000000000
--- a/Rich/RichInterfaces/include/RichInterfaces/IRichRefractiveIndex.h
+++ /dev/null
@@ -1,122 +0,0 @@
-/*****************************************************************************\
-* (c) Copyright 2000-2018 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.                                       *
-\*****************************************************************************/
-
-//-----------------------------------------------------------------------------
-/** @file IRichRefractiveIndex.h
- *
- *  Header file for tool interface : Rich::IRefractiveIndex
- *
- *  @author Chris Jones   Christopher.Rob.Jones@cern.ch
- *  @date   15/03/2002
- */
-//-----------------------------------------------------------------------------
-
-#pragma once
-
-// Gaudi
-#include "GaudiKernel/IAlgTool.h"
-
-// LHCbKernel
-#include "Kernel/RichRadIntersection.h"
-#include "Kernel/RichRadiatorType.h"
-
-namespace Rich {
-
-  /** @class IRefractiveIndex IRichRefractiveIndex.h
-   *
-   *  Interface for tool to calculate effective refractive indices for
-   *  each radiator
-   *
-   *  @author Chris Jones   Christopher.Rob.Jones@cern.ch
-   *  @date   15/03/2002
-   */
-
-  class IRefractiveIndex : public virtual IAlgTool {
-
-  public:
-    /// Interface ID
-    DeclareInterfaceID( IRefractiveIndex, 1, 0 );
-
-  public:
-    /// Scalar type to use
-    using ScType = float;
-
-  public:
-    /** Calculates the refractive index for a given radiator type at a
-     *  given photon energy.
-     *
-     *  @param rad    The radiator type
-     *  @param energy The photon energy at which the refractive index is to be calculated
-     *
-     *  @return The refractive index at the requested energy
-     */
-    virtual ScType refractiveIndex( const Rich::RadiatorType rad, const ScType energy ) const = 0;
-
-    /** Calculates the average refractive index for a given radiator type
-     *  for a given range of photon energies.
-     *
-     *  @param rad       The radiator type
-     *  @param energyBot The lower bound of photon energies
-     *  @param energyTop The upper bound of photon energies
-     *
-     *  @return The average refractive index between the two energy bounds
-     */
-    virtual ScType refractiveIndex( const Rich::RadiatorType rad, const ScType energyBot,
-                                    const ScType energyTop ) const = 0;
-
-    /** Calculates the average refractive index for a given radiator type
-     *  for all visable photon energies.
-     *
-     *  @param rad       The radiator type
-     *
-     *  @return The overall average refractive index
-     */
-    virtual ScType refractiveIndex( const Rich::RadiatorType rad ) const = 0;
-
-    /** Calculates the average refractive index for a given set of radiator intersections
-     *  for all visable photon energies.
-     *
-     *  @param intersections The radiator intersections
-     *
-     *  @return The overall average refractive index
-     */
-    virtual ScType refractiveIndex( const Rich::RadIntersection::Vector& intersections ) const = 0;
-
-    /** Calculates the refractive index R.M.S. for a given set of radiator intersections
-     *  for all visable photon energies.
-     *
-     *  @param intersections The radiator intersections
-     *
-     *  @return The refractive index R.M.S.
-     */
-    virtual ScType refractiveIndexRMS( const Rich::RadIntersection::Vector& intersections ) const = 0;
-
-    /** Calculates the refractive index standard deviation  for a given set of radiator
-     * intersections for all visable photon energies.
-     *
-     *  @param intersections The radiator intersections
-     *
-     *  @return The refractive index S.D.
-     */
-    virtual ScType refractiveIndexSD( const Rich::RadIntersection::Vector& intersections ) const = 0;
-
-    /** Calculates the average refractive index for a given set of radiator intersections
-     *  for all visable photon energies.
-     *
-     *  @param intersections The radiator intersections
-     *  @param energy The photon energy at which the refractive index is to be calculated
-     *
-     *  @return The overall average refractive index
-     */
-    virtual ScType refractiveIndex( const Rich::RadIntersection::Vector& intersections, const ScType energy ) const = 0;
-  };
-
-} // namespace Rich
diff --git a/Rich/RichInterfaces/include/RichInterfaces/IRichSnellsLawRefraction.h b/Rich/RichInterfaces/include/RichInterfaces/IRichSnellsLawRefraction.h
deleted file mode 100644
index 9ffaad754d10da279473c11375d5379706f2b1e2..0000000000000000000000000000000000000000
--- a/Rich/RichInterfaces/include/RichInterfaces/IRichSnellsLawRefraction.h
+++ /dev/null
@@ -1,100 +0,0 @@
-/*****************************************************************************\
-* (c) Copyright 2000-2018 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.                                       *
-\*****************************************************************************/
-
-//-----------------------------------------------------------------------------
-/** @file IRichSnellsLawRefraction.h
- *
- *  Header file for tool interface : Rich::ISnellsLawRefraction
- *
- *  @author Chris Jones   Christopher.Rob.Jones@cern.ch
- *  @date   03/01/2008
- */
-//-----------------------------------------------------------------------------
-
-#pragma once
-
-// from Gaudi
-#include "GaudiKernel/IAlgTool.h"
-
-// from MathCore
-#include "GaudiKernel/Point3DTypes.h"
-#include "GaudiKernel/Vector3DTypes.h"
-
-// Event Model
-namespace LHCb {
-  class RichTrackSegment;
-}
-
-namespace Rich {
-
-  //-----------------------------------------------------------------------------
-  /** @class ISnellsLawRefraction RichKernel/IRichSnellsLawRefraction.h
-   *
-   *  Interface to a tool which implements snells law refraction at Aerogel / Rich1Gas
-   *  boundary.
-   *
-   *  @author Chris Jones   Christopher.Rob.Jones@cern.ch
-   *  @date   03/01/2008
-   */
-  //-----------------------------------------------------------------------------
-
-  class ISnellsLawRefraction : public virtual IAlgTool {
-
-  public:
-    /// Interface ID
-    DeclareInterfaceID( ISnellsLawRefraction, 1, 0 );
-
-    /** Correct the direction vector and start point for refraction in going from Aerogel to
-     * Rich1Gas.
-     *
-     *  Uses the effective refractive index seen by the track segment in question.
-     *
-     *  @param[in]     startPoint The starting point
-     *  @param[in,out] dir   The direction to update (WARNING Must be a unit vector)
-     *  @param[in]     trSeg The aerogel track segment associated to the photon direction to update
-     */
-    virtual void aerogelToGas( Gaudi::XYZPoint& startPoint, Gaudi::XYZVector& dir,
-                               const LHCb::RichTrackSegment& trSeg ) const = 0;
-
-    /** Correct the direction vector and start point for refraction in going from Aerogel to
-     * Rich1Gas
-     *
-     *  Uses a simple average of the refractive index for the radiator volumes
-     *
-     *  @param[in]     startPoint The starting point
-     *  @param[in,out] dir        The direction to update (WARNING Must be a unit vector)
-     *  @param[in]     photonEnergy The energy of the photon (used to get the correct refractive
-     * indices)
-     */
-    virtual void aerogelToGas( Gaudi::XYZPoint& startPoint, Gaudi::XYZVector& dir,
-                               const double photonEnergy ) const = 0;
-
-    /** Correct the direction vector for refraction in going from Rich1Gas to aerogel
-     *
-     *  Uses the effective refractive index seen by the track segment in question.
-     *
-     *  @param[in,out] dir   The direction to update (WARNING Must be a unit vector)
-     *  @param[in]     trSeg The aerogel track segment associated to the photon direction to update
-     */
-    virtual void gasToAerogel( Gaudi::XYZVector& dir, const LHCb::RichTrackSegment& trSeg ) const = 0;
-
-    /** Correct the direction vector for refraction in going from Rich1Gas to aerogel
-     *
-     *  Uses a simple average of the refractive index for the radiator volumes
-     *
-     *  @param[in,out] dir        The direction to update (WARNING Must be a unit vector)
-     *  @param[in]     photonEnergy The energy of the photon (used to get the correct refractive
-     * indices)
-     */
-    virtual void gasToAerogel( Gaudi::XYZVector& dir, const double photonEnergy ) const = 0;
-  };
-
-} // namespace Rich
diff --git a/Rich/RichUtils/include/RichUtils/RichGeomPhoton.h b/Rich/RichUtils/include/RichUtils/RichGeomPhoton.h
index 5ffd52e59f82a87230145617be354e9a6a30714a..c1a7020438b3323ad8d7c68aac04ea777a9d8ffd 100644
--- a/Rich/RichUtils/include/RichUtils/RichGeomPhoton.h
+++ b/Rich/RichUtils/include/RichUtils/RichGeomPhoton.h
@@ -22,9 +22,6 @@
 
 #pragma once
 
-// std include
-#include <iostream>
-
 // geometry
 #include "GaudiKernel/Point3DTypes.h"
 #include "GaudiKernel/Vector3DTypes.h"
@@ -36,7 +33,12 @@
 #include "Kernel/MemPoolAlloc.h"
 
 // Forward declarations
-class DeRichSphMirror;
+namespace Rich::Detector {
+  class Mirror;
+}
+
+// std include
+#include <iostream>
 
 // General LHCb namespace
 namespace LHCb {
@@ -55,6 +57,8 @@ namespace LHCb {
   public:
     /// Container of photons
     using Vector = LHCb::STL::Vector<RichGeomPhoton>;
+    /// Mirror Type
+    using Mirror = Rich::Detector::Mirror;
 
   public:
     /// Default Constructor
@@ -84,10 +88,16 @@ namespace LHCb {
      *  @param activeFrac The fraction of the associate segment that this photon could have been
      * radiated from
      */
-    RichGeomPhoton( const float theta, const float phi, const Gaudi::XYZPoint& emissionPoint,
-                    const Gaudi::XYZVector& emissionDir, const Gaudi::XYZPoint& detectionPoint,
-                    const Gaudi::XYZPoint& sphMirrReflPoint, const Gaudi::XYZPoint& flatMirrReflPoint,
-                    const LHCb::RichSmartID smartID = LHCb::RichSmartID(), const float activeFrac = 0 )
+    RichGeomPhoton( const float             theta,                            // CK theta
+                    const float             phi,                              // CK phi
+                    const Gaudi::XYZPoint&  emissionPoint,                    // photon emission ptn
+                    const Gaudi::XYZVector& emissionDir,                      // photon emission dir
+                    const Gaudi::XYZPoint&  detectionPoint,                   // photon detection ptn
+                    const Gaudi::XYZPoint&  sphMirrReflPoint,                 // primary mirror refle. ptn
+                    const Gaudi::XYZPoint&  flatMirrReflPoint,                // secondary mirror refl. ptn
+                    const LHCb::RichSmartID smartID    = LHCb::RichSmartID(), // channel ID for detection ptn
+                    const float             activeFrac = 0                    // active fraction of track segment path
+                    )
         : m_CherenkovTheta( theta )
         , m_CherenkovPhi( phi )
         , m_emissionPoint( emissionPoint )
@@ -110,10 +120,15 @@ namespace LHCb {
      *  @param activeFrac The fraction of the associate segment that this photon could have been
      * radiated from
      */
-    RichGeomPhoton( const float theta, const float phi, const Gaudi::XYZPoint& emissionPoint,
-                    const Gaudi::XYZPoint& detectionPoint, const Gaudi::XYZPoint& sphMirrReflPoint,
-                    const Gaudi::XYZPoint& flatMirrReflPoint, const LHCb::RichSmartID smartID = LHCb::RichSmartID(),
-                    const float activeFrac = 0 )
+    RichGeomPhoton( const float             theta,                            // CK theta
+                    const float             phi,                              // CK phi
+                    const Gaudi::XYZPoint&  emissionPoint,                    // photon emission ptn
+                    const Gaudi::XYZPoint&  detectionPoint,                   // photon detection ptn
+                    const Gaudi::XYZPoint&  sphMirrReflPoint,                 // primary mirror refle. ptn
+                    const Gaudi::XYZPoint&  flatMirrReflPoint,                // secondary mirror refl. ptn
+                    const LHCb::RichSmartID smartID    = LHCb::RichSmartID(), // channel ID for detection ptn
+                    const float             activeFrac = 0                    // active fraction of track segment path
+                    )
         : m_CherenkovTheta( theta )
         , m_CherenkovPhi( phi )
         , m_emissionPoint( emissionPoint )
@@ -211,16 +226,16 @@ namespace LHCb {
     bool unambiguousPhoton() const noexcept { return m_unambiguousPhoton; }
 
     /// Set the associated primary mirror detector element
-    inline void setPrimaryMirror( const DeRichSphMirror* mirror ) noexcept { m_primaryMirror = mirror; }
+    inline void setPrimaryMirror( const Mirror* mirror ) noexcept { m_primaryMirror = mirror; }
 
     /// Access the associated primary mirror detector element
-    inline const DeRichSphMirror* primaryMirror() const noexcept { return m_primaryMirror; }
+    inline const Mirror* primaryMirror() const noexcept { return m_primaryMirror; }
 
     /// Set the associated secondary mirror detector element
-    inline void setSecondaryMirror( const DeRichSphMirror* mirror ) noexcept { m_secondaryMirror = mirror; }
+    inline void setSecondaryMirror( const Mirror* mirror ) noexcept { m_secondaryMirror = mirror; }
 
     /// Access the associated secondary mirror detector element
-    inline const DeRichSphMirror* secondaryMirror() const noexcept { return m_secondaryMirror; }
+    inline const Mirror* secondaryMirror() const noexcept { return m_secondaryMirror; }
 
     /**
      * Set accessor for the RichSmartID
@@ -312,10 +327,10 @@ namespace LHCb {
     LHCb::RichSmartID m_smartID;                ///< The channel ID for the photon detection point
 
     /// Pointer to the associated primary mirror detector element
-    const DeRichSphMirror* m_primaryMirror = nullptr;
+    const Mirror* m_primaryMirror = nullptr;
 
     /// Pointer to the associated secondary mirror detector element
-    const DeRichSphMirror* m_secondaryMirror = nullptr;
+    const Mirror* m_secondaryMirror = nullptr;
 
     /// Flag to indicate if an unambiguous photon or not
     bool m_unambiguousPhoton = false;
diff --git a/Rich/RichUtils/include/RichUtils/RichPixelCluster.h b/Rich/RichUtils/include/RichUtils/RichPixelCluster.h
index 1f8c01a799c39f7bebfccf1a1a3e2855e9c8d336..88a2f59e185cd0ef32ebdfdbb7f772f46a529814 100644
--- a/Rich/RichUtils/include/RichUtils/RichPixelCluster.h
+++ b/Rich/RichUtils/include/RichUtils/RichPixelCluster.h
@@ -45,7 +45,6 @@
 namespace Rich::Detector {
   class PD;
 }
-class DeRichPD;
 
 namespace Rich {
   // Needed to get vector printing to work
@@ -69,13 +68,8 @@ namespace Rich {
     /// Vector of clusters
     using Vector = LHCb::STL::Vector<PDPixelCluster>;
 
-    /// PD Type to use (depends on if DD4HEP or DetDesc is target detector description)
-#ifdef USE_DD4HEP
-    // For now use RichDet here as well. To Do migrate to DDD4HEP classes...
-    using PD = DeRichPD;
-#else
-    using PD = DeRichPD;
-#endif
+    /// PD Type to use
+    using PD = Rich::Detector::PD;
 
   public:
     /// Default Constructor
diff --git a/Rich/RichUtils/include/RichUtils/RichSIMDRayTracing.h b/Rich/RichUtils/include/RichUtils/RichSIMDRayTracing.h
index 8adea66c4afad399f4c57533e3e88b41c4a8d359..4f217019e937dab68a417d8799e92b9ef49bd458 100644
--- a/Rich/RichUtils/include/RichUtils/RichSIMDRayTracing.h
+++ b/Rich/RichUtils/include/RichUtils/RichSIMDRayTracing.h
@@ -24,7 +24,6 @@ namespace Rich::Detector {
   class Mirror;
   class PD;
 } // namespace Rich::Detector
-class DeRichPD;
 
 namespace Rich::RayTracingUtils {
 
@@ -38,14 +37,8 @@ namespace Rich::RayTracingUtils {
     using SmartIDs = Rich::SIMD::STDArray<LHCb::RichSmartID>;
     /// Type for mirror pointers
     using Mirrors = Rich::SIMD::STDArray<const Detector::Mirror*>;
-    /// PD Type to use (depends on if DD4HEP or DetDesc is target detector description)
-#ifdef USE_DD4HEP
-    // For now use RichDet here as well. To Do migrate to DDD4HEP classes...
-    // using PD = Detector::PD;
-    using PD = DeRichPD;
-#else
-    using PD = DeRichPD;
-#endif
+    /// PD Type
+    using PD = Detector::PD;
     /// SIMD Container of PDs
     using PDs = Rich::SIMD::STDArray<const PD*>;
     /// Type for Point
diff --git a/Rich/RichUtils/include/RichUtils/RichTrackSegment.h b/Rich/RichUtils/include/RichUtils/RichTrackSegment.h
index 68f4ed4b1a66942ac64e6f60453b9d8881362365..3821f6be7fabda9e1de76e33856817ed79f08da0 100644
--- a/Rich/RichUtils/include/RichUtils/RichTrackSegment.h
+++ b/Rich/RichUtils/include/RichUtils/RichTrackSegment.h
@@ -75,6 +75,9 @@ namespace LHCb {
     /// Vector of track segments
     using Vector = Rich::SIMD::STDVector<RichTrackSegment>;
 
+    /// Radiator Intersections
+    using RadIntersects = Rich::RadIntersection::Vector;
+
     /// Scalar float type
     using FP = Rich::SIMD::DefaultScalarFP;
 
@@ -288,7 +291,7 @@ namespace LHCb {
 
   public:
     /// Provides read-only access to the radiator intersections
-    inline const Rich::RadIntersection::Vector& radIntersections() const noexcept { return m_radIntersections; }
+    inline const RadIntersects& radIntersections() const noexcept { return m_radIntersections; }
 
     /** Update the track using a given transformation matrix and a fixed point
      *
@@ -561,7 +564,7 @@ namespace LHCb {
     // methods
 
     /// Provides write access to the radiator intersections
-    inline Rich::RadIntersection::Vector& radIntersections() noexcept { return m_radIntersections; }
+    inline RadIntersects& radIntersections() noexcept { return m_radIntersections; }
 
     /// Updates the cached information
     void updateCachedInfo();
@@ -592,7 +595,7 @@ namespace LHCb {
     Rich::DetectorType m_rich     = Rich::InvalidDetector; ///< Rich detector
 
     /// The raw intersections with the radiator volumes
-    Rich::RadIntersection::Vector m_radIntersections{1};
+    RadIntersects m_radIntersections{1};
 
     /// The middle point of the segment in the radiator volume (Scalar)
     Gaudi::XYZPoint m_middlePoint;