diff --git a/GeoModelTools/GeoModelXML/GeoModelXml/GeoModelXml/MDTProcessor.h b/GeoModelTools/GeoModelXML/GeoModelXml/GeoModelXml/MDTProcessor.h
new file mode 100644
index 0000000000000000000000000000000000000000..1c36635a169277aa90182a073bf522e0a6201bc4
--- /dev/null
+++ b/GeoModelTools/GeoModelXML/GeoModelXml/GeoModelXml/MDTProcessor.h
@@ -0,0 +1,34 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef GEO_MODEL_XML_MDT_PROCESSOR_H
+#define GEO_MODEL_XML_MDT_PROCESSOR_H
+#include <xercesc/util/XercesDefs.hpp>
+//
+//   Processor for mdt tags. This is a shortcut to create MDT mattresses at once, rather than going the full XML way
+//
+#include <string>
+#include <map>
+
+#include "GeoModelXml/ElementProcessor.h"
+class GmxUtil;
+class GeoNameTag;
+class GeoLogVol;
+class GeoPhysVol;
+
+class MDTProcessor: public ElementProcessor {
+public:
+    typedef struct {
+        GeoNameTag *name;
+        int id;
+        GeoLogVol *logVol;
+        bool alignable;
+    } MDTStore;
+    void process(const xercesc::DOMElement *element, GmxUtil &gmxUtil, GeoNodeList &toAdd);
+private:
+    std::map<std::string, MDTStore> m_map;
+    GeoPhysVol* BuildExampleVolume(std::string name);
+};
+
+#endif // MDT_PROCESSOR_H
diff --git a/GeoModelTools/GeoModelXML/GeoModelXml/src/LogvolProcessor.cxx b/GeoModelTools/GeoModelXML/GeoModelXml/src/LogvolProcessor.cxx
index 80fa1e59ada0a94743702b89fa9e01231e2ea9ef..c6a6736bcd58943748eb83314adce64fba913121 100644
--- a/GeoModelTools/GeoModelXML/GeoModelXml/src/LogvolProcessor.cxx
+++ b/GeoModelTools/GeoModelXML/GeoModelXml/src/LogvolProcessor.cxx
@@ -32,189 +32,189 @@ using namespace std;
 using namespace xercesc;
 
 void LogvolProcessor::process(const DOMElement *element, GmxUtil &gmxUtil, GeoNodeList &toAdd) {
-GeoLogVol *lv;
-GeoNameTag *physVolName;
+  GeoLogVol *lv;
+  GeoNameTag *physVolName;
 
-    gmxUtil.positionIndex.incrementLevel();
+  gmxUtil.positionIndex.incrementLevel();
 
-    XMLCh * name_tmp = XMLString::transcode("name");
-    char *name2release = XMLString::transcode(element->getAttribute(name_tmp));
-    string name(name2release);
-    XMLString::release(&name2release);
-    XMLString::release(&name_tmp);
+  XMLCh * name_tmp = XMLString::transcode("name");
+  char *name2release = XMLString::transcode(element->getAttribute(name_tmp));
+  string name(name2release);
+  XMLString::release(&name2release);
+  XMLString::release(&name_tmp);
 //
 //    Look for the logvol in the map; if not yet there, add it
 //
-    map<string, LogVolStore>::iterator entry;
-    if ((entry = m_map.find(name)) == m_map.end()) { // Not in registry; make a new item
+  map<string, LogVolStore>::iterator entry;
+  if ((entry = m_map.find(name)) == m_map.end()) { // Not in registry; make a new item
 //
 //    Name
 //
-        m_map[name] = LogVolStore();
-        LogVolStore *store = &m_map[name];
-        physVolName = new GeoNameTag(name);
-        store->name = physVolName;
-        store->id = 0;
+    m_map[name] = LogVolStore();
+    LogVolStore *store = &m_map[name];
+    physVolName = new GeoNameTag(name);
+    store->name = physVolName;
+    store->id = 0;
 //
 //    Get the shape.
 //
-        DOMDocument *doc = element->getOwnerDocument();
-        XMLCh * shape_tmp = XMLString::transcode("shape");
-        const XMLCh *shape = element->getAttribute(shape_tmp);
-        DOMElement *refShape = doc->getElementById(shape);
-        // Check it is a shape... its parent should be a <shapes>. DTD cannot do this for us.
-        DOMNode *parent = refShape->getParentNode();
-        if (XMLString::compareIString(parent->getNodeName(), XMLString::transcode("shapes")) != 0) {
+    DOMDocument *doc = element->getOwnerDocument();
+    XMLCh * shape_tmp = XMLString::transcode("shape");
+    const XMLCh *shape = element->getAttribute(shape_tmp);
+    DOMElement *refShape = doc->getElementById(shape);
+    // Check it is a shape... its parent should be a <shapes>. DTD cannot do this for us.
+    DOMNode *parent = refShape->getParentNode();
+    if (XMLString::compareIString(parent->getNodeName(), XMLString::transcode("shapes")) != 0) {
 
-            msglog << MSG::FATAL << "Processing logvol " << name <<
+      msglog << MSG::FATAL << "Processing logvol " << name <<
                     ". Error in gmx file. An IDREF for a logvol shape did not refer to a shape.\n" <<
                     "Shape ref was " << shape << "; exiting" << endmsg;
-            exit (1); // Need to improve...
-        }
+      exit (1); // Need to improve...
+    }
 //
 //    What sort of shape?
 //
-        name2release = XMLString::transcode(refShape->getNodeName());
-        string shapeType(name2release);
-        XMLString::release(&name2release);
-        XMLString::release(&shape_tmp);
+    name2release = XMLString::transcode(refShape->getNodeName());
+    string shapeType(name2release);
+    XMLString::release(&name2release);
+    XMLString::release(&shape_tmp);
 
-        GeoShape *s = (GeoShape *) gmxUtil.geoItemRegistry.find(shapeType)->process(refShape, gmxUtil);
+    GeoShape *s = (GeoShape *) gmxUtil.geoItemRegistry.find(shapeType)->process(refShape, gmxUtil);
 //
 //    Get the material
 //
-        XMLCh * material_tmp = XMLString::transcode("material");
-        const XMLCh *material = element->getAttribute(material_tmp);
-        DOMElement *refMaterial = doc->getElementById(material);
-        // Check it is a material... its parent should be a <materials>. DTD cannot do this for us.
-        parent = refMaterial->getParentNode();
-        XMLCh * materials_tmp = XMLString::transcode("materials");
-        if (XMLString::compareIString(parent->getNodeName(), materials_tmp) != 0) {
-            msglog << MSG::FATAL << "Processing logvol " << name <<
+    XMLCh * material_tmp = XMLString::transcode("material");
+    const XMLCh *material = element->getAttribute(material_tmp);
+    DOMElement *refMaterial = doc->getElementById(material);
+    // Check it is a material... its parent should be a <materials>. DTD cannot do this for us.
+    parent = refMaterial->getParentNode();
+    XMLCh * materials_tmp = XMLString::transcode("materials");
+    if (XMLString::compareIString(parent->getNodeName(), materials_tmp) != 0) {
+      msglog << MSG::FATAL << "Processing logvol " << name <<
                     ". Error in gmx file. An IDREF for a logvol material did not refer to a material.\n" <<
                     "Material ref was " << material << "; exiting" << endmsg;
-            exit (1); // Need to improve...
-        }
-	std::string nam_mat=XMLString::transcode(material);
+      exit (1); // Need to improve...
+    }
+	  std::string nam_mat=XMLString::transcode(material);
 
-	GeoMaterial* m=0;
+	  GeoMaterial* m=0;
 
-  if (gmxUtil.matManager)
-  {
-    if (!gmxUtil.matManager->isMaterialDefined(nam_mat))
+    if (gmxUtil.matManager)
     {
-      GeoMaterial* tempMat=(GeoMaterial *) gmxUtil.tagHandler.material.process(refMaterial, gmxUtil);
-      // we let GMX create the material and store it in the MM
+      if (!gmxUtil.matManager->isMaterialDefined(nam_mat))
+      {
+        GeoMaterial* tempMat=(GeoMaterial *) gmxUtil.tagHandler.material.process(refMaterial, gmxUtil);
+        // we let GMX create the material and store it in the MM
 
-      gmxUtil.matManager->addMaterial(tempMat);
+        gmxUtil.matManager->addMaterial(tempMat);
+      }
+      m=const_cast<GeoMaterial*>(gmxUtil.matManager->getMaterial(nam_mat));
     }
-    m=const_cast<GeoMaterial*>(gmxUtil.matManager->getMaterial(nam_mat));
-  }
-  else
-    m=(GeoMaterial *) gmxUtil.tagHandler.material.process(refMaterial, gmxUtil);
+    else
+      m=(GeoMaterial *) gmxUtil.tagHandler.material.process(refMaterial, gmxUtil);
 
 //
 //    Make the LogVol and add it to the map ready for next time
 //
-  lv = new GeoLogVol(name, s, m);
-  store->logVol = lv;
+    lv = new GeoLogVol(name, s, m);
+    store->logVol = lv;
 
-	XMLString::release(&material_tmp);
-	XMLString::release(&materials_tmp);
-}
-else { // Already in the registry; use it.
-  physVolName = entry->second.name;
-  lv = entry->second.logVol;
-}
+	  XMLString::release(&material_tmp);
+	  XMLString::release(&materials_tmp);
+  }
+  else { // Already in the registry; use it.
+    physVolName = entry->second.name;
+    lv = entry->second.logVol;
+  }
 
 
 //
 //    Process the logvol children (side effect: sets formulae for indexes before calculating them)
 //
-    GeoNodeList childrenAdd;
-    for (DOMNode *child = element->getFirstChild(); child != 0; child = child->getNextSibling()) {
-        if (child->getNodeType() == DOMNode::ELEMENT_NODE) {
-            DOMElement *el = dynamic_cast<DOMElement *> (child);
-            name2release = XMLString::transcode(el->getNodeName());
-            string name(name2release);
-            XMLString::release(&name2release);
-            gmxUtil.processorRegistry.find(name)->process(el, gmxUtil, childrenAdd);
-        }
+  GeoNodeList childrenAdd;
+  for (DOMNode *child = element->getFirstChild(); child != 0; child = child->getNextSibling()) {
+    if (child->getNodeType() == DOMNode::ELEMENT_NODE) {
+      DOMElement *el = dynamic_cast<DOMElement *> (child);
+      name2release = XMLString::transcode(el->getNodeName());
+      string name(name2release);
+      XMLString::release(&name2release);
+      gmxUtil.processorRegistry.find(name)->process(el, gmxUtil, childrenAdd);
     }
+  }
 //
 //   Make a list of things to be added
 //
-    toAdd.push_back(physVolName);
-    XMLCh * sensitive_tmp = XMLString::transcode("sensitive");
-    bool sensitive = element->hasAttribute(sensitive_tmp);
-    int sensId = 0;
-    //std::vector<int> extraSensIds;//extra Identfiers to be used in case we split this volume into multiple DetectorElements
-    map<string, int> index;
-    //map<string, int> updatedIndex;//extra indices to be used in case we split this volume
-    if (sensitive) {
-      gmxUtil.positionIndex.setCopyNo(m_map[name].id++);
-      gmxUtil.positionIndex.indices(index, gmxUtil.eval);
-      sensId = gmxUtil.gmxInterface()->sensorId(index);
-      //        toAdd.push_back(new GeoIdentifierTag(m_map[name].id)); // Normal copy number
-      toAdd.push_back(new GeoIdentifierTag(sensId));
-    }
-    else {
-      toAdd.push_back(new GeoIdentifierTag(m_map[name].id)); // Normal copy number
-      gmxUtil.positionIndex.setCopyNo(m_map[name].id++);
+  toAdd.push_back(physVolName);
+  XMLCh * sensitive_tmp = XMLString::transcode("sensitive");
+  bool sensitive = element->hasAttribute(sensitive_tmp);
+  int sensId = 0;
+  //std::vector<int> extraSensIds;//extra Identfiers to be used in case we split this volume into multiple DetectorElements
+  map<string, int> index;
+  //map<string, int> updatedIndex;//extra indices to be used in case we split this volume
+  if (sensitive) {
+    gmxUtil.positionIndex.setCopyNo(m_map[name].id++);
+    gmxUtil.positionIndex.indices(index, gmxUtil.eval);
+    sensId = gmxUtil.gmxInterface()->sensorId(index);
+    //        toAdd.push_back(new GeoIdentifierTag(m_map[name].id)); // Normal copy number
+    toAdd.push_back(new GeoIdentifierTag(sensId));
+  }
+  else {
+    toAdd.push_back(new GeoIdentifierTag(m_map[name].id)); // Normal copy number
+    gmxUtil.positionIndex.setCopyNo(m_map[name].id++);
+  }
+  XMLString::release(&sensitive_tmp);
+  //
+  //    Make a new PhysVol and add everything to it, then add it to the list of things for my caller to add
+  //
+  XMLCh * alignable_tmp = XMLString::transcode("alignable");
+  char *toRelease = XMLString::transcode(element->getAttribute(alignable_tmp));
+  string alignable(toRelease);
+  XMLString::release(&toRelease);
+  XMLString::release(&alignable_tmp);
+  if (sensitive || (alignable.compare(string("true")) == 0)) {
+    GeoFullPhysVol *pv = new GeoFullPhysVol(lv);
+    for (GeoNodeList::iterator node = childrenAdd.begin(); node != childrenAdd.end(); ++node) {
+	     pv->add(*node);
     }
-    XMLString::release(&sensitive_tmp);
+    toAdd.push_back(pv); // NB: the *PV is third item added, so reference as toAdd[2].
     //
-    //    Make a new PhysVol and add everything to it, then add it to the list of things for my caller to add
+    //    Add sensitive volumes to detector manager via GmxInterface
     //
-    XMLCh * alignable_tmp = XMLString::transcode("alignable");
-    char *toRelease = XMLString::transcode(element->getAttribute(alignable_tmp));
-    string alignable(toRelease);
-    XMLString::release(&toRelease);
-    XMLString::release(&alignable_tmp);
-    if (sensitive || (alignable.compare(string("true")) == 0)) {
-      GeoFullPhysVol *pv = new GeoFullPhysVol(lv);
-      for (GeoNodeList::iterator node = childrenAdd.begin(); node != childrenAdd.end(); ++node) {
-	pv->add(*node);
-      }
-      toAdd.push_back(pv); // NB: the *PV is third item added, so reference as toAdd[2].
-      //
-      //    Add sensitive volumes to detector manager via GmxInterface
-      //
-      if (sensitive) {
-	XMLCh * sensitive_tmp = XMLString::transcode("sensitive");
-	name2release = XMLString::transcode(element->getAttribute(sensitive_tmp));
-	string sensitiveName(name2release);
-	XMLString::release(&name2release);
-	XMLString::release(&sensitive_tmp);
-	//splitting sensors where we would like multiple DetectorElements per GeoVFullPhysVol (e.g.ITk Strips)
-	XMLCh * splitLevel_tmp = XMLString::transcode("splitLevel");
-	bool split = element->hasAttribute(splitLevel_tmp);
-	char* splitString;
-	int splitLevel = 1;
-	if (split) {
-	  splitString = XMLString::transcode(element->getAttribute(splitLevel_tmp));
-	  splitLevel = gmxUtil.evaluate(splitString);
-	  XMLString::release(&splitString);
-	  XMLString::release(&splitLevel_tmp);
-	  for(int i=0;i<splitLevel;i++){
-	    std::string field = "eta_module";//eventually specify in Xml the field to split in?
-	    std::pair<std::string,int> extraIndex(field,i);
-	    gmxUtil.gmxInterface()->addSplitSensor(sensitiveName, index,extraIndex, sensId, dynamic_cast<GeoVFullPhysVol *> (pv));
-	  }
-	}
-	else gmxUtil.gmxInterface()->addSensor(sensitiveName, index, sensId, dynamic_cast<GeoVFullPhysVol *> (pv));
-      }
+    if (sensitive) {
+      XMLCh * sensitive_tmp = XMLString::transcode("sensitive");
+      name2release = XMLString::transcode(element->getAttribute(sensitive_tmp));
+      string sensitiveName(name2release);
+      XMLString::release(&name2release);
+      XMLString::release(&sensitive_tmp);
+	    //splitting sensors where we would like multiple DetectorElements per GeoVFullPhysVol (e.g.ITk Strips)
+      XMLCh * splitLevel_tmp = XMLString::transcode("splitLevel");
+      bool split = element->hasAttribute(splitLevel_tmp);
+      char* splitString;
+	    int splitLevel = 1;
+	    if (split) {
+        splitString = XMLString::transcode(element->getAttribute(splitLevel_tmp));
+        splitLevel = gmxUtil.evaluate(splitString);
+        XMLString::release(&splitString);
+        XMLString::release(&splitLevel_tmp);
+        for(int i=0;i<splitLevel;i++){
+          std::string field = "eta_module";//eventually specify in Xml the field to split in?
+          std::pair<std::string,int> extraIndex(field,i);
+          gmxUtil.gmxInterface()->addSplitSensor(sensitiveName, index,extraIndex, sensId, dynamic_cast<GeoVFullPhysVol *> (pv));
+        }
+	    }
+	    else gmxUtil.gmxInterface()->addSensor(sensitiveName, index, sensId, dynamic_cast<GeoVFullPhysVol *> (pv));
     }
-    else {
-      GeoPhysVol *pv = new GeoPhysVol(lv);
-      for (GeoNodeList::iterator node = childrenAdd.begin(); node != childrenAdd.end(); ++node) {
-	pv->add(*node);
-      }
-      toAdd.push_back(pv);
+  }
+  else {
+    GeoPhysVol *pv = new GeoPhysVol(lv);
+    for (GeoNodeList::iterator node = childrenAdd.begin(); node != childrenAdd.end(); ++node) {
+      pv->add(*node);
     }
+    toAdd.push_back(pv);
+  }
 
-    gmxUtil.positionIndex.decrementLevel();
-    return;
+  gmxUtil.positionIndex.decrementLevel();
+  return;
 }
 
 void LogvolProcessor::zeroId(const xercesc::DOMElement *element) {
diff --git a/GeoModelTools/GeoModelXML/GeoModelXml/src/MDTProcessor.cxx b/GeoModelTools/GeoModelXML/GeoModelXml/src/MDTProcessor.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..77c7845c6504d4b6fbea62f236a28399b38c942a
--- /dev/null
+++ b/GeoModelTools/GeoModelXML/GeoModelXml/src/MDTProcessor.cxx
@@ -0,0 +1,110 @@
+/*
+  Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
+*/
+
+//
+//   Processor for MDT elements
+//
+//   Add name to list.
+//   Create a physvol using my logvol; add it to list.
+//
+//
+#include "GeoModelXml/MDTProcessor.h"
+#include "OutputDirector.h"
+
+#include <map>
+
+#include <xercesc/dom/DOM.hpp>
+#include "GeoModelKernel/GeoNameTag.h"
+#include "GeoModelKernel/GeoIdentifierTag.h"
+#include "GeoModelKernel/GeoLogVol.h"
+#include "GeoModelKernel/GeoPhysVol.h"
+#include "GeoModelKernel/GeoCons.h"
+#include "GeoModelKernel/GeoFullPhysVol.h"
+#include "GeoModelKernel/GeoVFullPhysVol.h"
+#include "GeoModelXml/GmxUtil.h"
+#include "GeoModelXml/GeoNodeList.h"
+#include "xercesc/util/XMLString.hpp"
+
+using namespace std;
+using namespace xercesc;
+
+void MDTProcessor::process(const DOMElement *element, GmxUtil &gmxUtil, GeoNodeList &toAdd) {
+GeoLogVol *lv;
+GeoPhysVol* pv;
+GeoNameTag *physVolName;
+
+    gmxUtil.positionIndex.incrementLevel();
+
+    XMLCh * name_tmp = XMLString::transcode("name");
+    char *name2release = XMLString::transcode(element->getAttribute(name_tmp));
+    string name(name2release);
+    XMLString::release(&name2release);
+    XMLString::release(&name_tmp);
+//
+//    Look for the logvol in the map; if not yet there, add it
+//
+    map<string, MDTStore>::iterator entry;
+    if ((entry = m_map.find(name)) == m_map.end()) { // Not in registry; make a new item
+//
+//    Name
+//
+        m_map[name] = MDTStore();
+        MDTStore *store = &m_map[name];
+        physVolName = new GeoNameTag(name);
+        store->name = physVolName;
+        store->id = 0;
+    }
+//
+//    Make the LogVol and add it to the map ready for next time
+//
+//  lv = new GeoLogVol(name, s, m);
+//  store->logVol = lv;
+
+else { // Already in the registry; use it.
+  physVolName = entry->second.name;
+  lv = entry->second.logVol;
+}
+
+      pv=BuildExampleVolume(name);
+
+      toAdd.push_back(pv);
+
+    gmxUtil.positionIndex.decrementLevel();
+    return;
+}
+
+#include "GeoModelKernel/Units.h"
+#define SYSTEM_OF_UNITS GeoModelKernelUnits
+
+GeoPhysVol* MDTProcessor::BuildExampleVolume(std::string name)
+{
+
+  // Define the units
+ #define gr   SYSTEM_OF_UNITS::gram
+ #define mole SYSTEM_OF_UNITS::mole
+ #define cm3  SYSTEM_OF_UNITS::cm3
+
+ // Define the chemical elements
+
+ static GeoElement*  el_Iron     = new GeoElement ("Iron"     ,"Fe" , 26.0 ,  55.847  *gr/mole);
+ static GeoElement*  el_Carbon   = new GeoElement ("Carbon"   ,"C"  ,  6.0 ,  12.0107 *gr/mole);
+
+ // Define the materials
+
+ // Steel: Iron + Carbon
+ GeoMaterial* mat_Steel  = new GeoMaterial("Steel", 7.9 *gr/cm3);
+ mat_Steel->add(el_Iron  , 0.98);
+ mat_Steel->add(el_Carbon, 0.02);
+ mat_Steel->lock();
+
+ // A cone
+GeoCons* cons = new GeoCons(10.*SYSTEM_OF_UNITS::cm, 20.*SYSTEM_OF_UNITS::cm, 30.*SYSTEM_OF_UNITS::cm,
+  40.*SYSTEM_OF_UNITS::cm, 25.*SYSTEM_OF_UNITS::cm, 0.*SYSTEM_OF_UNITS::degree, 270.*SYSTEM_OF_UNITS::degree);
+
+  GeoLogVol* consLog = new GeoLogVol(name, cons, mat_Steel);
+  GeoPhysVol* consPhys = new GeoPhysVol(consLog);
+
+  return consPhys;
+
+}