diff --git a/CMakeLists.txt b/CMakeLists.txt
index 37611f00a968bd3dbb5574d5787f5da6a36b552e..87991e55b12ec2ea4afe045da7dfe5de81ea4d96 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -44,6 +44,7 @@ set(${VarName}
     Det/VPDet
     Det/RichDet
     Det/MuonDet
+    Det/TorchDet
     Tools/GitEntityResolver
     Tools/XmlTools
 )
diff --git a/Det/TorchDet/CMakeLists.txt b/Det/TorchDet/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..c6e75b14ad197468ba5ebe868a0b86173d6869b0
--- /dev/null
+++ b/Det/TorchDet/CMakeLists.txt
@@ -0,0 +1,48 @@
+###############################################################################
+# (c) Copyright 2023 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.                                       #
+###############################################################################
+#[=======================================================================[.rst:
+Det/TorchDet
+------------
+#]=======================================================================]
+
+gaudi_add_library(TorchDetLib
+    SOURCES
+        src/lib/legacy/DeTorchDetector.cpp
+        src/lib/legacy/DeTorchModule.cpp
+    LINK
+        PUBLIC
+            Gaudi::GaudiKernel
+            Run2Support::DetDescLib
+            LHCb::LHCbKernel
+          )
+
+gaudi_add_module(TorchDet
+    SOURCES 
+        src/component/legacy/XmlDeTorchCnv.cpp
+    LINK
+        Run2Support::DetDescCnvLib
+        Run2Support::TorchDetLib
+)
+
+target_link_libraries(TorchDet
+  PRIVATE
+      fmt::fmt
+      LHCb::LHCbAlgsLib
+      Run2Support::XmlToolsLib
+      yaml-cpp
+    )
+
+gaudi_add_dictionary(TorchDetDict
+    HEADERFILES dict/TorchDetDict.h
+    SELECTION dict/TorchDetDict.xml
+    LINK Run2Support::TorchDetLib
+)
+
diff --git a/Det/TorchDet/dict/TorchDetDict.h b/Det/TorchDet/dict/TorchDetDict.h
new file mode 100644
index 0000000000000000000000000000000000000000..e64fe31e1b7fea23763c76af8a78d4ef946bfbd1
--- /dev/null
+++ b/Det/TorchDet/dict/TorchDetDict.h
@@ -0,0 +1,17 @@
+/*****************************************************************************\
+* (c) Copyright 2023 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.                                       *
+\*****************************************************************************/
+#ifdef TORCHDET_DETDICT_H
+#define TORCHDET_DETDICT_H 1
+
+#include "TorchDet/DeTorchDetector.h"
+#include "TorchDet/DeTorchModule.h"
+
+#endif
diff --git a/Det/TorchDet/dict/TorchDetDict.xml b/Det/TorchDet/dict/TorchDetDict.xml
new file mode 100644
index 0000000000000000000000000000000000000000..1f9dbdb3be5e783f42fab6bde455142850a58169
--- /dev/null
+++ b/Det/TorchDet/dict/TorchDetDict.xml
@@ -0,0 +1,17 @@
+<!--
+    (c) Copyright 2023 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.
+-->
+<lcgdict>
+
+  <class name="DeTorchDetector" />
+  <class name="DeTorchModule"   />
+  <class name="std::vector<DeTorchModule*>" />
+
+</lcgdict> 
diff --git a/Det/TorchDet/include/TorchDet/DeTorchDetector.h b/Det/TorchDet/include/TorchDet/DeTorchDetector.h
new file mode 100644
index 0000000000000000000000000000000000000000..92687a319b0f92cbeb48de393fa175fe611e8b45
--- /dev/null
+++ b/Det/TorchDet/include/TorchDet/DeTorchDetector.h
@@ -0,0 +1,69 @@
+/*****************************************************************************\
+* (c) Copyright 2023 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
+
+#include <string>
+
+namespace DeTorchDetectorLocation {
+  inline const std::string Default = "/dd/Structure/LHCb/AfterMagnetRegion/Torch";
+} // namespace DeTorchDetectorLocation
+
+#include "DetDesc/Condition.h"
+#include "DetDesc/DetectorElement.h"
+
+#  include "DeTorchModule.h"
+constexpr CLID CLID_DeTorchDetector = 22;
+
+class DeTorch : public DetDesc::DetectorElementPlus {
+public:
+  using DetectorElementPlus::DetectorElementPlus;
+
+  StatusCode initialize() override;
+
+  const CLID& clID() const override;
+
+  static const CLID& classID() { return CLID_DeTorchDetector; }
+
+  int sensitiveVolumeID( const Gaudi::XYZPoint& point ) const override;
+
+  const DeTorchModule* findModule( const Gaudi::XYZPoint& globalPoint ) const;
+
+  const std::vector<DeTorchModule*>& modules() const { return m_modules; }
+
+  unsigned int numModules() const { return m_modules.size(); }
+
+  unsigned int moduleNumber( const DeTorchModule* module ) const;
+
+  double radiatorPosition() const { return m_radiatorZPos; }
+
+  double fullDepth() const { return m_fullDepth; }
+
+  Gaudi::XYZPoint fromDetector( const Gaudi::XYZPoint& detectedPoint ) const {
+    return m_geometry->toGlobal( detectedPoint );
+  }
+
+private:
+  IGeometryInfoPlus* m_geometry = nullptr;
+
+  std::vector<DeTorchModule*> m_modules;
+
+  double m_radiatorZPos;
+  double m_fullDepth;
+  unsigned int m_modulesPerHalf;
+
+  mutable std::unique_ptr<MsgStream> m_msg;
+
+  MsgStream& msg() const {
+    if ( !m_msg ) m_msg.reset( new MsgStream( msgSvc(), "DeTorch" ) );
+    return *m_msg;
+  }
+};
+
diff --git a/Det/TorchDet/include/TorchDet/DeTorchModule.h b/Det/TorchDet/include/TorchDet/DeTorchModule.h
new file mode 100644
index 0000000000000000000000000000000000000000..112a7289339a83bfb462d349e516243476ad4431
--- /dev/null
+++ b/Det/TorchDet/include/TorchDet/DeTorchModule.h
@@ -0,0 +1,64 @@
+/*****************************************************************************\
+* (c) Copyright 2023 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
+
+// DetDesc
+#  include "DetDesc/DetectorElement.h"
+#  include "DetDesc/IGeometryInfo.h"
+
+constexpr CLID CLID_DeTorchModule = 23;
+
+class DeTorchModule : public DetDesc::DetectorElementPlus {
+public:
+  using DetectorElementPlus::DetectorElementPlus;
+
+  StatusCode initialize() override;
+
+  const CLID& clID() const override;
+
+  static const CLID& classID() { return CLID_DeTorchModule; }
+
+  double radiatorDepth() const { return m_radiatorDepth; }
+
+  double radiatorWidth() const { return m_radiatorWidth; }
+
+  double radiatorHeight() const { return m_radiatorHeight; }
+
+  unsigned int number() const { return m_moduleNumber; }
+
+  unsigned int half() const { return m_moduleHalf; }
+
+  Gaudi::XYZPoint toRadiator( const Gaudi::XYZPoint& globalPoint ) const;
+
+  Gaudi::XYZPoint toDetector( const Gaudi::XYZPoint& globalPoint ) const;
+
+  Gaudi::XYZPoint fromDetector( const Gaudi::XYZPoint& detectedPoint ) const;
+
+  double radiatorPosition() const;
+
+  bool inRadiator( const Gaudi::XYZPoint& globalPoint ) const;
+
+private:
+  IGeometryInfoPlus* m_geometry = nullptr;
+
+  double m_radiatorDepth;
+  double m_radiatorWidth;
+  double m_radiatorHeight;
+  double m_radiatorZOffset;
+  double m_radiatorYOffset;
+  double m_detectorYOffset;
+  double m_detectorZOffset;
+  double m_angleWedge;
+
+  unsigned int m_moduleHalf;
+  unsigned int m_moduleNumber;
+};
+
diff --git a/Det/TorchDet/src/component/legacy/XmlDeTorchCnv.cpp b/Det/TorchDet/src/component/legacy/XmlDeTorchCnv.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ec632ef7ef5141e907e22fc63d119433a804a379
--- /dev/null
+++ b/Det/TorchDet/src/component/legacy/XmlDeTorchCnv.cpp
@@ -0,0 +1,20 @@
+/*****************************************************************************\
+* (c) Copyright 2023 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 "DetDescCnv/XmlUserDetElemCnv.h"
+
+#include "TorchDet/DeTorchDetector.h"
+#include "TorchDet/DeTorchModule.h"
+
+typedef XmlUserDetElemCnv<DeTorch> XmlDeTorchDetectorCnv;
+DECLARE_CONVERTER( XmlDeTorchDetectorCnv )
+
+typedef XmlUserDetElemCnv<DeTorchModule> XmlDeTorchModuleCnv;
+DECLARE_CONVERTER( XmlDeTorchModuleCnv )
diff --git a/Det/TorchDet/src/lib/legacy/DeTorchDetector.cpp b/Det/TorchDet/src/lib/legacy/DeTorchDetector.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f610deb70c58894847294d1d511e73520b9f3f49
--- /dev/null
+++ b/Det/TorchDet/src/lib/legacy/DeTorchDetector.cpp
@@ -0,0 +1,61 @@
+/*****************************************************************************\
+* (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.                                       *
+\*****************************************************************************/
+#include "TorchDet/DeTorchDetector.h"
+
+const CLID& DeTorch::clID() const { return DeTorch::classID(); }
+
+StatusCode DeTorch::initialize() {
+
+  // Initialise the base class
+  StatusCode sc = DetectorElementPlus::initialize();
+
+  m_geometry = geometryPlus();
+
+  if ( sc.isFailure() ) {
+    msg() << MSG::ERROR << "Cannot initialize DeTorch" << endmsg;
+    return sc;
+  }
+
+  for ( const auto& half : this->childIDetectorElements() ) {
+
+    for ( const auto& imodule : half->childIDetectorElements() ) {
+
+      auto module = dynamic_cast<DeTorchModule*>( imodule );
+
+      if ( module ) m_modules.push_back( module );
+    }
+  }
+
+  m_modulesPerHalf = m_modules.size() / 2;
+  m_radiatorZPos   = param<double>( "TorchRadiatorZPos" );
+  m_fullDepth      = param<double>( "TorchFullDepth" );
+
+  return sc;
+}
+
+const DeTorchModule* DeTorch::findModule( const Gaudi::XYZPoint& globalPoint ) const {
+
+  auto it = std::find_if( m_modules.begin(), m_modules.end(),
+                          [&globalPoint]( const DeTorchModule* m ) -> bool { return m->isInside( globalPoint ); } );
+
+  return ( it != m_modules.end() ? *it : nullptr );
+}
+
+unsigned int DeTorch::moduleNumber( const DeTorchModule* module ) const {
+  return m_modulesPerHalf * module->half() + module->number();
+}
+
+int DeTorch::sensitiveVolumeID( const Gaudi::XYZPoint& point ) const {
+  auto module = findModule( point );
+  return moduleNumber( module );
+}
+
+
diff --git a/Det/TorchDet/src/lib/legacy/DeTorchModule.cpp b/Det/TorchDet/src/lib/legacy/DeTorchModule.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4c2e1ecdfc5720562f10ed8844a6be6f218f25e9
--- /dev/null
+++ b/Det/TorchDet/src/lib/legacy/DeTorchModule.cpp
@@ -0,0 +1,114 @@
+/*****************************************************************************\
+* (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.                                       *
+\*****************************************************************************/
+#include "TorchDet/DeTorchModule.h"
+#include "GaudiKernel/PhysicalConstants.h"
+
+const CLID& DeTorchModule::clID() const { return DeTorchModule::classID(); }
+
+StatusCode DeTorchModule::initialize() {
+
+  // Initialize the base object
+  StatusCode sc = DetectorElementPlus::initialize();
+
+  m_geometry = geometryPlus();
+
+  m_radiatorDepth  = param<double>( "TorchRadiatorDepth" );
+  m_radiatorWidth  = param<double>( "TorchRadiatorWidth" );
+  m_radiatorHeight = param<double>( "TorchRadiatorHeight" );
+  m_angleWedge     = param<double>( "TorchWedgeAngle" );
+  m_moduleNumber   = param<int>( "ModuleNumber" );
+
+  // Get the detector half
+  m_moduleHalf = ( param<std::string>( "ModuleLocation" ) == "Upper" ? 0 : 1 );
+
+  double detectorOffset  = param<double>( "TorchDetectorOffset" );
+  double radiatorZOffset = param<double>( "TorchRadiatorZOff" );
+  double radiatorYOffset = param<double>( "TorchRadiatorYOff" );
+
+  // Position of the centre of the front face of the radiator
+  m_radiatorYOffset = radiatorYOffset;
+  m_radiatorZOffset = radiatorZOffset - 0.5 * m_radiatorDepth;
+
+  // Position of the centre of the detector plane
+  m_detectorYOffset = m_radiatorYOffset + detectorOffset * std::cos( m_angleWedge ) + 0.5 * m_radiatorHeight;
+  m_detectorZOffset = m_radiatorZOffset - detectorOffset * std::sin( m_angleWedge );
+
+  return StatusCode::SUCCESS;
+}
+
+Gaudi::XYZPoint DeTorchModule::toRadiator( const Gaudi::XYZPoint& globalPoint ) const {
+
+  Gaudi::XYZPoint localPoint = m_geometry->toLocal( globalPoint );
+
+  double xlocal = localPoint.X();
+  double ylocal = localPoint.Y() - m_radiatorYOffset;
+  double zlocal = localPoint.Z() - m_radiatorZOffset;
+
+  return Gaudi::XYZPoint( xlocal, ylocal, zlocal );
+}
+
+Gaudi::XYZPoint DeTorchModule::toDetector( const Gaudi::XYZPoint& globalPoint ) const {
+
+  // Coordinate in the local system of the module
+  Gaudi::XYZPoint localPoint = m_geometry->toLocal( globalPoint );
+
+  double angleBlock = 0.5 * Gaudi::Units::pi - m_angleWedge;
+
+  double xlocal = localPoint.X();
+  double ylocal = 0;
+  double zlocal = 0;
+
+  ylocal += ( localPoint.Y() - m_detectorYOffset ) / std::cos( m_angleWedge );
+  zlocal += ( localPoint.Y() - m_detectorYOffset ) * std::cos( angleBlock );
+  zlocal += ( localPoint.Z() - m_detectorZOffset ) * std::sin( angleBlock );
+
+  return Gaudi::XYZPoint( xlocal, ylocal, zlocal );
+}
+
+Gaudi::XYZPoint DeTorchModule::fromDetector( const Gaudi::XYZPoint& detectedPoint ) const {
+
+  // Coordinate in the local system of the module
+
+  // double angleBlock = 0.5 * Gaudi::Units::pi - m_angleWedge;
+
+  double xlocal = detectedPoint.X();
+
+  double ylocal = m_detectorYOffset + detectedPoint.Y() * std::cos( m_angleWedge );
+  double zlocal = m_detectorZOffset - detectedPoint.Y() * std::sin( m_angleWedge );
+
+  Gaudi::XYZPoint globalPoint = m_geometry->toGlobal( Gaudi::XYZPoint( xlocal, ylocal, zlocal ) );
+
+  return globalPoint;
+}
+
+bool DeTorchModule::inRadiator( const Gaudi::XYZPoint& globalPoint ) const {
+
+  Gaudi::XYZPoint localPoint = toRadiator( globalPoint );
+
+  bool test = true;
+
+  test &= ( std::abs( localPoint.X() ) < 0.5 * m_radiatorWidth );
+  test &= ( std::abs( localPoint.Y() ) < 0.5 * m_radiatorHeight );
+
+  // Check on z-position
+  test &= ( localPoint.Z() > 0 && localPoint.Z() < m_radiatorDepth );
+
+  return test;
+}
+
+double DeTorchModule::radiatorPosition() const {
+
+  Gaudi::XYZPoint globalPoint = this->toGlobal( Gaudi::XYZPoint( 0, 0, 0 ) );
+
+  double zpos = globalPoint.Z() + m_radiatorZOffset;
+
+  return zpos;
+}