From 6d6964b346b323e226eb9d858a9c7ef256953f47 Mon Sep 17 00:00:00 2001
From: Markus Frank <Markus.Frank@cern.ch>
Date: Fri, 8 Nov 2019 18:31:11 +0100
Subject: [PATCH] Fix Geant4 conversion for Polyhedra and Polycone if start_phi
 != 0 (Issue https://github.com/AIDASoft/DD4hep/issues/578)

---
 DDCond/src/ConditionsContent.cpp              |   6 +-
 DDCond/src/ConditionsDependencyHandler.cpp    |   9 +-
 DDCore/include/DD4hep/ConditionDerived.h      |   2 +-
 DDCore/include/DD4hep/Conditions.h            |   4 +-
 DDCore/include/DD4hep/Shapes.h                |  85 +++++++++++-
 DDCore/include/DD4hep/config.h                |  19 ++-
 .../include/DD4hep/detail/ConditionsInterna.h |   4 +-
 DDCore/include/DD4hep/detail/ShapesInterna.h  |  76 +++++++++++
 DDCore/include/Parsers/detail/Dimension.h     |  30 +++--
 DDCore/include/Parsers/detail/Dimension.imp   |   4 +
 DDCore/include/XML/UnicodeValues.h            |   4 +
 DDCore/src/ConditionDerived.cpp               |   4 +-
 DDCore/src/Conditions.cpp                     |  10 +-
 DDCore/src/ConditionsInterna.cpp              |   4 +-
 DDCore/src/GeoDictionary.h                    |   5 +
 DDCore/src/Handle.cpp                         |   3 +
 DDCore/src/ShapeTags.h                        |   1 +
 DDCore/src/ShapeUtilities.cpp                 |  49 ++++++-
 DDCore/src/Shapes.cpp                         |   8 ++
 DDCore/src/ShapesInterna.cpp                  |  77 +++++++++++
 DDCore/src/plugins/ShapePlugins.cpp           |  75 +++++++----
 .../Geant4DetectorGeometryConstruction.cpp    | 121 +++++++++++++++++-
 DDG4/src/Geant4Converter.cpp                  |  28 ++--
 DDG4/src/Geant4ShapeConverter.cpp             |  10 +-
 examples/ClientTests/CMakeLists.txt           |   2 +-
 .../compact/Check_Shape_Polyhedra.xml         |  20 +++
 .../compact/Check_Shape_TwistedTube.xml       |  20 +++
 examples/ClientTests/ref/Ref_Polyhedra.txt    |  15 +++
 examples/ClientTests/scripts/Check_shape.py   |  48 ++++---
 .../ClientTests/scripts/Check_shape_dump.mac  |   2 +
 .../DDDB/src/plugins/DDDBDerivedCondTest.cpp  |  18 +--
 31 files changed, 650 insertions(+), 113 deletions(-)
 create mode 100644 DDCore/include/DD4hep/detail/ShapesInterna.h
 create mode 100644 DDCore/src/ShapesInterna.cpp
 create mode 100644 examples/ClientTests/compact/Check_Shape_Polyhedra.xml
 create mode 100644 examples/ClientTests/compact/Check_Shape_TwistedTube.xml
 create mode 100644 examples/ClientTests/ref/Ref_Polyhedra.txt
 create mode 100644 examples/ClientTests/scripts/Check_shape_dump.mac

diff --git a/DDCond/src/ConditionsContent.cpp b/DDCond/src/ConditionsContent.cpp
index d66ada4ae..c83a276b3 100644
--- a/DDCond/src/ConditionsContent.cpp
+++ b/DDCond/src/ConditionsContent.cpp
@@ -126,9 +126,13 @@ ConditionsContent::addDependency(ConditionDependency* dep)
     return *(ret.first);
   }
   ConditionKey::KeyMaker km(dep->target.hash);
+#if defined(DD4HEP_CONDITIONS_DEBUG)
   DetElement             de(dep->detector);
-  dep->release();
   const char* path = de.isValid() ? de.path().c_str() : "(global)";
+#else
+  const char* path = "";
+#endif
+  dep->release();
   except("DeConditionsRequests",
          "++ Dependency already exists: %s [%08X] [%016llX]",
          path, km.values.item_key, km.hash);
diff --git a/DDCond/src/ConditionsDependencyHandler.cpp b/DDCond/src/ConditionsDependencyHandler.cpp
index e34b758eb..602b023dc 100644
--- a/DDCond/src/ConditionsDependencyHandler.cpp
+++ b/DDCond/src/ConditionsDependencyHandler.cpp
@@ -248,9 +248,14 @@ void ConditionsDependencyHandler::do_callback(Work* work)   {
       // during the construction tries to access this one.
       // ---> Classic dead-lock
       except("DependencyHandler",
-             "++ Handler caught in infinite recursion loop. DE:%s Key:%s",
+             "++ Handler caught in infinite recursion loop. Key:%s %c%s%c",
              work->context.dependency->target.toString().c_str(),
-             work->context.dependency->detector.path().c_str());
+#if defined(DD4HEP_CONDITIONS_DEBUG)
+             '[',work->context.dependency->detector.path().c_str(),']'
+#else
+             ' ',"",' '
+#endif
+             );
     }
     ++work->callstack;
     work->condition = (*dep->callback)(dep->target, work->context).ptr();
diff --git a/DDCore/include/DD4hep/ConditionDerived.h b/DDCore/include/DD4hep/ConditionDerived.h
index 921eec820..54f8f95f1 100644
--- a/DDCore/include/DD4hep/ConditionDerived.h
+++ b/DDCore/include/DD4hep/ConditionDerived.h
@@ -348,7 +348,7 @@ namespace dd4hep {
       ConditionDependency();
       /// Access the dependency key
       Condition::key_type key()  const    {  return target.hash;                   }
-#ifdef DD4HEP_CONDITIONS_DEBUG
+#if defined(DD4HEP_CONDITIONS_DEBUG) || defined(DD4HEP_CONDITIONKEY_HAVE_NAME)
       /// Access the dependency key
       const char* name()  const           {  return target.name.c_str();           }
 #endif
diff --git a/DDCore/include/DD4hep/Conditions.h b/DDCore/include/DD4hep/Conditions.h
index 162099f88..151782777 100644
--- a/DDCore/include/DD4hep/Conditions.h
+++ b/DDCore/include/DD4hep/Conditions.h
@@ -181,7 +181,7 @@ namespace dd4hep {
     /// Access the type field of the condition
     const std::string& type()  const;
 
-#if !defined(DD4HEP_MINIMAL_CONDITIONS)
+#if defined(DD4HEP_CONDITIONS_DEBUG) || !defined(DD4HEP_MINIMAL_CONDITIONS)
     /// Access the value field of the condition as a string
     const std::string& value()  const;
     /// Access the comment field of the condition
@@ -244,7 +244,7 @@ namespace dd4hep {
    */
   class ConditionKey  {
   public:
-#ifdef DD4HEP_CONDITIONS_DEBUG
+#if defined(DD4HEP_CONDITIONS_DEBUG) || defined(DD4HEP_CONDITIONKEY_HAVE_NAME)
     /// Optional string identifier. Helps debugging a lot!
     std::string  name;
 #endif
diff --git a/DDCore/include/DD4hep/Shapes.h b/DDCore/include/DD4hep/Shapes.h
index f284302c3..54aa7a7ef 100644
--- a/DDCore/include/DD4hep/Shapes.h
+++ b/DDCore/include/DD4hep/Shapes.h
@@ -590,11 +590,11 @@ namespace dd4hep {
   
   /// Class describing a elliptical tube shape
   /**
-   *   TGeoEltu - cylindrical tube class. It takes 3 parameters :
-   *            Semi axis of ellipsis in x and y and half-length dz.
+   *   This is actually no TGeo shape. This implementation is a placeholder
+   *   for the Geant4 implementation G4TwistedTube.
+   *   In root it is implemented by a simple tube segment.
+   *   When converted to geant4 it will become a G4TwistedTube.
    *
-   *   For any further documentation please see the following ROOT documentation:
-   *   \see http://root.cern.ch/root/html/TGeoElTu.html
    *
    *   \author  M.Frank
    *   \version 1.0
@@ -640,6 +640,83 @@ namespace dd4hep {
     EllipticalTube& setDimensions(double a, double b, double dz);
   };
 
+  /// Class describing a twisted tube shape
+  /**
+   *   TGeoEltu - cylindrical tube class. It takes 3 parameters :
+   *            Semi axis of ellipsis in x and y and half-length dz.
+   *
+   *   For any further documentation please see the following ROOT documentation:
+   *   \see http://root.cern.ch/root/html/TGeoElTu.html
+   *
+   *   \author  M.Frank
+   *   \version 1.0
+   *   \ingroup DD4HEP_CORE
+   */
+  class TwistedTube : public Solid_type<TGeoTubeSeg> {
+  protected:
+    /// Internal helper method to support TwistedTube object construction
+    void make(const std::string& nam, double twist_angle, double rmin, double rmax,
+              double zneg, double zpos, int nsegments, double totphi);
+
+  public:
+    /// Default constructor
+    TwistedTube() = default;
+    /// Move Constructor
+    TwistedTube(TwistedTube&& e) = default;
+    /// Copy Constructor
+    TwistedTube(const TwistedTube& e) = default;
+    /// Constructor to be used with an existing object
+    template <typename Q> TwistedTube(const Q* p) : Solid_type<Object>(p) {   }
+    /// Constructor to assign an object
+    template <typename Q> TwistedTube(const Handle<Q>& e) : Solid_type<Object>(e) {   }
+
+    /// Constructor to create a new anonymous tube object with attribute initialization
+    TwistedTube(double twist_angle, double rmin, double rmax,
+                double dz, double dphi)
+    {  this->make("", twist_angle, rmin, rmax, -dz, dz, 1, dphi);  }
+    /// Constructor to create a new anonymous tube object with attribute initialization
+    TwistedTube(double twist_angle, double rmin, double rmax,
+                double dz, int nsegments, double totphi)
+    {  this->make("", twist_angle, rmin, rmax, -dz, dz, nsegments, totphi);  }
+    /// Constructor to create a new anonymous tube object with attribute initialization
+    TwistedTube(double twist_angle, double rmin, double rmax,
+                double zneg, double zpos, double totphi)
+    {  this->make("", twist_angle, rmin, rmax, zneg, zpos, 1, totphi);  }
+    /// Constructor to create a new anonymous tube object with attribute initialization
+    TwistedTube(double twist_angle, double rmin, double rmax,
+                double zneg, double zpos, int nsegments, double totphi)
+    {  this->make("", twist_angle, rmin, rmax, zneg, zpos, nsegments, totphi);  }
+
+    /// Constructor to create a new anonymous tube object with attribute initialization
+    TwistedTube(const std::string& nam, double twist_angle, double rmin, double rmax,
+                double dz, double dphi)
+    {  this->make(nam, twist_angle, rmin, rmax, -dz, dz, 1, dphi);  }
+    /// Constructor to create a new anonymous tube object with attribute initialization
+    TwistedTube(const std::string& nam, double twist_angle, double rmin, double rmax,
+                double dz, int nsegments, double totphi)
+    {  this->make(nam, twist_angle, rmin, rmax, -dz, dz, nsegments, totphi);  }
+    /// Constructor to create a new anonymous tube object with attribute initialization
+    TwistedTube(const std::string& nam, double twist_angle, double rmin, double rmax,
+                double zneg, double zpos, double totphi)
+    {  this->make(nam, twist_angle, rmin, rmax, zneg, zpos, 1, totphi);  }
+    /// Constructor to create a new anonymous tube object with attribute initialization
+    TwistedTube(const std::string& nam, double twist_angle, double rmin, double rmax,
+                double zneg, double zpos, int nsegments, double totphi)
+    {  this->make(nam, twist_angle, rmin, rmax, zneg, zpos, nsegments, totphi);  }
+
+    /// Constructor to create a new identified tube object with attribute initialization
+    template <typename A, typename B, typename DZ>
+    TwistedTube(const std::string& nam, const A& a, const B& b, const DZ& dz)
+    {  this->make(nam, _toDouble(a), _toDouble(b), _toDouble(dz));   }
+
+    /// Move Assignment operator
+    TwistedTube& operator=(TwistedTube&& copy) = default;
+    /// Copy Assignment operator
+    TwistedTube& operator=(const TwistedTube& copy) = default;
+    /// Set the tube dimensions
+    TwistedTube& setDimensions(double a, double b, double dz);
+  };
+
   /// Class describing a trap shape
   /**
    *   For any further documentation please see the following ROOT documentation:
diff --git a/DDCore/include/DD4hep/config.h b/DDCore/include/DD4hep/config.h
index e80a1e492..9b861a2f1 100644
--- a/DDCore/include/DD4hep/config.h
+++ b/DDCore/include/DD4hep/config.h
@@ -15,10 +15,17 @@
 
 #define DD4HEP_INSTANCE_COUNTS 1
 #define DD4HEP_USE_SAFE_CAST   1
+
+/// Enable to have more debugging information for conditions and keys
+/// If enabled it overrides DD4HEP_MINIMAL_CONDITIONS and sets it to true
+/// If enabled it overrides DD4HEP_CONDITIONKEY_HAVE_NAME and sets it to true
+#define DD4HEP_CONDITIONS_DEBUG  1
+
 /// Enable this if you want to minimize the footprint of conditions
 //#define DD4HEP_MINIMAL_CONDITIONS 1
+/// Enable flag to store conditions names to keys (needs some support from user code!)
+//#define DD4HEP_CONDITIONKEY_HAVE_NAME 1
 
-#define DD4HEP_CONDITIONS_DEBUG  1
 /// Valid implementations of the Gaudi plugin service are 1 and 2
 #define DD4HEP_PLUGINSVC_VERSION 2
 
@@ -33,9 +40,15 @@
 /// Namespace for the AIDA detector description toolkit
 namespace dd4hep {
 
+  /// Namespace for the conditions part of the AIDA detector description toolkit
+  namespace cond   {
+  }       /* End namespace cond      */
+
   /// Namespace for implementation details of the AIDA detector description toolkit
   namespace detail {
-
+    /// Namespace for the AIDA detector description matrix helpers
+    namespace matrix {
+    }     /* End namespace matrix    */
   }       /* End namespace detail    */
-}         /*   End namespace dd4hep  */
+}         /* End namespace dd4hep    */
 #endif    /* DD4HEP_CONFIG_H         */
diff --git a/DDCore/include/DD4hep/detail/ConditionsInterna.h b/DDCore/include/DD4hep/detail/ConditionsInterna.h
index ef3f8d728..c5764e2cb 100644
--- a/DDCore/include/DD4hep/detail/ConditionsInterna.h
+++ b/DDCore/include/DD4hep/detail/ConditionsInterna.h
@@ -57,14 +57,14 @@ namespace dd4hep {
      *  \ingroup DD4HEP_CONDITIONS
      */
     class ConditionObject
-#if !defined(DD4HEP_MINIMAL_CONDITIONS)
+#if defined(DD4HEP_CONDITIONS_DEBUG) || !defined(DD4HEP_MINIMAL_CONDITIONS)
       : public NamedObject
 #endif
     {
     public:
       /// Condition value (in string form)
       std::string          value;
-#if !defined(DD4HEP_MINIMAL_CONDITIONS)
+#if defined(DD4HEP_CONDITIONS_DEBUG) || !defined(DD4HEP_MINIMAL_CONDITIONS)
       /// Condition validity (in string form)
       std::string          validity;
       /// Condition address
diff --git a/DDCore/include/DD4hep/detail/ShapesInterna.h b/DDCore/include/DD4hep/detail/ShapesInterna.h
new file mode 100644
index 000000000..55ace5724
--- /dev/null
+++ b/DDCore/include/DD4hep/detail/ShapesInterna.h
@@ -0,0 +1,76 @@
+//==========================================================================
+//  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_SHAPESINTERNA_H
+#define DD4HEP_DDCORE_SHAPESINTERNA_H
+
+// Framework include files
+#include "DD4hep/Shapes.h"
+
+/// Namespace for the AIDA detector description toolkit
+namespace dd4hep {
+
+  /// Concrete object implementation for the Header handle
+  /**
+   *
+   *  \author  M.Frank
+   *  \version 1.0
+   *  \ingroup DD4HEP_CORE
+   */
+  class TwistedTubeObject: public TGeoTubeSeg {
+  private:
+    /// Inhibit move constructor
+    TwistedTubeObject(TwistedTubeObject&&) = delete;
+    /// Inhibit copy constructor
+    TwistedTubeObject(const TwistedTubeObject&) = delete;
+    /// Inhibit move assignment
+    TwistedTubeObject& operator=(TwistedTubeObject&&) = delete;
+    /// Inhibit copy assignment
+    TwistedTubeObject& operator=(const TwistedTubeObject&) = delete;
+  public:
+    double fPhiTwist {0};       // Twist angle from -fZHalfLength to fZHalfLength
+    double fNegativeEndz {0};   // -ve z endplate
+    double fPositiveEndz {0};   // +ve z endplate
+    int    fNsegments {0};      // Number of segments in totalPhi
+    
+  public:
+    /// Standard constructor
+    TwistedTubeObject() = default;
+    /// Initializing constructor
+    TwistedTubeObject(const char* pName,
+                      double  twistedangle,  // Twisted angle
+                      double  endinnerrad,   // Inner radius at endcap 
+                      double  endouterrad,   // Outer radius at endcap 
+                      double  negativeEndz,  // -ve z endplate
+                      double  positiveEndz,  // +ve z endplate
+                      int     nseg,          // Number of segments in totalPhi
+                      double  totphi);       // Total angle of all segments
+    /// Default destructor
+    virtual ~TwistedTubeObject() = default;
+    /// Access twist angle
+    double GetPhiTwist    () const { return fPhiTwist;     }
+    /// Access the negative z
+    double GetNegativeEndZ() const { return fNegativeEndz; }
+    /// Access the positive z
+    double GetPositiveEndZ() const { return fPositiveEndz; }
+    /// Access the number of segments
+    int    GetNsegments()    const { return fNsegments;    }
+    
+    /// in case shape has some negative parameters, these has to be computed in order to fit the mother
+    virtual TGeoShape *GetMakeRuntimeShape(TGeoShape *mother, TGeoMatrix * /*mat*/) const  override;
+    /// print shape parameters
+    virtual void InspectShape() const  override;
+
+    ClassDefOverride(TwistedTubeObject,0);
+  };
+}      /* End namespace dd4hep           */
+#endif /* DD4HEP_DDCORE_SHAPESINTERNA_H  */
diff --git a/DDCore/include/Parsers/detail/Dimension.h b/DDCore/include/Parsers/detail/Dimension.h
index 4ec720438..0723a291f 100644
--- a/DDCore/include/Parsers/detail/Dimension.h
+++ b/DDCore/include/Parsers/detail/Dimension.h
@@ -155,6 +155,10 @@ namespace dd4hep {
       double startphi() const;
       /// Access rotation constants: startphi
       double startphi(double default_value) const;
+      /// Access rotation constants: twist
+      double twist() const;
+      /// Access rotation constants: twist
+      double twist(double default_value) const;
 
       /// Access parameters: a
       double a() const;
@@ -364,9 +368,17 @@ namespace dd4hep {
       double dz() const;
       /// Access parameters: dz, if not present returns default
       double dz(double default_value) const;
-      /// Access min/max parameters: zmax
+      /// Access pos/neg parameters: zpos
+      double zpos() const;
+      /// Access pos/neg parameters: zpos
+      double zpos(double default_value) const;
+      /// Access pos/neg parameters: zneg
+      double zneg() const;
+      /// Access pos/neg parameters: zneg
+      double zneg(double default_value) const;
+      /// Access min/max parameters: zmin
       double zmin() const;
-      /// Access min/max parameters: zmax
+      /// Access min/max parameters: zmin
       double zmin(double default_value) const;
       /// Access min/max parameters: zmax
       double zmax() const;
@@ -449,6 +461,8 @@ namespace dd4hep {
 
       /// Access attribute values: nmodules
       int nmodules() const;
+      /// Access attribute values: nsegments
+      int nsegments() const;
       /// Access attribute values: nModules
       int nModules() const;
       /// Access attribute values: RowID
@@ -576,17 +590,17 @@ namespace dd4hep {
       /// Access min/max parameters: lunit
       double lunit(double default_value) const;
 
-      /// Access rotation constants: temperature
+      /// Access constants: temperature
       double temperature() const;
-      /// Access rotation constants: temperature
+      /// Access constants: temperature
       double temperature(double default_value) const;
-      /// Access rotation constants: pressure
+      /// Access constants: pressure
       double pressure() const;
-      /// Access rotation constants: pressure
+      /// Access constants: pressure
       double pressure(double default_value) const;
-      /// Access rotation constants: density
+      /// Access constants: density
       double density() const;
-      /// Access rotation constants: density
+      /// Access constants: density
       double density(double default_value) const;
 
       /// Access child element with tag "dimensions" as Dimension object
diff --git a/DDCore/include/Parsers/detail/Dimension.imp b/DDCore/include/Parsers/detail/Dimension.imp
index 636cb512b..8bf5d2b6d 100644
--- a/DDCore/include/Parsers/detail/Dimension.imp
+++ b/DDCore/include/Parsers/detail/Dimension.imp
@@ -55,6 +55,8 @@ XML_ATTR_ACCESSOR_DOUBLE(dz)
 XML_ATTR_ACCESSOR_DOUBLE(z0)
 XML_ATTR_ACCESSOR_DOUBLE(z1)
 XML_ATTR_ACCESSOR_DOUBLE(z2)
+XML_ATTR_ACCESSOR_DOUBLE(zpos)
+XML_ATTR_ACCESSOR_DOUBLE(zneg)
 XML_ATTR_ACCESSOR_DOUBLE(zmin)
 XML_ATTR_ACCESSOR_DOUBLE(zmax)
 XML_ATTR_ACCESSOR_DOUBLE(z_offset)
@@ -109,6 +111,7 @@ XML_ATTR_ACCESSOR_DOUBLE(phi1)
 XML_ATTR_ACCESSOR_DOUBLE(phi2)
 XML_ATTR_ACCESSOR_DOUBLE(deltaphi)
 XML_ATTR_ACCESSOR_DOUBLE(startphi)
+XML_ATTR_ACCESSOR_DOUBLE(twist)
 
 XML_ATTR_ACCESSOR(double, length)
 XML_ATTR_ACCESSOR(double, width)
@@ -163,6 +166,7 @@ XML_ATTR_ACCESSOR(bool, nocore)
 XML_ATTR_ACCESSOR_BOOL(nocore)
 
 XML_ATTR_ACCESSOR(int, nmodules)
+XML_ATTR_ACCESSOR(int, nsegments)
 XML_ATTR_ACCESSOR(int, nModules)
 XML_ATTR_ACCESSOR(int, RowID)
 XML_ATTR_ACCESSOR(int, nPads)
diff --git a/DDCore/include/XML/UnicodeValues.h b/DDCore/include/XML/UnicodeValues.h
index a09cb70cd..b5dd9437b 100644
--- a/DDCore/include/XML/UnicodeValues.h
+++ b/DDCore/include/XML/UnicodeValues.h
@@ -298,6 +298,7 @@ UNICODE (ntheta);
 UNICODE (number);
 UNICODE (numsides);
 UNICODE (nsides);
+UNICODE (nsegments);
 UNICODE (nsides_inner);
 UNICODE (nsides_outer);
 UNICODE (nz);
@@ -488,6 +489,7 @@ UNICODE (true);
 UNICODE (tube);
 UNICODE (tubes);
 UNICODE (tubs);
+UNICODE (twist);
 UNICODE (type);
 UNICODE (types);
 UNICODE (tx);
@@ -581,6 +583,8 @@ UNICODE (z4);
 UNICODE (Zeff);
 UNICODE (zhalf);
 UNICODE (zmin);
+UNICODE (zneg);
+UNICODE (zpos);
 UNICODE (zmax);
 UNICODE (zplane);
 UNICODE (zstart);
diff --git a/DDCore/src/ConditionDerived.cpp b/DDCore/src/ConditionDerived.cpp
index e5401f9d1..777d28d53 100644
--- a/DDCore/src/ConditionDerived.cpp
+++ b/DDCore/src/ConditionDerived.cpp
@@ -55,7 +55,7 @@ Condition ConditionUpdateContext::condition(const ConditionKey& key_value)  cons
     iov->iov_intersection(c.iov());
     return c;
   }
-#ifdef DD4HEP_CONDITIONS_DEBUG
+#if defined(DD4HEP_CONDITIONS_DEBUG) || defined(DD4HEP_CONDITIONKEY_HAVE_NAME)
   except("ConditionUpdateCall:","Failed to access non-existing condition:"+key_value.name);
 #else
   ConditionKey::KeyMaker key(key_value.hash);
@@ -117,7 +117,7 @@ ConditionResolver::~ConditionResolver()  {
 
 /// Throw exception on conditions access failure
 void ConditionUpdateContext::accessFailure(const ConditionKey& key_value)  const   {
-#ifdef DD4HEP_CONDITIONS_DEBUG
+#if defined(DD4HEP_CONDITIONS_DEBUG) || defined(DD4HEP_CONDITIONKEY_HAVE_NAME)
   except("ConditionUpdateCall",
          "%s [%016llX]: FAILED to access non-existing item:%s [%016llX]",
          dependency->target.name.c_str(), dependency->target.hash,
diff --git a/DDCore/src/Conditions.cpp b/DDCore/src/Conditions.cpp
index 1e6689714..15a457e9e 100644
--- a/DDCore/src/Conditions.cpp
+++ b/DDCore/src/Conditions.cpp
@@ -23,6 +23,14 @@
 using namespace std;
 using namespace dd4hep;
 
+#if defined(DD4HEP_CONDITIONS_DEBUG) && !defined(DD4HEP_CONDITIONKEY_HAVE_NAME)
+#define DD4HEP_CONDITIONKEY_HAVE_NAME 1
+#endif
+
+#if defined(DD4HEP_CONDITIONS_DEBUG) && defined(DD4HEP_MINIMAL_CONDITIONS)
+#undef DD4HEP_MINIMAL_CONDITIONS
+#endif
+
 /// Initializing constructor for a pure, undecorated conditions object
 Condition::Condition(key_type hash_key) : Handle<Object>()
 {
@@ -269,7 +277,7 @@ string ConditionKey::toString()  const    {
   dd4hep::ConditionKey::KeyMaker key(hash);
   char text[64];
   ::snprintf(text,sizeof(text),"%08X-%08X",key.values.det_key, key.values.item_key);
-#if !defined(DD4HEP_MINIMAL_CONDITIONS)
+#if defined(DD4HEP_CONDITIONS_DEBUG) || defined(DD4HEP_CONDITIONKEY_HAVE_NAME)
   if ( !name.empty() )   {
     stringstream str;
     str << "(" << name << ") " << text;
diff --git a/DDCore/src/ConditionsInterna.cpp b/DDCore/src/ConditionsInterna.cpp
index 3393cd5c7..eca1e178e 100644
--- a/DDCore/src/ConditionsInterna.cpp
+++ b/DDCore/src/ConditionsInterna.cpp
@@ -20,7 +20,7 @@
 using namespace std;
 using namespace dd4hep;
 
-#if defined(DD4HEP_MINIMAL_CONDITIONS)
+#if !defined(DD4HEP_CONDITIONS_DEBUG) && defined(DD4HEP_MINIMAL_CONDITIONS)
 DD4HEP_INSTANTIATE_HANDLE_UNNAMED(detail::ConditionObject);
 #else
 DD4HEP_INSTANTIATE_HANDLE_NAMED(detail::ConditionObject);
@@ -44,7 +44,7 @@ detail::ConditionObject::ConditionObject()
 }
 
 /// Standard constructor
-#if defined(DD4HEP_MINIMAL_CONDITIONS)
+#if !defined(DD4HEP_CONDITIONS_DEBUG) && defined(DD4HEP_MINIMAL_CONDITIONS)
 detail::ConditionObject::ConditionObject(const string& ,const string& )
   : data()
 #else
diff --git a/DDCore/src/GeoDictionary.h b/DDCore/src/GeoDictionary.h
index 3bc5f3791..2b5892d69 100644
--- a/DDCore/src/GeoDictionary.h
+++ b/DDCore/src/GeoDictionary.h
@@ -20,6 +20,7 @@
 #include "DD4hep/Volumes.h"
 #include "DD4hep/Shapes.h"
 #include "DD4hep/VolumeProcessor.h"
+#include "DD4hep/detail/ShapesInterna.h"
 
 // C/C++ include files
 #include <vector>
@@ -132,5 +133,9 @@ template vector<pair<string, int> >::iterator;
 #pragma link C++ class dd4hep::PlacedVolumeProcessor+;
 #pragma link C++ class dd4hep::PlacedVolumeScanner+;
 
+#pragma link C++ class dd4hep::TwistedTube+;
+#pragma link C++ class dd4hep::Solid_type<dd4hep::TwistedTubeObject>+;
+#pragma link C++ class dd4hep::TwistedTubeObject+;
+
 #endif  // __CINT__
 #endif  /* DD4HEP_DDCORE_ROOTDICTIONARY_H  */
diff --git a/DDCore/src/Handle.cpp b/DDCore/src/Handle.cpp
index d320e905a..01504728e 100644
--- a/DDCore/src/Handle.cpp
+++ b/DDCore/src/Handle.cpp
@@ -372,6 +372,7 @@ DD4HEP_INSTANTIATE_HANDLE(TGeoNodeOffset);
 #include "TGeoVolume.h"
 #include "TGeoCompositeShape.h"
 #include "TGeoShapeAssembly.h"
+#include "DD4hep/detail/ShapesInterna.h"
 DD4HEP_INSTANTIATE_HANDLE(TGeoVolumeAssembly,TGeoVolume,TGeoAtt);
 DD4HEP_INSTANTIATE_HANDLE(TGeoVolumeMulti,TGeoVolume,TGeoAtt);
 DD4HEP_INSTANTIATE_HANDLE(TGeoVolume,TGeoAtt,TAttLine,TAtt3D);
@@ -392,6 +393,8 @@ DD4HEP_INSTANTIATE_SHAPE_HANDLE(TGeoHype,TGeoTube);
 DD4HEP_INSTANTIATE_SHAPE_HANDLE(TGeoEltu,TGeoTube);
 DD4HEP_INSTANTIATE_SHAPE_HANDLE(TGeoTubeSeg,TGeoTube);
 DD4HEP_INSTANTIATE_SHAPE_HANDLE(TGeoCtub,TGeoTubeSeg,TGeoTube);
+using dd4hep::TwistedTubeObject;
+DD4HEP_INSTANTIATE_SHAPE_HANDLE(TwistedTubeObject,TGeoTubeSeg);
 
 DD4HEP_INSTANTIATE_SHAPE_HANDLE(TGeoTrap,TGeoArb8);
 DD4HEP_INSTANTIATE_SHAPE_HANDLE(TGeoGtra,TGeoArb8);
diff --git a/DDCore/src/ShapeTags.h b/DDCore/src/ShapeTags.h
index fe8757407..b46d9cdf5 100644
--- a/DDCore/src/ShapeTags.h
+++ b/DDCore/src/ShapeTags.h
@@ -26,6 +26,7 @@
 #define PARABOLOID_TAG      "Paraboloid"
 #define HYPERBOLOID_TAG     "Hyperboloid"
 #define ELLIPTICALTUBE_TAG  "EllipticalTube"
+#define TWISTEDTUBE_TAG     "TwistedTube"
 #define SPHERE_TAG          "Sphere"
 #define TORUS_TAG           "Torus"
 #define TRAP_TAG            "Trap"
diff --git a/DDCore/src/ShapeUtilities.cpp b/DDCore/src/ShapeUtilities.cpp
index 1daeb2ab7..bf0569bad 100644
--- a/DDCore/src/ShapeUtilities.cpp
+++ b/DDCore/src/ShapeUtilities.cpp
@@ -18,6 +18,7 @@
 #include "DD4hep/MatrixHelpers.h"
 #include "DD4hep/DD4hepUnits.h"
 #include "DD4hep/Printout.h"
+#include "DD4hep/detail/ShapesInterna.h"
 #include "ShapeTags.h"
 
 // C/C++ include files
@@ -82,7 +83,9 @@ namespace dd4hep {
     return check_shape_type<TGeoConeSeg>(solid) || check_shape_type<TGeoCone>(solid);
   }
   template <> bool isInstance<Tube>(const Handle<TGeoShape>& solid)  {
-    return check_shape_type<TGeoTubeSeg>(solid) || check_shape_type<TGeoCtub>(solid);
+    return check_shape_type<TGeoTubeSeg>(solid)
+      || check_shape_type<TGeoCtub>(solid)
+      || check_shape_type<TwistedTubeObject>(solid);
   }
   template <> bool isInstance<Polycone>(const Handle<TGeoShape>& solid)   {
     return check_shape_type<TGeoPcon>(solid)    || check_shape_type<TGeoPgon>(solid);
@@ -94,6 +97,9 @@ namespace dd4hep {
     }
     return false;
   }
+  template <> bool isInstance<TwistedTube>(const Handle<TGeoShape>& solid)  {
+    return check_shape_type<TwistedTubeObject>(solid);
+  }
   template <> bool isInstance<TruncatedTube>(const Handle<TGeoShape>& solid)   {
     return check_shape_type<TGeoCompositeShape>(solid)
       &&   ::strcmp(solid->GetTitle(), TRUNCATEDTUBE_TAG) == 0;
@@ -143,6 +149,10 @@ namespace dd4hep {
   template bool isA<Polycone>(const Handle<TGeoShape>& solid);
   template bool isA<EightPointSolid>(const Handle<TGeoShape>& solid);
 
+  template <> bool isA<TwistedTube>(const Handle<TGeoShape>& solid)   {
+    return check_shape_type<TwistedTubeObject>(solid)
+      &&   ::strcmp(solid->GetTitle(), TWISTEDTUBE_TAG) == 0;
+  }
   template <> bool isA<TruncatedTube>(const Handle<TGeoShape>& solid)   {
     return check_shape_type<TGeoCompositeShape>(solid)
       &&   ::strcmp(solid->GetTitle(), TRUNCATEDTUBE_TAG) == 0;
@@ -219,6 +229,12 @@ namespace dd4hep {
     const TGeoTubeSeg* sh = get_ptr<TGeoTubeSeg>(shape);
     return { sh->GetRmin(), sh->GetRmax(), sh->GetDz(), sh->GetPhi1()*units::deg, sh->GetPhi2()*units::deg };
   }
+  template <> vector<double> dimensions<TwistedTubeObject>(const TGeoShape* shape)    {
+    const TwistedTubeObject* sh = get_ptr<TwistedTubeObject>(shape);
+    return { sh->GetPhiTwist(), sh->GetRmin(), sh->GetRmax(),
+        sh->GetNegativeEndZ(), sh->GetPositiveEndZ(),
+        double(sh->GetNsegments()), sh->GetPhi2()*units::deg };
+  }
   template <> vector<double> dimensions<TGeoCtub>(const TGeoShape* shape)    {
     const TGeoCtub* sh = get_ptr<TGeoCtub>(shape);
     const Double_t*	lo = sh->GetNlow();
@@ -353,6 +369,7 @@ namespace dd4hep {
   template vector<double> dimensions<ConeSegment>      (const Handle<TGeoShape>& shape);
   template vector<double> dimensions<Tube>             (const Handle<TGeoShape>& shape);
   template vector<double> dimensions<CutTube>          (const Handle<TGeoShape>& shape);
+  template vector<double> dimensions<TwistedTube>      (const Handle<TGeoShape>& shape);
   template vector<double> dimensions<EllipticalTube>   (const Handle<TGeoShape>& shape);
   template vector<double> dimensions<Cone>             (const Handle<TGeoShape>& shape);
   template vector<double> dimensions<Trap>             (const Handle<TGeoShape>& shape);
@@ -418,6 +435,8 @@ namespace dd4hep {
         return dimensions<TGeoBBox>(shape.ptr());
       else if (cl == TGeoHalfSpace::Class())
         return dimensions<TGeoHalfSpace>(shape.ptr());
+      else if (cl == TGeoPgon::Class())
+        return dimensions<TGeoPgon>(shape.ptr());
       else if (cl == TGeoPcon::Class())
         return dimensions<TGeoPcon>(shape.ptr());
       else if (cl == TGeoConeSeg::Class())
@@ -432,6 +451,8 @@ namespace dd4hep {
         return dimensions<TGeoCtub>(shape.ptr());
       else if (cl == TGeoEltu::Class())
         return dimensions<TGeoEltu>(shape.ptr());
+      else if (cl == TwistedTubeObject::Class())
+        return dimensions<TwistedTubeObject>(shape.ptr());
       else if (cl == TGeoTrd1::Class())
         return dimensions<TGeoTrd1>(shape.ptr());
       else if (cl == TGeoTrd2::Class())
@@ -550,6 +571,24 @@ namespace dd4hep {
     pars[4] /= units::deg;
     Solid(sh)._setDimensions(&pars[0]);
   }
+  template <> void set_dimensions(TwistedTubeObject* sh, const std::vector<double>& params)   {
+    if ( params.size() != 7 )   {
+      invalidSetDimensionCall(sh,params);
+    }
+    auto pars = params;
+    sh->fPhiTwist = pars[0]/units::deg;
+    sh->fNegativeEndz = pars[3];
+    sh->fPositiveEndz = pars[4];
+    sh->fNsegments    = (int)pars[5];
+
+    pars[0] = pars[1];
+    pars[1] = pars[2];
+    pars[2] = (pars[3]+pars[4])/2.0;
+    pars[3] = 0.0;
+    pars[4] = pars[6];
+    pars.resize(5);
+    set_dimensions((TGeoTubeSeg*)sh, pars);
+  }
   template <> void set_dimensions(TGeoCtub* sh, const std::vector<double>& params)   {
     if ( params.size() != 11 )   {
       invalidSetDimensionCall(sh,params);
@@ -615,7 +654,7 @@ namespace dd4hep {
   }
   template <> void set_dimensions(TGeoPgon* sh, const std::vector<double>& params)   {
     auto pars = params;
-    if ( params.size() != 3 + 3*size_t(params[2]) )   {
+    if ( params.size() < 4 || params.size() != 4 + 3*size_t(params[3]) )   {
       invalidSetDimensionCall(sh,params);
     }
     pars[0]  /= units::deg;
@@ -624,7 +663,7 @@ namespace dd4hep {
   }
   template <> void set_dimensions(TGeoXtru* sh, const std::vector<double>& params)   {
     auto pars = params;
-    if ( params.size() != 1 + 4*size_t(params[0]) )   {
+    if ( params.size() < 1 || params.size() != 1 + 4*size_t(params[0]) )   {
       invalidSetDimensionCall(sh,params);
     }
     Solid(sh)._setDimensions(&pars[0]);
@@ -697,6 +736,8 @@ namespace dd4hep {
   {  set_dimensions(shape.ptr(), params);   }
   template <> void set_dimensions(CutTube shape, const std::vector<double>& params)
   {  set_dimensions(shape.ptr(), params);   }
+  template <> void set_dimensions(TwistedTube shape, const std::vector<double>& params)
+  {  set_dimensions(shape.ptr(), params);   }
   template <> void set_dimensions(EllipticalTube shape, const std::vector<double>& params)
   {  set_dimensions(shape.ptr(), params);   }
   template <> void set_dimensions(Trap shape, const std::vector<double>& params)
@@ -899,6 +940,8 @@ namespace dd4hep {
         set_dimensions(CutTube(shape), params);
       else if (cl == TGeoEltu::Class())
         set_dimensions(EllipticalTube(shape), params);
+      else if (cl == TwistedTubeObject::Class())
+        set_dimensions(TwistedTube(shape), params);
       else if (cl == TGeoTrd1::Class())
         set_dimensions(Trd1(shape), params);
       else if (cl == TGeoTrd2::Class())
diff --git a/DDCore/src/Shapes.cpp b/DDCore/src/Shapes.cpp
index 893a073dc..6e604d9df 100644
--- a/DDCore/src/Shapes.cpp
+++ b/DDCore/src/Shapes.cpp
@@ -18,6 +18,7 @@
 #include "DD4hep/MatrixHelpers.h"
 #include "DD4hep/DD4hepUnits.h"
 #include "DD4hep/Printout.h"
+#include "DD4hep/detail/ShapesInterna.h"
 #include "ShapeTags.h"
 
 // C/C++ include files
@@ -436,6 +437,13 @@ void EllipticalTube::make(const string& nam, double a, double b, double dz) {
   _assign(new TGeoEltu(nam.c_str(), a, b, dz), "", ELLIPTICALTUBE_TAG, true);
 }
 
+/// Internal helper method to support TwistedTube object construction
+void TwistedTube::make(const std::string& nam, double twist_angle, double rmin, double rmax,
+                       double zneg, double zpos, int nsegments, double totphi)   {
+  _assign(new TwistedTubeObject(nam.c_str(), twist_angle, rmin, rmax, zneg, zpos, nsegments, totphi/units::deg),
+          "", TWISTEDTUBE_TAG, true);
+}
+
 /// Constructor to be used when creating a new object with attribute initialization
 void Trd1::make(const string& nam, double x1, double x2, double y, double z) {
   _assign(new TGeoTrd1(nam.c_str(), x1, x2, y, z ), "", TRD1_TAG, true);
diff --git a/DDCore/src/ShapesInterna.cpp b/DDCore/src/ShapesInterna.cpp
new file mode 100644
index 000000000..30da0c302
--- /dev/null
+++ b/DDCore/src/ShapesInterna.cpp
@@ -0,0 +1,77 @@
+//==========================================================================
+//  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 includes
+#include "DD4hep/Printout.h"
+#include "DD4hep/detail/ShapesInterna.h"
+
+// C/C++ include files
+#include <climits>
+#include <iomanip>
+#include <cstdio>
+
+using namespace std;
+using namespace dd4hep;
+
+ClassImp(dd4hep::TwistedTubeObject)
+
+/// Initializing constructor
+TwistedTubeObject::TwistedTubeObject(const char* pName,
+                                     double  twistedangle,  // Twisted angle
+                                     double  innerrad,      // Inner radius at endcap 
+                                     double  outerrad,      // Outer radius at endcap 
+                                     double  negativeEndz,  // -ve z endplate
+                                     double  positiveEndz,  // +ve z endplate
+                                     int     nseg,          // Number of segments in totalPhi
+                                     double  totphi)        // Total angle of all segments
+  : TGeoTubeSeg(pName, innerrad, outerrad, (-negativeEndz+positiveEndz)/2.0, 0, totphi),
+  fPhiTwist(twistedangle), fNegativeEndz(negativeEndz), fPositiveEndz(positiveEndz), fNsegments(nseg)
+{
+}
+
+
+/// print shape parameters
+void TwistedTubeObject::InspectShape() const    {
+   printf("*** Shape TwistedTubeObject %s:  ***\n", GetName());
+   printf("    Rmin = %11.5f\n", GetRmin());
+   printf("    Rmax = %11.5f\n", GetRmax());
+   printf("    dz   = %11.5f\n", GetDz());
+   printf("    phi1 = %11.5f\n", GetPhi1());
+   printf("    phi2 = %11.5f\n", GetPhi2());
+   printf("    negativeEndz = %11.5f\n", GetNegativeEndZ());
+   printf("    positiveEndz = %11.5f\n", GetPositiveEndZ());
+   printf("    Nsegemnts    = %11.d\n",  GetNsegments());
+   printf(" Bounding box:\n");
+   TGeoBBox::InspectShape();
+}
+
+/// in case shape has some negative parameters, these has to be computed in order to fit the mother
+
+TGeoShape *TwistedTubeObject::GetMakeRuntimeShape(TGeoShape *mother, TGeoMatrix * /*mat*/) const
+{
+   if (!TestShapeBit(kGeoRunTimeShape)) return 0;
+   if (!mother->TestShapeBit(kGeoTube)) {
+      Error("GetMakeRuntimeShape", "Invalid mother for shape %s", GetName());
+      return 0;
+   }
+   Double_t rmin = fRmin;
+   Double_t rmax = fRmax;
+   if (fRmin<0)
+      rmin = ((TGeoTube*)mother)->GetRmin();
+   if ((fRmax<0) || (fRmax<=fRmin))
+      rmax = ((TGeoTube*)mother)->GetRmax();
+   
+   return (new TwistedTubeObject(GetName(), GetPhiTwist(), rmin, rmax,
+                                 GetNegativeEndZ(), GetPositiveEndZ(),
+                                 GetNsegments(), GetPhi2()));
+}
diff --git a/DDCore/src/plugins/ShapePlugins.cpp b/DDCore/src/plugins/ShapePlugins.cpp
index 1c1014d71..25976c16c 100644
--- a/DDCore/src/plugins/ShapePlugins.cpp
+++ b/DDCore/src/plugins/ShapePlugins.cpp
@@ -15,6 +15,7 @@
 #include "DD4hep/DetFactoryHelper.h"
 #include "DD4hep/Printout.h"
 #include "XML/Utilities.h"
+#include "../ShapeTags.h"
 #include "TGeoShapeAssembly.h"
 #include "TSystem.h"
 #include "TClass.h"
@@ -101,6 +102,28 @@ static Handle<TObject> create_Tube(Detector&, xml_h element)   {
 }
 DECLARE_XML_SHAPE(Tube__shape_constructor,create_Tube)
 
+static Handle<TObject> create_TwistedTube(Detector&, xml_h element)   {
+  xml_dim_t e(element);
+  Solid solid;
+  int nseg = 1;
+  double zpos = 0.0, zneg = 0.0;
+  if ( element.attr_nothrow(_U(nsegments)) )  {
+    nseg = e.nsegments();
+  }
+  if ( element.attr_nothrow(_U(dz)) )  {
+    zneg = -1.0*(zpos = e.dz());
+  }
+  else   {
+    zpos = e.zpos();
+    zneg = e.zneg();
+  }
+  solid = TwistedTube(e.twist(0.0), e.rmin(0.0),e.rmax(),zpos, zneg, nseg, e.deltaphi(2*M_PI));
+
+  if ( e.hasAttr(_U(name)) ) solid->SetName(e.attr<string>(_U(name)).c_str());
+  return solid;
+}
+DECLARE_XML_SHAPE(TwistedTube__shape_constructor,create_TwistedTube)
+
 static Handle<TObject> create_CutTube(Detector&, xml_h element)   {
   xml_dim_t e(element);
   Solid solid = CutTube(e.rmin(0.0),e.rmax(),e.dz(),
@@ -545,53 +568,59 @@ static Ref_t create_shape(Detector& description, xml_h e, Ref_t /* sens */)  {
     printout(INFO,"TestShape","Created successfull shape of type: %s",
              shape.typeStr().c_str());
     bool instance_test = false;
-    if ( 0 == strcasecmp(solid->GetTitle(),"box") )
+    if ( 0 == strcasecmp(solid->GetTitle(),BOX_TAG) )
       instance_test = isInstance<Box>(solid);
-    else if ( 0 == strcasecmp(solid->GetTitle(),"Tube") )
+    else if ( 0 == strcasecmp(solid->GetTitle(),TUBE_TAG) )
       instance_test = isInstance<Tube>(solid);
-    else if ( 0 == strcasecmp(solid->GetTitle(),"CutTube") )
+    else if ( 0 == strcasecmp(solid->GetTitle(),CUTTUBE_TAG) )
       instance_test = isInstance<CutTube>(solid);
-    else if ( 0 == strcasecmp(solid->GetTitle(),"Cone") )
+    else if ( 0 == strcasecmp(solid->GetTitle(),CONE_TAG) )
       instance_test = isInstance<Cone>(solid);
-    else if ( 0 == strcasecmp(solid->GetTitle(),"Trd1") )
+    else if ( 0 == strcasecmp(solid->GetTitle(),TRD1_TAG) )
       instance_test = isInstance<Trd1>(solid);
-    else if ( 0 == strcasecmp(solid->GetTitle(),"Trd2") )
+    else if ( 0 == strcasecmp(solid->GetTitle(),TRD2_TAG) )
       instance_test = isInstance<Trd2>(solid);
-    else if ( 0 == strcasecmp(solid->GetTitle(),"Torus") )
+    else if ( 0 == strcasecmp(solid->GetTitle(),TORUS_TAG) )
       instance_test = isInstance<Torus>(solid);
-    else if ( 0 == strcasecmp(solid->GetTitle(),"Sphere") )
+    else if ( 0 == strcasecmp(solid->GetTitle(),SPHERE_TAG) )
       instance_test = isInstance<Sphere>(solid);
-    else if ( 0 == strcasecmp(solid->GetTitle(),"HalfSpace") )
+    else if ( 0 == strcasecmp(solid->GetTitle(),HALFSPACE_TAG) )
       instance_test = isInstance<HalfSpace>(solid);
-    else if ( 0 == strcasecmp(solid->GetTitle(),"ConeSegment") )
+    else if ( 0 == strcasecmp(solid->GetTitle(),CONESEGMENT_TAG) )
       instance_test = isInstance<ConeSegment>(solid);
-    else if ( 0 == strcasecmp(solid->GetTitle(),"Paraboloid") )
+    else if ( 0 == strcasecmp(solid->GetTitle(),PARABOLOID_TAG) )
       instance_test = isInstance<Paraboloid>(solid);
-    else if ( 0 == strcasecmp(solid->GetTitle(),"Hyperboloid") )
+    else if ( 0 == strcasecmp(solid->GetTitle(),HYPERBOLOID_TAG) )
       instance_test = isInstance<Hyperboloid>(solid);
     else if ( 0 == strcasecmp(solid->GetTitle(),"PolyhedraRegular") )
       instance_test = isInstance<PolyhedraRegular>(solid);
-    else if ( 0 == strcasecmp(solid->GetTitle(),"Polyhedra") )
+    else if ( 0 == strcasecmp(solid->GetTitle(),POLYHEDRA_TAG) )
       instance_test = isInstance<Polyhedra>(solid);
-    else if ( 0 == strcasecmp(solid->GetTitle(),"EllipticalTube") )
+    else if ( 0 == strcasecmp(solid->GetTitle(),ELLIPTICALTUBE_TAG) )
       instance_test = isInstance<EllipticalTube>(solid);
-    else if ( 0 == strcasecmp(solid->GetTitle(),"ExtrudedPolygon") )
+    else if ( 0 == strcasecmp(solid->GetTitle(),EXTRUDEDPOLYGON_TAG) )
       instance_test = isInstance<ExtrudedPolygon>(solid);
-    else if ( 0 == strcasecmp(solid->GetTitle(),"Polycone") )
+    else if ( 0 == strcasecmp(solid->GetTitle(),POLYCONE_TAG) )
       instance_test = isInstance<Polycone>(solid);
-    else if ( 0 == strcasecmp(solid->GetTitle(),"EightPointSolid") )   {
+    else if ( 0 == strcasecmp(solid->GetTitle(),TWISTEDTUBE_TAG) )   {
+      instance_test  =  isInstance<TwistedTube>(solid);
+      instance_test &=  isInstance<Tube>(solid);
+      instance_test &=  isA<TwistedTube>(solid);
+      instance_test &= !isA<Tube>(solid);
+    }
+    else if ( 0 == strcasecmp(solid->GetTitle(),EIGHTPOINTSOLID_TAG) )   {
       instance_test  =  isInstance<EightPointSolid>(solid);
       instance_test &= !isInstance<Trap>(solid);
       instance_test &=  isA<EightPointSolid>(solid);
       instance_test &= !isA<Trap>(solid);
     }
-    else if ( 0 == strcasecmp(solid->GetTitle(),"Trap") )   {
+    else if ( 0 == strcasecmp(solid->GetTitle(),TRAP_TAG) )   {
       instance_test  =  isInstance<EightPointSolid>(solid);
       instance_test &=  isInstance<Trap>(solid);
       instance_test &=  isA<Trap>(solid);
       instance_test &= !isA<EightPointSolid>(solid);
     }
-    else if ( 0 == strcasecmp(solid->GetTitle(),"SubtractionSolid") )  {
+    else if ( 0 == strcasecmp(solid->GetTitle(),SUBTRACTION_TAG) )  {
       instance_test  =  isInstance<BooleanSolid>(solid);
       instance_test &=  isInstance<SubtractionSolid>(solid);
       instance_test &= !isA<IntersectionSolid>(solid);
@@ -599,7 +628,7 @@ static Ref_t create_shape(Detector& description, xml_h e, Ref_t /* sens */)  {
       instance_test &=  isA<SubtractionSolid>(solid);
       instance_test &= !isA<PseudoTrap>(solid);
     }
-    else if ( 0 == strcasecmp(solid->GetTitle(),"UnionSolid") )  {
+    else if ( 0 == strcasecmp(solid->GetTitle(),UNION_TAG) )  {
       instance_test  =  isInstance<BooleanSolid>(solid);
       instance_test &=  isInstance<UnionSolid>(solid);
       instance_test &= !isA<IntersectionSolid>(solid);
@@ -607,7 +636,7 @@ static Ref_t create_shape(Detector& description, xml_h e, Ref_t /* sens */)  {
       instance_test &= !isA<SubtractionSolid>(solid);
       instance_test &= !isA<PseudoTrap>(solid);
     }
-    else if ( 0 == strcasecmp(solid->GetTitle(),"IntersectionSolid") )  {
+    else if ( 0 == strcasecmp(solid->GetTitle(),INTERSECTION_TAG) )  {
       instance_test  =  isInstance<BooleanSolid>(solid);
       instance_test &=  isInstance<IntersectionSolid>(solid);
       instance_test &=  isA<IntersectionSolid>(solid);
@@ -615,7 +644,7 @@ static Ref_t create_shape(Detector& description, xml_h e, Ref_t /* sens */)  {
       instance_test &= !isA<SubtractionSolid>(solid);
       instance_test &= !isA<PseudoTrap>(solid);
     }
-    else if ( 0 == strcasecmp(solid->GetTitle(),"TruncatedTube") )  {
+    else if ( 0 == strcasecmp(solid->GetTitle(),TRUNCATEDTUBE_TAG) )  {
       instance_test  =  isInstance<BooleanSolid>(solid);
       instance_test &=  isInstance<TruncatedTube>(solid);
       instance_test &=  isA<TruncatedTube>(solid);
@@ -624,7 +653,7 @@ static Ref_t create_shape(Detector& description, xml_h e, Ref_t /* sens */)  {
       instance_test &= !isA<UnionSolid>(solid);
       instance_test &= !isA<SubtractionSolid>(solid);
     }
-    else if ( 0 == strcasecmp(solid->GetTitle(),"PseudoTrap") )  {
+    else if ( 0 == strcasecmp(solid->GetTitle(),PSEUDOTRAP_TAG) )  {
       instance_test  =  isInstance<BooleanSolid>(solid);
       instance_test &=  isInstance<PseudoTrap>(solid);
       instance_test &=  isA<PseudoTrap>(solid);
diff --git a/DDG4/plugins/Geant4DetectorGeometryConstruction.cpp b/DDG4/plugins/Geant4DetectorGeometryConstruction.cpp
index ea035da34..3666b6b37 100644
--- a/DDG4/plugins/Geant4DetectorGeometryConstruction.cpp
+++ b/DDG4/plugins/Geant4DetectorGeometryConstruction.cpp
@@ -58,6 +58,15 @@ namespace dd4hep {
       int  m_geoInfoPrintLevel;
       /// Property: G4 GDML dump file name (default: empty. If non empty, dump)
       std::string m_dumpGDML;
+      /// Property: DD4hep path to volume to be printed (default: empty)
+      std::string m_volumePath;
+
+      /// Write GDML file
+      int writeGDML();
+      /// Print geant4 volume
+      int printVolume();
+      /// Check geant4 volume
+      int checkVolume();
 
     public:
       /// Initializing constructor for DDG4
@@ -66,23 +75,32 @@ namespace dd4hep {
       virtual ~Geant4DetectorGeometryConstruction();
       /// Geometry construction callback. Called at "Construct()"
       void constructGeo(Geant4DetectorConstructionContext* ctxt);
+      /// Install command control messenger to write GDML file from command prompt.
+      virtual void installCommandMessenger()   override;
     };
   }    // End namespace sim
 }      // End namespace dd4hep
 
 
 // Framework include files
-#include "DD4hep/InstanceCount.h"
-#include "DD4hep/Printout.h"
-#include "DD4hep/Detector.h"
+#include <DD4hep/InstanceCount.h>
+#include <DD4hep/DetectorTools.h>
+#include "DD4hep/DD4hepUnits.h"
+#include <DD4hep/Printout.h>
+#include <DD4hep/Detector.h>
 
 #include "DDG4/Geant4HierarchyDump.h"
+#include "DDG4/Geant4UIMessenger.h"
 #include "DDG4/Geant4Converter.h"
 #include "DDG4/Geant4Kernel.h"
 #include "DDG4/Factories.h"
 
 // Geant4 include files
+#include <G4LogicalVolume.hh>
 #include "G4PVPlacement.hh"
+#include <G4Material.hh>
+#include <G4VSolid.hh>
+
 //#ifdef GEANT4_HAS_GDML
 #include "G4GDMLParser.hh"
 //#endif
@@ -94,7 +112,7 @@ DECLARE_GEANT4ACTION(Geant4DetectorGeometryConstruction)
 
 /// Initializing constructor for other clients
 Geant4DetectorGeometryConstruction::Geant4DetectorGeometryConstruction(Geant4Context* ctxt, const string& nam)
-  : Geant4DetectorConstruction(ctxt,nam)
+: Geant4DetectorConstruction(ctxt,nam)
 {
   declareProperty("DebugMaterials",    m_debugMaterials);
   declareProperty("DebugElements",     m_debugElements);
@@ -110,6 +128,7 @@ Geant4DetectorGeometryConstruction::Geant4DetectorGeometryConstruction(Geant4Con
 
   declareProperty("DumpHierarchy",     m_dumpHierarchy);
   declareProperty("DumpGDML",          m_dumpGDML="");
+  declareProperty("VolumePath",        m_volumePath="");
   InstanceCount::increment(this);
 }
 
@@ -143,19 +162,111 @@ void Geant4DetectorGeometryConstruction::constructGeo(Geant4DetectorConstruction
     Geant4HierarchyDump dmp(ctxt->description);
     dmp.dump("",w);
   }
+  ctxt->world = w;
+  if ( !m_dumpGDML.empty() || ::getenv("DUMP_GDML") ) writeGDML();
+  enableUI();
+}
+
+/// Print geant4 volume
+int Geant4DetectorGeometryConstruction::printVolume()  {
+  if ( !m_volumePath.empty() )   {
+    Detector& det = context()->kernel().detectorDescription();
+    PlacedVolume top = det.world().placement();
+    PlacedVolume pv = detail::tools::findNode(top, m_volumePath);
+    if ( pv.isValid() )   {
+      auto& g4map = Geant4Mapping::instance().data();
+      auto it = g4map.g4Volumes.find(pv.volume());
+      if ( it != g4map.g4Volumes.end() )   {
+        const G4LogicalVolume* vol = (*it).second;
+        auto* sol = vol->GetSolid(); 
+        string txt;
+        stringstream str;
+        str << *(vol->GetMaterial()) << endl;
+        str << *sol;
+        stringstream istr(str.str());
+        printP2("+++  Dump of ROOT   solid: %s", m_volumePath.c_str());
+        pv.volume().solid()->InspectShape();
+        printP2("+++  Dump of GEANT4 solid: %s", m_volumePath.c_str());
+        while(istr.good())   {
+          getline(istr,txt);
+          printP2(txt.c_str());
+        }
+        printP2("Shape: %s  cubic volume: %8.3g mm^3  area: %8.3g mm^2",
+                sol->GetName().c_str(), sol->GetCubicVolume(), sol->GetSurfaceArea());
+        return 1;
+      }
+    }
+    warning("+++ printVolume: FAILED to find the volume %s from the top volume",m_volumePath.c_str());
+  }
+  warning("+++ printVolume: Property VolumePath not set. [Ignored]");
+  return 0;
+}
+
+/// Check geant4 volume
+int Geant4DetectorGeometryConstruction::checkVolume()  {
+  if ( !m_volumePath.empty() )   {
+    Detector& det = context()->kernel().detectorDescription();
+    PlacedVolume top = det.world().placement();
+    PlacedVolume pv = detail::tools::findNode(top, m_volumePath);
+    if ( pv.isValid() )   {
+      auto& g4map = Geant4Mapping::instance().data();
+      auto it = g4map.g4Volumes.find(pv.volume());
+      if ( it != g4map.g4Volumes.end() )   {
+        const G4LogicalVolume* vol = (*it).second;
+        auto* g4_sol = vol->GetSolid();
+        Box   rt_sol = pv.volume().solid();
+        G4ThreeVector pMin, pMax;
+        double conv = (dd4hep::centimeter/CLHEP::centimeter)/2.0;
+        g4_sol->BoundingLimits(pMin,pMax);
+        printP2("Geant4 Shape: %s  cubic volume: %8.3g mm^3  area: %8.3g mm^2",
+                g4_sol->GetName().c_str(), g4_sol->GetCubicVolume(), g4_sol->GetSurfaceArea());
+        printP2("Geant4 Bounding box extends:    %8.3g  %8.3g %8.3g",
+                (pMax.x()-pMin.x())*conv, (pMax.y()-pMin.y())*conv, (pMax.z()-pMin.z())*conv);
+        printP2("ROOT   Bounding box dimensions: %8.3g  %8.3g %8.3g",
+                rt_sol->GetDX(), rt_sol->GetDY(), rt_sol->GetDZ());
+        
+        return 1;
+      }
+    }
+    warning("+++ checkVolume: FAILED to find the volume %s from the top volume",m_volumePath.c_str());
+  }
+  warning("+++ checkVolume: Property VolumePath not set. [Ignored]");
+  return 0;
+}
+
+/// Write GDML file
+int Geant4DetectorGeometryConstruction::writeGDML()  {
+  G4VPhysicalVolume* w  = context()->world();
   //#ifdef GEANT4_HAS_GDML
   if ( !m_dumpGDML.empty() ) {
     G4GDMLParser parser;
     parser.Write(m_dumpGDML.c_str(), w);
+    info("+++ writeGDML: Wrote GDML file: %s", m_dumpGDML.c_str());
+    return 1;
   }
   else {
     const char* gdml_dmp = ::getenv("DUMP_GDML");
     if ( gdml_dmp )    {
       G4GDMLParser parser;
       parser.Write(gdml_dmp, w);
+      info("+++ writeGDML: Wrote GDML file: %s", gdml_dmp);
+      return 1;
     }
   }
+  warning("+++ writeGDML: Neither property DumpGDML nor environment DUMP_GDML set. No file written!");
   //#endif
-  ctxt->world = w;
+  return 0;
+}
+
+/// Install command control messenger to write GDML file from command prompt.
+void Geant4DetectorGeometryConstruction::installCommandMessenger()   {
+  this->Geant4DetectorConstruction::installCommandMessenger();
+  m_control->addCall("writeGDML", "GDML: write geometry to file: '"+m_dumpGDML+"' [uses property DumpGDML]",
+                     Callback(this).make(&Geant4DetectorGeometryConstruction::writeGDML));
+  m_control->addCall("printVolume", "Print Geant4 volume properties [uses property VolumePath]",
+                     Callback(this).make(&Geant4DetectorGeometryConstruction::printVolume));
+  m_control->addCall("checkVolume", "Check Geant4 volume properties [uses property VolumePath]",
+                     Callback(this).make(&Geant4DetectorGeometryConstruction::checkVolume));
 }
 
+
diff --git a/DDG4/src/Geant4Converter.cpp b/DDG4/src/Geant4Converter.cpp
index efc6f6b5d..4aed87219 100644
--- a/DDG4/src/Geant4Converter.cpp
+++ b/DDG4/src/Geant4Converter.cpp
@@ -107,26 +107,16 @@ void Geant4AssemblyVolume::imprint(Geant4GeometryInfo& info,
                                    G4int copyNumBase,
                                    G4bool surfCheck )
 {
-  TGeoVolume* vol = parent->GetVolume();
   static int level=0;
-  ++level;
-
-
-  unsigned int  numberOfDaughters;
+  TGeoVolume* vol = parent->GetVolume();
+  unsigned int  numberOfDaughters = 
+    (copyNumBase == 0) ? pMotherLV->GetNoDaughters() : copyNumBase;
 
-  if( copyNumBase == 0 )
-  {
-    numberOfDaughters = pMotherLV->GetNoDaughters();
-  }
-  else
-  {
-    numberOfDaughters = copyNumBase;
-  }
+  ++level;
 
   // We start from the first available index
   //
   numberOfDaughters++;
-
   ImprintsCountPlus();
 
   vector<G4AssemblyTriplet> triplets = pAssembly->fTriplets;
@@ -1028,20 +1018,20 @@ void* Geant4Converter::handleLimitSet(LimitSet limitset, const set<const TGeoVol
 /// Convert the geometry visualisation attributes to the corresponding Geant4 object(s).
 void* Geant4Converter::handleVis(const string& /* name */, VisAttr attr) const {
   Geant4GeometryInfo& info = data();
-  G4VisAttributes* g4 = info.g4Vis[attr];
-  if (!g4) {
+  G4VisAttributes*    g4   = info.g4Vis[attr];
+  if ( !g4 ) {
     float red = 0, green = 0, blue = 0;
-    int style = attr.lineStyle();
+    int   style = attr.lineStyle();
     attr.rgb(red, green, blue);
     g4 = new G4VisAttributes(attr.visible(), G4Colour(red, green, blue, attr.alpha()));
     //g4->SetLineWidth(attr->GetLineWidth());
     g4->SetDaughtersInvisible(!attr.showDaughters());
-    if (style == VisAttr::SOLID) {
+    if ( style == VisAttr::SOLID ) {
       g4->SetLineStyle(G4VisAttributes::unbroken);
       g4->SetForceWireframe(false);
       g4->SetForceSolid(true);
     }
-    else if (style == VisAttr::WIREFRAME || style == VisAttr::DASHED) {
+    else if ( style == VisAttr::WIREFRAME || style == VisAttr::DASHED ) {
       g4->SetLineStyle(G4VisAttributes::dashed);
       g4->SetForceSolid(false);
       g4->SetForceWireframe(true);
diff --git a/DDG4/src/Geant4ShapeConverter.cpp b/DDG4/src/Geant4ShapeConverter.cpp
index e79d2edb8..31d5c2723 100644
--- a/DDG4/src/Geant4ShapeConverter.cpp
+++ b/DDG4/src/Geant4ShapeConverter.cpp
@@ -144,28 +144,26 @@ namespace dd4hep {
 
     template <> G4VSolid* convertShape<TGeoPgon>(const TGeoShape* shape)  {
       const TGeoPgon* sh = (const TGeoPgon*) shape;
-      double phi_start = sh->GetPhi1() * DEGREE_2_RAD;
-      double phi_total = (sh->GetDphi() + sh->GetPhi1()) * DEGREE_2_RAD;
       vector<double> rmin, rmax, z;
       for (Int_t i = 0; i < sh->GetNz(); ++i) {
         rmin.emplace_back(sh->GetRmin(i) * CM_2_MM);
         rmax.emplace_back(sh->GetRmax(i) * CM_2_MM);
         z.emplace_back(sh->GetZ(i) * CM_2_MM);
       }
-      return new G4Polyhedra(sh->GetName(), phi_start, phi_total, sh->GetNedges(), sh->GetNz(), &z[0], &rmin[0], &rmax[0]);
+      return new G4Polyhedra(sh->GetName(), sh->GetPhi1() * DEGREE_2_RAD, sh->GetDphi() * DEGREE_2_RAD,
+                             sh->GetNedges(), sh->GetNz(), &z[0], &rmin[0], &rmax[0]);
     }
 
     template <> G4VSolid* convertShape<TGeoPcon>(const TGeoShape* shape)  {
       const TGeoPcon* sh = (const TGeoPcon*) shape;
-      double phi_start = sh->GetPhi1() * DEGREE_2_RAD;
-      double phi_total = (sh->GetDphi() + sh->GetPhi1()) * DEGREE_2_RAD;
       vector<double> rmin, rmax, z;
       for (Int_t i = 0; i < sh->GetNz(); ++i) {
         rmin.emplace_back(sh->GetRmin(i) * CM_2_MM);
         rmax.emplace_back(sh->GetRmax(i) * CM_2_MM);
         z.emplace_back(sh->GetZ(i) * CM_2_MM);
       }
-      return new G4Polycone(sh->GetName(), phi_start, phi_total, sh->GetNz(), &z[0], &rmin[0], &rmax[0]);
+      return new G4Polycone(sh->GetName(), sh->GetPhi1() * DEGREE_2_RAD, sh->GetDphi() * DEGREE_2_RAD,
+                            sh->GetNz(), &z[0], &rmin[0], &rmax[0]);
     }
 
     template <> G4VSolid* convertShape<TGeoCone>(const TGeoShape* shape)  {
diff --git a/examples/ClientTests/CMakeLists.txt b/examples/ClientTests/CMakeLists.txt
index 5da5b90e6..9c72d472f 100644
--- a/examples/ClientTests/CMakeLists.txt
+++ b/examples/ClientTests/CMakeLists.txt
@@ -191,7 +191,7 @@ dd4hep_add_test_reg( ClientTests_Save_ROOT_MiniTel_LONGTEST
 #  Test basic shapes by comparing mesh vertices with reference file
 foreach (test Box Cone ConeSegment Tube ElTube
     CutTube Hyperboloid Paraboloid EightPointSolid Eightpoint_Reflect_Volume Eightpoint_Reflect_DetElement
-    Polycone PseudoTrap PseudoTrap2 Sphere Torus
+    Polycone Polyheadra PseudoTrap PseudoTrap2 Sphere Torus
     Trap Trd1 Trd2 TruncatedTube ExtrudedPolygon)
   dd4hep_add_test_reg( ClientTests_Check_Shape_${test}
       COMMAND    "${CMAKE_INSTALL_PREFIX}/bin/run_test_ClientTests.sh"
diff --git a/examples/ClientTests/compact/Check_Shape_Polyhedra.xml b/examples/ClientTests/compact/Check_Shape_Polyhedra.xml
new file mode 100644
index 000000000..cfa0079c7
--- /dev/null
+++ b/examples/ClientTests/compact/Check_Shape_Polyhedra.xml
@@ -0,0 +1,20 @@
+<lccdd>
+  <includes>
+    <gdmlFile ref="CheckShape.xml"/>
+  </includes>
+
+  <detectors>
+    <detector id="1" name="Shape_Test" type="DD4hep_TestShape_Creator">
+      <check vis="Shape1_vis">
+        <shape type="Polyhedra" numsides="1" startphi="-10*degree" deltaphi="20*degree">
+          <plane rmin="1775*mm"   rmax="1851.5*mm" z="0*mm"/>
+          <plane rmin="1775*mm"   rmax="1851.5*mm" z="3082.39*mm"/>
+          <plane rmin="1851.5*mm" rmax="1851.5*mm" z="3215.42*mm"/>
+        </shape>
+        <position x="30*cm"  y="30*cm" z="50*cm"/>
+        <rotation x="0"      y="0"     z="0"/>
+      </check>
+      <test  type="DD4hep_Mesh_Verifier" ref="${DD4hepExamplesINSTALL}/examples/ClientTests/ref/Ref_Polyhedra.txt" create="CheckShape_create"/>
+    </detector>
+  </detectors>
+</lccdd>
diff --git a/examples/ClientTests/compact/Check_Shape_TwistedTube.xml b/examples/ClientTests/compact/Check_Shape_TwistedTube.xml
new file mode 100644
index 000000000..56431eacb
--- /dev/null
+++ b/examples/ClientTests/compact/Check_Shape_TwistedTube.xml
@@ -0,0 +1,20 @@
+<lccdd>
+  <includes>
+    <gdmlFile ref="CheckShape.xml"/>
+  </includes>
+
+  <detectors>
+    <detector id="1" name="Shape_TwistedTube" type="DD4hep_TestShape_Creator">
+      <check vis="Shape1_vis">
+        <shape type="TwistedTube" twist="20*degree" rmin="10*cm" rmax="30*cm" dz="40*cm" deltaphi="45*degree" />
+        <position x="30"  y="30"   z="30"/>
+        <rotation x="0"   y="0"    z="0"/>
+      </check>
+<a>
+      <test  type="DD4hep_Mesh_Verifier" ref="${DD4hepExamplesINSTALL}/examples/ClientTests/ref/Ref_TwistedTube.txt" create="CheckShape_create"/>
+</a>
+      <test  type="DD4hep_Mesh_Verifier" ref="${DD4hepExamplesINSTALL}/examples/ClientTests/ref/Ref_TwistedTube.txt" create="1"/>
+
+    </detector>
+  </detectors>
+</lccdd>
diff --git a/examples/ClientTests/ref/Ref_Polyhedra.txt b/examples/ClientTests/ref/Ref_Polyhedra.txt
new file mode 100644
index 000000000..9704ce336
--- /dev/null
+++ b/examples/ClientTests/ref/Ref_Polyhedra.txt
@@ -0,0 +1,15 @@
+ShapeCheck[0] TGeoPgon         12 Mesh-points:
+TGeoPgon         Polyhedra N(mesh)=12  N(vert)=12  N(seg)=20  N(pols)=10
+TGeoPgon         0   Local  ( 177.50,  -31.30,    0.00) Global ( 207.50,   -1.30,   50.00)
+TGeoPgon         1   Local  ( 177.50,   31.30,    0.00) Global ( 207.50,   61.30,   50.00)
+TGeoPgon         2   Local  ( 185.15,  -32.65,    0.00) Global ( 215.15,   -2.65,   50.00)
+TGeoPgon         3   Local  ( 185.15,   32.65,    0.00) Global ( 215.15,   62.65,   50.00)
+TGeoPgon         4   Local  ( 177.50,  -31.30,  308.24) Global ( 207.50,   -1.30,  358.24)
+TGeoPgon         5   Local  ( 177.50,   31.30,  308.24) Global ( 207.50,   61.30,  358.24)
+TGeoPgon         6   Local  ( 185.15,  -32.65,  308.24) Global ( 215.15,   -2.65,  358.24)
+TGeoPgon         7   Local  ( 185.15,   32.65,  308.24) Global ( 215.15,   62.65,  358.24)
+TGeoPgon         8   Local  ( 185.15,  -32.65,  321.54) Global ( 215.15,   -2.65,  371.54)
+TGeoPgon         9   Local  ( 185.15,   32.65,  321.54) Global ( 215.15,   62.65,  371.54)
+TGeoPgon         10  Local  ( 185.15,  -32.65,  321.54) Global ( 215.15,   -2.65,  371.54)
+TGeoPgon         11  Local  ( 185.15,   32.65,  321.54) Global ( 215.15,   62.65,  371.54)
+TGeoPgon         Bounding box:  dx=   6.60 dy=  32.65 dz= 160.77 Origin: x= 181.40 y=   0.00 z= 160.77
diff --git a/examples/ClientTests/scripts/Check_shape.py b/examples/ClientTests/scripts/Check_shape.py
index 214474711..1ed692dc6 100644
--- a/examples/ClientTests/scripts/Check_shape.py
+++ b/examples/ClientTests/scripts/Check_shape.py
@@ -15,29 +15,39 @@ def run():
   kernel = DDG4.Kernel()
   # Configure UI
   geant4 = DDG4.Geant4(kernel, tracker='Geant4TrackerCombineAction')
-  geant4.setupCshUI(vis=True)
-  if len(sys.argv) >= 2 and sys.argv[1] == "batch":
-    kernel.UI = ''
-  elif len(sys.argv) >= 3 and (sys.argv[1] == "batch" or sys.argv[2] == "batch"):
-    kernel.UI = ''
-  elif len(sys.argv) == 2 and sys.argv[1] != "batch":
-    kernel.loadGeometry(sys.argv[1])
-  elif len(sys.argv) == 3 and sys.argv[1] != "batch":
-    kernel.loadGeometry(sys.argv[2])
-  elif len(sys.argv) == 3 and sys.argv[2] != "batch":
-    kernel.loadGeometry(sys.argv[1])
-  #
+  geo = None
+  vis = False
+  batch = False
+  #pdb.set_trace()
+  for i in xrange(len(sys.argv)):
+    c = sys.argv[i].upper()
+    if c.find('BATCH') < 2 and c.find('BATCH') >= 0: batch = True
+    if c[:4] == '-GEO': geo = sys.argv[i+1]
+    if c[:4] == '-VIS': vis = True
+
+  ui = geant4.setupCshUI(ui=None,vis=vis)
+  if batch: kernel.UI = ''
+  print('Geometry:'+str(geo))
+  kernel.loadGeometry(geo)
   # Configure field
   geant4.setupTrackingField(prt=True)
   # Now build the physics list:
-  phys = kernel.physicsList()
-  phys.extends = 'QGSP_BERT'
-  phys.enableUI()
-  phys.dump()
-
+  geant4.setupPhysics('')
+  kernel.physicsList().enableUI()
   DDG4.setPrintLevel(DDG4.OutputLevel.DEBUG)
-  geant4.execute()
-
+  #
+  #      '/ddg4/ConstructGeometry/DumpGDML   test.gdml',
+  #      '/ddg4/ConstructGeometry/writeGDML',
+  ui.Commands = [
+      '/ddg4/ConstructGeometry/VolumePath /world_volume_1/Shape_Test_0/Shape_Test_vol_0_0',
+      '/ddg4/ConstructGeometry/printVolume',
+      'exit'
+      ]
+  kernel.NumEvents = 0
+  kernel.configure()
+  kernel.initialize()
+  kernel.run()
+  kernel.terminate()
 
 if __name__ == "__main__":
   run()
diff --git a/examples/ClientTests/scripts/Check_shape_dump.mac b/examples/ClientTests/scripts/Check_shape_dump.mac
new file mode 100644
index 000000000..66a5efcc4
--- /dev/null
+++ b/examples/ClientTests/scripts/Check_shape_dump.mac
@@ -0,0 +1,2 @@
+/ddg4/ConstructGeometry/VolumePath /world_volume_1/Shape_Test_0/Shape_Test_vol_0_0
+/ddg4/ConstructGeometry/printVolume
diff --git a/examples/DDDB/src/plugins/DDDBDerivedCondTest.cpp b/examples/DDDB/src/plugins/DDDBDerivedCondTest.cpp
index ead7d6920..b87cf2221 100644
--- a/examples/DDDB/src/plugins/DDDBDerivedCondTest.cpp
+++ b/examples/DDDB/src/plugins/DDDBDerivedCondTest.cpp
@@ -81,8 +81,8 @@ namespace  {
     virtual ~ConditionUpdate1() {    }
     /// Interface to client Callback in order to update the condition
     virtual Condition operator()(const ConditionKey& key, ConditionUpdateContext& ) override final {
-      printout(context.level,"ConditionUpdate1","++ Building dependent condition: %s",key.name.c_str());
-      Condition    target(key.name,"Alignment");
+      printout(context.level,"ConditionUpdate1","++ Building dependent condition: %s",key.toString().c_str());
+      Condition    target("","Alignment");
       target.bind<AlignmentData>();
       return target;
     }
@@ -99,7 +99,7 @@ namespace  {
       catch(const exception& exc)   {
         ++context.numFail1;
         printout(ERROR,"ConditionUpdate2","++ Failed to build condition %s: %s",
-                 ctxt.key(0).name.c_str(), exc.what());
+                 ctxt.key(0).toString().c_str(), exc.what());
       }
     }
   };
@@ -120,8 +120,8 @@ namespace  {
     virtual ~ConditionUpdate2() {    }
     /// Interface to client Callback in order to update the condition
     virtual Condition operator()(const ConditionKey& key, ConditionUpdateContext&)  override final  {
-      printout(context.level,"ConditionUpdate2","++ Building dependent condition: %s",key.name.c_str());
-      Condition     target(key.name,"Alignment");
+      printout(context.level,"ConditionUpdate2","++ Building dependent condition: %s",key.toString().c_str());
+      Condition     target("","Alignment");
       target.bind<AlignmentData>();
       return target;
     }
@@ -140,7 +140,7 @@ namespace  {
       catch(const exception& exc)   {
         ++context.numFail2;
         printout(ERROR,"ConditionUpdate2","++ Failed to build condition %s: %s",
-                 ctxt.key(0).name.c_str(), exc.what());
+                 ctxt.key(0).toString().c_str(), exc.what());
       }
     }
   };
@@ -161,8 +161,8 @@ namespace  {
     virtual ~ConditionUpdate3() {    }
     /// Interface to client Callback in order to update the condition
     virtual Condition operator()(const ConditionKey& key, ConditionUpdateContext&)  override final  {
-      printout(context.level,"ConditionUpdate3","++ Building dependent condition: %s",key.name.c_str());
-      Condition    target(key.name,"Alignment");
+      printout(context.level,"ConditionUpdate3","++ Building dependent condition: %s",key.toString().c_str());
+      Condition    target("","Alignment");
       target.bind<AlignmentData>();
       return target;
     }
@@ -183,7 +183,7 @@ namespace  {
       catch(const exception& exc)   {
         ++context.numFail3;
         printout(ERROR,"ConditionUpdate3","++ Failed to build condition %s: %s",
-                 ctxt.key(0).name.c_str(), exc.what());
+                 ctxt.key(0).toString().c_str(), exc.what());
       }
     }
   };
-- 
GitLab