diff --git a/InnerDetector/InDetDetDescr/InDetTrackingGeometry/InDetTrackingGeometry/SCT_OverlapDescriptor.h b/InnerDetector/InDetDetDescr/InDetTrackingGeometry/InDetTrackingGeometry/SCT_OverlapDescriptor.h
index af32b8ccf2bc294d80012225e65994bfe1722bd0..c9cd74465d086df775d0b79b0a6e58bc80d41529 100644
--- a/InnerDetector/InDetDetDescr/InDetTrackingGeometry/InDetTrackingGeometry/SCT_OverlapDescriptor.h
+++ b/InnerDetector/InDetDetDescr/InDetTrackingGeometry/InDetTrackingGeometry/SCT_OverlapDescriptor.h
@@ -74,7 +74,7 @@ namespace InDet {
        public:
 
          /** Constructor */
-         SCT_OverlapDescriptor();
+         SCT_OverlapDescriptor(bool addMoreSurfaces = false, int eta_slices = 3);
          
          /** Destructor */
          virtual ~SCT_OverlapDescriptor() = default;
@@ -91,6 +91,8 @@ namespace InDet {
         private:
           bool dumpSurfaces(std::vector<Trk::SurfaceIntersection>& surfaces) const;
           bool                                 m_robustMode;
+          bool                                 m_addMoreSurfaces;
+          int                                  m_etaSlices;         
           mutable std::atomic<const SCT_ID*>   m_sctIdHelper{nullptr};
     };
 
diff --git a/InnerDetector/InDetDetDescr/InDetTrackingGeometry/InDetTrackingGeometry/SiLayerBuilder.h b/InnerDetector/InDetDetDescr/InDetTrackingGeometry/InDetTrackingGeometry/SiLayerBuilder.h
index 346544a8ce6d37a4db9cbd4bb476095ebc6934da..7d15b770b9ae6b8f62ae50a89a0789e3ab6ac88b 100644
--- a/InnerDetector/InDetDetDescr/InDetTrackingGeometry/InDetTrackingGeometry/SiLayerBuilder.h
+++ b/InnerDetector/InDetDetDescr/InDetTrackingGeometry/InDetTrackingGeometry/SiLayerBuilder.h
@@ -95,7 +95,8 @@ namespace InDet {
       std::vector< const Trk::CylinderLayer* >* dressCylinderLayers(const std::vector< const Trk::CylinderLayer* >& dLayers) const;
       
       /** create the disc layers, if no vector is given, then it's the first pass, else it's the DBM for the Pixels */
-      std::vector< const Trk::DiscLayer* >* createDiscLayers(std::vector<const Trk::DiscLayer* >* dLayers = NULL) const;
+      std::vector< const Trk::DiscLayer* >* createDiscLayers(std::vector<const Trk::DiscLayer* >* dLayers = NULL) const;      
+      std::vector< const Trk::DiscLayer* >* createRingLayers() const;
         
       const Trk::LayerMaterialProperties* barrelLayerMaterial(double r, double hz) const;  //!< helper method to construct barrel material
       const Trk::LayerMaterialProperties* endcapLayerMaterial(double rMin, double rMax) const; //!< helper method to construct endcap material
@@ -137,7 +138,12 @@ namespace InDet {
       static std::vector<const Trk::DiscLayer*>      s_splitDiscLayers;                 //!< cached SLHC/split disc layers for projective layout
                                                      
       bool                                           m_runGeometryValidation;           //!< run the validation of the geometry ( no empty bins)
-            
+      
+      std::vector<int>                               m_layerIndicesBarrel;
+      std::vector<int>                               m_layerIndicesEndcap;
+      bool                                           m_useRingLayout;   
+      
+      bool                                           m_addMoreSurfaces   ;              //!< to add additional surfaces to the SCT_OverlapDescriptor (used for ITk specific case)
                       
   };
 
diff --git a/InnerDetector/InDetDetDescr/InDetTrackingGeometry/InDetTrackingGeometry/StagedTrackingGeometryBuilder.h b/InnerDetector/InDetDetDescr/InDetTrackingGeometry/InDetTrackingGeometry/StagedTrackingGeometryBuilder.h
index 11ba120faf493c68e6b91c2d3a62481aafa8c350..56ec490d3e38f80e0210d884042e92266746e024 100644
--- a/InnerDetector/InDetDetDescr/InDetTrackingGeometry/InDetTrackingGeometry/StagedTrackingGeometryBuilder.h
+++ b/InnerDetector/InDetDetDescr/InDetTrackingGeometry/InDetTrackingGeometry/StagedTrackingGeometryBuilder.h
@@ -210,6 +210,12 @@ namespace InDet {
 
       /** helper method needed for the Ring layout */
       void checkForInsert(std::vector<double>& radii, double radius) const;
+      
+      void checkForInsert(double rmin, double rmax, std::vector<std::pair<double, double>>& radii) const;
+
+      /** Private helper method for merging of rings with z-overlap */
+      std::vector<const Trk::Layer*> checkZoverlap(std::vector<const Trk::Layer*>& lays) const; 
+      const Trk::Layer* mergeDiscLayers(std::vector<const Trk::Layer*>& dlays) const;
 
       // helper tools for the geometry building
       ToolHandleArray<Trk::ILayerProvider>           m_layerProviders;          //!< Helper Tools for the Layer creation, includes beam pipe builder   
@@ -260,7 +266,30 @@ namespace InDet {
       std::sort(radii.begin(),radii.end());   
   }
 
+  inline void StagedTrackingGeometryBuilder::checkForInsert(double rmin, double rmax, std::vector<std::pair<double, double>>& radii) const {
 
+    // range into non-overlapping layers
+
+    if (!radii.size()) radii.push_back(std::pair<double,double>(rmin,rmax));
+    
+    unsigned int ir=0;
+    while ( ir != radii.size() && rmin > radii[ir].second ) ir++;
+
+    if (ir==radii.size()) radii.push_back(std::pair<double,double>(rmin,rmax));
+    // insert ?
+    else if (rmax<radii[ir].first) radii.insert(radii.begin()+ir,std::pair<double,double>(rmin,rmax));
+    // overlaps
+    else {
+      // resolve low edge
+      if (rmin<radii[ir].first) radii[ir].first=rmin;
+      // resolve upper edge
+      unsigned int imerge = ir;
+      while (imerge<radii.size()-1 && rmax>radii[imerge+1].first) imerge++;
+      radii[ir].second = rmax > radii[imerge].second ? rmax : radii[imerge].second;
+      if (imerge>ir) radii.erase(radii.begin()+ir+1,radii.begin()+imerge);       
+    }
+  }
+  
 } // end of namespace
 
 #endif //INDETTRACKINGGEOMETRY_STAGEDTRACKINGGEOMETRYBUILDER_H
diff --git a/InnerDetector/InDetDetDescr/InDetTrackingGeometry/src/PixelOverlapDescriptor.cxx b/InnerDetector/InDetDetDescr/InDetTrackingGeometry/src/PixelOverlapDescriptor.cxx
index e614a33efff94200d6e5d8774578da5e41a4c735..f90a666114e6fa2379e09eddd9bd13cb73bc96ef 100644
--- a/InnerDetector/InDetDetDescr/InDetTrackingGeometry/src/PixelOverlapDescriptor.cxx
+++ b/InnerDetector/InDetDetDescr/InDetTrackingGeometry/src/PixelOverlapDescriptor.cxx
@@ -42,14 +42,13 @@ InDet::PixelOverlapDescriptor::reachableSurfaces(
     tmp->detectorType() == Trk::DetectorElemType::Silicon
       ? static_cast<const InDetDD::SiDetectorElement*>(tmp)
       : nullptr;
-  // now get the overlap options
   if (sElement) {
     size_t newCapacity = cSurfaces.size();
-    if (m_robustMode) {
-      newCapacity += 8;
-    } else if (m_addMoreSurfaces and sElement->isBarrel()) {
+    if (m_robustMode and m_addMoreSurfaces and sElement->isBarrel()) {
       // sum up the defined slices to evaluate the new capacity
       newCapacity += (2*m_phiSlices+ 2*(m_etaSlices*(2*m_phiSlices+1)));
+    } else if (m_robustMode) {
+      newCapacity += 8;
     } else {
       newCapacity += 1;
       if (sElement->isBarrel()) {
@@ -58,6 +57,7 @@ InDet::PixelOverlapDescriptor::reachableSurfaces(
     }
     cSurfaces.reserve(newCapacity);
 
+    // now get the overlap options
     //!< position phi and surface phi - rescale to 0 -> 2PI
     double surfacePhi = tsf.center().phi() + M_PI;
     double positionPhi = pos.phi() + M_PI;
diff --git a/InnerDetector/InDetDetDescr/InDetTrackingGeometry/src/SCT_OverlapDescriptor.cxx b/InnerDetector/InDetDetDescr/InDetTrackingGeometry/src/SCT_OverlapDescriptor.cxx
index 2155f4808f3b9de8fd2e483d4849e829989365fb..f708e6b20f2b8e3d7985e29504ea478fe7d8df3e 100644
--- a/InnerDetector/InDetDetDescr/InDetTrackingGeometry/src/SCT_OverlapDescriptor.cxx
+++ b/InnerDetector/InDetDetDescr/InDetTrackingGeometry/src/SCT_OverlapDescriptor.cxx
@@ -18,8 +18,10 @@
 #include "StoreGate/StoreGateSvc.h"
 #include "InDetIdentifier/SCT_ID.h"
 
-InDet::SCT_OverlapDescriptor::SCT_OverlapDescriptor()
-  : m_robustMode(true)
+InDet::SCT_OverlapDescriptor::SCT_OverlapDescriptor(bool addMoreSurfaces, int eta_slices)
+  : m_robustMode(true),
+  m_addMoreSurfaces(addMoreSurfaces), 
+  m_etaSlices(eta_slices)
 {}
 
 /** get the compatible surfaces */
@@ -31,14 +33,6 @@ InDet::SCT_OverlapDescriptor::reachableSurfaces(
   const Amg::Vector3D&) const
 
 {
-  size_t newCapacity = cSurfaces.size() + 2;
-  if (m_robustMode) {
-    newCapacity += 16;
-  } else {
-    newCapacity += 6;
-  }
-  cSurfaces.reserve(newCapacity);
-
   // first add the target surface and the backside surface (in the if statement)
   cSurfaces.emplace_back(Trk::Intersection(pos, 0., true), &tsf);
 
@@ -48,13 +42,26 @@ InDet::SCT_OverlapDescriptor::reachableSurfaces(
     tmp->detectorType() == Trk::DetectorElemType::Silicon
       ? static_cast<const InDetDD::SiDetectorElement*>(tmp)
       : nullptr;
- 
-  //!< position phi and surface phi - rescale to 0 -> 2PI
-  double surfacePhi = tsf.center().phi() + M_PI;
-  double positionPhi = pos.phi() + M_PI;
-
-  // now get the overlap options
+      
   if (sElement) {
+    
+    size_t newCapacity = cSurfaces.size() + 2;
+    if (m_robustMode and m_addMoreSurfaces and sElement->isBarrel()) {
+      // sum up the defined slices to evaluate the new capacity
+      // only uses one additional slice in phi
+      newCapacity += (2 + 6*m_etaSlices)*2;
+    } else if (m_robustMode) {
+      newCapacity += 16;
+    } else {
+      newCapacity += 6;
+    }
+    cSurfaces.reserve(newCapacity);
+    
+    //!< position phi and surface phi - rescale to 0 -> 2PI
+    double surfacePhi = tsf.center().phi() + M_PI;
+    double positionPhi = pos.phi() + M_PI;
+
+    // now get the overlap options
     addOtherSide(sElement, cSurfaces);
 
     // 8-cell-connectivity depending on track/surface geometry
@@ -76,6 +83,33 @@ InDet::SCT_OverlapDescriptor::reachableSurfaces(
       nElement = sElement->prevInPhi();
       addNextInEtaOS(nElement, cSurfaces);
       addPrevInEtaOS(nElement, cSurfaces);
+      
+      if (m_addMoreSurfaces and sElement->isBarrel()) {  
+        unsigned int next = 1;
+        const InDetDD::SiDetectorElement* currentElement = sElement->nextInEta();
+        while (currentElement and next<(unsigned int)m_etaSlices) {
+          addNextInEtaOS(currentElement,cSurfaces);
+          currentElement = currentElement->nextInEta();
+          if (currentElement) {
+            addNextInPhiOS(currentElement,cSurfaces);
+            addPrevInPhiOS(currentElement,cSurfaces);
+          }
+          next++;
+        }
+        
+        unsigned int prev = 1;
+        currentElement = sElement->prevInEta();
+        while (currentElement and prev<(unsigned int)m_etaSlices) {
+          addPrevInEtaOS(currentElement,cSurfaces);
+          currentElement = currentElement->prevInEta();
+          if (currentElement) {
+            addNextInPhiOS(currentElement,cSurfaces);
+            addPrevInPhiOS(currentElement,cSurfaces);
+          }
+          prev++;
+        }
+      }      
+      
     } else {
       // get the phi information
       if (surfacePhi < positionPhi) {
diff --git a/InnerDetector/InDetDetDescr/InDetTrackingGeometry/src/SiLayerBuilder.cxx b/InnerDetector/InDetDetDescr/InDetTrackingGeometry/src/SiLayerBuilder.cxx
index d5398de1c95e40b1e01801212d9a59722b41c43e..03a646e381619c671e6dcef3e24398500d150f8d 100644
--- a/InnerDetector/InDetDetDescr/InDetTrackingGeometry/src/SiLayerBuilder.cxx
+++ b/InnerDetector/InDetDetDescr/InDetTrackingGeometry/src/SiLayerBuilder.cxx
@@ -69,7 +69,9 @@ InDet::SiLayerBuilder::SiLayerBuilder(const std::string& t, const std::string& n
   m_identification("Pixel"),
   m_splitMode(0),
   m_splitTolerance(10.),   
-  m_runGeometryValidation(true)
+  m_runGeometryValidation(true),
+  m_useRingLayout(false),
+  m_addMoreSurfaces(false)
 {
   declareInterface<Trk::ILayerBuilder>(this);
   // general steering
@@ -98,6 +100,12 @@ InDet::SiLayerBuilder::SiLayerBuilder(const std::string& t, const std::string& n
   declareProperty("SplitTolerance"                   , m_splitTolerance);      
   // Validation
   declareProperty("GeometryValidation"               , m_runGeometryValidation);
+  // for splitting the geometry
+  declareProperty("LayerIndicesBarrel"               , m_layerIndicesBarrel);
+  declareProperty("LayerIndicesEndcap"               , m_layerIndicesEndcap);
+  declareProperty("UseRingLayout"                    , m_useRingLayout);
+  // For OverlapDescriptor settings
+  declareProperty("AddMoreSurfaces"                  , m_addMoreSurfaces);
 }
 
 // destructor
@@ -176,7 +184,9 @@ const std::vector< const Trk::CylinderLayer* >* InDet::SiLayerBuilder::cylindric
   for (int i = 0; i < siNumerology.numLayers(); i++)
        if (siNumerology.useLayer(i)) barrelLayers++;
   
-
+  if (not m_layerIndicesBarrel.empty())
+    barrelLayers = m_layerIndicesBarrel.size();
+         
   // screen output
   ATH_MSG_DEBUG( "Configured to build " << barrelLayers << " (active) barrel layers (out of " << siNumerology.numLayers() << " )" );
   if (!m_barrelAdditionalLayerR.empty())
@@ -213,21 +223,29 @@ const std::vector< const Trk::CylinderLayer* >* InDet::SiLayerBuilder::cylindric
   for (; sidetIter != m_siMgr->getDetectorElementEnd(); ++sidetIter){
      // Barrel check
      if ((*sidetIter) && (*sidetIter)->isBarrel()){
+       Identifier    currentId((*sidetIter)->identify());
+       int currentlayerIndex = m_pixIdHelper ? m_pixIdHelper->layer_disk(currentId) : m_sctIdHelper->layer_disk(currentId);
+       if (not m_layerIndicesBarrel.empty()) {
+         if (std::find(m_layerIndicesBarrel.begin(), m_layerIndicesBarrel.end(), currentlayerIndex) == m_layerIndicesBarrel.end())
+           continue;
+       }
        // unit test
        ++barrelModules;
        // get the identifier
-       Identifier    currentId((*sidetIter)->identify());
-       int currentlayer = m_pixIdHelper ? m_pixIdHelper->layer_disk(currentId) : m_sctIdHelper->layer_disk(currentId);
        //skip the layer if it is chosen to be switched off
-       if ( !m_siMgr->numerology().useLayer(currentlayer) ) continue;
+       if ( !m_siMgr->numerology().useLayer(currentlayerIndex) ) continue;
+       
+       int currentlayer = m_layerIndicesBarrel.empty() ? 
+                          currentlayerIndex : (currentlayerIndex-m_layerIndicesBarrel.at(0));
+       
        // (A) Determination of phi / eta sectors  ---------------------------------------------------
        // only do the exercise if it hasn't been done already 
        if (layerPhiSectors[currentlayer] == 0){                        
           ATH_MSG_VERBOSE("Pre-processing Elements from Layer (id from idHelper): " << currentlayer );      
           // set number of phiSectors
-          layerPhiSectors[currentlayer] = m_siMgr->numerology().numPhiModulesForLayer(currentlayer);
+          layerPhiSectors[currentlayer] = m_siMgr->numerology().numPhiModulesForLayer(currentlayerIndex);
           // set number of etaSectors
-          layerZsectors[currentlayer] = m_siMgr->numerology().numEtaModulesForLayer(currentlayer);
+          layerZsectors[currentlayer] = m_siMgr->numerology().numEtaModulesForLayer(currentlayerIndex);
           // get the HalfLength of the Layer
           const InDetDD::SiDetectorElement* countPtr = (*sidetIter);
           // needed for the complex z binning if activated
@@ -237,7 +255,7 @@ const std::vector< const Trk::CylinderLayer* >* InDet::SiLayerBuilder::cylindric
           // walk all along to negative eta
           while ((countPtr->prevInEta()))
                  countPtr = countPtr->prevInEta();
-           layerMinZ[currentlayer] = countPtr->center().z() - 0.5*fabs(countPtr->length());
+           layerMinZ[currentlayer] = countPtr->center().z() - 0.5*std::abs(countPtr->length());
            zboundaries.push_back(layerMinZ[currentlayer]);
            lastModuleZ   = countPtr->center().z();
            // register the layer minZ into the zboundaries         
@@ -250,14 +268,14 @@ const std::vector< const Trk::CylinderLayer* >* InDet::SiLayerBuilder::cylindric
                   zboundaries.push_back(currentZboundary);
                   lastModuleZ   = currentModuleZ;
            }
-           layerMaxZ[currentlayer] = fabs(countPtr->center().z()) + 0.5*fabs(countPtr->length());
+           layerMaxZ[currentlayer] = std::abs(countPtr->center().z()) + 0.5*std::abs(countPtr->length());
            zboundaries.push_back(layerMaxZ[currentlayer]);
            
            // complex z binning mode
            layerZboundaries[currentlayer] = zboundaries;
            // chose which one to register for the split mode (SLHC)
            layerHalfLength[currentlayer] =  layerMinZ[currentlayer]*layerMinZ[currentlayer] > layerMaxZ[currentlayer]*layerMaxZ[currentlayer] ?
-               fabs(layerMinZ[currentlayer]) : layerMaxZ[currentlayer];
+               std::abs(layerMinZ[currentlayer]) : layerMaxZ[currentlayer];
            // get the haflength of the layer
            takeSmaller( minHalflengthZ, layerHalfLength[currentlayer]);
            takeBigger( maxHalflengthZ, layerHalfLength[currentlayer]);
@@ -300,7 +318,7 @@ const std::vector< const Trk::CylinderLayer* >* InDet::SiLayerBuilder::cylindric
        Trk::SurfaceOrderPosition surfaceOrder(sharedSurface, orderPosition);
        if (takeIt) (layerSurfaces[currentlayer]).push_back(surfaceOrder);
      
-     } else if (!(*sidetIter)) // barrel chek and screen output
+    } else if (!(*sidetIter))
         ATH_MSG_WARNING("nullptr to Barrel module given by SiDetectorManager! Please check db & dict.xml");
   
   } // SiDet Loop
@@ -344,7 +362,7 @@ const std::vector< const Trk::CylinderLayer* >* InDet::SiLayerBuilder::cylindric
       // create the BinKeyUtility - the phi binning is identical
       double halfPhiStep = M_PI/layerPhiSectors[layerCounter];
       // protection in case phi value was fluctuating around 0 or M_PI in parsing
-      if (fabs(layerMinPhi[layerCounter]+layerMaxPhi[layerCounter])< halfPhiStep && fabs(M_PI+layerMinPhi[layerCounter]) < 0.5*halfPhiStep ){
+      if (std::abs(layerMinPhi[layerCounter]+layerMaxPhi[layerCounter])< halfPhiStep && std::abs(M_PI+layerMinPhi[layerCounter]) < 0.5*halfPhiStep ){
           ATH_MSG_VERBOSE("Detected module fluctuation around +/- M_PI, correcting for it.");
           ATH_MSG_VERBOSE("    min phi / max phi detected  : "  << layerMinPhi[layerCounter] << " / " << layerMaxPhi[layerCounter] );
           layerMinPhi[layerCounter] += 2*halfPhiStep;
@@ -415,7 +433,7 @@ const std::vector< const Trk::CylinderLayer* >* InDet::SiLayerBuilder::cylindric
       // split mode > 0 : compare to minHalflength
       double compareHalfLengthZ = m_splitMode < 0 ? maxHalflengthZ : minHalflengthZ;
       
-      splitDone = m_splitMode && fabs(layerHalfLength[layerCounter]-compareHalfLengthZ) > m_splitTolerance;
+      splitDone = m_splitMode && std::abs(layerHalfLength[layerCounter]-compareHalfLengthZ) > m_splitTolerance;
       if (m_splitMode){
            ATH_MSG_DEBUG( "[ Split mode / part 1 ] Layer Halflength determined as: " << layerHalfLength[layerCounter]);
            ATH_MSG_DEBUG( "                               while minHalflengthZ is: " << minHalflengthZ );
@@ -455,7 +473,7 @@ const std::vector< const Trk::CylinderLayer* >* InDet::SiLayerBuilder::cylindric
       Trk::OverlapDescriptor* olDescriptor = nullptr;
       if (m_pixelCase)
           olDescriptor = new InDet::PixelOverlapDescriptor;
-      else olDescriptor = new  InDet::SCT_OverlapDescriptor;
+      else olDescriptor = new  InDet::SCT_OverlapDescriptor(m_addMoreSurfaces);
       // for eventual use with the passive layer
       currentLayerRadius = layerRadius[layerCounter];
 
@@ -524,7 +542,7 @@ const std::vector< const Trk::DiscLayer* >* InDet::SiLayerBuilder::discLayers()
 
   // check for DBMS
   int nDBMLayers = m_siMgr->numerology().numEndcapsDBM();
-  if (!nDBMLayers) return createDiscLayers();
+  if (!nDBMLayers) return ((m_pixelCase and m_useRingLayout) ? createRingLayers() : createDiscLayers());
   
   ATH_MSG_DEBUG( "Found " << m_siMgr->numerology().numEndcapsDBM() << " DBM layers active, building first ECs, then DBMS");
   std::vector<const Trk::DiscLayer*>* ecLayers = createDiscLayers();
@@ -662,7 +680,7 @@ std::vector< const Trk::DiscLayer* >* InDet::SiLayerBuilder::createDiscLayers(st
            }
         }
         // we take the phi / r binning only from the closer to IP module 
-        if ( !(*sidetIter)->otherSide() || fabs(currentZ) < fabs((*sidetIter)->otherSide()->center().z())){
+        if ( !(*sidetIter)->otherSide() || std::abs(currentZ) < std::abs((*sidetIter)->otherSide()->center().z())){
             // take phi-min and phimax
             takeSmaller(discPhiMin[currentlayer][currentring],currentPhi);
             takeBigger(discPhiMax[currentlayer][currentring],currentPhi);
@@ -683,7 +701,7 @@ std::vector< const Trk::DiscLayer* >* InDet::SiLayerBuilder::createDiscLayers(st
        takeSmaller(minRmin,discRmin[iec]); takeBigger(maxRmax,discRmax[iec]);
        // average it out
        discZpos[iec]        = 0.5 * (discZmin[iec] + discZmax[iec]);
-       discThickness[iec]   = isDBM ? 1. : fabs(discZmax[iec]-discZmin[iec]);
+       discThickness[iec]   = isDBM ? 1. : std::abs(discZmax[iec]-discZmin[iec]);
        // make the map z / index
        discZposLayerIndex.insert(std::make_pair(discZpos[iec],iec));
   }
@@ -701,7 +719,7 @@ std::vector< const Trk::DiscLayer* >* InDet::SiLayerBuilder::createDiscLayers(st
         currentlayer += (*sidetIter)->center().z() > 0. ? endcapLayers : 0;
         // decision which module to take
         const InDetDD::SiDetectorElement* otherSide = (*sidetIter)->otherSide();    
-        bool takeIt =  (!otherSide || fabs((*sidetIter)->center().z()) < fabs(otherSide->center().z()) );
+        bool takeIt =  (!otherSide || std::abs((*sidetIter)->center().z()) < std::abs(otherSide->center().z()) );
         const InDetDD::SiDetectorElement* chosenSide = takeIt ?  (*sidetIter) : otherSide;
         // get the center position
         const Amg::Vector3D& orderPosition = chosenSide->center();
@@ -760,7 +778,7 @@ std::vector< const Trk::DiscLayer* >* InDet::SiLayerBuilder::createDiscLayers(st
        if (discRsectors==1){
             double halfPhiStep = M_PI/discPhiSectors[discCounter][0];
             // protection in case phi value was fluctuating around 0 or M_PI in parsing
-            if (fabs(discPhiMin[discCounter][0]+discPhiMax[discCounter][0])< halfPhiStep && fabs(discPhiMin[discCounter][0]) < 0.5*halfPhiStep ){
+            if (std::abs(discPhiMin[discCounter][0]+discPhiMax[discCounter][0])< halfPhiStep && std::abs(discPhiMin[discCounter][0]) < 0.5*halfPhiStep ){
                 ATH_MSG_VERBOSE("Detected module fluctuation around +/- M_PI, correcting for it.");
                 ATH_MSG_VERBOSE("    min phi / max phi detected  : "  << discPhiMin[discCounter][0] << " / " <<discPhiMax[discCounter][0] );
                 discPhiMin[discCounter][0] += 2*halfPhiStep;
@@ -1022,7 +1040,322 @@ std::vector< const Trk::DiscLayer* >* InDet::SiLayerBuilder::createDiscLayers(st
   return discLayers;
 }
 
+/** LayerBuilder interface method - returning ring-like layers */
+/** this is ITk pixel specific and doesn't include DBM modules */
+std::vector< const Trk::DiscLayer* >* InDet::SiLayerBuilder::createRingLayers() const {
+ 
+  // get general layout
+  InDetDD::SiDetectorElementCollection::const_iterator sidetIter = m_siMgr->getDetectorElementBegin();
+    
+  // save way to estimate the number of barrels
+  unsigned int endcapLayers = 0;
+  for (int i = 0; i < m_siMgr->numerology().numDiskLayers(); i++) {
+    if (not m_layerIndicesEndcap.empty() and 
+      std::find(m_layerIndicesEndcap.begin(), m_layerIndicesEndcap.end(), i)==m_layerIndicesEndcap.end() ) continue;
+    if (m_siMgr->numerology().useDiskLayer(i)) {
+      endcapLayers+=m_siMgr->numerology().numDisksForLayer(i);
+    }
+  }
+  
+  ATH_MSG_DEBUG( "Configured to build " << endcapLayers << " *2 disc-like layers  (+ additional support layers)." );
+ 
+  if (m_splitMode) 
+      ATH_MSG_DEBUG( "[ Split mode ] Some layers may bee cached." );
 
+  // prepare the vectors
+  std::vector<double>                                     discZmin(2*endcapLayers,10e10);
+  std::vector<double>                                     discZmax(2*endcapLayers,-10e10);
+  std::vector<double>                                     discZpos(2*endcapLayers,0.);
+  std::vector<double>                                     discRmin(2*endcapLayers,10e10);
+  std::vector<double>                                     discRmax(2*endcapLayers,0);
+  std::vector<double>                                     discThickness(2*endcapLayers,0.);  
+  std::vector<int>                                        discPhiSectors(2*endcapLayers,-1);
+  std::vector<double>                                     discPhiMin(2*endcapLayers,10e10);
+  std::vector<double>                                     discPhiMax(2*endcapLayers,-10e10);
+  std::vector< std::vector<Trk::SurfaceOrderPosition> >   discSurfaces(2*endcapLayers, std::vector<Trk::SurfaceOrderPosition>());  
+    
+  // let's make sure the discs are ordered in z: that's the z / map index
+  std::map< double, int>                                  discZposLayerIndex;  
+   
+  int endcapModules = 0;
+  int sumCheckEndcapModules = 0;
+  unsigned int currentdisk  = 0;
+  unsigned int currentring  = 0;
+  unsigned int currentlayer = 0;
+  
+  // [-A-] ------------------------ first LOOP over Detector Elements of sensitive layers -------------------------------                 
+  // -- get the missing dimensions by loop over DetElements
+  sidetIter = m_siMgr->getDetectorElementBegin();  
+  for (; sidetIter != m_siMgr->getDetectorElementEnd(); ++sidetIter){
+     // take it - if 
+     // a) you have a detector element ... protection
+     // b) the detector element is EC
+     if ( (*sidetIter) && (*sidetIter)->isEndcap() ){     
+        // get the identifier & calculate current layer and current disk from it     
+        Identifier    currentId((*sidetIter)->identify());
+        currentring  = m_pixIdHelper->layer_disk(currentId);
+        if (not m_layerIndicesEndcap.empty() and std::find(m_layerIndicesEndcap.begin(), m_layerIndicesEndcap.end(), currentring) == m_layerIndicesEndcap.end())
+          continue;
+        
+        double currentZ = (*sidetIter)->center().z();
+        currentdisk = (unsigned int)m_pixIdHelper->eta_module(currentId);
+        currentlayer = currentdisk;
+        for (unsigned int i = 0; i < currentring; i++) {
+          if (not m_layerIndicesEndcap.empty() and 
+            std::find(m_layerIndicesEndcap.begin(), m_layerIndicesEndcap.end(), i)==m_layerIndicesEndcap.end() ) continue;
+          if (m_siMgr->numerology().useDiskLayer(i)) {
+            currentlayer+=m_siMgr->numerology().numDisksForLayer(i);
+          }
+        }
+        // parse all z positions for the mean value of the discs
+        currentlayer += currentZ > 0. ? endcapLayers : 0;
+        
+        // increase the counter of endcap modules
+        endcapModules++;
+        
+        takeSmallerBigger(discZmin[currentlayer],discZmax[currentlayer],currentZ);
+
+        // set the disc Rmin / Rmax  
+        double currentRmin = (*sidetIter)->rMin();
+        double currentRmax = (*sidetIter)->rMax();
+        
+        // the current phi 
+        double currentPhi = (*sidetIter)->center().phi();
+        takeSmaller(discRmin[currentlayer],currentRmin);
+        takeBigger( discRmax[currentlayer],currentRmax);       
+        
+        //fill the number of phi sectors for the different rings
+        if (discPhiSectors[currentlayer]<0){
+          ATH_MSG_VERBOSE("Pre-processing Elements from Disk/Layer (id from idHelper): " << currentring << "/" << currentdisk );
+          // get the number of phi sectors
+          unsigned int phiSectorsRing = m_siMgr->numerology().numPhiModulesForLayerDisk(currentring, currentdisk);
+          ATH_MSG_VERBOSE("--> has " << phiSectorsRing << " phi sectors");
+          discPhiSectors[currentlayer]=phiSectorsRing;
+        }
+//         we take the phi / r binning only from the closer to IP module 
+        // take phi-min and phimax
+        takeSmaller(discPhiMin[currentlayer],currentPhi);
+        takeBigger(discPhiMax[currentlayer],currentPhi);
+        
+        const InDetDD::SiDetectorElement* detElement = (*sidetIter);
+        // get the center position
+        const Amg::Vector3D& orderPosition = detElement->center();
+        // register the chosen side in the object array
+        Trk::SharedObject<const Trk::Surface> sharedSurface(&(detElement->surface()), Trk::do_not_delete<const Trk::Surface>);
+        Trk::SurfaceOrderPosition surfaceOrder(sharedSurface, orderPosition);
+        discSurfaces[currentlayer].push_back(surfaceOrder);
+        
+     } else if (!(*sidetIter))
+        ATH_MSG_WARNING("nullptr to Endcap module given by SCT_DetectorManager! Please check db & dict.xml");
+  } // DetElement loop 
+
+  ATH_MSG_VERBOSE("Estimating the average z position and the radius for each disk.");
+  // get the average z-position per layer & estimate thes thickness
+  for (unsigned int iec=0; iec<2*endcapLayers; ++iec){
+    // average it out
+    discZpos[iec]        = 0.5 * (discZmin[iec] + discZmax[iec]);
+    discThickness[iec]   = std::abs(discZmax[iec]-discZmin[iec]);
+    // make the map z / index
+    discZposLayerIndex.insert(std::make_pair(discZpos[iec],iec));
+  }
+      
+  // [-B-] ------------------------ Construction of the layers -----------------------------------
+  // construct the layers
+  std::vector< const Trk::DiscLayer* >* discLayers = new std::vector< const Trk::DiscLayer* >;
+  std::vector<double>::iterator discZposIter = discZpos.begin();
+  int discCounter = 0;
+                                              
+  for ( ; discZposIter != discZpos.end(); ++discZposIter){
+    // dynamic estimation 1: estimate the layer thickness dynamically
+    double thickness = discThickness[discCounter]+m_endcapEnvelope;       
+    
+    // screen output           
+    ATH_MSG_DEBUG( "Building a DiscLayer with single R sectors. " );
+    ATH_MSG_DEBUG( "  -> At Z - Position      :  " << discZpos[discCounter] );
+    ATH_MSG_DEBUG( "  -> With Thickness       :  " << thickness   << " i- ncludes envelope tolerance : " << m_endcapEnvelope );
+    ATH_MSG_DEBUG( "  -> With Rmin/Rmax (est) :  " << discRmin[discCounter] << " / " << discRmax[discCounter] );
+    
+    // prepare the binned array, it can be with one to several rings            
+    Trk::BinnedArray<Trk::Surface>* currentBinnedArray = nullptr;
+    
+    double halfPhiStep = M_PI/discPhiSectors[discCounter];
+    // protection in case phi value was fluctuating around 0 or M_PI in parsing
+    if (std::abs(discPhiMin[discCounter]+discPhiMax[discCounter])< halfPhiStep && std::abs(discPhiMin[discCounter]) < 0.5*halfPhiStep ){
+      ATH_MSG_VERBOSE("Detected module fluctuation around +/- M_PI, correcting for it.");
+      ATH_MSG_VERBOSE("    [0 - ] min phi / max phi detected  : "  << discPhiMin[discCounter] << " / " <<discPhiMax[discCounter]);
+      discPhiMin[discCounter] += 2*halfPhiStep;
+    }
+    
+    // prepare min phi and max phi & eventually a sub stepvalue
+    ATH_MSG_VERBOSE("    [1 - ] min phi / max phi detected  : " << discPhiMin[discCounter] << " / " << discPhiMax[discCounter] );
+    double minPhiCorrected = discPhiMin[discCounter]-halfPhiStep;
+    double maxPhiCorrected = discPhiMax[discCounter]+halfPhiStep;
+    // catch if the minPhi falls below M_PI
+    if (minPhiCorrected < -M_PI){
+      minPhiCorrected += 2*halfPhiStep;
+      maxPhiCorrected += 2*halfPhiStep;
+    }
+    
+    ATH_MSG_VERBOSE("    min phi / max phi corrected : " << minPhiCorrected << " / " << maxPhiCorrected );
+    ATH_MSG_VERBOSE("Constructing a one-dimensional BinnedArray with phiMin / phiMax (bins) = " 
+                     << minPhiCorrected << " / " << maxPhiCorrected
+                     << " (" << discPhiSectors[discCounter] << ")");
+    
+    Trk::BinUtility* currentBinUtility = new Trk::BinUtility(discPhiSectors[discCounter],
+                                                             minPhiCorrected,
+                                                             maxPhiCorrected,
+                                                             Trk::closed,
+                                                             Trk::binPhi);
+    
+    // a one-dimensional BinnedArray is sufficient
+    currentBinnedArray = new Trk::BinnedArray1D<Trk::Surface>(discSurfaces[discCounter],currentBinUtility);
+    
+    int discSurfacesNum = (discSurfaces[discCounter]).size();
+    ATH_MSG_DEBUG( "Constructed BinnedArray for DiscLayer with "<< discSurfacesNum << " SubSurfaces." );
+
+    // always run the geometry validation to catch flaws
+        
+    // checking for :
+    //   - empty surface bins
+    //   - doubly filled bins
+    std::map< const Trk::Surface*,Amg::Vector3D > uniqueSurfaceMap;
+    std::map< const Trk::Surface*,Amg::Vector3D >::iterator usmIter = uniqueSurfaceMap.end();
+    // check the registered surfaces in the binned array
+    const std::vector<const Trk::Surface*>& arraySurfaces = currentBinnedArray->arrayObjects();
+    size_t dsumCheckSurfaces = 0;
+    double lastPhi = 0.;
+    for (const auto & asurfIter : arraySurfaces){
+      if ( asurfIter ) {
+        ++dsumCheckSurfaces;
+        usmIter = uniqueSurfaceMap.find(asurfIter);
+        lastPhi = asurfIter->center().phi();
+        if ( usmIter != uniqueSurfaceMap.end() )
+          ATH_MSG_WARNING("Non-unique surface found with eta/phi = " << asurfIter->center().eta() << " / " << asurfIter->center().phi());
+        else uniqueSurfaceMap[asurfIter] = asurfIter->center();
+      } else 
+        ATH_MSG_WARNING("Zero-pointer in array detected in this ring, last valid phi value was = " << lastPhi);
+    }
+    sumCheckEndcapModules +=  dsumCheckSurfaces;   
+    
+    ATH_MSG_DEBUG( "  -> With Rmin/Rmax :  " << discRmin[discCounter] << " / " << discRmax[discCounter] );
+    
+    // get the layer material from the helper method
+    const Trk::LayerMaterialProperties* layerMaterial = endcapLayerMaterial(discRmin[discCounter],discRmax[discCounter]);
+
+    // position & bounds of the active Layer
+    Amg::Transform3D  activeLayerTransform;
+    activeLayerTransform = Amg::Translation3D(0.,0.,discZpos[discCounter]);
+    
+    Trk::DiscBounds* activeLayerBounds    = new Trk::DiscBounds(discRmin[discCounter],discRmax[discCounter]);
+    std::vector<Trk::BinUtility*>* binUtils = new std::vector<Trk::BinUtility*>;
+    // prepare the right overlap descriptor       
+    Trk::OverlapDescriptor* olDescriptor = new  InDet::DiscOverlapDescriptor(currentBinnedArray, binUtils, true);
+        
+    // layer creation; deletes currentBinnedArray in baseclass 'Layer' upon destruction
+    // activeLayerTransform deleted in 'Surface' baseclass
+    Trk::DiscLayer* activeLayer = new Trk::DiscLayer(activeLayerTransform,
+                                                     activeLayerBounds,
+                                                     currentBinnedArray,
+                                                     *layerMaterial,
+                                                     thickness,
+                                                     olDescriptor);
+    // cleanup
+    delete layerMaterial;
+    // register the layer to the surfaces --- if necessary to the other sie as well
+    const std::vector<const Trk::Surface*>& layerSurfaces     = currentBinnedArray->arrayObjects();
+    registerSurfacesToLayer(layerSurfaces,*activeLayer);
+    discLayers->push_back(activeLayer);
+    // increase the disc counter by one
+    ++discCounter;
+  }  
+
+  ATH_MSG_DEBUG( endcapModules << " Endcap Modules parsed for Disc Layer dimensions." );
+  ATH_MSG_DEBUG( sumCheckEndcapModules << " Endcap Modules filled in Disc Layer Arrays." );
+  if ( endcapModules-sumCheckEndcapModules )
+    ATH_MSG_WARNING( endcapModules-sumCheckEndcapModules << " Modules not registered properly in binned array." );       
+
+ 
+  // sort the vector
+  Trk::DiscLayerSorterZ zSorter;
+  std::vector<const Trk::DiscLayer*>::iterator sortIter = discLayers->begin();
+  std::vector<const Trk::DiscLayer*>::iterator sortEnd   = discLayers->end(); 
+  std::sort(sortIter, sortEnd, zSorter);
+ 
+  // if there are additional layers to be built - never build for the DBM loop
+  if (!m_endcapAdditionalLayerPosZ.empty()){
+    // sort also the additional layer z positions
+    auto addLayerIter     = m_endcapAdditionalLayerPosZ.begin();
+    auto addLayerIterEnd  = m_endcapAdditionalLayerPosZ.end();
+    auto addLayerTypeIter = m_endcapAdditionalLayerType.begin();
+    // reassign the iterators
+    sortIter = discLayers->begin();
+    sortEnd   = discLayers->end();
+    // get the last rmin / rmax
+    double lastRmin = 0.;
+    double lastRmax = 0.;
+    // build the additional layers -------------------------------------------
+    for ( ; sortIter != sortEnd || addLayerIter != addLayerIterEnd; ){
+      // cache befor last parameters are overwritten 
+      double layerRmin       = lastRmin;
+      double layerRmax       = lastRmax;
+      double layerZposition   = 0.; 
+      // check if the z-position is smaller than the 
+      if ( sortIter != sortEnd){
+        // get the current z position to guarantee a symmetrical setup
+        layerZposition = (*sortIter)->surfaceRepresentation().center().z();
+        // get the bounds for the rMin / rMax setting
+        const Trk::DiscBounds* currentBounds = dynamic_cast<const Trk::DiscBounds*>(&((*sortIter)->surfaceRepresentation().bounds()));
+        lastRmin = currentBounds ? currentBounds->rMin() : 0.;
+        lastRmax = currentBounds ? currentBounds->rMax() : 0.;
+        ++sortIter;           
+      }
+      if ( addLayerIter != addLayerIterEnd){
+        // symmetric setup around 0.
+        double rMin = layerZposition > 0. ? layerRmin : lastRmin;
+        double rMax = layerZposition > 0. ? layerRmax : lastRmax;
+        // the passive layer
+        Trk::DiscLayer* passiveLayer = nullptr;
+        // passive layer creation
+        Amg::Transform3D passiveDiscTransf = Amg::Transform3D(Amg::Translation3D(0., 0., *addLayerIter));
+        if (*addLayerTypeIter) {
+          ATH_MSG_DEBUG("Building an additional DiscLayer w/o sensitive modules at");
+          // create the material and the passive layer
+          const Trk::LayerMaterialProperties* passiveLayerMaterial = endcapLayerMaterial(rMin, rMax);
+          passiveLayer = new Trk::DiscLayer(passiveDiscTransf,
+                                            new Trk::DiscBounds(rMin, rMax),
+                                            *passiveLayerMaterial,
+                                            1. * Gaudi::Units::mm);
+          // cleanup of the layer material
+          // --------------------------------------------------------------
+          delete passiveLayerMaterial;
+        } else {
+          passiveLayer = new Trk::DiscLayer(passiveDiscTransf, 
+                                            new Trk::DiscBounds(rMin, rMax), 
+                                            nullptr);
+        }
+        ATH_MSG_DEBUG( "  -> At Z - Position       :  " << *addLayerIter );
+        ATH_MSG_DEBUG( "  -> With Rmin/Rmax (corr) :  " << rMin << " / " << rMax );
+         
+        // increase the iterator and push back the new layer
+        ++addLayerIter; 
+        discLayers->push_back(passiveLayer);
+      }
+    } // the additional layers are build ------------------------------------
+    
+    // another round of sorting needed after adding the passive layers
+    sortIter = discLayers->begin();
+    sortEnd   = discLayers->end(); 
+    std::sort(sortIter, sortEnd, zSorter);
+  }
+
+  ATH_MSG_DEBUG("Returning: " << discLayers->size() << " disk-like layers to the volume builder");
+  for (const auto& dl : (*discLayers)){
+    ATH_MSG_VERBOSE(" ----> Pointer location : " << dl);
+    ATH_MSG_VERBOSE(" ----> Disk layer located at : " << dl->surfaceRepresentation().center().z());
+  }
+ 
+  return discLayers;
+}
 
 std::vector< const Trk::CylinderLayer* >* InDet::SiLayerBuilder::dressCylinderLayers(const std::vector< const Trk::CylinderLayer* >& detectionLayers ) const {
 
diff --git a/InnerDetector/InDetDetDescr/InDetTrackingGeometry/src/StagedTrackingGeometryBuilder.cxx b/InnerDetector/InDetDetDescr/InDetTrackingGeometry/src/StagedTrackingGeometryBuilder.cxx
index fc54f8798b151a9d023fc50c9f5792a58937a3a2..3d474b5ad6da00f6d52443dcfcbc4e572e15f9be 100644
--- a/InnerDetector/InDetDetDescr/InDetTrackingGeometry/src/StagedTrackingGeometryBuilder.cxx
+++ b/InnerDetector/InDetDetDescr/InDetTrackingGeometry/src/StagedTrackingGeometryBuilder.cxx
@@ -8,14 +8,18 @@
 
 // InDet
 #include "InDetTrackingGeometry/StagedTrackingGeometryBuilder.h"
+#include "InDetTrackingGeometry/DiscOverlapDescriptor.h"
+#include "InDetReadoutGeometry/SiDetectorElement.h"
 // EnvelopeDefinitionService
 #include "SubDetectorEnvelopes/IEnvelopeDefSvc.h"
 // Trk interfaces
+#include "TrkDetDescrInterfaces/ILayerBuilder.h"
 #include "TrkDetDescrInterfaces/ILayerProvider.h"
 #include "TrkDetDescrInterfaces/ITrackingVolumeCreator.h"
 #include "TrkDetDescrInterfaces/ILayerArrayCreator.h"
 // Trk Geometry stuff
 #include "TrkDetDescrUtils/BinnedArray.h"
+#include "TrkDetDescrUtils/BinnedArray1D1D.h"
 #include "TrkVolumes/VolumeBounds.h"
 #include "TrkVolumes/CylinderVolumeBounds.h"
 #include "TrkGeometry/TrackingVolume.h"
@@ -67,6 +71,8 @@ InDet::StagedTrackingGeometryBuilder::StagedTrackingGeometryBuilder(const std::s
   // force robust layer indexing  
   declareProperty("IndexStaticLayers",                m_indexStaticLayers);
   declareProperty("CheckForRingLayout",               m_checkForRingLayout);
+  // minimal radial distance between rings to allow a split
+  declareProperty("MinimalRadialGapForVolumeSplit",   m_ringTolerance);
   // volume namespace & contaienr name
   declareProperty("VolumeNamespace",                  m_namespace); 
   declareProperty("ExitVolumeName",                   m_exitVolume);
@@ -201,6 +207,9 @@ const Trk::TrackingGeometry* InDet::StagedTrackingGeometryBuilder::trackingGeome
             // [b] cache is not empty - let's see what is going on:
             ATH_MSG_VERBOSE("       -> new sector does not fit the current cache specs -> flushing the cache." );
             // create the outer boundary
+            //TODO CHECK THIS (NOEMI)
+//             double flushRadius = layerSetupCache[layerSetupCache.size()-1].rMax > lSetup.rMin ? 
+// 	      0.5*(layerSetupCache[layerSetupCache.size()-1].rMax + lSetup.rMax) :  0.5*(layerSetupCache[layerSetupCache.size()-1].rMax + lSetup.rMin)  ;
             double flushRadius = 0.5*(layerSetupCache[layerSetupCache.size()-1].rMax + lSetup.rMin);
             // create a flush volume - clears the cache
             const Trk::TrackingVolume* fVolume = createFlushVolume(layerSetupCache,lastFlushRadius,flushRadius,maximumLayerExtendZ);
@@ -300,7 +309,7 @@ const Trk::TrackingVolume* InDet::StagedTrackingGeometryBuilder::packVolumeTripl
                                                                    -zMax,-zPosCentral,
                                                                    volumeBase+"::NegativeEndcap",
                                                                    (Trk::BinningType)layerSetup.binningEndcap,
-								   false);
+                                                                   false);
 
   const Trk::TrackingVolume* centralVolume = 
          m_trackingVolumeCreator->createTrackingVolume(layerSetup.centralLayers,
@@ -315,7 +324,7 @@ const Trk::TrackingVolume* InDet::StagedTrackingGeometryBuilder::packVolumeTripl
                                                                     zPosCentral,zMax,
                                                                     volumeBase+"::PositiveEndcap",
                                                                     (Trk::BinningType)layerSetup.binningEndcap,
-								    false);
+                                                                    false);
    
    // the base volumes have been created
    ATH_MSG_VERBOSE('\t' << '\t'<< "Volumes have been created, now pack them into a triple.");
@@ -473,24 +482,50 @@ bool InDet::StagedTrackingGeometryBuilder::setupFitsCache(LayerSetup& layerSetup
 }
  
 bool InDet::StagedTrackingGeometryBuilder::ringLayout(const std::vector<const Trk::Layer*>& layers, std::vector<double>& rmins, std::vector<double>& rmaxs) const {
-    // get the maximum extent in z
-    ATH_MSG_INFO("Checking for Ring layout ... ");
-    for (const auto & ring : layers){
-        // Surface
-        const Trk::Surface&     ringSurface = ring->surfaceRepresentation(); 
-        const Trk::DiscBounds*  ringBounds  = dynamic_cast<const Trk::DiscBounds*>(&(ringSurface.bounds()));
-        if (ringBounds){
-            // get the main parameters
-            double zpos         = ringSurface.center().z();
-            double rMin         = ringBounds->rMin();
-            double rMax         = ringBounds->rMax();
-            // take and check
-            checkForInsert(rmins,rMin);
-            checkForInsert(rmaxs,rMax);
-            ATH_MSG_INFO(" -> Ring at z-position " << zpos << " - with rMin/rMax = " << rMin << "/" << rMax );
-        }
+  // get the maximum extent in z
+  std::vector<std::pair<double,double>> radii;
+  ATH_MSG_DEBUG("Checking for Ring layout ... ");
+  for (auto& ring : layers) {
+    // Surface
+    const Trk::Surface&     ringSurface = ring->surfaceRepresentation(); 
+    const Trk::DiscBounds*  ringBounds  = dynamic_cast<const Trk::DiscBounds*>(&(ringSurface.bounds()));
+    if (ringBounds){
+      // get the main parameters
+      double zpos         = ringSurface.center().z();
+      double rMin         = ringBounds->rMin();
+      double rMax         = ringBounds->rMax();
+      // take and check the couple rmin/rmax
+      checkForInsert(rMin, rMax, radii);
+      ATH_MSG_DEBUG(" -> Ring at z-position " << zpos << " - with rMin/rMax = " << rMin << "/" << rMax );
     }
-    return (rmins.size() > 1 );
+  }
+  
+  // you need a post processing of the (rmin,rmax) in order to fit z-overlapping disks in the same ring
+  std::vector<std::pair<double,double>> tmpradii;
+  
+  for (auto& rs: radii) {
+    bool found = false;
+    for (auto& tmprs: tmpradii) {
+      if ((rs.first<tmprs.second and rs.second>tmprs.first) ) {
+	tmprs.first  = std::min(tmprs.first ,rs.first );
+	tmprs.second = std::max(tmprs.second,rs.second);
+	found = true;
+	break;
+      }
+    }
+    if (found) continue;
+    tmpradii.push_back(rs);
+  }
+   
+  // now you fill rmin and rmax
+  rmins.clear(); rmaxs.clear();
+  for (auto& r: tmpradii) {
+    rmins.push_back(r.first);
+    rmaxs.push_back(r.second);
+  }
+   
+  //add rmin and rmax
+  return (rmins.size() > 1 );
 }                                              
  
  
@@ -532,36 +567,67 @@ const Trk::TrackingVolume* InDet::StagedTrackingGeometryBuilder::createTrackingV
                 if (dring) groupedDiscs[rPos].push_back(dring);
             }
         }
-        // we are now grouped in cylinder rings per volume
-        for (int idset = 0; idset < int(groupedDiscs.size()); idset++){
-            // always keep the boundaries in mind for the radial extend
-            double crmin = idset ? ringRmaxa[idset-1]+m_layerEnvelopeCover : innerRadius;
-            double crmax = ringRmaxa[idset]+m_layerEnvelopeCover;
-	    if(idset==int(groupedDiscs.size())-1 && !doAdjustOuterRadius) crmax = outerRadius; 
-            // now create the sub volume
-            std::string ringVolumeName = volumeName+"Ring"+std::to_string(idset);
-            const Trk::TrackingVolume* ringVolume = m_trackingVolumeCreator->createTrackingVolume(groupedDiscs[idset],
-                                                                                                  *m_materialProperties,
-                                                                                                  crmin,crmax,
-                                                                                                  zMin,zMax,
-                                                                                                  ringVolumeName,
-                                                                                                  binningType);
-             // push back into the 
-             ringVolumes.push_back(ringVolume);
+      // layer merging may be needed 
+      std::vector< std::vector< const Trk::Layer*> > mergedLayers;
+      std::vector< float > mergedRmax;
+      std::vector< std::vector< int > > merge;
+      std::vector<int> laySet(1,0); merge.push_back(laySet);
+      double rCurr = ringRmaxa[0];
+      mergedRmax.push_back(rCurr);
+      for (int idset = 1; idset < int(groupedDiscs.size()); idset++){
+        if (ringRmins[idset]<=rCurr + m_ringTolerance) {
+          merge.back().push_back(idset);
+          if (ringRmaxa[idset]>mergedRmax.back()) mergedRmax.back()=ringRmaxa[idset]; 
+        } else {
+          merge.push_back(std::vector<int>(1,idset));
+          mergedRmax.push_back(ringRmaxa[idset]);
         }
-        // set the outer radius
-        if(doAdjustOuterRadius) outerRadius = ringRmaxa[ringRmaxa.size()-1]+m_layerEnvelopeCover;
-        //
-        ATH_MSG_INFO("      -> adjusting the outer radius to the last ring at " << outerRadius );
-        ATH_MSG_INFO("      -> created " << ringVolumes.size() << " ring volumes for Volume '" << volumeName << "'.");
-        // create the tiple container
-        return m_trackingVolumeCreator->createContainerTrackingVolume(ringVolumes,
-                                                                      *m_materialProperties,
-                                                                      volumeName,
-                                                                      m_buildBoundaryLayers,
-                                                                      m_replaceJointBoundaries);
-        
-        
+        rCurr = ringRmaxa[idset];
+      } 
+      for ( auto layset : merge ) {
+        std::vector<const Trk::Layer*> ringSet;
+        for ( auto lay : layset ) {
+          for ( auto ring : groupedDiscs[lay]) {
+            float zPos = ring->surfaceRepresentation().center().z();
+            if (!ringSet.size() || zPos>ringSet.back()->surfaceRepresentation().center().z()) ringSet.push_back(ring);
+            else {
+              std::vector<const Trk::Layer*>::iterator lit = ringSet.begin();
+              while (lit!=ringSet.end() && zPos>(*lit)->surfaceRepresentation().center().z()) lit++;
+              ringSet.insert(lit,ring);  
+            }   
+          }
+        } 
+        // rings ordered in z : resolve overlap
+        mergedLayers.push_back(checkZoverlap(ringSet));
+      }
+      // we are now grouped in cylinder rings per volume
+      for (int idset = 0; idset < int(mergedLayers.size()); idset++){
+        // always keep the boundaries in mind for the radial extend
+        double crmin = idset ? mergedRmax[idset-1]+m_layerEnvelopeCover : innerRadius;
+        double crmax = mergedRmax[idset]+m_layerEnvelopeCover;
+        if(idset==int(mergedLayers.size())-1 && !doAdjustOuterRadius) crmax = outerRadius; 
+        // now create the sub volume
+        std::string ringVolumeName = volumeName+"Ring"+std::to_string(idset);
+        const Trk::TrackingVolume* ringVolume = m_trackingVolumeCreator->createTrackingVolume(mergedLayers[idset],
+                                                                                              *m_materialProperties,
+                                                                                              crmin,crmax,
+                                                                                              zMin,zMax,
+                                                                                              ringVolumeName,
+                                                                                              binningType);
+        // push back into the 
+        ringVolumes.push_back(ringVolume);
+      }
+      // set the outer radius
+      if(doAdjustOuterRadius) outerRadius = ringRmaxa[ringRmaxa.size()-1]+m_layerEnvelopeCover;
+      //
+      ATH_MSG_INFO("      -> adjusting the outer radius to the last ring at " << outerRadius );
+      ATH_MSG_INFO("      -> created " << ringVolumes.size() << " ring volumes for Volume '" << volumeName << "'.");
+      // create the tiple container
+      return m_trackingVolumeCreator->createContainerTrackingVolume(ringVolumes,
+                                                                    *m_materialProperties,
+                                                                    volumeName,
+                                                                    m_buildBoundaryLayers,
+                                                                    m_replaceJointBoundaries);
     } else 
         return m_trackingVolumeCreator->createTrackingVolume(layers,
                                                              *m_materialProperties,
@@ -608,12 +674,12 @@ const Trk::TrackingVolume* InDet::StagedTrackingGeometryBuilder::createFlushVolu
            // take the given outer radius for the last one - median otherwise
            double orE = ((ilS+1)==layerSetupCache.size()) ? outerRadius : 0.5*(layerSetupCache[ilS+1].minRadiusEndcap+layerSetupCache[ilS].maxRadiusEndcap);
            double orC = ((ilS+1)==layerSetupCache.size()) ? outerRadius : 0.5*(layerSetupCache[ilS+1].minRadiusCenter+layerSetupCache[ilS].maxRadiusCenter);
-	   // Adjust last volumes in R to the same maximal radial extends!
-	   if(ilS==layerSetupCache.size()-1) {
-	     ATH_MSG_VERBOSE("Processing last volume");
-	     ATH_MSG_VERBOSE("  --> adjust volumes to same extends: orE=" << orE << " orC=" << orC);
-	     if(orE>orC) orC=orE; else orE=orC;
-	   }
+           // Adjust last volumes in R to the same maximal radial extends!
+           if(ilS==layerSetupCache.size()-1) {
+             ATH_MSG_VERBOSE("Processing last volume");
+             ATH_MSG_VERBOSE("  --> adjust volumes to same extends: orE=" << orE << " orC=" << orC);
+             if(orE>orC) orC=orE; else orE=orC;
+           }
            // create the three volumes
            const Trk::TrackingVolume* nVolume = createTrackingVolume(layerSetupCache[ilS].negativeLayers,
                                                                      irE,orE,
@@ -710,3 +776,146 @@ const Trk::TrackingVolume* InDet::StagedTrackingGeometryBuilder::packVolumeTripl
                                                                 m_replaceJointBoundaries);
    return tripleContainer;
 }
+
+
+std::vector<const Trk::Layer*> InDet::StagedTrackingGeometryBuilder::checkZoverlap(std::vector<const Trk::Layer*>& lays) const 
+{
+    // check disc layer overlaps in z, merge if appropriate
+    std::vector<const Trk::Layer*> mergedDiscLayers;
+    std::vector<const Trk::Layer*> toMerge;
+    double zlast = 0.; bool overlaps = false;
+    for (auto lay : lays) {
+        float zpos= lay->surfaceRepresentation().center().z();
+        float thick = 0.5*lay->thickness();
+        if (lay==lays.front()) toMerge.push_back(lay);
+        else { 
+          if ( zpos - thick<zlast) {
+            toMerge.push_back(lay);
+            overlaps = true;   
+          } else {
+            if ( toMerge.size()==1 ) mergedDiscLayers.push_back(toMerge[0]);
+            else if (toMerge.size()>1) {
+              const Trk::Layer* nd = mergeDiscLayers(toMerge);
+              if (nd) mergedDiscLayers.push_back(nd); 
+              else {
+                ATH_MSG_DEBUG("radial merge of rings failed, return the input layer set");
+                return lays;
+              }
+            }
+            toMerge.clear(); toMerge.push_back(lay);
+          }
+        }
+        zlast = zpos+thick;
+    }
+    if (toMerge.size()==1) mergedDiscLayers.push_back(toMerge[0]);
+    else if (toMerge.size()>1) {
+      const Trk::Layer* nd = mergeDiscLayers(toMerge);
+      if (nd) mergedDiscLayers.push_back(nd); 
+      else {
+        ATH_MSG_DEBUG("radial merge of rings failed, return the input layer set");
+        return lays;
+      }
+    }
+
+    if (overlaps) return mergedDiscLayers;
+
+    return lays;
+}
+
+const Trk::Layer* InDet::StagedTrackingGeometryBuilder::mergeDiscLayers (std::vector<const Trk::Layer*>& inputDiscs) const {
+ 
+  // on the input, disc layers overlapping in thickness : merge to a new DiscLayer
+  std::pair<float,float> zb(1.e5,-1.e5);
+  // order discs in radius
+  std::vector< std::pair<float,float> > rbounds; std::vector<size_t> discOrder;
+  size_t id=0;
+  for ( auto  lay : inputDiscs ) {
+    zb.first = fmin( zb.first, lay->surfaceRepresentation().center().z()-0.5*lay->thickness());
+    zb.second = fmax( zb.second, lay->surfaceRepresentation().center().z()+0.5*lay->thickness());
+    const Trk::DiscBounds* db = dynamic_cast<const Trk::DiscBounds*>(&(lay->surfaceRepresentation().bounds()));
+    if (!db) {
+      ATH_MSG_WARNING("attempt to merge non-disc layers, bailing out");
+      return 0;    
+    }
+    float r = db->rMin();
+    if (!rbounds.size() ||  r>rbounds.back().first) {
+      rbounds.push_back(std::pair<float,float> (r,db->rMax()));  
+      discOrder.push_back(id);
+    } else {
+      int ir=rbounds.size()-1;
+      while (ir>=0) {
+        if ( r>rbounds[ir].first ) break; 
+        ir--;
+      }
+      rbounds.insert(rbounds.begin()+ir+1,std::pair<float,float> (r,db->rMax()));  
+      discOrder.insert(discOrder.begin()+ir+1,id);           
+    }
+    id++;
+  }
+  
+  std::vector<float> rsteps; std::vector<const Trk::Surface*> surfs; 
+  std::vector<Trk::BinUtility*>* binUtils=new std::vector<Trk::BinUtility*>(); 
+  rsteps.push_back(rbounds[0].first);
+  for (unsigned int id=0; id<discOrder.size(); id++) {
+    unsigned int index=discOrder[id];
+    const Trk::SurfaceArray* surfArray = inputDiscs[index]->surfaceArray();    
+    if (surfArray) {
+      if (surfArray->binUtility()->binningValue()!=Trk::binPhi) {
+        ATH_MSG_WARNING("attempt to merge 2D disc arrays, bailing out");
+        return 0;
+      }
+      binUtils->push_back(surfArray->binUtility()->clone());
+      if (id+1<discOrder.size()) rsteps.push_back( 0.5*(rbounds[id].second+rbounds[id+1].first));
+      const std::vector<const Trk::Surface*> ringSurf =surfArray->arrayObjects();
+      surfs.insert(surfs.end(),ringSurf.begin(),ringSurf.end());
+    }  
+  }
+  rsteps.push_back(rbounds.back().second);
+
+  std::vector< std::pair< Trk::SharedObject<const Trk::Surface>, Amg::Vector3D >  > surfaces;
+  for ( auto  sf : surfs ) {
+    Trk::SharedObject<const Trk::Surface> sharedSurface(sf,Trk::do_not_delete<const Trk::Surface>);
+    std::pair< Trk::SharedObject<const Trk::Surface>, Amg::Vector3D >  surfaceOrder(sharedSurface, sf->center());
+    surfaces.push_back(surfaceOrder);
+  }
+
+  // create merged binned array
+  Trk::BinnedArray<Trk::Surface>* mergeBA = new Trk::BinnedArray1D1D<Trk::Surface>(surfaces,new Trk::BinUtility(rsteps,Trk::open,Trk::binR),binUtils);
+
+  // prepare the overlap descriptor       
+  std::vector<Trk::BinUtility*> clonedBinUtils = std::vector<Trk::BinUtility*>();
+  for (auto bu : *binUtils) clonedBinUtils.push_back(bu->clone());
+  Trk::OverlapDescriptor* olDescriptor = new InDet::DiscOverlapDescriptor(mergeBA,&clonedBinUtils,true);
+    
+  // position & bounds of the disc layer
+  double disc_thickness = std::fabs(zb.second-zb.first);
+  double disc_pos = (zb.first+zb.second)*0.5;
+
+  Amg::Transform3D transf;
+  transf = Amg::Translation3D(0.,0.,disc_pos);
+
+  // get the layer material from the first merged layer
+  const Trk::LayerMaterialProperties* disc_material = inputDiscs[0]->layerMaterialProperties()->clone();
+
+  // create disc layer
+  const Trk::DiscLayer* layer = new Trk::DiscLayer(transf,
+                                                   new Trk::DiscBounds(rsteps.front(),rsteps.back()),
+                                                   mergeBA,
+                                                   *disc_material,
+                                                   disc_thickness,
+                                                   olDescriptor); 
+  
+   // register the layer to the surfaces 
+   const std::vector<const Trk::Surface*>& layerSurfaces     = mergeBA->arrayObjects();
+   for (auto sf : layerSurfaces) {
+     const InDetDD::SiDetectorElement* detElement = dynamic_cast<const InDetDD::SiDetectorElement*>(sf->associatedDetectorElement());
+     const std::vector<const Trk::Surface*>& allSurfacesVector = detElement->surfaces();
+     for (auto subsf : allSurfacesVector)  
+       Trk::IGeometryBuilder::associateLayer(*layer, const_cast<Trk::Surface&>(*subsf));
+   }
+   
+   for (auto disc : inputDiscs)   delete disc;      // cleanup
+
+   return layer; 
+
+}
diff --git a/Tracking/TrkConfig/python/AtlasTrackingGeometrySvcConfig.py b/Tracking/TrkConfig/python/AtlasTrackingGeometrySvcConfig.py
index 3df2543aa4797152918d34f2bc7b6d23c01587fd..95a939792c7935042e66d0b4e718c16a12d61f28 100644
--- a/Tracking/TrkConfig/python/AtlasTrackingGeometrySvcConfig.py
+++ b/Tracking/TrkConfig/python/AtlasTrackingGeometrySvcConfig.py
@@ -6,6 +6,7 @@ Trk__TrackingGeometrySvc=CompFactory.Trk.TrackingGeometrySvc
 Trk__GeometryBuilder=CompFactory.Trk.GeometryBuilder
 from IOVDbSvc.IOVDbSvcConfig import addFoldersSplitOnline
 from SubDetectorEnvelopes.SubDetectorEnvelopesConfigNew import EnvelopeDefSvcCfg 
+from AthenaCommon.Constants import VERBOSE
 
 from GaudiKernel.GaudiHandles import PrivateToolHandleArray
 
@@ -178,6 +179,177 @@ def _getInDetTrackingGeometryBuilder(name, flags,result, envelopeDefinitionSvc,
                                                 # Probably they should just be dropped, but I leave this comment for the moment so reviewers can have a think as well.
                                                 
                                                 # Barrel Entry layers (in old config) etc were removed in 323990adfce581a635ae1809fd2ecc6a093a704c (!)
+
+
+def _getITkTrackingGeometryBuilder(name, flags,result, envelopeDefinitionSvc, namePrefix='', setLayerAssociation = True, buildTrtStrawLayers = False):
+  # Based on https://gitlab.cern.ch/atlas/athena/blob/master/InnerDetector/InDetDetDescr/InDetTrackingGeometry/python/ConfiguredInDetTrackingGeometryBuilder.py
+  # A lot of comments below are to help people understand differences from the above, in case we need to revert some simplifications I made
+  # i.e. this is far from complete, but is better than what was there before.
+  
+  # beampipe        
+  InDet__BeamPipeBuilder=CompFactory.InDet.BeamPipeBuilder
+  beamPipeBuilder = InDet__BeamPipeBuilder(name=namePrefix+'BeamPipeBuilder')
+  beamPipeBuilder.OutputLevel=VERBOSE
+  result.addPublicTool(beamPipeBuilder)
+  BeamPipeBinning = 2  
+  
+  Trk__LayerProvider=CompFactory.Trk.LayerProvider
+  beamPipeProvider = Trk__LayerProvider(name=namePrefix+'BeamPipeProvider')
+  beamPipeProvider.LayerBuilder = beamPipeBuilder
+  beamPipeProvider.OutputLevel=VERBOSE
+  result.addPublicTool(beamPipeProvider)  
+  
+  layerProviders = [beamPipeProvider]
+  binnings_barrel = [BeamPipeBinning]
+  binnings_endcap = [BeamPipeBinning]   
+  colors          = [2]
+  
+  # Pixel
+  if flags.Detector.GeometryITkPixel:
+    InDet__SiLayerBuilder=CompFactory.InDet.SiLayerBuilder
+    PixelLayerBuilderInner = InDet__SiLayerBuilder(name=namePrefix+'PixelLayerBuilderInner')
+    PixelLayerBuilderInner.PixelCase            = True
+    PixelLayerBuilderInner.Identification       = 'ITkPixelInner'
+    PixelLayerBuilderInner.SiDetManagerLocation = 'ITkPixel'
+    PixelLayerBuilderInner.LayerIndicesBarrel   = [0,1]
+    PixelLayerBuilderInner.LayerIndicesEndcap   = [0,1,2]
+    PixelLayerBuilderInner.UseRingLayout=True
+    # Pixel barrel specifications
+    PixelLayerBuilderInner.BarrelLayerBinsZ     = 1 #TODO Update with meaningful bins
+    PixelLayerBuilderInner.BarrelLayerBinsPhi   = 1 #TODO Update with meaningful bins
+    PixelLayerBuilderInner.EndcapLayerBinsR     = 1 #TODO Update with meaningful bins
+    PixelLayerBuilderInner.EndcapLayerBinsPhi   = 1 #TODO Update with meaningful bins
+    #PixelLayerBuilderInner.OutputLevel=VERBOSE
+    
+    # set the layer association
+    PixelLayerBuilderInner.SetLayerAssociation  = setLayerAssociation
+
+    # the binning type of the layers   a
+    PixelLayerBinning = 2
+    # add it to tool service
+    result.addPublicTool(PixelLayerBuilderInner)
+    
+    pixelProviderInner = Trk__LayerProvider(name=namePrefix+'PixelProviderInner')
+    pixelProviderInner.LayerBuilder = PixelLayerBuilderInner
+    #pixelProviderInner.OutputLevel=VERBOSE
+    result.addPublicTool(pixelProviderInner)
+    # put them to the caches
+    layerProviders  += [pixelProviderInner]
+    binnings_barrel += [ PixelLayerBinning ]
+    binnings_endcap += [ PixelLayerBinning ]
+    colors          += [ 3 ]
+    
+    PixelLayerBuilderOuter = InDet__SiLayerBuilder(name=namePrefix+'PixelLayerBuilderOuter')
+    PixelLayerBuilderOuter.PixelCase            = True
+    PixelLayerBuilderOuter.Identification       = 'ITkPixelOuter'
+    PixelLayerBuilderOuter.SiDetManagerLocation = 'ITkPixel'
+    PixelLayerBuilderOuter.LayerIndicesBarrel   = [2,3,4]
+    PixelLayerBuilderOuter.LayerIndicesEndcap   = [3,4,5,6,7,8]
+    PixelLayerBuilderOuter.UseRingLayout=True
+    # Pixel barrel specifications
+    PixelLayerBuilderOuter.BarrelLayerBinsZ     = 1 #TODO Update with meaningful bins
+    PixelLayerBuilderOuter.BarrelLayerBinsPhi   = 1 #TODO Update with meaningful bins
+    PixelLayerBuilderOuter.EndcapLayerBinsR     = 1 #TODO Update with meaningful bins
+    PixelLayerBuilderOuter.EndcapLayerBinsPhi   = 1 #TODO Update with meaningful bins
+    PixelLayerBuilderOuter.OutputLevel=VERBOSE
+    
+    # set the layer association
+    PixelLayerBuilderOuter.SetLayerAssociation  = setLayerAssociation
+
+    # the binning type of the layers   a
+    PixelLayerBinning = 2
+    # add it to tool service
+    result.addPublicTool(PixelLayerBuilderOuter)
+    
+    pixelProviderOuter = Trk__LayerProvider(name=namePrefix+'PixelProviderOuter')
+    pixelProviderOuter.LayerBuilder = PixelLayerBuilderOuter
+    pixelProviderOuter.OutputLevel=VERBOSE
+    result.addPublicTool(pixelProviderOuter)
+    # put them to the caches
+    layerProviders  += [pixelProviderOuter]
+    binnings_barrel += [ PixelLayerBinning ]
+    binnings_endcap += [ PixelLayerBinning ]
+    colors          += [ 3 ]
+
+  if flags.Detector.GeometryITkStrip:
+    # SCT building
+    InDet__SiLayerBuilder=CompFactory.InDet.SiLayerBuilder
+    SCT_LayerBuilder = InDet__SiLayerBuilder(name=namePrefix+'SCT_LayerBuilder')
+    SCT_LayerBuilder.PixelCase                       = False
+    SCT_LayerBuilder.Identification                  = 'ITkStrip'
+    SCT_LayerBuilder.SiDetManagerLocation            = 'ITkStrip'
+    SCT_LayerBuilder.AddMoreSurfaces                 = True
+    # additionall layers - handle with care !
+    SCT_LayerBuilder.BarrelLayerBinsZ                = 1 #TODO Update with meaningful bins
+    SCT_LayerBuilder.BarrelLayerBinsPhi              = 1 #TODO Update with meaningful bins
+    # SCT endcap specifications                          
+    SCT_LayerBuilder.EndcapLayerBinsR                = 1 #TODO Update with meaningful bins
+    SCT_LayerBuilder.EndcapLayerBinsPhi              = 1 #TODO Update with meaningful bins
+    # set the layer association                   
+    SCT_LayerBuilder.SetLayerAssociation             = setLayerAssociation        
+    # the binning type of the layer     
+    SCT_LayerBinning = 2
+    # SCT -> ToolSvc                             
+    result.addPublicTool(SCT_LayerBuilder)
+    
+    stripProvider = Trk__LayerProvider(name=namePrefix+'StripProvider')
+    stripProvider.LayerBuilder = SCT_LayerBuilder
+    result.addPublicTool(stripProvider)
+    
+    # put them to the caches
+    layerProviders  += [stripProvider]
+    binnings_barrel += [ SCT_LayerBinning ]
+    binnings_endcap += [ SCT_LayerBinning ]
+    colors          += [ 4 ]
+  
+  # helpers for the InDetTrackingGeometry Builder : layer array creator
+  Trk__LayerArrayCreator=CompFactory.Trk.LayerArrayCreator
+  InDetLayerArrayCreator = Trk__LayerArrayCreator(name = 'InDetLayerArrayCreator')
+  InDetLayerArrayCreator.EmptyLayerMode           = 2 # deletes empty material layers from arrays
+  # add to ToolSvc
+  result.addPublicTool(InDetLayerArrayCreator)  
+
+  # helpers for the InDetTrackingGeometry Builder : volume array creator
+  Trk__TrackingVolumeArrayCreator= CompFactory.Trk.TrackingVolumeArrayCreator
+  InDetTrackingVolumeArrayCreator = Trk__TrackingVolumeArrayCreator(name = 'InDetTrackingVolumeArrayCreator')
+  # add to ToolSvc
+  result.addPublicTool(InDetTrackingVolumeArrayCreator)  
+
+  # helpers for the InDetTrackingGeometry Builder : tracking volume helper for gluing
+  Trk__TrackingVolumeHelper=CompFactory.Trk.TrackingVolumeHelper
+  InDetTrackingVolumeHelper                             = Trk__TrackingVolumeHelper(name ='InDetTrackingVolumeHelper')
+  # the material bins - assume defaults
+  # add to ToolSvc
+  result.addPublicTool(InDetTrackingVolumeHelper)  
+  
+  # helpers for the InDetTrackingGeometry Builder : cylinder volume creator
+  Trk__CylinderVolumeCreator=CompFactory.Trk.CylinderVolumeCreator
+  InDetCylinderVolumeCreator = Trk__CylinderVolumeCreator(name = 'InDetCylinderVolumeCreator')
+  # give it the layer array creator
+  InDetCylinderVolumeCreator.LayerArrayCreator = InDetLayerArrayCreator
+  InDetCylinderVolumeCreator.TrackingVolumeArrayCreator = InDetTrackingVolumeArrayCreator
+  InDetCylinderVolumeCreator.TrackingVolumeHelper       = InDetTrackingVolumeHelper
+        
+  # specifiy the binning, passive layers, entry layers - assume defaults
+  # add to ToolSvc
+  result.addPublicTool(InDetCylinderVolumeCreator)  
+
+  # the tracking geometry builder
+  InDet__StagedTrackingGeometryBuilder=CompFactory.InDet.StagedTrackingGeometryBuilder
+  return InDet__StagedTrackingGeometryBuilder(namePrefix+name,
+                                              LayerBuilders     = layerProviders,
+                                              LayerBinningTypeCenter    = binnings_barrel,
+                                              LayerBinningTypeEndcap    = binnings_endcap,
+                                              ColorCodes                = colors,
+                                              EnvelopeDefinitionSvc     = envelopeDefinitionSvc,
+                                              TrackingVolumeCreator     = InDetCylinderVolumeCreator,
+                                              LayerArrayCreator         = InDetLayerArrayCreator,
+                                              CheckForRingLayout        = True,
+                                              MinimalRadialGapForVolumeSplit = 2.,
+                                              ReplaceAllJointBoundaries = True,
+                                              BuildBoundaryLayers=True,
+                                              ExitVolumeName='InDet::Containers::InnerDetector',
+                                              OutputLevel=VERBOSE)
   
 # Replaces https://gitlab.cern.ch/atlas/athena/blob/master/Calorimeter/CaloTrackingGeometry/python/ConfiguredCaloTrackingGeometryBuilder.py
 def _getCaloTrackingGeometryBuilder(name, flags,result, envelopeDefinitionSvc, trackingVolumeHelper, namePrefix=''):
@@ -226,6 +398,11 @@ def TrackingGeometrySvcCfg( flags , name = 'AtlasTrackingGeometrySvc', doMateria
       
       atlas_geometry_builder.InDetTrackingGeometryBuilder = inDetTrackingGeometryBuilder
       
+    elif flags.Detector.GeometryITk:
+      inDetTrackingGeometryBuilder = _getITkTrackingGeometryBuilder(name ='InDetTrackingGeometryBuilder', flags=flags, result=result,
+                                                                    envelopeDefinitionSvc=atlas_env_def_service)
+      atlas_geometry_builder.InDetTrackingGeometryBuilder = inDetTrackingGeometryBuilder
+      
     if flags.Detector.GeometryCalo:
       Trk__CylinderVolumeCreator=CompFactory.Trk.CylinderVolumeCreator
       caloVolumeCreator = Trk__CylinderVolumeCreator("CaloVolumeCreator")
@@ -281,7 +458,7 @@ def TrackingGeometrySvcCfg( flags , name = 'AtlasTrackingGeometrySvc', doMateria
        result.merge(_setupCondDB(flags, CoolDataBaseFolder))
     elif  flags.TrackingGeometry.MaterialSource == 'Input':
       Trk__InputLayerMaterialProvider=CompFactory.Trk.InputLayerMaterialProvider
-      atlasMaterialProvider = Trk__InputLayerMaterialProvider('AtlasMaterialProvider', LayerMaterialMapKey='')
+      atlasMaterialProvider = Trk__InputLayerMaterialProvider('AtlasMaterialProvider')
       atlas_geometry_processors += [ atlasMaterialProvider ]
       
     if doMaterialValidation:
diff --git a/Tracking/TrkDetDescr/TrkDetDescrInterfaces/TrkDetDescrInterfaces/IGeometryBuilder.h b/Tracking/TrkDetDescr/TrkDetDescrInterfaces/TrkDetDescrInterfaces/IGeometryBuilder.h
index 96fd035c35ae2afdcbb7450cf83ead43ecac3631..26edfcf24e3300fb21fe67277bddd2a984af28e3 100755
--- a/Tracking/TrkDetDescr/TrkDetDescrInterfaces/TrkDetDescrInterfaces/IGeometryBuilder.h
+++ b/Tracking/TrkDetDescr/TrkDetDescrInterfaces/TrkDetDescrInterfaces/IGeometryBuilder.h
@@ -1,7 +1,7 @@
-/*
-  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
-*/
-
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
 ///////////////////////////////////////////////////////////////////
 // IGeometryBuilder.hm (c) ATLAS Detector software
 ///////////////////////////////////////////////////////////////////
@@ -13,15 +13,17 @@
 #include "GaudiKernel/IAlgTool.h"
 // Trk - enum
 #include "TrkDetDescrUtils/GeometrySignature.h"
+#include "TrkSurfaces/Surface.h"
 // STL
 #include <vector>
 
-#include "CxxUtils/checker_macros.h"
-
+#include "CxxUtils/checker_macros.h"
+
 namespace Trk {
 
   class TrackingGeometry;
   class TrackingVolume;
+  class Layer;
 
   /** Interface ID for IGeometryBuilders*/  
   static const InterfaceID IID_IGeometryBuilder("IGeometryBuilder", 1, 0);
@@ -56,6 +58,13 @@ namespace Trk {
       /** The unique signature */
       virtual GeometrySignature geometrySignature() const = 0;
       
+      protected:
+      /** Protected method to register the Layer to the Surface */
+      void associateLayer(const Layer& lay, Surface& sf) const
+      {
+        sf.associateLayer(lay);
+      }
+      
   };
 
 } // end of namespace
diff --git a/Tracking/TrkExtrapolation/TrkExUnitTests/share/TrkExUnitTestITkConfig.py b/Tracking/TrkExtrapolation/TrkExUnitTests/share/TrkExUnitTestITkConfig.py
new file mode 100644
index 0000000000000000000000000000000000000000..4a7aebbfb484df2ddf1b9172d4a711b328dce737
--- /dev/null
+++ b/Tracking/TrkExtrapolation/TrkExUnitTests/share/TrkExUnitTestITkConfig.py
@@ -0,0 +1,147 @@
+# Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
+from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator 
+from AthenaConfiguration.ComponentFactory import CompFactory
+
+
+def PositionMomentumWriterCfg(configFlags, name="PositionMomentumWriter", **kwargs) :
+  result = ComponentAccumulator()
+
+  Trk__PositionMomentumWriter = CompFactory.Trk.PositionMomentumWriter
+  posMomWriter = Trk__PositionMomentumWriter(name, **kwargs)
+  result.addPublicTool(posMomWriter)
+  #result.setPrivateTools(posMomWriter)
+  return result, posMomWriter
+
+def ExtrapolationEngineTestCfg(configFlags, name = "ExtrapolationEngineTest", **kwargs ) :
+  result=ComponentAccumulator()  
+  
+  from AtlasGeoModel.GeoModelConfig import GeoModelCfg
+  gmsAcc = GeoModelCfg(configFlags)
+  result.merge(gmsAcc)
+
+  #from TrkConfig.AtlasExtrapolationEngineConfig import AtlasExtrapolationEngineCfg
+  #kwargs["ExtrapolationEngine"] = result.popToolsAndMerge(AtlasExtrapolationEngineCfg(configFlags, nameprefix=''))
+  
+  from TrkConfig.AtlasExtrapolationEngineConfig import AtlasExtrapolationEngineCfg
+  extrapAcc = AtlasExtrapolationEngineCfg(configFlags)
+  extrapolationEngine = extrapAcc.getPrimary()
+  result.merge(extrapAcc)
+  kwargs["ExtrapolationEngine"] = extrapolationEngine
+
+  posMomAcc, posMomWriter = PositionMomentumWriterCfg(configFlags)
+  result.merge(posMomAcc)
+  kwargs.setdefault('PositionMomentumWriter', posMomWriter)
+     
+  Trk__ExtrapolationEngineTest = CompFactory.Trk.ExtrapolationEngineTest
+  extrapolationTest = Trk__ExtrapolationEngineTest(name, **kwargs)
+  result.addEventAlgo(extrapolationTest)
+  
+  return result
+
+if __name__=="__main__":
+    from AthenaCommon.Configurable import Configurable
+    from AthenaCommon.Logging import log
+    from AthenaCommon.Constants import VERBOSE
+    from AthenaConfiguration.AllConfigFlags import ConfigFlags
+    
+    Configurable.configurableRun3Behavior = True
+    
+    ## Just enable ID for the moment.
+    ConfigFlags.Input.isMC             = True
+    
+    ConfigFlags.GeoModel.useLocalGeometry = True
+    detectors = [
+      "ITkPixel",
+      "ITkStrip"
+    ]
+    
+    from AthenaConfiguration.DetectorConfigFlags import setupDetectorsFromList
+    setupDetectorsFromList(ConfigFlags, detectors, toggle_geometry=True)
+
+    ConfigFlags.GeoModel.AtlasVersion = "ATLAS-P2-ITK-24-00-00"
+    ConfigFlags.IOVDb.GlobalTag = "OFLCOND-SIM-00-00-00"
+    ConfigFlags.GeoModel.Align.Dynamic = False
+    ConfigFlags.TrackingGeometry.MaterialSource = "Input"
+    ConfigFlags.Beam.Type =''
+    
+    ConfigFlags.Detector.GeometryCalo  = False
+    ConfigFlags.Detector.GeometryMuon  = False
+    
+    # This should run serially for the moment.
+    ConfigFlags.Concurrency.NumThreads = 1
+    ConfigFlags.Concurrency.NumConcurrentEvents = 1
+    
+    log.debug('Lock config flags now.')
+    ConfigFlags.lock()
+    
+    log.debug('dumping config flags now.')
+    ConfigFlags.dump()
+
+    from AthenaConfiguration.MainServicesConfig import MainServicesCfg
+    cfg=MainServicesCfg(ConfigFlags)
+    
+    from AthenaConfiguration.ComponentFactory import CompFactory
+    
+    from PixelGeoModelXml.ITkPixelGeoModelConfig import ITkPixelGeometryCfg
+    itkPixel = ITkPixelGeometryCfg(ConfigFlags)
+    cfg.merge(itkPixel)
+    
+    from StripGeoModelXml.ITkStripGeoModelConfig import ITkStripGeometryCfg
+    itkStrip = ITkStripGeometryCfg(ConfigFlags)
+    cfg.merge(itkStrip)
+    
+    from BeamPipeGeoModel.BeamPipeGMConfig import BeamPipeGeometryCfg
+    cfg.merge(BeamPipeGeometryCfg(ConfigFlags))
+    
+    from TrkConfig.AtlasTrackingGeometrySvcConfig import TrackingGeometrySvcCfg
+    cfg.merge(TrackingGeometrySvcCfg(ConfigFlags))
+    
+    histSvc = CompFactory.THistSvc(Output = ["val DATAFILE='ExtrapolationEngineTest.root' TYPE='ROOT' OPT='RECREATE'"])
+    histSvc.OutputLevel=VERBOSE
+    cfg.addService( histSvc )
+    
+    topoAcc=ExtrapolationEngineTestCfg(ConfigFlags,
+                                       NumberOfTestsPerEvent   = 100,
+                                       # parameters mode: 0 - neutral tracks, 1 - charged particles 
+                                       ParametersMode          = 1,
+                                       # do the full test backwards as well            
+                                       BackExtrapolation       = False,
+                                       # Smear the production vertex - standard primary vertex paramters
+                                       SmearOrigin             = False,
+                                       SimgaOriginD0           = 2./3.,
+                                       SimgaOriginZ0           = 50.,
+                                       SmearFlatOriginZ0       = False,
+                                       Z0Min                   = -150.,
+                                       Z0Max                   =  150.,
+                                       Z0Values                = [-150., 0., 150.],
+                                       SmearFlatOriginD0       = False,
+                                       D0Min                   = -2.0,
+                                       D0Max                   =  2.0,
+                                       # pT range for testing
+                                       PtMin                   = 1000,
+                                       PtMax                   = 1000,
+                                       # The test range in Eta                      
+                                       EtaMin                  =  -5.,
+                                       EtaMax                  =   5.,
+                                       #EtaMin                  =  -2.0
+                                       #EtaMax                  =   2.0
+                                       #PhiMin                  =  -0.5
+                                       #PhiMax                  =   0.5
+                                       # Configure how you wanna run                  
+                                       CollectSensitive        = True,
+                                       CollectPassive          = True,
+                                       CollectBoundary         = True,
+                                       CollectMaterial         = True,
+                                       UseHGTD                 = False,
+                                       # the path limit to test                        
+                                       PathLimit               = -1.,
+                                       )
+    cfg.merge(topoAcc)
+    
+    #vp1 = CompFactory.VP1Alg() 
+    #cfg.addEventAlgo(vp1)
+
+    cfg.run(1000)
+    f=open("ExtrapolationEngineTestConfig.pkl","wb")
+    cfg.store(f)
+    f.close()