diff --git a/Scintillator/ScintDetDescr/ScintReadoutGeometry/ScintReadoutGeometry/ScintDetectorElement.h b/Scintillator/ScintDetDescr/ScintReadoutGeometry/ScintReadoutGeometry/ScintDetectorElement.h
index 15970043cf0cc33c6bbe78e463471c74c9055896..064ee04d716301f4754ca4e33e2227d5f74261b0 100644
--- a/Scintillator/ScintDetDescr/ScintReadoutGeometry/ScintReadoutGeometry/ScintDetectorElement.h
+++ b/Scintillator/ScintDetDescr/ScintReadoutGeometry/ScintReadoutGeometry/ScintDetectorElement.h
@@ -17,9 +17,9 @@
 #include "Identifier/Identifier.h"
 #include "Identifier/IdentifierHash.h"
 #include "ScintReadoutGeometry/ScintDetectorDesign.h"
-// #include "ScintReadoutGeometry/ScintLocalPosition.h"
+#include "ScintReadoutGeometry/ScintLocalPosition.h"
 #include "TrkEventPrimitives/ParamDefs.h"
-// #include "ScintReadoutGeometry/ScintIntersect.h"
+#include "ScintReadoutGeometry/ScintIntersect.h"
 #include "ScintReadoutGeometry/ScintCommonItems.h"
 #include "ScintReadoutGeometry/ScintDD_Defs.h"
 #include "GeoPrimitives/CLHEPtoEigenConverter.h"
diff --git a/Scintillator/ScintDetDescr/ScintReadoutGeometry/src/ScintDetectorElement.cxx b/Scintillator/ScintDetDescr/ScintReadoutGeometry/src/ScintDetectorElement.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..3dc94fa2d9120289fa24fe3ea6b4fea83c7cff5b
--- /dev/null
+++ b/Scintillator/ScintDetDescr/ScintReadoutGeometry/src/ScintDetectorElement.cxx
@@ -0,0 +1,1129 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+/**
+ * @file ScintDetectorElement.cxx
+ * Implementation file for class ScintDetectorElement
+ * @author Grant Gorfine
+ * Based on version developed by David Calvet.
+**/
+
+#include "ScintReadoutGeometry/ScintDetectorElement.h"
+
+#include "ScintIdentifier/VetoID.h"
+// #include "ScintIdentifier/TriggerID.h"
+// #include "ScintIdentifier/PreshowerID.h"
+
+#include "GeoModelKernel/GeoVFullPhysVol.h"
+#include "GeoModelUtilities/GeoAlignmentStore.h"
+#include "FaserDetDescr/FaserDetectorID.h"
+
+#include "CLHEP/Geometry/Point3D.h"
+#include "CLHEP/Geometry/Vector3D.h"
+#include "CLHEP/Vector/ThreeVector.h"
+#include "CLHEP/Units/PhysicalConstants.h" // for M_PI
+#include "CLHEP/Units/SystemOfUnits.h"
+
+// #include "InDetReadoutGeometry/SiCellId.h"
+// #include "InDetReadoutGeometry/SiReadoutCellId.h"
+#include "ScintReadoutGeometry/VetoDetectorDesign.h"
+// #include "InDetReadoutGeometry/StripStereoAnnulusDesign.h"
+
+
+#include "ScintReadoutGeometry/ScintCommonItems.h"
+
+#include "TrkSurfaces/PlaneSurface.h"
+#include "TrkSurfaces/SurfaceBounds.h"
+
+#include <cmath>
+#include <cassert>
+#include <limits>
+
+namespace ScintDD {
+using Trk::distPhi;
+using Trk::distEta;
+using Trk::distDepth;
+
+// Constructor with parameters:
+ScintDetectorElement::ScintDetectorElement(const Identifier &id,
+                                     const ScintDetectorDesign *design,
+                                     const GeoVFullPhysVol *geophysvol,
+                                     const ScintCommonItems * commonItems,
+                                     const GeoAlignmentStore* geoAlignStore) :
+  TrkDetElementBase(geophysvol),
+  m_id(id),
+  m_design(design),
+  m_commonItems(commonItems),
+  m_cacheValid(false),
+  m_firstTime(true),
+  m_mutex(),
+  m_surface{},
+  m_surfaces{},
+  m_geoAlignStore(geoAlignStore)
+{
+  //The following are fixes for coverity bug 11955, uninitialized scalars:
+//   const bool boolDefault(true);
+//   m_depthDirection=boolDefault;
+//   m_phiDirection=boolDefault;
+//   m_etaDirection=boolDefault;
+  const double defaultMin(std::numeric_limits<double>::max());
+  const double defaultMax(std::numeric_limits<double>::lowest());
+  m_minX=defaultMin;
+  m_maxX=defaultMax;
+  m_minY=defaultMin;
+  m_maxY=defaultMax;
+  m_minZ=defaultMin;
+  m_maxZ=defaultMax;
+
+  m_hitEta = m_design->etaAxis();
+  m_hitPhi = m_design->phiAxis();
+  m_hitDepth = m_design->depthAxis();
+  ///
+  
+ commonConstructor();
+}
+
+void
+ScintDetectorElement::commonConstructor() 
+{
+  if (!m_id.is_valid()) throw std::runtime_error("ScintDetectorElement: Invalid identifier");
+
+  // Set booleans for wether we are veto/trigger/preshower
+  m_isVeto = getIdHelper()->is_veto(m_id);
+  m_isTrigger = getIdHelper()->is_trigger(m_id);
+  m_isPreshower = getIdHelper()->is_preshower(m_id);
+  if (!m_isVeto && !m_isTrigger && !m_isPreshower)
+  {
+    if (msgLvl(MSG::WARNING)) msg(MSG::WARNING) << "Element id is not for veto, trigger or preshower" << endmsg;
+  }
+  else if ((m_isVeto && m_isTrigger) || (m_isVeto && m_isPreshower) || (m_isTrigger && m_isPreshower))
+  {
+    if (msgLvl(MSG::WARNING)) msg(MSG::WARNING) << "Element id belongs to more than one of veto, trigger or preshower" << endmsg;
+  }
+  
+  // Set IdHash.
+  if (isVeto())
+  {
+      const VetoID* vetoId = dynamic_cast<const VetoID* >(getIdHelper());
+      m_idHash = vetoId->plate_hash(m_id);
+  }
+  else if (isTrigger())
+  {
+      m_idHash = 64000; //FIXME - will blow up on invalid hash if ever reached
+  }
+  else if (isPreshower())
+  {
+      m_idHash = 64000; //FIXME
+  }
+  
+  if (!m_idHash.is_valid()) throw std::runtime_error("ScintDetectorElement: Unable to set IdentifierHash");
+
+  // Increase the reference count of the ScintDetectorDesign objects.
+  m_design->ref();
+
+  // Increase the reference count of the ScintCommonItems objects.
+  m_commonItems->ref();
+
+  // Should we reference count the geophysvol as well?
+
+}
+
+
+// Destructor:
+ScintDetectorElement::~ScintDetectorElement()
+{
+  // The design is reference counted so that it will not be deleted until the last element is deleted.
+  m_design->unref();
+
+  m_commonItems->unref();
+}
+
+void 
+ScintDetectorElement::updateCache() const
+{
+  std::lock_guard<std::recursive_mutex> lock(m_mutex);
+
+  bool firstTimeTmp = m_firstTime;
+  m_firstTime = false;
+  m_cacheValid = true;
+  
+  const GeoTrf::Transform3D & geoTransform = transformHit();
+     
+  HepGeom::Point3D<double> centerGeoModel(0., 0., 0.);
+  m_centerCLHEP = Amg::EigenTransformToCLHEP(geoTransform) * centerGeoModel;
+  m_center = Amg::Vector3D(m_centerCLHEP[0],m_centerCLHEP[1],m_centerCLHEP[2]);
+  
+  //
+  // Determine directions depth, eta and phi axis in reconstruction local frame
+  // ie depth away from interaction point
+  //    phi in direction of increasing phi
+  //    eta in direction of increasing z in barrel, and increasing r in endcap
+  //
+    
+  // depthAxis, xAxis, and yAxis are defined to be x,y,z respectively for all detectors for hit local frame.
+  // depthAxis, xAxis, and yAxis are defined to be z,x,y respectively for all detectors for reco local frame.
+  static const HepGeom::Vector3D<double> localAxes[3] = {
+    HepGeom::Vector3D<double>(1,0,0),
+    HepGeom::Vector3D<double>(0,1,0),
+    HepGeom::Vector3D<double>(0,0,1)
+  };
+  
+  static const HepGeom::Vector3D<double> & localRecoXAxis = localAxes[locX];     // Defined to be same as x axis
+  static const HepGeom::Vector3D<double> & localRecoYAxis = localAxes[locY];     // Defined to be same as y axis
+  static const HepGeom::Vector3D<double> & localRecoDepthAxis = localAxes[distDepth]; // Defined to be same as z axis
+  
+  // We only need to calculate the rough orientation once.
+  //For it to change would require extreme unrealistic misalignment changes.
+//   if (firstTimeTmp) {
+    // Determine the unit vectors in global frame
+        
+    // const HepGeom::Vector3D<double> &geoModelXAxis = localAxes[locX];
+    // const HepGeom::Vector3D<double> &geoModelYAxis = localAxes[locY];
+    // const HepGeom::Vector3D<double> &geoModelDepthAxis = localAxes[m_hitDepth];
+
+    // HepGeom::Vector3D<double> globalDepthAxis(Amg::EigenTransformToCLHEP(geoTransform) * geoModelDepthAxis);
+    // HepGeom::Vector3D<double> globalXAxis(Amg::EigenTransformToCLHEP(geoTransform) * geoModelXAxis);
+    // HepGeom::Vector3D<double> globalYAxis(Amg::EigenTransformToCLHEP(geoTransform) * geoModelYAxis);
+
+    // // unit radial vector
+    // HepGeom::Vector3D<double> unitR(m_center.x(), m_center.y(), 0.);
+     
+    // unitR.setMag(1.);
+
+    // HepGeom::Vector3D<double> nominalEta;
+    // HepGeom::Vector3D<double> nominalNormal;
+    // HepGeom::Vector3D<double> nominalPhi(-unitR.y(), unitR.x(), 0);
+  
+    // // In Barrel like geometry, the etaAxis is along increasing z, and normal is in increasing radial direction.
+    // // In Endcap like geometry, the etaAxis is along increasing r, and normal is in decreasing z direction,
+    // // We base whether it is barrel like or endcap like by the orientation of the local z axis of the 
+    // // the element. This allows the use of endcap identifiers in a TB setup. A warning message is issued however if
+    // // the orientation and identifier are not consistent (ie a barrel like orientation with an endcap identifier).
+
+    // bool barrelLike = true;
+    // nominalEta.setZ(1);
+    // if (std::abs(globalEtaAxis.dot(nominalEta)) < 0.5) { // Check that it is in roughly the right direction.
+    //   barrelLike = false;
+    // }   
+
+    // if (isBarrel() && !barrelLike) {      
+    //   if (msgLvl(MSG::WARNING)) msg(MSG::WARNING) << "Element has endcap like orientation with barrel identifier."
+    //                                               << endmsg;
+    // } else if (!isBarrel() && barrelLike) {
+    //   if (msgLvl(MSG::WARNING)) msg(MSG::WARNING) << "Element has barrel like orientation with endcap identifier."
+    //                                               << endmsg;
+    // }
+    
+    // if (barrelLike) {
+    //   nominalEta.setZ(1);
+    //   nominalNormal =  unitR;
+    // } else { // endcap like
+    //   nominalNormal.setZ(-1);
+    //   nominalEta = unitR;
+    // }
+
+    // // Determine if axes are to have there directions swapped.
+
+    // //
+    // // Depth axis.
+    // //
+    // double depthDir = globalDepthAxis.dot(nominalNormal);
+    // m_depthDirection = true;
+    // if (depthDir < 0) {
+    //   if (m_design->depthSymmetric()) {
+    //     m_depthDirection = false;
+    //   } else {
+    //     if (msgLvl(MSG::WARNING)) msg(MSG::WARNING) << "Unable to swap local depth axis." << endmsg;
+    //   }
+    // }
+    // if (std::abs(depthDir) < 0.5) { // Check that it is in roughly the right direction.
+    //   msg(MSG::ERROR) << "Orientation of local depth axis does not follow correct convention." << endmsg;
+    //   // throw std::runtime_error("Orientation of local depth axis does not follow correct convention.");
+    //   m_depthDirection = true; // Don't swap.
+    // }
+    
+    // //
+    // // Phi axis
+    // //
+    // double phiDir = globalPhiAxis.dot(nominalPhi);
+    // m_phiDirection = true;
+    // if (phiDir < 0) {
+    //   if (m_design->phiSymmetric()) {
+    //     m_phiDirection = false;
+    //   } else {
+    //     if (msgLvl(MSG::WARNING)) msg(MSG::WARNING) << "Unable to swap local xPhi axis." << endmsg;
+    //   }
+    // }
+    
+    // if (std::abs(phiDir) < 0.5) { // Check that it is in roughly the right direction.
+    //   msg(MSG::ERROR) << "Orientation of local xPhi axis does not follow correct convention." << endmsg;
+    //   // throw std::runtime_error("Orientation of local xPhi axis does not follow correct convention.");
+    //   m_phiDirection = true; // Don't swap.
+    // }
+    
+    // //
+    // // Eta axis
+    // //
+    // double etaDir = globalEtaAxis.dot(nominalEta);
+    // m_etaDirection = true;
+    // if (etaDir < 0) {
+    //   if (m_design->etaSymmetric()) {
+    //     m_etaDirection = false;
+    //   } else {
+    //     if (msgLvl(MSG::DEBUG)) msg(MSG::DEBUG) << "Unable to swap local xEta axis." << endmsg;
+    //   }
+    // }
+    // if (std::abs(etaDir) < 0.5) { // Check that it is in roughly the right direction.
+    //   msg(MSG::ERROR) << "Orientation of local xEta axis does not follow correct convention." << endmsg;
+    //   // throw std::runtime_error("Orientation of local xEta axis does not follow correct convention.");
+    //   m_etaDirection = true; // Don't swap
+    // }   
+
+//   } // end if (firstTimeTmp)
+  
+
+
+  m_transformCLHEP = Amg::EigenTransformToCLHEP(geoTransform) * recoToHitTransform();
+  //m_transform = m_commonItems->solenoidFrame() * geoTransform * recoToHitTransform();
+  m_transform = Amg::CLHEPTransformToEigen(m_transformCLHEP);
+  
+  // Check that local frame is right-handed. (ie transform has no reflection)
+  // This can be done by checking that the determinant is >0.
+  if (firstTimeTmp) { // Only need to check this once.
+    HepGeom::Transform3D & t = m_transformCLHEP;
+    double det = t(0,0) * (t(1,1)*t(2,2) - t(1,2)*t(2,1)) -
+                 t(0,1) * (t(1,0)*t(2,2) - t(1,2)*t(2,0)) +
+                 t(0,2) * (t(1,0)*t(2,1) - t(1,1)*t(2,0));
+    if (det < 0) {
+    //   if (m_design->depthSymmetric()) {
+    //     if (msgLvl(MSG::DEBUG))
+    //       msg(MSG::DEBUG) << "Local frame is left-handed, Swapping depth axis to make it right handed."
+    //                       << endmsg;
+    //     m_depthDirection = !m_depthDirection;
+    //     m_transformCLHEP = Amg::EigenTransformToCLHEP(geoTransform) * recoToHitTransform();
+    //     m_transform = Amg::CLHEPTransformToEigen(m_transformCLHEP);
+    //     //m_transform = m_commonItems->solenoidFrame() * geoTransform * recoToHitTransform();
+    //    } else {
+        if (msgLvl(MSG::WARNING)) msg(MSG::WARNING) << "Local frame is left-handed." << endmsg;
+    //   }
+    }
+  }
+  
+  
+  // Initialize various cached members
+  // The unit vectors
+  HepGeom::Vector3D<double> normalCLHEP = m_transformCLHEP * localRecoDepthAxis;
+  m_normal = Amg::Vector3D( normalCLHEP[0], normalCLHEP[1], normalCLHEP[2]);
+  
+
+  m_xAxisCLHEP = m_transformCLHEP * localRecoXAxis;
+  m_yAxisCLHEP = m_transformCLHEP * localRecoYAxis;
+
+  m_xAxis = Amg::Vector3D(m_xAxisCLHEP[0],m_xAxisCLHEP[1],m_xAxisCLHEP[2]);
+  m_yAxis = Amg::Vector3D(m_yAxisCLHEP[0],m_yAxisCLHEP[1],m_yAxisCLHEP[2]);
+
+  getExtent(m_minX, m_maxX, m_minY, m_maxY, m_minZ, m_maxZ);
+
+
+  // Determin isStereo
+//   if (firstTimeTmp) {
+//     if (isSCT() && m_otherSide) {
+//       double sinStereoThis = std::abs(sinStereo());
+//       double sinStereoOther = std::abs(m_otherSide->sinStereo());
+//       if (sinStereoThis == sinStereoOther) {
+//         // If they happend to be equal then set side0 as axial and side1 as stereo.
+//         const SCT_ID* sctId = dynamic_cast<const SCT_ID *>(getIdHelper());
+//         if (sctId) {
+//           int side = sctId->side(m_id);
+//           m_isStereo = (side == 1);
+//         }
+//       } else {
+//         // set the stereo side as the one with largest absolute sinStereo.
+//         m_isStereo = (sinStereoThis > sinStereoOther);
+//       }
+//     } else {
+//       m_isStereo = false;
+//     }
+//   }    
+}
+
+
+const GeoTrf::Transform3D &
+ScintDetectorElement::transformHit() const
+{
+  if (m_geoAlignStore) {
+    const GeoTrf::Transform3D* ptrXf = m_geoAlignStore->getAbsPosition(getMaterialGeom());
+    if (ptrXf) return *ptrXf;
+  }
+  return getMaterialGeom()->getAbsoluteTransform();
+}
+
+const Amg::Transform3D &
+ScintDetectorElement::transform() const
+{
+  std::lock_guard<std::recursive_mutex> lock(m_mutex);
+  if (!m_cacheValid) updateCache();
+  return m_transform;
+}
+
+const HepGeom::Transform3D &
+ScintDetectorElement::transformCLHEP() const
+{
+  //stuff to get the CLHEP version of the local to global transform.
+  std::lock_guard<std::recursive_mutex> lock(m_mutex);
+  if (!m_cacheValid) updateCache();
+  return m_transformCLHEP;
+}
+
+const HepGeom::Transform3D 
+ScintDetectorElement::defTransformCLHEP() const
+{
+  if (m_geoAlignStore) {
+    const GeoTrf::Transform3D* ptrXf = m_geoAlignStore->getDefAbsPosition(getMaterialGeom());
+    if (ptrXf) return Amg::EigenTransformToCLHEP(*ptrXf) * recoToHitTransform();
+  }
+  return Amg::EigenTransformToCLHEP(getMaterialGeom()->getDefAbsoluteTransform()) * recoToHitTransform();
+}  
+   
+const Amg::Transform3D 
+ScintDetectorElement::defTransform() const
+{
+  HepGeom::Transform3D tmpTransform = defTransformCLHEP();
+  return Amg::CLHEPTransformToEigen(tmpTransform);
+}
+
+const HepGeom::Transform3D 
+ScintDetectorElement::recoToHitTransform() const
+{
+
+  // Determine the reconstruction local (LocalPosition) to global transform.
+
+  std::lock_guard<std::recursive_mutex> lock(m_mutex);
+  if (m_firstTime) updateCache();
+
+  // global = transform * recoLocal
+  //        = transfromHit * hitLocal
+  //        = transformHit * recoToHitTransform * recoLocal
+  // recoToHitTransform takes recoLocal to hitLocal
+  // x,y,z -> y,z,x 
+  // equiv to a rotation around Y of 90 deg followed by a rotation around X of 90deg
+  // 
+  // recoToHit is static as it needs to be calculated once only.
+  // We use the HepGeom::Transform3D constructor which takes one coordinates system to another where the
+  // coordinate system is defined by it center and two axes.
+  // distPhi, distEta are the reco local axes and hitPhi and hitEta are the hit local axes.
+  // It assume phi, eta, depth makes a right handed system which is the case.
+  static const HepGeom::Vector3D<double> localAxes[3] = {
+    HepGeom::Vector3D<double>(1,0,0),
+    HepGeom::Vector3D<double>(0,1,0),
+    HepGeom::Vector3D<double>(0,0,1)
+  };
+  //static 
+    
+  const HepGeom::Transform3D recoToHit(HepGeom::Point3D<double>(0,0,0),localAxes[distPhi],localAxes[distEta],
+                                       HepGeom::Point3D<double>(0,0,0),localAxes[m_hitPhi],localAxes[m_hitEta]);
+  
+  // Swap direction of axis as appropriate
+  CLHEP::Hep3Vector scale(1,1,1);
+  if (!m_phiDirection)   scale[distPhi]   = -1;
+  if (!m_etaDirection)   scale[distEta]   = -1;
+  if (!m_depthDirection) scale[distDepth] = -1;
+  return recoToHit * HepGeom::Scale3D(scale[0],scale[1],scale[2]);
+}
+
+const Amg::Transform3D &
+ScintDetectorElement::moduleTransform() const
+{
+  return  (isModuleFrame()) ?  transform() : m_otherSide->transform();
+}
+
+  Amg::Transform3D
+  ScintDetectorElement::defModuleTransform() const
+{
+ return  (isModuleFrame()) ? defTransform() : m_otherSide->defTransform();
+}  
+
+
+// Take a transform in the local reconstruction and return it in the module frame
+// For a given transform l in frame A. The equivalent transform in frame B is
+//  B.inverse() * A * l * A.inverse() * B
+// Here A is the local to global transform of the element and B is the local to global
+// transform of the module.
+// If we are already in the module frame then there is nothing to do, we just return the
+// transform that is input. Otherwise we use the above formula.
+Amg::Transform3D 
+ScintDetectorElement::localToModuleFrame(const Amg::Transform3D & localTransform) const
+{
+  if (isModuleFrame()) {
+    return localTransform;
+  } else {
+    return m_otherSide->transform().inverse() * transform() * localTransform * transform().inverse() *  m_otherSide->transform();
+  }
+}
+
+Amg::Transform3D 
+ScintDetectorElement::localToModuleTransform() const
+{
+  if (isModuleFrame()) {
+    return Amg::Transform3D(); // Identity
+  } else {
+    return  m_otherSide->transform().inverse() * transform();
+  }
+}
+      
+
+bool 
+ScintDetectorElement::isModuleFrame() const
+{
+  // The module frame is the axial side.
+  // NB isStereo returns false for the pixel and so
+  // isModuleFrame is always true for the pixel.
+
+  return !isStereo();
+}
+
+
+const Amg::Vector3D & 
+ScintDetectorElement::center() const
+{
+  std::lock_guard<std::recursive_mutex> lock(m_mutex);
+  if (!m_cacheValid) updateCache();
+  return m_center;
+}
+
+const Amg::Vector3D & 
+ScintDetectorElement::normal() const
+{
+  std::lock_guard<std::recursive_mutex> lock(m_mutex);
+  if (!m_cacheValid) updateCache();
+  return m_normal;
+}
+
+const HepGeom::Vector3D<double> & 
+ScintDetectorElement::etaAxisCLHEP() const
+{
+  std::lock_guard<std::recursive_mutex> lock(m_mutex);
+  if (!m_cacheValid) updateCache();
+  return m_etaAxisCLHEP;
+}
+
+const HepGeom::Vector3D<double> & 
+ScintDetectorElement::phiAxisCLHEP() const
+{
+  std::lock_guard<std::recursive_mutex> lock(m_mutex);
+  if (!m_cacheValid) updateCache();
+  return m_phiAxisCLHEP;
+}
+
+const Amg::Vector3D & 
+ScintDetectorElement::etaAxis() const
+{
+  std::lock_guard<std::recursive_mutex> lock(m_mutex);
+  if (!m_cacheValid) updateCache();
+  return m_etaAxis;
+}
+
+const Amg::Vector3D & 
+ScintDetectorElement::phiAxis() const
+{
+  std::lock_guard<std::recursive_mutex> lock(m_mutex);
+  if (!m_cacheValid) updateCache();
+  return m_phiAxis;
+}
+
+Amg::Vector2D
+ScintDetectorElement::hitLocalToLocal(double xEta, double xPhi) const  // Will change order to phi,eta
+{
+  std::lock_guard<std::recursive_mutex> lock(m_mutex);
+  if (!m_cacheValid) updateCache();
+  if (!m_etaDirection) xEta = -xEta;
+  if (!m_phiDirection) xPhi = -xPhi;
+  return Amg::Vector2D(xPhi, xEta);
+}
+
+HepGeom::Point3D<double>
+ScintDetectorElement::hitLocalToLocal3D(const HepGeom::Point3D<double> & hitPosition) const
+{
+  // Equiv to transform().inverse * transformHit() * hitPosition
+  std::lock_guard<std::recursive_mutex> lock(m_mutex);
+  if (!m_cacheValid) updateCache();
+  double xDepth = hitPosition[m_hitDepth];
+  double xPhi = hitPosition[m_hitPhi];
+  double xEta = hitPosition[m_hitEta];
+  if (!m_depthDirection) xDepth = -xDepth;
+  if (!m_phiDirection) xPhi = -xPhi;
+  if (!m_etaDirection) xEta = -xEta;
+  return HepGeom::Point3D<double>(xPhi, xEta, xDepth);
+}
+
+
+bool ScintDetectorElement::isPixel() const
+{
+  return m_isPixel;
+}
+
+bool ScintDetectorElement::isSCT() const
+{
+  return !m_isPixel;
+}
+
+bool ScintDetectorElement::isBarrel() const
+{
+  return m_isBarrel;
+}
+
+bool ScintDetectorElement::isDBM() const 
+{ 
+  return m_isDBM;
+} 
+
+bool ScintDetectorElement::isBlayer() const
+{
+  if (isPixel() && isBarrel()) {
+    const PixelID* p_pixelId = static_cast<const PixelID *>(getIdHelper());
+    return (0==p_pixelId->layer_disk(m_id));
+  } else {
+    return false;
+  }
+} 
+
+bool ScintDetectorElement::isInnermostPixelLayer() const
+{
+  if (isPixel() && isBarrel()) {
+    const PixelID* p_pixelId = static_cast<const PixelID *>(getIdHelper());
+    return (0==p_pixelId->layer_disk(m_id));
+  } else {
+    return false;
+  }
+}  
+
+bool ScintDetectorElement::isNextToInnermostPixelLayer() const
+{
+  if (isPixel() && isBarrel()) {
+    const PixelID* p_pixelId = static_cast<const PixelID *>(getIdHelper());
+    return (1==p_pixelId->layer_disk(m_id));
+  } else {
+    return false;
+  }
+}  
+
+// compute sin(tilt angle) at center:
+double ScintDetectorElement::sinTilt() const
+{
+  std::lock_guard<std::recursive_mutex> lock(m_mutex);
+  if (!m_cacheValid) updateCache();
+
+  // Tilt is defined as the angle between a refVector and the sensor normal.
+  // In barrel refVector = unit vector radial.
+  // in endcap it is assumed there is no tilt.
+  // sinTilt = (refVector cross normal) . z
+
+  // tilt angle is not defined for the endcap
+  if (isEndcap()) return 0;
+  
+  // Angle between normal and radial vector.
+  // HepGeom::Vector3D<double> refVector(m_center.x(), m_center.y(), 0);
+  // return (refVector.cross(m_normal)).z()/refVector.mag();
+  // or the equivalent
+  return (m_center.x() * m_normal.y() - m_center.y() * m_normal.x()) / m_center.perp();
+}
+
+  double ScintDetectorElement::sinTilt(const Amg::Vector2D &localPos) const
+{
+  std::lock_guard<std::recursive_mutex> lock(m_mutex);
+  if (!m_cacheValid) updateCache();
+
+  // tilt angle is not defined for the endcap
+  if (isEndcap()) return 0;
+
+  HepGeom::Point3D<double> point=globalPositionCLHEP(localPos);
+  return sinTilt(point);
+}
+
+double ScintDetectorElement::sinTilt(const HepGeom::Point3D<double> &globalPos) const
+{ 
+  std::lock_guard<std::recursive_mutex> lock(m_mutex);
+  if (!m_cacheValid) updateCache();
+
+  // It is assumed that the global position is already in the plane of the element.
+
+  // tilt angle is not defined for the endcap
+  if (isEndcap()) return 0;
+  
+  // Angle between normal and radial vector.
+  //HepGeom::Vector3D<double> refVector(globalPos.x(), globalPos.y(), 0);
+  //return (refVector.cross(m_normal)).z()/refVector.mag();
+  // or the equivalent
+  return (globalPos.x() * m_normal.y() - globalPos.y() * m_normal.x()) / globalPos.perp();
+}
+
+double ScintDetectorElement::sinStereo() const
+{
+  std::lock_guard<std::recursive_mutex> lock(m_mutex);
+  if (!m_cacheValid) updateCache();
+
+  // Stereo is the angle between a refVector and a vector along the strip/pixel in eta direction.
+  // I'm not sure how the sign should be defined. I've defined it here
+  // with rotation sense respect to normal,
+  // where normal is away from IP in barrel and in -ve z direction in endcap
+
+  // In Barrel refVector = unit vector along z axis,
+  // in endcap refVector = unit vector radial.
+  //
+  // sinStereo = (refVector cross stripAxis) . normal
+  //           = (refVector cross etaAxis) . normal
+  //           = refVector . (etaAxis cross normal)
+  //           = refVector . phiAxis  
+  //
+  // in Barrel we use
+  // sinStereo = refVector . phiAxis
+  //           = phiAxis.z()
+  //
+  // in endcap we use
+  // sinStereo = (refVector cross etaAxis) . normal
+  //           = -(center cross etaAxis) . zAxis
+  //           = (etaAxis cross center). z() 
+
+  double sinStereo;
+  if (isBarrel()) {
+    sinStereo = m_phiAxis.z();
+  } else { // endcap
+    sinStereo = (m_center.y() * m_etaAxis.x() - m_center.x() * m_etaAxis.y()) / m_center.perp();
+  }      
+  return sinStereo;
+}
+
+  double ScintDetectorElement::sinStereo(const Amg::Vector2D &localPos) const
+{
+  std::lock_guard<std::recursive_mutex> lock(m_mutex);
+  if (!m_cacheValid) updateCache();
+
+  HepGeom::Point3D<double> point=globalPositionCLHEP(localPos);
+  return sinStereo(point);
+}
+
+double ScintDetectorElement::sinStereo(const HepGeom::Point3D<double> &globalPos) const
+{
+  //
+  // sinStereo =  (refVector cross stripAxis) . normal
+  //
+
+  std::lock_guard<std::recursive_mutex> lock(m_mutex);
+  if (!m_cacheValid) updateCache();
+
+  double sinStereo;
+  if (isBarrel()) {
+    if (m_design->shape() != InDetDD::Trapezoid) {
+      sinStereo = m_phiAxis.z();
+    } else { // trapezoid
+      assert (minWidth() != maxWidth());
+      double radius = width() * length() / (maxWidth() - minWidth());
+      HepGeom::Vector3D<double> stripAxis = radius * m_etaAxisCLHEP + globalPos - m_centerCLHEP;
+      sinStereo = (stripAxis.x() * m_normal.y() - stripAxis.y() * m_normal.x()) / stripAxis.mag();
+    }
+  } else { // endcap
+    if (m_design->shape() != InDetDD::Trapezoid) {
+      sinStereo = (globalPos.y() * m_etaAxis.x() - globalPos.x() * m_etaAxis.y()) / globalPos.perp();
+    } else { // trapezoid      
+      assert (minWidth() != maxWidth());
+      double radius = width() * length() / (maxWidth() - minWidth());
+      // Only need projection in xy plane.
+      double stripAxisX  = globalPos.x() - m_center.x() + m_etaAxis.x()*radius;
+      double stripAxisY  = globalPos.y() - m_center.y() + m_etaAxis.y()*radius;
+      double norm  = 1./(radius*sqrt(stripAxisX*stripAxisX + stripAxisY*stripAxisY));
+      sinStereo  = norm * (stripAxisX * globalPos.y() - stripAxisY * globalPos.x());
+    }
+  }
+  return sinStereo;
+}
+
+bool 
+ScintDetectorElement::isStereo() const 
+{
+  std::lock_guard<std::recursive_mutex> lock(m_mutex);
+  if (m_firstTime) updateCache();
+  return m_isStereo;
+}
+
+
+double 
+ScintDetectorElement::sinStereoLocal(const Amg::Vector2D &localPos) const
+{
+  // The equation below will work for rectangle detectors as well in which 
+  // case it will return 0. But we return zero immediately as there is no point doing the calculation.
+  if (m_design->shape() == InDetDD::Box) return 0;
+  double oneOverRadius = (maxWidth() - minWidth()) /  (width() * length());
+  double x = localPos[distPhi];
+  double y = localPos[distEta];
+  return -x*oneOverRadius / sqrt( (1+y*oneOverRadius)*(1+y*oneOverRadius) + x*oneOverRadius*x*oneOverRadius );
+}
+
+
+double 
+ScintDetectorElement::sinStereoLocal(const HepGeom::Point3D<double> &globalPos) const
+{
+  return sinStereoLocal(localPosition(globalPos));
+}
+
+// Special method for SCT to retrieve the two ends of a "strip"
+  std::pair<Amg::Vector3D,Amg::Vector3D> ScintDetectorElement::endsOfStrip(const Amg::Vector2D &position) const
+{
+  const std::pair<Amg::Vector2D,Amg::Vector2D> localEnds=
+    m_design->endsOfStrip(position);
+  return std::pair<Amg::Vector3D,Amg::Vector3D >(globalPosition(localEnds.first),
+                                                 globalPosition(localEnds.second));
+}
+
+
+Trk::Surface & 
+ScintDetectorElement::surface()
+{
+  if (not m_surface) m_surface.set(std::make_unique<Trk::PlaneSurface>(*this));
+  return *m_surface;
+}
+  
+const Trk::Surface & 
+ScintDetectorElement::surface() const
+{
+  if (not m_surface) m_surface.set(std::make_unique<Trk::PlaneSurface>(*this));
+  return *m_surface;
+}
+  
+const std::vector<const Trk::Surface*>& ScintDetectorElement::surfaces() const 
+{
+    std::lock_guard<std::recursive_mutex> lock(m_mutex);
+    if (!m_surfaces.size()) {
+        // get this surface
+        m_surfaces.push_back(&surface());
+        // get the other side surface
+        if (otherSide()) {
+            m_surfaces.push_back(&(otherSide()->surface()));
+        }
+    }
+    // return the surfaces
+    return m_surfaces;
+}  
+  
+const Trk::SurfaceBounds & 
+ScintDetectorElement::bounds() const
+{
+  return m_design->bounds();
+}
+  
+// Get min/max or r, z,and phi
+void ScintDetectorElement::getExtent(double &xMin, double &xMax, 
+                                  double &yMin, double &yMax,
+                                  double &zMin, double &zMax) const
+{
+
+  HepGeom::Point3D<double> corners[4];
+  getCorners(corners);
+
+  bool first = true;
+
+  double phiOffset = 0.;
+
+  double radialShift = 0.;
+  const HepGeom::Transform3D rShift = HepGeom::TranslateX3D(radialShift);//in local frame, radius is x
+
+  for (int i = 0; i < 4; i++) {
+
+    if (testDesign) corners[i].transform(rShift);
+
+    HepGeom::Point3D<double> globalPoint = globalPosition(corners[i]);
+
+    double rPoint = globalPoint.perp();
+    double zPoint = globalPoint.z();
+    double phiPoint = globalPoint.phi();
+    
+    // Use first point to initializa min/max values.
+    if (first) {
+
+      // Put phi in a range so that we are not near -180/+180 division.
+      // Do this by adding an offset if phi > 90 CLHEP::deg or < -90 CLHEP::deg. 
+      // This offset is later removed.
+      if (phiPoint < -0.5 * M_PI) {
+        phiOffset = -0.5 * M_PI;
+      } else if  (phiPoint > 0.5 * M_PI) {
+        phiOffset = 0.5 * M_PI;
+      }
+      phiMin = phiMax = phiPoint - phiOffset;
+      rMin = rMax = rPoint;
+      zMin = zMax = zPoint;
+
+    } else {
+      phiPoint -= phiOffset;
+      // put phi back in -M_PI < phi < +M_PI range
+      if (phiPoint < -M_PI) phiPoint += 2. * M_PI;
+      if (phiPoint > M_PI)  phiPoint -= 2. * M_PI;
+      phiMin = std::min(phiMin, phiPoint);
+      phiMax = std::max(phiMax, phiPoint);
+      rMin = std::min(rMin, rPoint);
+      rMax = std::max(rMax, rPoint);
+      zMin = std::min(zMin, zPoint);
+      zMax = std::max(zMax, zPoint);
+    }
+    first = false;
+  }
+
+  // put phi back in -M_PI < phi < +M_PI range
+  phiMin += phiOffset;
+  phiMax += phiOffset;
+  if (phiMin < -M_PI) phiMin += 2. * M_PI;
+  if (phiMin > M_PI)  phiMin -= 2. * M_PI;
+  if (phiMax < -M_PI) phiMax += 2. * M_PI;
+  if (phiMax > M_PI)  phiMax -= 2. * M_PI;
+
+}
+
+
+
+// Get eta/phi extent. Returns min/max eta and phi and r (for barrel)
+// or z (for endcap) Takes as input the vertex spread in z (+-deltaZ).
+// Gets 4 corners of the sensor and calculates eta phi for each corner
+// for both +/- vertex spread.  The returned phi is between -M_PI and M_PI
+// with the direction minPhi to maxPhi always in the positive sense,
+// so if the element extends across the -180/180 boundary then minPhi will
+// be greater than maxPhi.
+void ScintDetectorElement::getEtaPhiRegion(double deltaZ, double &etaMin, double &etaMax, double &phiMin, 
+                                        double &phiMax, double &rz) const
+{
+  std::lock_guard<std::recursive_mutex> lock(m_mutex);
+  if (!m_cacheValid) updateCache();
+
+  HepGeom::Point3D<double> corners[4];
+  getCorners(corners);
+
+  bool first = true;
+
+  double phiOffset = 0.;
+
+  for (int i = 0; i < 4; i++) {
+    double etaMinPoint;
+    double etaMaxPoint;
+    double phiPoint;
+
+    // Get the eta phi value for this corner.
+    getEtaPhiPoint(corners[i], deltaZ, etaMinPoint, etaMaxPoint, phiPoint);
+
+    if (first) { // Use the first point to initialize the min/max values.
+
+      // Put phi in a range so that we are not near -180/+180 division.
+      // Do this by adding an offset if phi > 90 CLHEP::deg or < -90 CLHEP::deg. 
+      // This offset is later removed.
+      if (phiPoint < -0.5 * M_PI) {
+        phiOffset = -0.5 * M_PI;
+      } else if  (phiPoint > 0.5 * M_PI) {
+        phiOffset = 0.5 * M_PI;
+      }
+      phiMin = phiMax = phiPoint - phiOffset;
+      etaMin = etaMinPoint;
+      etaMax = etaMaxPoint;
+    } else {
+      phiPoint -= phiOffset;
+      // put phi back in -M_PI < phi < +M_PI range
+      if (phiPoint < -M_PI) phiPoint += 2. * M_PI;
+      if (phiPoint > M_PI)  phiPoint -= 2. * M_PI;
+      phiMin = std::min(phiMin, phiPoint);
+      phiMax = std::max(phiMax, phiPoint);
+      etaMin = std::min(etaMin, etaMinPoint);
+      etaMax = std::max(etaMax, etaMaxPoint);
+    }
+    first = false;
+  }
+
+  // put phi back in -M_PI < phi < +M_PI range
+  phiMin += phiOffset;
+  phiMax += phiOffset;
+  if (phiMin < -M_PI) phiMin += 2. * M_PI;
+  if (phiMin > M_PI)  phiMin -= 2. * M_PI;
+  if (phiMax < -M_PI) phiMax += 2. * M_PI;
+  if (phiMax > M_PI)  phiMax -= 2. * M_PI;
+
+  // Calculate rz = r (barrel) or z (endcap)
+  // Use center of sensor ((0,0,0) in local coordinates) for determining this.
+  //  HepGeom::Point3D<double> globalCenter = globalPosition(HepGeom::Point3D<double>(0,0,0));
+  if (isBarrel()) {
+    rz = center().perp(); // r
+  } else {
+    rz = center().z();  // z
+  }
+
+}
+
+// Gets eta phi for a point given in local coordinates. deltaZ is specified to
+// account for the vertex spread. phi is independent of this vertex
+// spread. etaMax will correspond to zMin (-deltaZ) and etaMin will
+// correspond to zMax (+deltaZ).
+void ScintDetectorElement::getEtaPhiPoint(const HepGeom::Point3D<double> & point, double deltaZ, 
+                                       double &etaMin, double &etaMax, double &phi) const
+{
+  // Get the point in global coordinates.
+  HepGeom::Point3D<double> globalPoint = globalPosition(point);
+
+  double r = globalPoint.perp();
+  double z = globalPoint.z();
+  
+  double thetaMin = atan2(r,(z + deltaZ));
+  etaMax = -log(tan(0.5 * thetaMin));
+  double thetaMax = atan2(r,(z - deltaZ));
+  etaMin = -log(tan(0.5 * thetaMax));
+  
+  phi = globalPoint.phi();
+}
+
+void ScintDetectorElement::getCorners(HepGeom::Point3D<double> *corners) const
+{
+  std::lock_guard<std::recursive_mutex> lock(m_mutex);
+  if (!m_cacheValid) updateCache();
+
+  // This makes the assumption that the forward SCT detectors are orientated such that 
+  // the positive etaAxis corresponds to the top of the detector where the width is largest.
+  // This is currently always the case.
+  // For the SCT barrel and pixel detectors minWidth and maxWidth are the same and so should 
+  // work for all orientations.
+
+  double minWidth = m_design->minWidth();
+  double maxWidth = m_design->maxWidth();
+  double length   = m_design->length();
+  
+  // Lower left
+  corners[0][distPhi] = -0.5 * minWidth;
+  corners[0][distEta] = -0.5 * length;
+  corners[0][distDepth] = 0.;
+
+  // Lower right
+  corners[1][distPhi] =  0.5 * minWidth;
+  corners[1][distEta] = -0.5 * length;
+  corners[1][distDepth] = 0.;
+
+  // Upper Right
+  corners[2][distPhi] = 0.5 * maxWidth;
+  corners[2][distEta] = 0.5 * length;
+  corners[2][distDepth] = 0.;
+
+  // Upper left
+  corners[3][distPhi] = -0.5 * maxWidth;
+  corners[3][distEta] =  0.5 * length;
+  corners[3][distDepth] = 0.;
+}
+
+SiIntersect
+ScintDetectorElement::inDetector(const Amg::Vector2D & localPosition, 
+                              double phiTol, double etaTol) const
+{
+  return m_design->inDetector(localPosition, phiTol, etaTol);
+}
+
+  
+SiIntersect 
+ScintDetectorElement::inDetector(const HepGeom::Point3D<double> & globalPosition, double phiTol, double etaTol) const
+{
+  return m_design->inDetector(localPosition(globalPosition), phiTol, etaTol);
+}
+
+bool 
+ScintDetectorElement::nearBondGap(Amg::Vector2D localPosition, double etaTol) const
+{
+  return m_design->nearBondGap(localPosition, etaTol);
+}
+
+bool
+ScintDetectorElement::nearBondGap(HepGeom::Point3D<double> globalPosition, double etaTol) const
+{
+  return m_design->nearBondGap(localPosition(globalPosition), etaTol);
+}  
+
+Amg::Vector2D
+ScintDetectorElement::rawLocalPositionOfCell(const SiCellId &cellId) const
+{
+  return m_design->localPositionOfCell(cellId);
+}
+
+Amg::Vector2D
+ScintDetectorElement::rawLocalPositionOfCell(const Identifier & id) const
+{
+  SiCellId cellId = cellIdFromIdentifier(id);
+  return m_design->localPositionOfCell(cellId);
+}
+
+int 
+ScintDetectorElement::numberOfConnectedCells(const SiCellId cellId) const
+{
+  SiReadoutCellId readoutId = m_design->readoutIdOfCell(cellId);
+  return m_design->numberOfConnectedCells(readoutId);
+}
+
+SiCellId 
+ScintDetectorElement::connectedCell(const SiCellId cellId, int number) const
+{
+  SiReadoutCellId readoutId = m_design->readoutIdOfCell(cellId);
+  return m_design->connectedCell(readoutId, number);
+}
+
+
+SiCellId 
+ScintDetectorElement::cellIdOfPosition(const Amg::Vector2D &localPosition) const
+{
+  return m_design->cellIdOfPosition(localPosition);
+}
+
+Identifier
+ScintDetectorElement::identifierOfPosition(const Amg::Vector2D &localPosition) const
+{
+  SiCellId cellId = m_design->cellIdOfPosition(localPosition);
+  return identifierFromCellId(cellId);
+}
+
+Identifier 
+ScintDetectorElement::identifierFromCellId(const SiCellId & cellId) const
+{
+  Identifier id; // Will be initialized in an invalid state.
+
+  // If something fails it returns the id in an invalid state.
+
+  if (cellId.isValid()) {
+
+    if (isPixel()) {
+      const PixelID * pixelIdHelper = static_cast<const PixelID *>(getIdHelper());
+      if (pixelIdHelper) {
+        id = pixelIdHelper->pixel_id(m_id, cellId.phiIndex(), cellId.etaIndex());
+      }
+    } else {
+      const SCT_ID * sctIdHelper = static_cast<const SCT_ID *>(getIdHelper());
+      if (sctIdHelper) {
+        id = sctIdHelper->strip_id(m_id, cellId.strip());
+      }
+    }
+  }
+
+  return id;
+}
+
+SiCellId   
+ScintDetectorElement::cellIdFromIdentifier(const Identifier & identifier) const
+{
+  SiCellId cellId; // Initialized in invalid state.
+
+  // If something fails it returns the cellId in an invalid state.
+
+  if (identifier.is_valid()) {
+  
+    if (isPixel()) {
+      const PixelID * pixelIdHelper = static_cast<const PixelID *>(getIdHelper());
+      if (pixelIdHelper) {
+        cellId = SiCellId(pixelIdHelper->phi_index(identifier), pixelIdHelper->eta_index(identifier));
+      }
+    } else {
+      const SCT_ID * sctIdHelper = static_cast<const SCT_ID *>(getIdHelper());
+      if (sctIdHelper) {
+        cellId =  SiCellId(sctIdHelper->strip(identifier));
+      }
+    }
+  }
+  
+  return cellId;
+}
+
+} // namespace InDetDD