diff --git a/GeoModelCore/GeoModelHelpers/GeoModelHelpers/GeoDeDuplicator.h b/GeoModelCore/GeoModelHelpers/GeoModelHelpers/GeoDeDuplicator.h
index 60a4cfd17b5920de8e7d86f2d349395f8afd72b4..547252a61df4fa8eda1063b0a51b05deff2fcf88 100644
--- a/GeoModelCore/GeoModelHelpers/GeoModelHelpers/GeoDeDuplicator.h
+++ b/GeoModelCore/GeoModelHelpers/GeoModelHelpers/GeoDeDuplicator.h
@@ -7,8 +7,12 @@
 #include "GeoModelKernel/GeoPhysVol.h"
 #include "GeoModelKernel/GeoShape.h"
 #include "GeoModelKernel/GeoTransform.h"
+#include "GeoModelKernel/GeoAlignableTransform.h"
+#include "GeoModelKernel/GeoPhysVol.h"
+#include "GeoModelKernel/GeoFullPhysVol.h"
 #include "GeoModelKernel/GeoSerialIdentifier.h"
 #include "GeoModelKernel/GeoNameTag.h"
+#include "GeoModelKernel/GeoIdentifierTag.h"
 
 #include "GeoModelHelpers/GeoLogVolSorter.h"
 #include "GeoModelHelpers/GeoPhysVolSorter.h"
@@ -16,7 +20,7 @@
 #include "GeoModelHelpers/TransformSorter.h"
 
 #include <set>
-#include <map>
+#include <unordered_map>
 #include <mutex>
 #include <thread>
 /***
@@ -75,6 +79,7 @@ class GeoDeDuplicator {
         using GeoTrfPtr =  GeoIntrusivePtr<GeoTransform>;
         using GeoPhysVolPtr = GeoIntrusivePtr<GeoPhysVol>;
         using GeoSerialIdPtr = GeoIntrusivePtr<GeoSerialIdentifier>;
+        using GeoIdPtr = GeoIntrusivePtr<GeoIdentifierTag>;
         using GeoNamePtr = GeoIntrusivePtr<GeoNameTag>;
 
         /** @brief Standard constructor */
@@ -104,6 +109,12 @@ class GeoDeDuplicator {
         GeoNamePtr nameTag(const std::string& tagName) const;
         /** @brief Returns a new GeoSerial Id  */
         GeoSerialIdPtr serialId(const int id) const;
+        /** @brief Returns a new GeoIdentifier tag */
+        GeoIdPtr geoId(const int id) const;
+
+        /** @brief Clones a physical volume. All components in the tree are 
+         *         parsed through the deduplication chain */
+        PVLink clone(PVConstLink vol) const;
 
         /** @brief Toggles whether shape deduplication shall be enabled */
         void setShapeDeDuplication(bool enable);
@@ -113,7 +124,6 @@ class GeoDeDuplicator {
         void setTransformDeDuplication(bool enable);
         /** @brief Toggles whether physVol node deduplication shall be enabled */
         void setPhysVolDeDuplication(bool enable);
-
         /** @brief Clears the shared Shape / Transform / SerialId & NameTag cache */
         static void clearSharedCaches();
     private:
@@ -125,8 +135,9 @@ class GeoDeDuplicator {
         using LogVolSet = std::set<GeoLogVolPtr, GeoLogVolSorter>;
         using TrfSet = std::set<GeoTrfPtr, GeoTrf::TransformSorter>;
         using ShapeSet = std::set<GeoShapePtr, GeoShapeSorter>;
-        using SerialIdMap = std::map<int, GeoSerialIdPtr>;
-        using NameTagMap = std::map<std::string, GeoNamePtr>;
+        using SerialIdMap = std::unordered_map<int, GeoSerialIdPtr>;
+        using GeoIdMap = std::unordered_map<int, GeoIdPtr>;
+        using NameTagMap = std::unordered_map<std::string, GeoNamePtr>;
 
         mutable PhysVolSet m_physVolStore{};
         mutable LogVolSet m_logVolStore{};
@@ -136,6 +147,7 @@ class GeoDeDuplicator {
         static ShapeSet s_shapeStore;
         static SerialIdMap s_serialIds;
         static NameTagMap s_nameTags;
+        static GeoIdMap s_geoIds;
 
         mutable std::mutex m_mutex{};
 };
diff --git a/GeoModelCore/GeoModelHelpers/src/GeoDeDuplicator.cxx b/GeoModelCore/GeoModelHelpers/src/GeoDeDuplicator.cxx
index 19432f217f40839aadecf876a62f2b4c8f0bce73..e4b88500916956e1915d7b6690815cb073b3bf7d 100644
--- a/GeoModelCore/GeoModelHelpers/src/GeoDeDuplicator.cxx
+++ b/GeoModelCore/GeoModelHelpers/src/GeoDeDuplicator.cxx
@@ -8,6 +8,7 @@ GeoDeDuplicator::TrfSet GeoDeDuplicator::s_trfStore{};
 GeoDeDuplicator::ShapeSet GeoDeDuplicator::s_shapeStore{};
 GeoDeDuplicator::SerialIdMap GeoDeDuplicator::s_serialIds{};
 GeoDeDuplicator::NameTagMap GeoDeDuplicator::s_nameTags{};
+GeoDeDuplicator::GeoIdMap GeoDeDuplicator::s_geoIds{};
 
 namespace {
     std::mutex s_mutex{};
@@ -31,6 +32,7 @@ void GeoDeDuplicator::clearSharedCaches() {
     s_shapeStore.clear();
     s_serialIds.clear();
     s_nameTags.clear();
+    s_geoIds.clear();
 }
 
 GeoDeDuplicator::GeoTrfPtr 
@@ -86,7 +88,8 @@ GeoDeDuplicator::GeoNamePtr GeoDeDuplicator::nameTag(const std::string& tagName)
     s_nameTags.insert(std::make_pair(tagName, newTag));
     return newTag;
 }
-GeoDeDuplicator::GeoSerialIdPtr GeoDeDuplicator::serialId(const int id) const {
+GeoDeDuplicator::GeoSerialIdPtr 
+    GeoDeDuplicator::serialId(const int id) const {
     std::lock_guard guard{s_mutex};
     SerialIdMap::const_iterator itr = s_serialIds.find(id);
     if (itr != s_serialIds.end()){
@@ -95,4 +98,59 @@ GeoDeDuplicator::GeoSerialIdPtr GeoDeDuplicator::serialId(const int id) const {
     GeoSerialIdPtr newId = make_intrusive<GeoSerialIdentifier>(id);
     s_serialIds.insert(std::make_pair(id, newId));
     return newId;
+}
+GeoDeDuplicator::GeoIdPtr 
+    GeoDeDuplicator::geoId(const int id) const {
+    std::lock_guard guard{s_mutex};
+    GeoIdMap::const_iterator itr = s_geoIds.find(id);
+    if (itr != s_geoIds.end()){
+        return itr->second;
+    }
+    GeoIdPtr newId = make_intrusive<GeoIdentifierTag>(id);
+    s_geoIds.insert(std::make_pair(id, newId));
+    return newId;
+}
+
+PVLink GeoDeDuplicator::clone(PVConstLink vol) const {
+    PVLink newVol{};
+    bool tryPhysVolDeDup{m_deDuplicatePhysVol};
+    GeoLogVolPtr logVol{const_cast<GeoLogVol*>(vol->getLogVol())};
+    if (dynamic_cast<const GeoPhysVol*>(vol.get())) {
+        newVol = make_intrusive<GeoPhysVol>(cacheVolume(logVol));
+    } else {
+        newVol = make_intrusive<GeoFullPhysVol>(cacheVolume(logVol));
+        tryPhysVolDeDup = false;
+    }
+    for(unsigned int chNode =0; chNode < newVol->getNChildNodes(); ++chNode) {
+        GeoIntrusivePtr<const GeoGraphNode>node{*newVol->getChildNode(chNode)};
+        /** transform nodes */
+        if (typeid(*node) == typeid(GeoAlignableTransform)) {
+            const auto geoTrf = dynamic_pointer_cast<const GeoAlignableTransform>(node);
+            newVol->add(make_intrusive<GeoAlignableTransform>(geoTrf->getDefTransform()));
+        } else if (typeid(*node) == typeid(GeoTransform)) {
+            const auto geoTrf = dynamic_pointer_cast<const GeoTransform>(node);
+            auto geoTrfNonConst = const_pointer_cast(geoTrf);
+            newVol->add(cacheTransform(geoTrfNonConst));
+        } 
+        /** physical volumes */
+        else if (auto physVol = dynamic_pointer_cast<const GeoVPhysVol>(node); physVol) {
+            newVol->add(clone(physVol));
+        } else if (auto geoId = dynamic_pointer_cast<const GeoIdentifierTag>(node); geoId) {
+            std::lock_guard guard{s_mutex};
+            newVol->add(s_geoIds.insert(std::make_pair(geoId->getIdentifier(), const_pointer_cast(geoId))).first->second);
+        } else if (auto serialId = dynamic_pointer_cast<const GeoSerialIdentifier>(node); serialId) {
+            std::lock_guard guard{s_mutex};
+            newVol->add(s_serialIds.insert(std::make_pair(serialId->getBaseId(), const_pointer_cast(serialId))).first->second);
+        } else if (auto nameTag = dynamic_pointer_cast<const GeoNameTag>(node); nameTag) {
+            std::lock_guard guard{s_mutex};
+            newVol->add(s_nameTags.insert(std::make_pair(nameTag->getName(), const_pointer_cast(nameTag))).first->second);
+        } else {
+            /// Just copy what's left
+            newVol->add(const_pointer_cast(node));
+        }
+    }
+    if (tryPhysVolDeDup){
+        newVol = cacheVolume(dynamic_pointer_cast<GeoPhysVol>(newVol));
+    }
+    return newVol;
 }
\ No newline at end of file
diff --git a/GeoModelTools/GeoModelXML/GeoModelXml/src/AssemblyProcessor.cxx b/GeoModelTools/GeoModelXML/GeoModelXml/src/AssemblyProcessor.cxx
index 8c1b225d09f691265bd1e1f9e0535cc1f5da5c7c..e893f7b0665c645c878b2c86fc944a3a82a42f93 100644
--- a/GeoModelTools/GeoModelXML/GeoModelXml/src/AssemblyProcessor.cxx
+++ b/GeoModelTools/GeoModelXML/GeoModelXml/src/AssemblyProcessor.cxx
@@ -50,7 +50,7 @@ void AssemblyProcessor::process(const DOMElement *element, GmxUtil &gmxUtil, Geo
         //
         //    Name
         AssemblyStore& store {m_map[name]};
-        physVolName = make_intrusive<GeoNameTag>(name); 
+        physVolName = nameTag(name); 
         store.name = physVolName;
     } else { // Already in the registry; use it.
         physVolName = entry->second.name;
@@ -58,7 +58,7 @@ void AssemblyProcessor::process(const DOMElement *element, GmxUtil &gmxUtil, Geo
     lv = gmxUtil.getAssemblyLV();
     toAdd.push_back(physVolName);
     gmxUtil.positionIndex.setCopyNo(m_map[name].id);
-    toAdd.push_back(make_intrusive<GeoIdentifierTag>(m_map[name].id++)); 
+    toAdd.push_back(geoId(m_map[name].id++)); 
 //
 //    Process the assembly's children
 //
diff --git a/GeoModelTools/GeoModelXML/GeoModelXml/src/LogvolProcessor.cxx b/GeoModelTools/GeoModelXML/GeoModelXml/src/LogvolProcessor.cxx
index 8638d8794b97c7fac71807f571d0f1882025c21e..11251f58fe6e20f468a76bdfef14c1bf30c0ba6d 100644
--- a/GeoModelTools/GeoModelXML/GeoModelXml/src/LogvolProcessor.cxx
+++ b/GeoModelTools/GeoModelXML/GeoModelXml/src/LogvolProcessor.cxx
@@ -115,7 +115,7 @@ void LogvolProcessor::process(const DOMElement *element, GmxUtil &gmxUtil, GeoNo
     //   
     LogVolStore* store{&m_map[name]};
     if(isNamed) {
-        nameTag_physVolName = make_intrusive<GeoNameTag>(name);
+        nameTag_physVolName = nameTag(name);
         store->name = nameTag_physVolName;
     }   
     //
@@ -228,15 +228,15 @@ void LogvolProcessor::process(const DOMElement *element, GmxUtil &gmxUtil, GeoNo
             newName.append("_");
             newName.append(std::to_string(index_i.second));
     }
-    nameTag_physChildVolName = make_intrusive<GeoNameTag>(newName);//Make sensitive always have a name, to extra Id information from
+    nameTag_physChildVolName = nameTag(newName);//Make sensitive always have a name, to extra Id information from
     toAdd.push_back(nameTag_physChildVolName);
     if(hasIdentifier) { //TODO: check if all "sensitive" volumes must have an identifier. If that's the case, then we can remove this "if" here
-        toAdd.push_back(make_intrusive<GeoIdentifierTag>(sensId));
+        toAdd.push_back(geoId(sensId));
     }
   }
   else {
       if(hasIdentifier) {
-          toAdd.push_back(make_intrusive<GeoIdentifierTag>(m_map[name].id)); // Normal copy number
+          toAdd.push_back(geoId(m_map[name].id)); // Normal copy number
           gmxUtil.positionIndex.setCopyNo(m_map[name].id++);
       }
   }