diff --git a/DDCore/include/DD4hep/Detector.h b/DDCore/include/DD4hep/Detector.h
index 16fffc5bc37cc13edfe63d2be8b9f19beeaeb1bf..95a57da98c7ef68879d09a300e42e9b73606c313 100644
--- a/DDCore/include/DD4hep/Detector.h
+++ b/DDCore/include/DD4hep/Detector.h
@@ -26,6 +26,7 @@
 #include "DD4hep/NamedObject.h"
 #include "DD4hep/Segmentations.h"
 #include "DD4hep/VolumeManager.h"
+#include "DD4hep/OpticalSurfaceManager.h"
 #include "DD4hep/ExtensionEntry.h"
 #include "DD4hep/BuildType.h"
 
@@ -124,6 +125,9 @@ namespace dd4hep {
     /// Return handle to the VolumeManager
     virtual VolumeManager volumeManager() const = 0;
 
+    /// Access the optical surface manager
+    virtual OpticalSurfaceManager surfaceManager()  const = 0;
+
     /// Accessor to the map of header entries
     virtual Header header() const = 0;
     /// Accessor to the header entry
@@ -269,7 +273,7 @@ namespace dd4hep {
     virtual Detector& addDetector(const Handle<NamedObject>& detector) = 0;
     /// Add a field component by named reference to the detector description
     virtual Detector& addField(const Handle<NamedObject>& field) = 0;
-
+    
     /// Deprecated call (use fromXML): Read compact geometry description or alignment file
     virtual void fromCompact(const std::string& fname, DetectorBuildType type = BUILD_DEFAULT) = 0;
     /// Read any geometry description or alignment file
diff --git a/DDCore/include/DD4hep/OpticalSurfaceManager.h b/DDCore/include/DD4hep/OpticalSurfaceManager.h
new file mode 100644
index 0000000000000000000000000000000000000000..ddb4c316feb3b996a1f4be99e1aee47d2a9ca88d
--- /dev/null
+++ b/DDCore/include/DD4hep/OpticalSurfaceManager.h
@@ -0,0 +1,72 @@
+//==========================================================================
+//  AIDA Detector description implementation 
+//--------------------------------------------------------------------------
+// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
+// All rights reserved.
+//
+// For the licensing terms see $DD4hepINSTALL/LICENSE.
+// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
+//
+// Author     : M.Frank
+//
+//==========================================================================
+#ifndef DD4HEP_DDCORE_OPTICALSURFACEMANAGER_H
+#define DD4HEP_DDCORE_OPTICALSURFACEMANAGER_H
+
+// Framework include files
+#include "DD4hep/OpticalSurfaces.h"
+
+// ROOT include files
+#include "TGeoManager.h"
+
+/// Namespace for the AIDA detector description toolkit
+namespace dd4hep {
+
+  /// Class to support the handling of optical surfaces.
+  /**
+   *
+   *   \author  M.Frank
+   *   \version 1.0
+   *   \ingroup DD4HEP_CORE
+   */
+  class OpticalSurfaceManager: public Handle<TGeoManager> {
+  public:
+    typedef TGeoManager Object;
+
+  public:
+    /// Default constructor
+    OpticalSurfaceManager() = default;
+    /// Copy constructor
+    OpticalSurfaceManager(const OpticalSurfaceManager& e) = default;
+    /// Constructor taking object pointer
+    OpticalSurfaceManager(TGeoManager* obj) : Handle<Object>(obj) { }
+    /// Constructor from same-type handle
+    OpticalSurfaceManager(const Handle<Object>& e) : Handle<Object>(e) { }
+    /// Constructor from arbitrary handle
+    template <typename Q>
+    OpticalSurfaceManager(const Handle<Q>& e) : Handle<Object>(e) { }
+    /// Initializing constructor.
+    OpticalSurfaceManager(Detector& description);
+    /// Assignment operator
+    OpticalSurfaceManager& operator=(const OpticalSurfaceManager& m) = default;
+
+    /// static accessor calling DD4hepOpticalSurfaceManagerPlugin if necessary
+    static OpticalSurfaceManager getOpticalSurfaceManager(Detector& description);
+
+#if ROOT_VERSION_CODE > ROOT_VERSION(6,16,0)
+    /// Access skin surface by its identifier
+    SkinSurface    getSkinSurface(DetElement de, const std::string& nam)  const;
+    /// Access border surface by its identifier
+    BorderSurface  getBorderSurface(DetElement de, const std::string& nam)  const;
+    /// Access optical surface data by its identifier
+    OpticalSurface getSurface(DetElement de, const std::string& nam)  const;
+    /// Add skin surface to manager
+    void addSkinSurface(SkinSurface surf)  const;
+    /// Add border surface to manager
+    void addBorderSurface(BorderSurface surf)  const;
+    /// Add optical surface data to manager
+    void addSurface(OpticalSurface surf)  const;
+#endif
+  };
+}         /* End namespace dd4hep                  */
+#endif    /* DD4HEP_DDCORE_OPTICALSURFACEMANAGER_H */
diff --git a/DDCore/include/DD4hep/OpticalSurfaces.h b/DDCore/include/DD4hep/OpticalSurfaces.h
new file mode 100644
index 0000000000000000000000000000000000000000..556fb2406d942fed649d977be5a58ca0829f4499
--- /dev/null
+++ b/DDCore/include/DD4hep/OpticalSurfaces.h
@@ -0,0 +1,143 @@
+//==========================================================================
+//  AIDA Detector description implementation 
+//--------------------------------------------------------------------------
+// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
+// All rights reserved.
+//
+// For the licensing terms see $DD4hepINSTALL/LICENSE.
+// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
+//
+// Author     : M.Frank
+//
+//==========================================================================
+#ifndef DD4HEP_DDCORE_OPTICALSURFACES_H
+#define DD4HEP_DDCORE_OPTICALSURFACES_H
+
+// Framework include files
+#include "DD4hep/Volumes.h"
+#include "DD4hep/DetElement.h"
+
+#if ROOT_VERSION_CODE > ROOT_VERSION(6,16,0)
+
+// ROOT include files
+#include "TGeoOpticalSurface.h"
+
+/// Namespace for the AIDA detector description toolkit
+namespace dd4hep {
+
+  /// Class to support the handling of optical surfaces.
+  /**
+   *
+   *   \author  M.Frank
+   *   \version 1.0
+   *   \ingroup DD4HEP_CORE
+   */
+  class OpticalSurface : public Handle<TGeoOpticalSurface> {
+  public:
+    typedef TGeoOpticalSurface     Object;
+    typedef Object Finish;
+    typedef Object Model;
+    typedef Object Type;
+    typedef Object::ESurfaceModel  EModel;
+    typedef Object::ESurfaceFinish EFinish;
+    typedef Object::ESurfaceType   EType;
+    
+  public:
+    /// Default constructor
+    OpticalSurface() = default;
+    /// Copy constructor
+    OpticalSurface(const OpticalSurface& e) = default;
+    /// Constructor taking object pointer
+    OpticalSurface(Object* obj) : Handle<Object>(obj) { }
+    /// Constructor from same-type handle
+    OpticalSurface(const Handle<Object>& e) : Handle<Object>(e) {  }
+    /// Constructor from arbitrary handle
+    template <typename Q>
+    OpticalSurface(const Handle<Q>& e) : Handle<Object>(e) { }
+    /// Initializing constructor.
+    OpticalSurface(Detector& description,
+                   const std::string& name,
+                   EModel  model    = Model::kMglisur,
+                   EFinish finish   = Finish::kFpolished,
+                   EType   type     = Type::kTdielectric_dielectric,
+                   double  value    = 1.0);
+
+    /// Assignment operator
+    OpticalSurface& operator=(const OpticalSurface& m) = default;
+  };
+
+  /// Class to support the handling of optical surfaces.
+  /**
+   *
+   *   \author  M.Frank
+   *   \version 1.0
+   *   \ingroup DD4HEP_CORE
+   */
+  class SkinSurface : public Handle<TGeoSkinSurface> {
+  public:
+    typedef TGeoSkinSurface Object;
+
+  public:
+    /// Default constructor
+    SkinSurface() = default;
+    /// Copy constructor
+    SkinSurface(const SkinSurface& e) = default;
+    /// Constructor taking object pointer
+    SkinSurface(Object* obj) : Handle<Object>(obj) { }
+    /// Constructor from same-type handle
+    SkinSurface(const Handle<Object>& e) : Handle<Object>(e) {  }
+    /// Constructor from arbitrary handle
+    template <typename Q>
+    SkinSurface(const Handle<Q>& e) : Handle<Object>(e) { }
+    /// Initializing constructor.
+    SkinSurface(DetElement de, const std::string& nam, OpticalSurface surf, Volume vol);
+
+    /// Assignment operator
+    SkinSurface& operator=(const SkinSurface& m) = default;
+
+    /// Access surface data
+    OpticalSurface surface()  const;
+    /// Access the node of the skin surface
+    Volume  volume()   const;
+  };
+
+  /// Class to support the handling of optical surfaces.
+  /**
+   *
+   *   \author  M.Frank
+   *   \version 1.0
+   *   \ingroup DD4HEP_CORE
+   */
+  class BorderSurface : public Handle<TGeoBorderSurface> {
+  public:
+    typedef TGeoBorderSurface Object;
+
+  public:
+    /// Default constructor
+    BorderSurface() = default;
+    /// Copy constructor
+    BorderSurface(const BorderSurface& e) = default;
+    /// Constructor taking object pointer
+    BorderSurface(Object* obj) : Handle<Object>(obj) { }
+    /// Constructor from same-type handle
+    BorderSurface(const Handle<Object>& e) : Handle<Object>(e) {  }
+    /// Constructor from arbitrary handle
+    template <typename Q>
+    BorderSurface(const Handle<Q>& e) : Handle<Object>(e) { }
+    /// Initializing constructor: Creates the object and registers it to the manager
+    BorderSurface(DetElement de, const std::string& nam, OpticalSurface surf, PlacedVolume left, PlacedVolume right);
+
+    /// Assignment operator
+    BorderSurface& operator=(const BorderSurface& m) = default;
+    /// Access surface data
+    OpticalSurface surface()  const;
+    /// Access the left node of the border surface
+    PlacedVolume   left()   const;
+    /// Access the right node of the border surface
+    PlacedVolume   right()  const;
+  };
+
+
+}         /* End namespace dd4hep              */
+#endif    /* ROOT_VERSION                      */
+#endif    /* DD4HEP_DDCORE_OPTICALSURFACES_H   */
diff --git a/DDCore/include/DD4hep/PropertyTable.h b/DDCore/include/DD4hep/PropertyTable.h
new file mode 100644
index 0000000000000000000000000000000000000000..06f00209c5ca0bcf29af149ea5ca51c3d3923aa7
--- /dev/null
+++ b/DDCore/include/DD4hep/PropertyTable.h
@@ -0,0 +1,64 @@
+//==========================================================================
+//  AIDA Detector description implementation 
+//--------------------------------------------------------------------------
+// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
+// All rights reserved.
+//
+// For the licensing terms see $DD4hepINSTALL/LICENSE.
+// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
+//
+// Author     : M.Frank
+//
+//==========================================================================
+#ifndef DD4HEP_DDCORE_PROPERTYTABLE_H
+#define DD4HEP_DDCORE_PROPERTYTABLE_H
+
+#include "RVersion.h"
+#if ROOT_VERSION_CODE > ROOT_VERSION(6,16,0)
+
+// Framework include files
+#include "DD4hep/Handle.h"
+
+// ROOT include files
+#include "TGDMLMatrix.h"
+
+/// Namespace for the AIDA detector description toolkit
+namespace dd4hep {
+
+  /// Class to support the handling of optical surfaces.
+  /**
+   *
+   *   \author  M.Frank
+   *   \version 1.0
+   *   \ingroup DD4HEP_CORE
+   */
+  class PropertyTable : public Handle<TGDMLMatrix> {
+  public:
+    typedef TGDMLMatrix Object;
+    
+  public:
+    /// Default constructor
+    PropertyTable() = default;
+    /// Copy constructor
+    PropertyTable(const PropertyTable& e) = default;
+    /// Constructor from same-type handle
+    PropertyTable(const Handle<Object>& e) : Handle<Object>(e) {  }
+    /// Constructor from arbitray handle
+    template <typename Q>
+    PropertyTable(const Handle<Q>& e) : Handle<Object>(e) { }
+    /// Initializing constructor using object pointer
+    PropertyTable(Object* obj) : Handle<Object>(obj) { }
+    /// Initializing constructor.
+    PropertyTable(Detector& description,
+                  const std::string& table_name,
+                  const std::string& property_name,
+                  size_t             num_rows,
+                  size_t             num_cols);
+
+    /// Assignment operator
+    PropertyTable& operator=(const PropertyTable& m) = default;
+  };
+
+}         /* End namespace dd4hep              */
+#endif    /* ROOT_VERSION                      */
+#endif    /* DD4HEP_DDCORE_PROPERTYTABLE_H     */
diff --git a/DDCore/include/DD4hep/Volumes.h b/DDCore/include/DD4hep/Volumes.h
index b5cd215235a7bd54d234c15d2a0064ed770394a9..9606331e2e60318f0b5d89581fb47f0dee0477a2 100644
--- a/DDCore/include/DD4hep/Volumes.h
+++ b/DDCore/include/DD4hep/Volumes.h
@@ -167,7 +167,7 @@ namespace dd4hep {
     PlacedVolume(const PlacedVolume& e) = default;
     /// Copy assignment from other handle type
     template <typename T> PlacedVolume(const Handle<T>& e) : Handle<TGeoNode>(e) {  }
-    /// Constructor to be used when reading the already parsed DOM tree
+    /// Constructor taking implementation object pointer
     PlacedVolume(const TGeoNode* e) : Handle<TGeoNode>(e) {  }
     /// Assignment operator (must match copy constructor)
     PlacedVolume& operator=(const PlacedVolume& v)  = default;
diff --git a/DDCore/include/XML/UnicodeValues.h b/DDCore/include/XML/UnicodeValues.h
index b6affce1eb9eb3d1544a6e85869804b68f0b7aec..d6d022711b583a03b9e820d6ddf4ebe64c360226 100644
--- a/DDCore/include/XML/UnicodeValues.h
+++ b/DDCore/include/XML/UnicodeValues.h
@@ -56,6 +56,7 @@ UNICODE (barrel);
 UNICODE (barrel_envelope);
 UNICODE (beampipe);
 UNICODE (beta);
+UNICODE (bordersurface);
 UNICODE (box);
 UNICODE (build);
 
@@ -74,6 +75,7 @@ UNICODE (close_geometry);
 UNICODE (cm);
 UNICODE (coefficient);
 UNICODE (coefficients);
+UNICODE (coldim);
 UNICODE (color);
 UNICODE (collection);
 UNICODE (collections);
@@ -150,6 +152,7 @@ UNICODE (fields);
 UNICODE (field_name);
 UNICODE (file);
 UNICODE (files);
+UNICODE (finish);
 UNICODE (first);
 UNICODE (firstposition);
 UNICODE (firstrotation);
@@ -262,9 +265,12 @@ UNICODE (M);
 UNICODE (material);
 UNICODE (materialref);
 UNICODE (materials);
+UNICODE (matrices);
+UNICODE (matrix);
 UNICODE (member);
 UNICODE (MeV);
 UNICODE (mm);
+UNICODE (model);
 UNICODE (module);
 UNICODE (modules);
 UNICODE (module_component);
@@ -300,6 +306,7 @@ UNICODE (O);
 UNICODE (offset);
 UNICODE (open);
 UNICODE (operation);
+UNICODE (opticalsurface);
 UNICODE (overlap);
 UNICODE (outer);
 UNICODE (outer_field);
@@ -352,6 +359,7 @@ UNICODE (positionRPhiZ);
 UNICODE (pressure);
 UNICODE (projective_cylinder);
 UNICODE (projective_zplane);
+UNICODE (property);
 UNICODE (properties);
 UNICODE (psi);
 
@@ -424,6 +432,7 @@ UNICODE (showDaughters);
 UNICODE (size);
 UNICODE (signed);
 UNICODE (skew);
+UNICODE (skinsurface);
 UNICODE (slice);
 UNICODE (slices);
 UNICODE (solid);
@@ -452,6 +461,8 @@ UNICODE (strength);
 UNICODE (structure);
 UNICODE (subtraction);
 UNICODE (support);
+UNICODE (surface);
+UNICODE (surfaces);
 UNICODE (system);
 UNICODE (symbol);
 
diff --git a/DDCore/include/XML/XMLElements.h b/DDCore/include/XML/XMLElements.h
index c88a987dcfe0eaf94cd056a9b7086cb673e358b6..e8ed1587cb8630b9e6d1f8754837f04d5217a930 100644
--- a/DDCore/include/XML/XMLElements.h
+++ b/DDCore/include/XML/XMLElements.h
@@ -816,6 +816,10 @@ namespace dd4hep {
         return m_element.hasAttr(name);
       }
       /// Access attribute with implicit return type conversion
+      template <class T> T attr(const XmlAttr* att) const {
+        return m_element.attr<T>(att);
+      }
+      /// Access attribute with implicit return type conversion
       template <class T> T attr(const XmlChar* tag_value) const {
         return m_element.attr<T>(tag_value);
       }
diff --git a/DDCore/src/DetectorImp.h b/DDCore/src/DetectorImp.h
index 0a7a8f144e2c691f424d8d23443fe10f8c33645e..9d2dd46723de6355e5591f9126b25f4237549dfe 100644
--- a/DDCore/src/DetectorImp.h
+++ b/DDCore/src/DetectorImp.h
@@ -177,6 +177,11 @@ namespace dd4hep {
     virtual VolumeManager volumeManager() const  override {
       return m_volManager;
     }
+    /// Access the optical surface manager
+    virtual OpticalSurfaceManager surfaceManager()  const  override  {
+      return OpticalSurfaceManager(m_manager);
+    }
+
     /// Return handle to the combined electromagentic field description.
     virtual OverlayedField field() const  override {
       return m_field;
diff --git a/DDCore/src/OpticalSurfaceManager.cpp b/DDCore/src/OpticalSurfaceManager.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3473c16456a88e9c5f82d0aa29c59a37fce6746a
--- /dev/null
+++ b/DDCore/src/OpticalSurfaceManager.cpp
@@ -0,0 +1,83 @@
+//==========================================================================
+//  AIDA Detector description implementation 
+//--------------------------------------------------------------------------
+// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
+// All rights reserved.
+//
+// For the licensing terms see $DD4hepINSTALL/LICENSE.
+// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
+//
+// Author     : M.Frank
+//
+//==========================================================================
+
+// Framework include files
+#include "DD4hep/OpticalSurfaceManager.h"
+#include "DD4hep/Detector.h"
+#include "DD4hep/Printout.h"
+#include "DD4hep/detail/Handle.inl"
+
+// C/C++ includes
+#include <sstream>
+#include <iomanip>
+
+DD4HEP_INSTANTIATE_HANDLE(TGeoManager);
+
+using namespace std;
+using namespace dd4hep;
+
+/// static accessor calling DD4hepOpticalSurfaceManagerPlugin if necessary
+OpticalSurfaceManager OpticalSurfaceManager::getOpticalSurfaceManager(Detector& description)  {
+  return description.surfaceManager();
+}
+
+#if ROOT_VERSION_CODE > ROOT_VERSION(6,16,0)
+
+/// Access skin surface by its identifier
+SkinSurface  OpticalSurfaceManager::getSkinSurface(DetElement de, const string& nam)  const   {
+  if ( de.isValid() )  {
+    string n = de.path() + '#' + nam;
+    return access()->GetSkinSurface(n.c_str());
+  }
+  except("SkinSurface",
+         "++ Cannot access SkinSurface %s without valid detector element!",nam.c_str());
+  return SkinSurface();
+}
+
+/// Access border surface by its identifier
+BorderSurface  OpticalSurfaceManager::getBorderSurface(DetElement de, const string& nam)  const   {
+  if ( de.isValid() )  {
+    string n = de.path() + '#' + nam;
+    return access()->GetBorderSurface(n.c_str());
+  }
+  except("BorderSurface",
+         "++ Cannot access BorderSurface %s without valid detector element!",nam.c_str());
+  return BorderSurface();
+}
+
+/// Access optical surface data by its identifier
+OpticalSurface OpticalSurfaceManager::getSurface(DetElement de, const string& nam)  const   {
+  if ( de.isValid() )  {
+    string n = de.path() + '#' + nam;
+    return access()->GetOpticalSurface(n.c_str());
+  }
+  except("OpticalSurface",
+         "++ Cannot access OpticalSurface %s without valid detector element!",nam.c_str());
+  return OpticalSurface();
+}
+
+/// Add skin surface to manager
+void OpticalSurfaceManager::addSkinSurface(SkinSurface surf)  const   {
+  access()->AddSkinSurface(surf.ptr());
+}
+
+/// Add border surface to manager
+void OpticalSurfaceManager::addBorderSurface(BorderSurface surf)  const   {
+  access()->AddBorderSurface(surf.ptr());
+}
+
+/// Add optical surface data to manager
+void OpticalSurfaceManager::addSurface(OpticalSurface surf)  const   {
+  access()->AddOpticalSurface(surf.ptr());
+}
+#endif
diff --git a/DDCore/src/OpticalSurfaces.cpp b/DDCore/src/OpticalSurfaces.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3d6dfa9adb871a37d5d485c467e218af46dc4716
--- /dev/null
+++ b/DDCore/src/OpticalSurfaces.cpp
@@ -0,0 +1,112 @@
+//==========================================================================
+//  AIDA Detector description implementation 
+//--------------------------------------------------------------------------
+// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
+// All rights reserved.
+//
+// For the licensing terms see $DD4hepINSTALL/LICENSE.
+// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
+//
+// Author     : M.Frank
+//
+//==========================================================================
+
+// Framework include files
+#include "DD4hep/OpticalSurfaces.h"
+#include "DD4hep/NamedObject.h"
+#include "DD4hep/Detector.h"
+#include "DD4hep/Printout.h"
+#include "DD4hep/World.h"
+
+#include "DD4hep/detail/Handle.inl"
+
+// C/C++ includes
+#include <sstream>
+#include <iomanip>
+
+using namespace std;
+using namespace dd4hep;
+
+#if ROOT_VERSION_CODE > ROOT_VERSION(6,16,0)
+
+DD4HEP_INSTANTIATE_HANDLE(TGeoSkinSurface);
+DD4HEP_INSTANTIATE_HANDLE(TGeoBorderSurface);
+DD4HEP_INSTANTIATE_HANDLE(TGeoOpticalSurface);
+
+/// Initializing constructor.
+OpticalSurface::OpticalSurface(Detector& description,
+                               const string& nam,
+                               EModel  model,
+                               EFinish finish,
+                               EType   type,
+                               double  value)
+{
+  unique_ptr<Object> s(new Object(nam.c_str(), model, finish, type, value));
+  description.manager().AddOpticalSurface(m_element=s.release());
+}
+
+/// Initializing constructor: Creates the object and registers it to the manager
+SkinSurface::SkinSurface(DetElement de, const string& nam, OpticalSurface surf, Volume vol)
+{
+  if ( de.isValid() )  {
+    string n = de.path() + '#' + nam;
+    if ( vol.isValid() )  {
+      if ( surf.isValid() )   {
+        World wrld = de.world();
+        unique_ptr<Object> s(new Object(n.c_str(), surf->GetName(), surf.ptr(), vol.ptr()));
+        wrld.detectorDescription().manager().AddSkinSurface(m_element=s.release());
+        return;
+      }
+      except("SkinSurface","++ Cannot create SkinSurface %s without valid optical surface!",n.c_str());
+    }
+    except("SkinSurface","++ Cannot create SkinSurface %s without valid volume!",n.c_str());
+  }
+  except("SkinSurface",
+         "++ Cannot create SkinSurface %s which is not connected to a valid detector element!",nam.c_str());
+}
+
+/// Access surface data
+OpticalSurface SkinSurface::surface()  const    {
+  return (TGeoOpticalSurface*)(access()->GetSurface());
+}
+
+/// Access the node of the skin surface
+Volume   SkinSurface::volume()   const    {
+  return access()->GetVolume();
+}
+
+/// Initializing constructor: Creates the object and registers it to the manager
+BorderSurface::BorderSurface(DetElement de, const string& nam, OpticalSurface surf, PlacedVolume lft, PlacedVolume rht)
+{
+  if ( de.isValid() )  {
+    string n = de.path() + '#' + nam;
+    if ( lft.isValid() && rht.isValid() )  {
+      if ( surf.isValid() )   {
+        World wrld = de.world();
+        unique_ptr<Object> s(new Object(n.c_str(), surf->GetName(), surf.ptr(), lft.ptr(), rht.ptr()));
+        wrld.detectorDescription().manager().AddBorderSurface(m_element=s.release());
+        return;
+      }
+      except("BorderSurface","++ Cannot create BorderSurface %s without valid optical surface!",n.c_str());
+    }
+    except("BorderSurface","++ Cannot create BorderSurface %s without valid placements!",n.c_str());
+  }
+  except("BorderSurface",
+         "++ Cannot create BorderSurface %s which is not connected to a valid detector element!",nam.c_str());
+}
+
+/// Access surface data
+OpticalSurface BorderSurface::surface()  const    {
+  return (TGeoOpticalSurface*)(access()->GetSurface());
+}
+
+/// Access the left node of the border surface
+PlacedVolume   BorderSurface::left()   const    {
+  return (TGeoNode*)access()->GetNode1();
+}
+
+/// Access the right node of the border surface
+PlacedVolume   BorderSurface::right()  const    {
+  return access()->GetNode2();
+}
+#endif
diff --git a/DDCore/src/PropertyTable.cpp b/DDCore/src/PropertyTable.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6bc9fecaab6912103857198e5272d8cb399032ca
--- /dev/null
+++ b/DDCore/src/PropertyTable.cpp
@@ -0,0 +1,44 @@
+//==========================================================================
+//  AIDA Detector description implementation 
+//--------------------------------------------------------------------------
+// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
+// All rights reserved.
+//
+// For the licensing terms see $DD4hepINSTALL/LICENSE.
+// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
+//
+// Author     : M.Frank
+//
+//==========================================================================
+
+// Framework include files
+#include "DD4hep/PropertyTable.h"
+#include "DD4hep/NamedObject.h"
+#include "DD4hep/Detector.h"
+#include "DD4hep/Printout.h"
+
+#include "DD4hep/detail/Handle.inl"
+
+// C/C++ includes
+#include <sstream>
+#include <iomanip>
+
+using namespace std;
+using namespace dd4hep;
+
+#if ROOT_VERSION_CODE > ROOT_VERSION(6,16,0)
+
+DD4HEP_INSTANTIATE_HANDLE(TGDMLMatrix);
+
+/// Initializing constructor.
+PropertyTable::PropertyTable(Detector&     description,
+                             const string& table_name,
+                             const string& property_name,
+                             size_t        num_rows,
+                             size_t        num_cols)
+{
+  unique_ptr<Object> s(new Object(table_name.c_str(), num_rows, num_cols));
+  s->SetTitle(property_name.c_str());
+  description.manager().AddGDMLMatrix(m_element=s.release());
+}
+#endif
diff --git a/DDCore/src/plugins/Compact2Objects.cpp b/DDCore/src/plugins/Compact2Objects.cpp
index 0f914784abf532686aa9aa779fff47d6189e624f..037d7a54a2f00ec028f27c936f4ad6cd233dcbf4 100644
--- a/DDCore/src/plugins/Compact2Objects.cpp
+++ b/DDCore/src/plugins/Compact2Objects.cpp
@@ -15,6 +15,9 @@
 #include "DD4hep/DetFactoryHelper.h"
 #include "DD4hep/DetectorTools.h"
 #include "DD4hep/MatrixHelpers.h"
+#include "DD4hep/PropertyTable.h"
+#include "DD4hep/OpticalSurfaces.h"
+#include "DD4hep/OpticalSurfaceManager.h"
 #include "DD4hep/IDDescriptor.h"
 #include "DD4hep/DD4hepUnits.h"
 #include "DD4hep/FieldTypes.h"
@@ -72,6 +75,10 @@ namespace dd4hep {
   template <> void Converter<Property>::operator()(xml_h element) const;
   template <> void Converter<CartesianField>::operator()(xml_h element) const;
   template <> void Converter<SensitiveDetector>::operator()(xml_h element) const;
+#if ROOT_VERSION_CODE > ROOT_VERSION(6,16,0)
+  template <> void Converter<OpticalSurface>::operator()(xml_h element) const;
+  template <> void Converter<PropertyTable>::operator()(xml_h element) const;
+#endif
   template <> void Converter<DetElement>::operator()(xml_h element) const;
   template <> void Converter<GdmlFile>::operator()(xml_h element) const;
   template <> void Converter<JsonFile>::operator()(xml_h element) const;
@@ -443,28 +450,35 @@ template <> void Converter<Material>::operator()(xml_h e) const {
 #if ROOT_VERSION_CODE >= ROOT_VERSION(6,12,0)
     mix->ComputeDerivedQuantities();
 #endif
-    //fg: calling SetDensity for TGeoMixture results in incorrect radLen and intLen ( computed only from first element ) 
-    // // Update estimated density if not provided.
-    // if ( has_density )   {
-    //   mix->SetDensity(dens_val);
-    // }
-    // else if (!has_density && mix && 0 == mix->GetDensity()) {
-    //   double dens = 0.0;
-    //   for (composites.reset(), ifrac=0; composites; ++composites, ++ifrac) {
-    //     string nam = composites.attr<string>(_U(ref));
-    //     comp_mat = mgr.GetMaterial(nam.c_str());
-    //     dens += composites.attr<double>(_U(n)) * comp_mat->GetDensity();
-    //   }
-    //   for (fractions.reset(); fractions; ++fractions) {
-    //     string nam = fractions.attr<string>(_U(ref));
-    //     comp_mat = mgr.GetMaterial(nam.c_str());
-    //     dens += composites.attr<double>(_U(n)) * comp_mat->GetDensity();
-    //   }
-    //   printout(WARNING, "Compact", "++ Material: %s with NO density. "
-    //            "Set density to %7.3 g/cm**3", matname, dens);
-    //   mix->SetDensity(dens);
-    // }
-    
+#if ROOT_VERSION_CODE > ROOT_VERSION(6,16,0)
+    /// In case there were material properties specified: convert them here
+    for(xml_coll_t properties(x_mat, _U(property)); properties; ++properties) {
+      xml_elt_t p = properties;
+      if ( p.hasAttr(_U(ref)) )   {
+        string ref = p.attr<string>(_U(ref));
+        TGDMLMatrix* m = mgr.GetGDMLMatrix(ref.c_str());
+        if ( m )  {
+          //TODO: mat->AddProperty(p.attr<string>(_U(name)).c_str(), m);
+          mat->AddProperty(p.attr<string>(_U(name)).c_str(), ref.c_str());
+          continue;
+        }
+        // ERROR
+        throw_print("Compact2Objects[ERROR]: Converting material:" + mname + " Property missing: " + ref);
+      }
+    }
+#endif
+    xml_h temp = x_mat.child(_U(T), false);
+    if ( temp.ptr() )   {
+      double temp_val    = temp.attr<double>(_U(value));
+      double temp_unit   = temp.attr<double>(_U(unit), 1.0 /* _toDouble("kelvin") */);
+      mat->SetTemperature(temp_val*temp_unit);
+    }
+    xml_h pressure = x_mat.child(_U(P), false);
+    if ( pressure.ptr() )   {
+      double pressure_val    = pressure.attr<double>(_U(value));
+      double pressure_unit   = pressure.attr<double>(_U(unit),1.0 /* _toDouble("pascal") */);
+      mat->SetPressure(pressure_val*pressure_unit);
+    }
   }
   TGeoMedium* medium = mgr.GetMedium(matname);
   if (0 == medium) {
@@ -591,6 +605,51 @@ template <> void Converter<Atom>::operator()(xml_h e) const {
   }
 }
 
+#if ROOT_VERSION_CODE > ROOT_VERSION(6,16,0)
+/** Convert compact optical surface objects (defines)
+ *
+ *
+ */
+template <> void Converter<OpticalSurface>::operator()(xml_h element) const {
+  xml_attr_t attr;
+  xml_elt_t  e = element;
+  OpticalSurface::EModel  model  = OpticalSurface::Model::kMglisur;
+  OpticalSurface::EFinish finish = OpticalSurface::Finish::kFpolished;
+  OpticalSurface::EType   type   = OpticalSurface::Type::kTdielectric_metal;
+  Double_t value = 0;
+  if ( (attr=e.attr<xml_attr_t>(_U(type)))   ) type   = OpticalSurface::Type::StringToType(e.attr<string>(attr).c_str());
+  if ( (attr=e.attr<xml_attr_t>(_U(model)))  ) model  = OpticalSurface::Model::StringToModel(e.attr<string>(attr).c_str());
+  if ( (attr=e.attr<xml_attr_t>(_U(finish))) ) finish = OpticalSurface::Finish::StringToFinish(e.attr<string>(attr).c_str());
+  if ( (attr=e.attr<xml_attr_t>(_U(value)))  ) value  = e.attr<double>(attr);
+  OpticalSurface surf(description, e.attr<string>(_U(name)), model, finish, type, value);
+  for (xml_coll_t props(e, _U(property)); props; ++props)  {
+    surf->AddProperty(props.attr<string>(_U(name)).c_str(), props.attr<string>(_U(ref)).c_str());
+  }
+}
+
+/** Convert compact property table objects (defines)
+ *
+ *  <matrix coldim="2" name="RINDEX0xf5972d0" values="1.5e-06 1.0013 1. ...."/>
+ *
+ */
+template <> void Converter<PropertyTable>::operator()(xml_h e) const {
+  string val;
+  vector<float> values;
+  size_t cols = e.attr<long>(_U(coldim));
+  stringstream str(e.attr<string>(_U(values)));
+
+  values.reserve(1024);
+  while ( !str.eof() )   {
+    str >> val;
+    values.push_back(_toDouble(val));
+  }
+  /// Create table and register table
+  PropertyTable table(description, e.attr<string>(_U(name)), "", values.size()/cols, cols);
+  for (size_t i=0, n=values.size(); i<n; ++i)
+    table->Set(i/cols, i%cols, values[i]);
+}
+#endif
+
 /** Convert compact visualization attribute to Detector visualization attribute
  *
  *  <vis name="SiVertexBarrelModuleVis"
@@ -863,7 +922,7 @@ template <> void Converter<LimitSet>::operator()(xml_h e) const {
  *  ... </properties>
  */
 template <> void Converter<Property>::operator()(xml_h e) const {
-  string            name = e.attr<string>(_U(name));
+  string name = e.attr<string>(_U(name));
   Detector::Properties& prp  = description.properties();
   if ( name.empty() )
     throw_print("Failed to convert properties. No name given!");
@@ -1284,9 +1343,15 @@ template <> void Converter<Compact>::operator()(xml_h element) const {
   xml_coll_t(compact, _U(materials)).for_each(_U(element), Converter<Atom>(description));
   xml_coll_t(compact, _U(materials)).for_each(_U(material), Converter<Material>(description));
   xml_coll_t(compact, _U(properties)).for_each(_U(attributes), Converter<Property>(description));
+#if ROOT_VERSION_CODE > ROOT_VERSION(6,16,0)
+  /// These two must be parsed early, because they are needed by the detector constructors
+  xml_coll_t(compact, _U(properties)).for_each(_U(matrix), Converter<PropertyTable>(description));
+  xml_coll_t(compact, _U(surfaces)).for_each(_U(opticalsurface), Converter<OpticalSurface>(description));
+#endif
+  
   xml_coll_t(compact, _U(display)).for_each(_U(include), Converter<DetElementInclude>(description));
   xml_coll_t(compact, _U(display)).for_each(_U(vis), Converter<VisAttr>(description));
-
+  
   if (element.hasChild(_U(world)))
     (Converter<World>(description))(xml_h(compact.child(_U(world))));
 
diff --git a/DDG4/include/DDG4/Geant4Converter.h b/DDG4/include/DDG4/Geant4Converter.h
index 938b63def84726045e5e2674b465b6427938c7aa..b3fd7ffa902bae695e9abd13db386f7dd7a63457 100644
--- a/DDG4/include/DDG4/Geant4Converter.h
+++ b/DDG4/include/DDG4/Geant4Converter.h
@@ -66,6 +66,19 @@ namespace dd4hep {
       /// Create geometry conversion
       Geant4Converter& create(DetElement top);
 
+#if ROOT_VERSION_CODE > ROOT_VERSION(6,16,0)
+      /// Convert the geometry type material into the corresponding Geant4 object(s).
+      virtual void* handleMaterialProperties(TObject* matrix) const;
+
+      /// Convert the optical surface to Geant4
+      void* handleOpticalSurface(TObject* surface) const;
+
+      /// Convert the skin surface to Geant4
+      void* handleSkinSurface(TObject* surface) const;
+
+      /// Convert the border surface to Geant4
+      void* handleBorderSurface(TObject* surface) const;
+#endif
       /// Convert the geometry type material into the corresponding Geant4 object(s).
       virtual void* handleMaterial(const std::string& name, Material medium) const;
 
diff --git a/DDG4/include/DDG4/Geant4GeometryInfo.h b/DDG4/include/DDG4/Geant4GeometryInfo.h
index af0cde3f3941e61827feb7c10ca2bbbc7aecdecc..398809e19f0600bface01be6af5f3ed925c7ccbb 100644
--- a/DDG4/include/DDG4/Geant4GeometryInfo.h
+++ b/DDG4/include/DDG4/Geant4GeometryInfo.h
@@ -18,6 +18,7 @@
 #include "DD4hep/Objects.h"
 #include "DD4hep/Printout.h"
 #include "DD4hep/GeoHandler.h"
+#include "DD4hep/PropertyTable.h"
 #include "DDG4/Geant4Primitives.h"
 
 // C/C++ include files
@@ -39,8 +40,12 @@ class G4Region;
 class G4UserLimits;
 class G4VisAttributes;
 class G4VPhysicalVolume;
+class G4OpticalSurface;
+class G4LogicalSkinSurface;
+class G4LogicalBorderSurface;
 class G4AssemblyVolume;
 class G4VSensitiveDetector;
+class G4PhysicsOrderedFreeVector;
 
 /// Namespace for the AIDA detector description toolkit
 namespace dd4hep {
@@ -94,6 +99,19 @@ namespace dd4hep {
       Geant4GeometryMaps::PlacementMap     g4Placements;
       Geant4GeometryMaps::AssemblyMap      g4AssemblyVolumes;
       Geant4GeometryMaps::VolumeImprintMap g4VolumeImprints;
+      struct PropertyVector  {
+        std::vector<double> bins;
+        std::vector<double> values;
+        std::string name, title;
+        PropertyVector() = default;
+        ~PropertyVector() = default;
+      };
+#if ROOT_VERSION_CODE > ROOT_VERSION(6,16,0)
+      std::map<PropertyTable,  PropertyVector*>                g4OpticalProperties;
+      std::map<OpticalSurface, G4OpticalSurface*>              g4OpticalSurfaces;
+      std::map<SkinSurface,    G4LogicalSkinSurface*>          g4SkinSurfaces;
+      std::map<BorderSurface,  G4LogicalBorderSurface*>        g4BorderSurfaces;
+#endif
       std::map<Region, G4Region*>                              g4Regions;
       std::map<VisAttr, G4VisAttributes*>                      g4Vis;
       std::map<LimitSet, G4UserLimits*>                        g4Limits;
diff --git a/DDG4/src/Geant4Converter.cpp b/DDG4/src/Geant4Converter.cpp
index b5ff59e343dd528e00bec42079ce28c5ccaf468d..66ebe6342932c3475985d9da0d4891911f431d56 100644
--- a/DDG4/src/Geant4Converter.cpp
+++ b/DDG4/src/Geant4Converter.cpp
@@ -17,6 +17,7 @@
 #include "DD4hep/Volumes.h"
 #include "DD4hep/Printout.h"
 #include "DD4hep/DD4hepUnits.h"
+#include "DD4hep/PropertyTable.h"
 #include "DD4hep/detail/ObjectsInterna.h"
 #include "DD4hep/detail/DetectorInterna.h"
 
@@ -87,6 +88,10 @@
 #include "G4ElectroMagneticField.hh"
 #include "G4FieldManager.hh"
 #include "G4ReflectionFactory.hh"
+#include "G4OpticalSurface.hh"
+#include "G4LogicalSkinSurface.hh"
+#include "G4LogicalBorderSurface.hh"
+#include "G4MaterialPropertiesTable.hh"
 #include "CLHEP/Units/SystemOfUnits.h"
 
 // C/C++ include files
@@ -340,7 +345,8 @@ void* Geant4Converter::handleElement(const string& name, const Atom element) con
 
 /// Dump material in GDML format to output stream
 void* Geant4Converter::handleMaterial(const string& name, Material medium) const {
-  G4Material* mat = data().g4Materials[medium];
+  Geant4GeometryInfo& info = data();
+  G4Material* mat = info.g4Materials[medium];
   if (!mat) {
     PrintLevel lvl = debugMaterials ? ALWAYS : outputLevel;
     mat = G4Material::GetMaterial(name, false);
@@ -395,11 +401,29 @@ void* Geant4Converter::handleMaterial(const string& name, Material medium) const
         mat = new G4Material(name, z, a, density, state, 
                              material->GetTemperature(), material->GetPressure());
       }
+#if ROOT_VERSION_CODE > ROOT_VERSION(6,16,0)
+      /// Attach the material properties if any
+      G4MaterialPropertiesTable* tab = 0;
+      TListIter propIt(&material->GetProperties());
+      for(TObject* obj=*propIt; obj; obj = propIt.Next())  {
+        TNamed* n = (TNamed*)obj;
+        TGDMLMatrix *matrix = info.manager->GetGDMLMatrix(n->GetTitle());
+        if ( 0 == tab )  {
+          tab = new G4MaterialPropertiesTable();
+          mat->SetMaterialPropertiesTable(tab);
+        }
+        Geant4GeometryInfo::PropertyVector* v =
+          (Geant4GeometryInfo::PropertyVector*)handleMaterialProperties(matrix);
+        G4MaterialPropertyVector* vec =
+          new G4MaterialPropertyVector(&v->bins[0], &v->values[0], v->bins.size());
+        tab->AddProperty(n->GetName(), vec);
+      }
+#endif
       stringstream str;
       str << (*mat);
       printout(lvl, "Geant4Converter", "++ Created G4 %s", str.str().c_str());
     }
-    data().g4Materials[medium] = mat;
+    info.g4Materials[medium] = mat;
   }
   return mat;
 }
@@ -1025,6 +1049,184 @@ void Geant4Converter::handleProperties(Detector::Properties& prp) const {
   }
 }
 
+#if ROOT_VERSION_CODE > ROOT_VERSION(6,16,0)
+/// Convert the geometry type material into the corresponding Geant4 object(s).
+void* Geant4Converter::handleMaterialProperties(TObject* matrix) const    {
+  TGDMLMatrix* m = (TGDMLMatrix*)matrix;
+  Geant4GeometryInfo& info = data();
+  Geant4GeometryInfo::PropertyVector* g4 = info.g4OpticalProperties[m];
+  if (!g4) {
+    g4 = new Geant4GeometryInfo::PropertyVector();
+    size_t rows = m->GetRows();
+    g4->name    = m->GetName();
+    g4->title   = m->GetTitle();
+    g4->bins.reserve(rows);
+    g4->values.reserve(rows);
+    for(size_t i=0; i<rows; ++i)  {
+      g4->bins.push_back(m->Get(0,i)  /*   *CLHEP::eV/units::eV   */);
+      g4->values.push_back(m->Get(1,i));
+    }
+    info.g4OpticalProperties[m] = g4;
+  }
+  return g4;
+}
+
+static G4OpticalSurfaceFinish geant4_surface_finish(TGeoOpticalSurface::ESurfaceFinish f)   {
+#define TO_G4_FINISH(x)  case TGeoOpticalSurface::kF##x : return x;
+  switch(f)   {
+    TO_G4_FINISH(polished);              // smooth perfectly polished surface
+    TO_G4_FINISH(polishedfrontpainted);  // smooth top-layer (front) paint
+    TO_G4_FINISH(polishedbackpainted);   // same is 'polished' but with a back-paint
+ 
+    TO_G4_FINISH(ground);                // rough surface
+    TO_G4_FINISH(groundfrontpainted);    // rough top-layer (front) paint
+    TO_G4_FINISH(groundbackpainted);     // same as 'ground' but with a back-paint
+
+    TO_G4_FINISH(polishedlumirrorair);   // mechanically polished surface, with lumirror
+    TO_G4_FINISH(polishedlumirrorglue);  // mechanically polished surface, with lumirror & meltmount
+    TO_G4_FINISH(polishedair);           // mechanically polished surface
+    TO_G4_FINISH(polishedteflonair);     // mechanically polished surface, with teflon
+    TO_G4_FINISH(polishedtioair);        // mechanically polished surface, with tio paint
+    TO_G4_FINISH(polishedtyvekair);      // mechanically polished surface, with tyvek
+    TO_G4_FINISH(polishedvm2000air);     // mechanically polished surface, with esr film
+    TO_G4_FINISH(polishedvm2000glue);    // mechanically polished surface, with esr film & meltmount
+
+    TO_G4_FINISH(etchedlumirrorair);     // chemically etched surface, with lumirror
+    TO_G4_FINISH(etchedlumirrorglue);    // chemically etched surface, with lumirror & meltmount
+    TO_G4_FINISH(etchedair);             // chemically etched surface
+    TO_G4_FINISH(etchedteflonair);       // chemically etched surface, with teflon
+    TO_G4_FINISH(etchedtioair);          // chemically etched surface, with tio paint
+    TO_G4_FINISH(etchedtyvekair);        // chemically etched surface, with tyvek
+    TO_G4_FINISH(etchedvm2000air);       // chemically etched surface, with esr film
+    TO_G4_FINISH(etchedvm2000glue);      // chemically etched surface, with esr film & meltmount
+
+    TO_G4_FINISH(groundlumirrorair);     // rough-cut surface, with lumirror
+    TO_G4_FINISH(groundlumirrorglue);    // rough-cut surface, with lumirror & meltmount
+    TO_G4_FINISH(groundair);             // rough-cut surface
+    TO_G4_FINISH(groundteflonair);       // rough-cut surface, with teflon
+    TO_G4_FINISH(groundtioair);          // rough-cut surface, with tio paint
+    TO_G4_FINISH(groundtyvekair);        // rough-cut surface, with tyvek
+    TO_G4_FINISH(groundvm2000air);       // rough-cut surface, with esr film
+    TO_G4_FINISH(groundvm2000glue);      // rough-cut surface, with esr film & meltmount
+
+    // for DAVIS model
+    TO_G4_FINISH(Rough_LUT);             // rough surface
+    TO_G4_FINISH(RoughTeflon_LUT);       // rough surface wrapped in Teflon tape
+    TO_G4_FINISH(RoughESR_LUT);          // rough surface wrapped with ESR
+    TO_G4_FINISH(RoughESRGrease_LUT);    // rough surface wrapped with ESR and coupled with opical grease
+    TO_G4_FINISH(Polished_LUT);          // polished surface
+    TO_G4_FINISH(PolishedTeflon_LUT);    // polished surface wrapped in Teflon tape
+    TO_G4_FINISH(PolishedESR_LUT);       // polished surface wrapped with ESR
+    TO_G4_FINISH(PolishedESRGrease_LUT); // polished surface wrapped with ESR and coupled with opical grease
+    TO_G4_FINISH(Detector_LUT);          // polished surface with optical grease
+  default:
+    printout(ERROR,"Geant4Surfaces","++ Unknown finish style: %d [%s]. Assume polished!",
+             int(f), TGeoOpticalSurface::FinishToString(f));
+    return polished;
+  }
+#undef TO_G4_FINISH
+}
+
+static G4SurfaceType geant4_surface_type(TGeoOpticalSurface::ESurfaceType t)   {
+#define TO_G4_TYPE(x)  case TGeoOpticalSurface::kT##x : return x;
+  switch(t)   {
+    TO_G4_TYPE(dielectric_metal);      // dielectric-metal interface
+    TO_G4_TYPE(dielectric_dielectric); // dielectric-dielectric interface
+    TO_G4_TYPE(dielectric_LUT);        // dielectric-Look-Up-Table interface
+    TO_G4_TYPE(dielectric_LUTDAVIS);   // dielectric-Look-Up-Table DAVIS interface
+    TO_G4_TYPE(dielectric_dichroic);   // dichroic filter interface
+    TO_G4_TYPE(firsov);                // for Firsov Process
+    TO_G4_TYPE(x_ray);                  // for x-ray mirror process
+  default:
+    printout(ERROR,"Geant4Surfaces","++ Unknown finish style: %d [%s]. Assume polished!",
+             int(t), TGeoOpticalSurface::TypeToString(t));
+    return dielectric_metal;
+  }
+#undef TO_G4_TYPE
+}
+
+static G4OpticalSurfaceModel geant4_surface_model(TGeoOpticalSurface::ESurfaceModel m)   {
+#define TO_G4_MODEL(x)  case TGeoOpticalSurface::kM##x : return x;
+  switch(m)   {
+    TO_G4_MODEL(glisur);  // original GEANT3 model
+    TO_G4_MODEL(unified); // UNIFIED model
+    TO_G4_MODEL(LUT);     // Look-Up-Table model
+    TO_G4_MODEL(DAVIS);   // DAVIS model
+    TO_G4_MODEL(dichroic); // dichroic filter
+  default:
+    printout(ERROR,"Geant4Surfaces","++ Unknown finish style: %d [%s]. Assume polished!",
+             int(m), TGeoOpticalSurface::ModelToString(m));
+    return glisur;
+  }
+#undef TO_G4_MODEL
+}
+
+/// Convert the optical surface to Geant4
+void* Geant4Converter::handleOpticalSurface(TObject* surface) const    {
+  TGeoOpticalSurface* s    = (TGeoOpticalSurface*)surface;
+  Geant4GeometryInfo& info = data();
+  G4OpticalSurface*   g4   = info.g4OpticalSurfaces[s];
+  if (!g4) {
+    G4SurfaceType          type   = geant4_surface_type(s->GetType());
+    G4OpticalSurfaceModel  model  = geant4_surface_model(s->GetModel());
+    G4OpticalSurfaceFinish finish = geant4_surface_finish(s->GetFinish());
+    g4 = new G4OpticalSurface(s->GetName(), model, finish, type, s->GetValue());
+    g4->SetSigmaAlpha(s->GetSigmaAlpha());
+    // not implemented: g4->SetPolish(s->GetPolish());
+    G4MaterialPropertiesTable* tab = 0;
+    TListIter it(&s->GetProperties());
+    for(TObject* obj = *it; obj; obj = it.Next())  {
+      TNamed* n = (TNamed*)obj;
+      TGDMLMatrix *matrix = info.manager->GetGDMLMatrix(n->GetTitle());
+      if ( 0 == tab )  {
+        tab = new G4MaterialPropertiesTable();
+        g4->SetMaterialPropertiesTable(tab);
+      }
+      Geant4GeometryInfo::PropertyVector* v =
+        (Geant4GeometryInfo::PropertyVector*)handleMaterialProperties(matrix);
+      if ( !v )  {  // Error!
+        except("Geant4OpticalSurface","++ Failed to convert opt.surface %s. Property table %s is not defined!",
+               s->GetName(), n->GetTitle());
+      }
+      G4MaterialPropertyVector* vec =
+        new G4MaterialPropertyVector(&v->bins[0], &v->values[0], v->bins.size());
+      tab->AddProperty(n->GetName(), vec);
+    }
+    info.g4OpticalSurfaces[s] = g4;
+  }
+  return g4;
+}
+
+/// Convert the skin surface to Geant4
+void* Geant4Converter::handleSkinSurface(TObject* surface) const   {
+  TGeoSkinSurface*    surf = (TGeoSkinSurface*)surface;
+  Geant4GeometryInfo& info = data();
+  G4LogicalSkinSurface* g4 = info.g4SkinSurfaces[surf];
+  if (!g4) {
+    G4OpticalSurface* s  = info.g4OpticalSurfaces[OpticalSurface(surf->GetSurface())];
+    G4LogicalVolume*  v = info.g4Volumes[surf->GetVolume()];
+    g4 = new G4LogicalSkinSurface(surf->GetName(), v, s);
+    info.g4SkinSurfaces[surf] = g4;
+  }
+  return g4;
+}
+
+/// Convert the border surface to Geant4
+void* Geant4Converter::handleBorderSurface(TObject* surface) const   {
+  TGeoBorderSurface*    surf = (TGeoBorderSurface*)surface;
+  Geant4GeometryInfo&   info = data();
+  G4LogicalBorderSurface* g4 = info.g4BorderSurfaces[surf];
+  if (!g4) {
+    G4OpticalSurface*  s  = info.g4OpticalSurfaces[OpticalSurface(surf->GetSurface())];
+    G4VPhysicalVolume* n1 = info.g4Placements[surf->GetNode1()];
+    G4VPhysicalVolume* n2 = info.g4Placements[surf->GetNode2()];
+    g4 = new G4LogicalBorderSurface(surf->GetName(), n1, n2, s);
+    info.g4BorderSurfaces[surf] = g4;
+  }
+  return g4;
+}
+#endif
+
 /// Convert the geometry type SensitiveDetector into the corresponding Geant4 object(s).
 void Geant4Converter::printSensitive(SensitiveDetector sens_det, const set<const TGeoVolume*>& /* volumes */) const {
   Geant4GeometryInfo&     info = data();
@@ -1104,12 +1306,19 @@ template <typename O, typename C, typename F> void handleRefs(const O* o, const
     (o->*pmf)("", *i);
   }
 }
+
 template <typename O, typename C, typename F> void handle(const O* o, const C& c, F pmf) {
   for (typename C::const_iterator i = c.begin(); i != c.end(); ++i) {
     (o->*pmf)((*i)->GetName(), *i);
   }
 }
 
+template <typename O, typename F> void handleArray(const O* o, const TObjArray* c, F pmf) {
+  TObjArrayIter arr(c);
+  for(TObject* i = *arr; i; i=arr.Next())
+    (o->*pmf)(i);
+}
+
 template <typename O, typename C, typename F> void handleMap(const O* o, const C& c, F pmf) {
   for (typename C::const_iterator i = c.begin(); i != c.end(); ++i)
     (o->*pmf)((*i).first, (*i).second);
@@ -1137,20 +1346,30 @@ Geant4Converter& Geant4Converter::create(DetElement top) {
   //outputLevel = WARNING;
   //setPrintLevel(VERBOSE);
 
-  handle(this, geo.volumes, &Geant4Converter::collectVolume);
-  handle(this, geo.solids,  &Geant4Converter::handleSolid);
+#if ROOT_VERSION_CODE > ROOT_VERSION(6,16,0)
+  handleArray(this, geo.manager->GetListOfGDMLMatrices(), &Geant4Converter::handleMaterialProperties);
+  handleArray(this, geo.manager->GetListOfOpticalSurfaces(), &Geant4Converter::handleOpticalSurface);
+#endif
+  
+  handle(this,     geo.volumes, &Geant4Converter::collectVolume);
+  handle(this,     geo.solids,  &Geant4Converter::handleSolid);
   printout(outputLevel, "Geant4Converter", "++ Handled %ld solids.", geo.solids.size());
-  handleRefs(this, geo.vis, &Geant4Converter::handleVis);
+  handleRefs(this, geo.vis,     &Geant4Converter::handleVis);
   printout(outputLevel, "Geant4Converter", "++ Handled %ld visualization attributes.", geo.vis.size());
-  handleMap(this, geo.limits, &Geant4Converter::handleLimitSet);
+  handleMap(this,  geo.limits,  &Geant4Converter::handleLimitSet);
   printout(outputLevel, "Geant4Converter", "++ Handled %ld limit sets.", geo.limits.size());
-  handleMap(this, geo.regions, &Geant4Converter::handleRegion);
+  handleMap(this,  geo.regions, &Geant4Converter::handleRegion);
   printout(outputLevel, "Geant4Converter", "++ Handled %ld regions.", geo.regions.size());
-  handle(this, geo.volumes, &Geant4Converter::handleVolume);
+  handle(this,     geo.volumes, &Geant4Converter::handleVolume);
   printout(outputLevel, "Geant4Converter", "++ Handled %ld volumes.", geo.volumes.size());
-  handleRMap(this, *m_data, &Geant4Converter::handleAssembly);
+  handleRMap(this, *m_data,     &Geant4Converter::handleAssembly);
   // Now place all this stuff appropriately
-  handleRMap(this, *m_data, &Geant4Converter::handlePlacement);
+  handleRMap(this, *m_data,     &Geant4Converter::handlePlacement);
+#if ROOT_VERSION_CODE > ROOT_VERSION(6,16,0)
+  /// Handle concrete surfaces
+  handleArray(this, geo.manager->GetListOfSkinSurfaces(),   &Geant4Converter::handleSkinSurface);
+  handleArray(this, geo.manager->GetListOfBorderSurfaces(), &Geant4Converter::handleBorderSurface);
+#endif
   //==================== Fields
   handleProperties(m_detDesc.properties());
   if ( printSensitives )  {