From 9726f40494acbe9ddcdc6667e54340a683f341aa Mon Sep 17 00:00:00 2001
From: Markus FRANK <Markus.Frank@cern.ch>
Date: Sat, 31 Oct 2020 00:39:38 +0100
Subject: [PATCH] Try to fix reflections for volumes and assemblies

---
 DDCore/include/DD4hep/DetectorImp.h           |   3 +
 DDCore/include/Parsers/detail/Dimension.h     |   4 +
 DDCore/include/Parsers/detail/Dimension.imp   |   2 +
 DDCore/include/XML/UnicodeValues.h            |   1 +
 DDCore/src/DetectorImp.cpp                    |  39 +++---
 DDCore/src/Volumes.cpp                        |  20 +--
 DDEve/src/Display.cpp                         |   3 +
 DDEve/src/Utilities.cpp                       |   2 -
 DDG4/include/DDG4/Geant4Converter.h           |  20 +--
 DDG4/include/DDG4/Geant4HierarchyDump.h       |  16 ++-
 .../Geant4DetectorGeometryConstruction.cpp    |  44 +++---
 DDG4/python/DDG4.py                           |   4 +-
 DDG4/src/Geant4Converter.cpp                  |  66 ++++++---
 DDG4/src/Geant4HierarchyDump.cpp              |  54 ++++----
 DDG4/src/Geant4ParticleGenerator.cpp          |  20 +--
 examples/ClientTests/CMakeLists.txt           |   2 +-
 .../compact/NestedBoxReflection.xml           |  56 ++++++--
 .../ClientTests/scripts/Check_reflection.py   |  95 ++++++++++++-
 .../ClientTests/scripts/Check_shape_vis.mac   |   4 +-
 examples/ClientTests/scripts/SiliconBlock.py  |   6 +-
 .../src/NestedBoxReflection_geo.cpp           | 129 +++++++++++-------
 21 files changed, 391 insertions(+), 199 deletions(-)

diff --git a/DDCore/include/DD4hep/DetectorImp.h b/DDCore/include/DD4hep/DetectorImp.h
index 6a5e397ca..c7c2f6e97 100644
--- a/DDCore/include/DD4hep/DetectorImp.h
+++ b/DDCore/include/DD4hep/DetectorImp.h
@@ -93,6 +93,9 @@ namespace dd4hep {
     /// Local method (no interface): Load volume manager.
     void imp_loadVolumeManager();
 
+    /// Build reflections the ROOT way. To be called once the geometry is closed
+    void buildReflections();
+    
     /// Default constructor used by ROOT I/O
     DetectorImp();
 
diff --git a/DDCore/include/Parsers/detail/Dimension.h b/DDCore/include/Parsers/detail/Dimension.h
index c3a201e34..ceed06f94 100644
--- a/DDCore/include/Parsers/detail/Dimension.h
+++ b/DDCore/include/Parsers/detail/Dimension.h
@@ -467,6 +467,10 @@ namespace dd4hep {
 
       /// Access attribute values: length
       double length() const;
+      /// Access attribute values: level
+      int    level() const;
+      /// Access attribute values: level
+      int    level(int default_value) const;
       /// Access attribute values: width
       double width() const;
       /// Access attribute values: height
diff --git a/DDCore/include/Parsers/detail/Dimension.imp b/DDCore/include/Parsers/detail/Dimension.imp
index e0c1fbc14..d7dff15e5 100644
--- a/DDCore/include/Parsers/detail/Dimension.imp
+++ b/DDCore/include/Parsers/detail/Dimension.imp
@@ -21,6 +21,8 @@
 
 XML_ATTR_ACCESSOR(int, id)
 XML_ATTR_ACCESSOR_INT(id)
+XML_ATTR_ACCESSOR(int, level)
+XML_ATTR_ACCESSOR_INT(level)
 XML_ATTR_ACCESSOR(bool, combineHits)
 XML_ATTR_ACCESSOR(int, station)
 
diff --git a/DDCore/include/XML/UnicodeValues.h b/DDCore/include/XML/UnicodeValues.h
index 9cfbbf03e..083656939 100644
--- a/DDCore/include/XML/UnicodeValues.h
+++ b/DDCore/include/XML/UnicodeValues.h
@@ -254,6 +254,7 @@ UNICODE (layers);
 UNICODE (description);
 UNICODE (lccdd);
 UNICODE (length);
+UNICODE (level);
 UNICODE (limit);
 UNICODE (limits);
 UNICODE (limitset);
diff --git a/DDCore/src/DetectorImp.cpp b/DDCore/src/DetectorImp.cpp
index 2ec4b8e1d..60306c36d 100644
--- a/DDCore/src/DetectorImp.cpp
+++ b/DDCore/src/DetectorImp.cpp
@@ -174,6 +174,8 @@ DetectorImp::DetectorImp(const string& name)
   //if ( gGeoManager ) delete gGeoManager;
   m_manager = new TGeoManager(name.c_str(), "Detector Geometry");
   {
+    m_manager->AddNavigator();
+    m_manager->SetCurrentNavigator(0);
     gGeoManager = m_manager;
 #if 1 //FIXME: eventually this should be set to 1 - needs fixes in examples ...
     TGeoElementTable*	table = m_manager->GetElementTable();
@@ -648,23 +650,25 @@ namespace {
       }
     }
   };
-  void build_reflections(TGeoManager* mgr)    {
-    TGeoIterator next(mgr->GetTopVolume());
-    TGeoNode *node;
-    while ((node=next())) {
-      TGeoMatrix* m = node->GetMatrix();
-      if (m->IsReflection()) {
-        Volume vol(node->GetVolume());
-        TGeoMatrix* mclone = new TGeoCombiTrans(*m);
-        mclone->RegisterYourself();
-        // Reflect just the rotation component
-        mclone->ReflectZ(kFALSE, kTRUE);
-        TGeoNodeMatrix* nodematrix = (TGeoNodeMatrix*)node;
-        nodematrix->SetMatrix(mclone);
-        printout(INFO,"Detector","Reflecting volume: %s ",vol.name());
-        Volume refl = vol.reflect(vol.sensitiveDetector());
-        node->SetVolume(refl.ptr());
-      }
+}
+
+/// Build reflections the ROOT way. To be called once the geometry is closed
+void DetectorImp::buildReflections()    {
+  TGeoIterator next(manager().GetTopVolume());
+  TGeoNode *node;
+  while ((node=next())) {
+    TGeoMatrix* m = node->GetMatrix();
+    if (m->IsReflection()) {
+      Volume vol(node->GetVolume());
+      TGeoMatrix* mclone = new TGeoCombiTrans(*m);
+      mclone->RegisterYourself();
+      // Reflect just the rotation component
+      mclone->ReflectZ(kFALSE, kTRUE);
+      TGeoNodeMatrix* nodematrix = (TGeoNodeMatrix*)node;
+      nodematrix->SetMatrix(mclone);
+      printout(INFO,"Detector","Reflecting volume: %s ",vol.name());
+      Volume refl = vol.reflect(vol.sensitiveDetector());
+      node->SetVolume(refl.ptr());
     }
   }
 }
@@ -690,7 +694,6 @@ void DetectorImp::endDocument(bool close_geometry)    {
     /// Since we allow now for anonymous shapes,
     /// we will rename them to use the name of the volume they are assigned to
     mgr->CloseGeometry();
-    build_reflections(mgr);
   }
   ShapePatcher patcher(m_volManager, m_world);
   patcher.patchShapes();
diff --git a/DDCore/src/Volumes.cpp b/DDCore/src/Volumes.cpp
index bb44dcfe8..454abad2a 100644
--- a/DDCore/src/Volumes.cpp
+++ b/DDCore/src/Volumes.cpp
@@ -266,6 +266,13 @@ namespace {
     }
     return vol;
   }
+
+  int get_copy_number(TGeoVolume* par)    {
+    TObjArray* a = par ? par->GetNodes() : 0;
+    int copy_nr = (a ? a->GetEntries() : 0);
+    return copy_nr;
+  }
+
 }
 
 /// Default constructor
@@ -568,12 +575,6 @@ Volume Volume::divide(const std::string& divname, int iaxis, int ndiv,
   return nullptr;
 }
 
-Int_t get_copy_number(TGeoVolume* par)    {
-  TObjArray* a = par ? par->GetNodes() : 0;
-  Int_t copy_nr = (a ? a->GetEntries() : 0);
-  return copy_nr;
-}
-
 PlacedVolume _addNode(TGeoVolume* par, TGeoVolume* daughter, int id, TGeoMatrix* transform) {
   TGeoVolume* parent = par;
   if ( !parent )   {
@@ -608,7 +609,6 @@ PlacedVolume _addNode(TGeoVolume* par, TGeoVolume* daughter, int id, TGeoMatrix*
       Double_t det =
         r[0]*r[4]*r[8] + r[3]*r[7]*r[2] + r[6]*r[1]*r[5] -
         r[2]*r[4]*r[6] - r[5]*r[7]*r[0] - r[8]*r[1]*r[3];
-
       /// We have a left handed matrix (determinant < 0). This is a reflection!
       if ( det < 0e0 )   {
         transform->SetBit(TGeoMatrix::kGeoReflection);
@@ -1014,14 +1014,14 @@ std::string dd4hep::toStringMesh(PlacedVolume place, int prec)   {
 
 
   if ( vol->IsA() == TGeoVolumeAssembly::Class() )    {
-    for(Int_t i=0; i<vol->GetNdaughters(); ++i)  {
+    for(int i=0; i<vol->GetNdaughters(); ++i)  {
       os << toStringMesh(vol->GetNode(i), prec) << endl;
     }
     return os.str();
   }
 
   // Prints shape parameters
-  Int_t nvert = 0, nsegs = 0, npols = 0;
+  int nvert = 0, nsegs = 0, npols = 0;
   sol->GetMeshNumbers(nvert, nsegs, npols);
   Double_t* points = new Double_t[3*nvert];
   sol->SetPoints(points);
@@ -1032,7 +1032,7 @@ std::string dd4hep::toStringMesh(PlacedVolume place, int prec)   {
      << " N(mesh)=" << sol->GetNmeshVertices()
      << "  N(vert)=" << nvert << "  N(seg)=" << nsegs << "  N(pols)=" << npols << endl;
     
-  for(Int_t i=0; i<nvert; ++i)   {
+  for(int i=0; i<nvert; ++i)   {
     Double_t* p = points + 3*i;
     Double_t global[3], local[3] = {p[0], p[1], p[2]};
     mat->LocalToMaster(local, global);
diff --git a/DDEve/src/Display.cpp b/DDEve/src/Display.cpp
index c2344b352..7383a4919 100644
--- a/DDEve/src/Display.cpp
+++ b/DDEve/src/Display.cpp
@@ -46,6 +46,7 @@
 #include "TEveCompound.h"
 #include "TEveBoxSet.h"
 #include "TEvePointSet.h"
+#include "TEveGeoShape.h"
 #include "TEveTrackPropagator.h"
 #include "TGeoManager.h"
 
@@ -94,6 +95,8 @@ Display::Display(TEveManager* eve)
   EvePgonSetProjectedContextMenu::install(this);
   ElementListContextMenu::install(this);
   m_detDesc = &Detector::getInstance();
+  TEveGeoShape::GetGeoMangeur()->AddNavigator();
+  TEveGeoShape::GetGeoMangeur()->SetCurrentNavigator(0);
   m_evtHandler = new GenericEventHandler();
   m_evtHandler->Subscribe(this);
   m_detDesc->addExtension<Display>(this);
diff --git a/DDEve/src/Utilities.cpp b/DDEve/src/Utilities.cpp
index 88b357acc..f5d3d09a0 100644
--- a/DDEve/src/Utilities.cpp
+++ b/DDEve/src/Utilities.cpp
@@ -195,8 +195,6 @@ std::pair<bool,TEveElement*> Utilities::LoadDetElement(DetElement de,int levels,
     if (pv.isValid()) {
       TGeoNode* n = pv.ptr();
       TGeoMatrix* matrix = n->GetMatrix();
-      gGeoManager = 0;
-      gGeoManager = new TGeoManager();
       std::pair<bool,TEveElement*> e = createEveShape(0, levels, parent, n, *matrix, de.name());
       TEveElementList* list = dynamic_cast<TEveElementList*>(e.second);
       if ( list )  {
diff --git a/DDG4/include/DDG4/Geant4Converter.h b/DDG4/include/DDG4/Geant4Converter.h
index a71b6810e..d5e097178 100644
--- a/DDG4/include/DDG4/Geant4Converter.h
+++ b/DDG4/include/DDG4/Geant4Converter.h
@@ -32,24 +32,26 @@ namespace dd4hep {
     class Geant4Converter : public detail::GeoHandler, public Geant4Mapping {
     public:
       /// Property: Flag to debug materials during conversion mechanism
-      bool debugMaterials  = false;
+      bool debugMaterials   = false;
       /// Property: Flag to debug elements during conversion mechanism
-      bool debugElements   = false;
+      bool debugElements    = false;
       /// Property: Flag to debug shapes during conversion mechanism
-      bool debugShapes     = false;
+      bool debugShapes      = false;
       /// Property: Flag to debug volumes during conversion mechanism
-      bool debugVolumes    = false;
+      bool debugVolumes     = false;
       /// Property: Flag to debug placements during conversion mechanism
-      bool debugPlacements = false;
+      bool debugPlacements  = false;
+      /// Property: Flag to debug reflections during conversion mechanism
+      bool debugReflections = false;
       /// Property: Flag to debug regions during conversion mechanism
-      bool debugRegions    = false;
+      bool debugRegions     = false;
       /// Property: Flag to debug surfaces during conversion mechanism
-      bool debugSurfaces   = false;
+      bool debugSurfaces    = false;
 
       /// Property: Flag to dump all placements after the conversion procedure
-      bool printPlacements = false;
+      bool printPlacements  = false;
       /// Property: Flag to dump all sensitives after the conversion procedure
-      bool printSensitives = false;
+      bool printSensitives  = false;
 
       /// Property: Check geometrical overlaps for volume placements and G4 imprints 
       bool       checkOverlaps;
diff --git a/DDG4/include/DDG4/Geant4HierarchyDump.h b/DDG4/include/DDG4/Geant4HierarchyDump.h
index d9c3305b4..e28ee2400 100644
--- a/DDG4/include/DDG4/Geant4HierarchyDump.h
+++ b/DDG4/include/DDG4/Geant4HierarchyDump.h
@@ -33,11 +33,23 @@ namespace dd4hep {
      */
     class Geant4HierarchyDump {
     public:
-      Detector& m_detDesc;
+      enum {
+	G4DUMP_ALL     = 0xFFFFFFFF,
+	G4DUMP_LOGVOL  = 1 << 0,
+	G4DUMP_SOLID   = 1 << 1,
+	G4DUMP_SENSDET = 1 << 2,
+	G4DUMP_LIMITS  = 1 << 3,
+	G4DUMP_REGION  = 1 << 4,
+	G4DUMP_MATRIX  = 1 << 5,
+	G4DUMP_LAST
+      };
+
+      Detector&     m_detDesc;
+      unsigned long m_flags = G4DUMP_ALL;
 
     public:
       /// Initializing Constructor
-      Geant4HierarchyDump(Detector& description);
+      Geant4HierarchyDump(Detector& description, unsigned long flags = G4DUMP_ALL);
       /// Standard destructor
       virtual ~Geant4HierarchyDump();
       /// Dump the volume hierarchy as it is known to geant 4
diff --git a/DDG4/plugins/Geant4DetectorGeometryConstruction.cpp b/DDG4/plugins/Geant4DetectorGeometryConstruction.cpp
index 01c13b887..8fa0687e4 100644
--- a/DDG4/plugins/Geant4DetectorGeometryConstruction.cpp
+++ b/DDG4/plugins/Geant4DetectorGeometryConstruction.cpp
@@ -32,27 +32,29 @@ namespace dd4hep {
      *  \ingroup DD4HEP_SIMULATION
      */
     class Geant4DetectorGeometryConstruction : public Geant4DetectorConstruction   {
-      /// Property: Dump geometry hierarchy
-      bool m_dumpHierarchy   = false;
+      /// Property: Dump geometry hierarchy if not NULL. Flags can steer actions. 
+      unsigned long m_dumpHierarchy = 0;
       /// Property: Flag to debug materials during conversion mechanism
-      bool m_debugMaterials  = false;
+      bool m_debugMaterials         = false;
       /// Property: Flag to debug elements during conversion mechanism
-      bool m_debugElements   = false;
+      bool m_debugElements          = false;
       /// Property: Flag to debug shapes during conversion mechanism
-      bool m_debugShapes     = false;
+      bool m_debugShapes            = false;
       /// Property: Flag to debug volumes during conversion mechanism
-      bool m_debugVolumes    = false;
+      bool m_debugVolumes           = false;
       /// Property: Flag to debug placements during conversion mechanism
-      bool m_debugPlacements = false;
+      bool m_debugPlacements        = false;
+      /// Property: Flag to debug reflections during conversion mechanism
+      bool m_debugReflections       = false;
       /// Property: Flag to debug regions during conversion mechanism
-      bool m_debugRegions    = false;
+      bool m_debugRegions           = false;
       /// Property: Flag to debug regions during conversion mechanism
-      bool m_debugSurfaces   = false;
+      bool m_debugSurfaces          = false;
 
       /// Property: Flag to dump all placements after the conversion procedure
-      bool m_printPlacements = false;
+      bool m_printPlacements        = false;
       /// Property: Flag to dump all sensitives after the conversion procedure
-      bool m_printSensitives = false;
+      bool m_printSensitives        = false;
 
       /// Property: Printout level of info object
       int  m_geoInfoPrintLevel;
@@ -129,6 +131,7 @@ Geant4DetectorGeometryConstruction::Geant4DetectorGeometryConstruction(Geant4Con
   declareProperty("DebugShapes",       m_debugShapes);
   declareProperty("DebugVolumes",      m_debugVolumes);
   declareProperty("DebugPlacements",   m_debugPlacements);
+  declareProperty("DebugReflections",  m_debugReflections);
   declareProperty("DebugRegions",      m_debugRegions);
   declareProperty("DebugSurfaces",     m_debugSurfaces);
 
@@ -151,13 +154,14 @@ void Geant4DetectorGeometryConstruction::constructGeo(Geant4DetectorConstruction
   Geant4Mapping&  g4map = Geant4Mapping::instance();
   DetElement      world = ctxt->description.world();
   Geant4Converter conv(ctxt->description, outputLevel());
-  conv.debugMaterials  = m_debugMaterials;
-  conv.debugElements   = m_debugElements;
-  conv.debugShapes     = m_debugShapes;
-  conv.debugVolumes    = m_debugVolumes;
-  conv.debugPlacements = m_debugPlacements;
-  conv.debugRegions    = m_debugRegions;
-  conv.debugSurfaces   = m_debugSurfaces;
+  conv.debugMaterials   = m_debugMaterials;
+  conv.debugElements    = m_debugElements;
+  conv.debugShapes      = m_debugShapes;
+  conv.debugVolumes     = m_debugVolumes;
+  conv.debugRegions     = m_debugRegions;
+  conv.debugSurfaces    = m_debugSurfaces;
+  conv.debugPlacements  = m_debugPlacements;
+  conv.debugReflections = m_debugReflections;
 
   ctxt->geometry       = conv.create(world).detach();
   ctxt->geometry->printLevel = outputLevel();
@@ -167,8 +171,8 @@ void Geant4DetectorGeometryConstruction::constructGeo(Geant4DetectorConstruction
   context()->kernel().setWorld(w);
   // Create Geant4 volume manager only if not yet available
   g4map.volumeManager();
-  if ( m_dumpHierarchy )   {
-    Geant4HierarchyDump dmp(ctxt->description);
+  if ( m_dumpHierarchy != 0 )   {
+    Geant4HierarchyDump dmp(ctxt->description, m_dumpHierarchy);
     dmp.dump("",w);
   }
   ctxt->world = w;
diff --git a/DDG4/python/DDG4.py b/DDG4/python/DDG4.py
index a6689f676..07eee9f27 100644
--- a/DDG4/python/DDG4.py
+++ b/DDG4/python/DDG4.py
@@ -688,9 +688,9 @@ class Geant4:
     phys.adopt(opt)
     return opt
 
-  def setupGun(self, name, particle, energy, isotrop=True,
+  def setupGun(self, name, particle, energy, typ="Geant4ParticleGun", isotrop=True,
                multiplicity=1, position=(0.0, 0.0, 0.0), register=True, **args):
-    gun = GeneratorAction(self.kernel(), "Geant4ParticleGun/" + name, True)
+    gun = GeneratorAction(self.kernel(), typ + "/" + name, True)
     for i in args.items():
       setattr(gun, i[0], i[1])
     gun.energy = energy
diff --git a/DDG4/src/Geant4Converter.cpp b/DDG4/src/Geant4Converter.cpp
index c7cfdaebc..5fe2d9b87 100644
--- a/DDG4/src/Geant4Converter.cpp
+++ b/DDG4/src/Geant4Converter.cpp
@@ -130,12 +130,12 @@ void Geant4AssemblyVolume::imprint(Geant4GeometryInfo&   info,
 
     G4Transform3D Ta( *(triplets[i].GetRotation()),
                       triplets[i].GetTranslation() );
-    if ( triplets[i].IsReflection() )  { Ta = Ta * G4ReflectZ3D(); }
+    if ( triplets[i].IsReflection() )  {
+      Ta = Ta * G4ReflectZ3D();
+    }
 
     G4Transform3D Tfinal = transformation * Ta;
-
-    if ( triplets[i].GetVolume() )
-    {
+    if ( triplets[i].GetVolume() )    {
       // Generate the unique name for the next PV instance
       // The name has format:
       //
@@ -161,6 +161,11 @@ void Geant4AssemblyVolume::imprint(Geant4GeometryInfo&   info,
       // (as we allow 3D transformation use G4ReflectionFactory to
       //  take into account eventual reflection)
       //
+#if 0
+      printout(INFO,"Geant4Converter","+++ Place %svolume %s in assembly.",
+	       triplets[i].IsReflection() ? "REFLECTED " : "",
+	       detail::tools::placementPath(new_chain).c_str());
+#endif
       G4PhysicalVolumesPair pvPlaced
         = G4ReflectionFactory::Instance()->Place( Tfinal,
                                                   pvName.str().c_str(),
@@ -784,11 +789,16 @@ void* Geant4Converter::handleAssembly(const string& name, const TGeoNode* node)
       MyTransform3D transform(tr->GetTranslation(),tr->IsRotation() ? tr->GetRotationMatrix() : s_identity_rot);
 
       if ( is_left_handed(tr) )   {
-        //transform = transform * G4ReflectZ3D();
-        printout(ALWAYS, "Geant4Converter", "+++ Assembly: **** : Placing reflected assembly. dau:%s "
-                 "to mother %s Tr:x=%8.3f y=%8.3f z=%8.3f",
+	G4Scale3D     scale;
+	G4Rotate3D    rot;
+	G4Translate3D trans;
+	transform.getDecomposition(scale, rot, trans);
+	printout(debugReflections ? ALWAYS : lvl, "Geant4Converter",
+		 "+++ Placing reflected ASSEMBLY. dau:%s to mother %s "
+		 "Tr:x=%8.1f y=%8.1f z=%8.1f   Scale:x=%4.2f y=%4.2f z=%4.2f",
                  dau_vol->GetName(), mot_vol->GetName(),
-                 transform.dx(), transform.dy(), transform.dz());
+                 transform.dx(), transform.dy(), transform.dz(),
+		 scale.xx(), scale.yy(), scale.zz());
       }
 
       if ( dau_vol->IsA() == TGeoVolumeAssembly::Class() )  {
@@ -837,6 +847,7 @@ void* Geant4Converter::handlePlacement(const string& name, const TGeoNode* node)
     printout(lvl, "Geant4Converter", "++ Placement %s not converted [Veto'ed for simulation]",node->GetName());
     return 0;
   }
+#if 0
   if ( g4 )    {
     const TGeoNode*   old_node = (*g4it).first.ptr();
     const TGeoNode*   new_node = node;
@@ -844,11 +855,13 @@ void* Geant4Converter::handlePlacement(const string& name, const TGeoNode* node)
     TGeoVolume* new_vol  = new_node->GetVolume();
     TGeoMatrix* old_tr   = old_node->GetMatrix();
     TGeoMatrix* new_tr   = new_node->GetMatrix();
-    printout(ALWAYS, "Geant4Converter", "+++ Placement: **** Reuse: OLD: %s vol: %s %s   NEW: %s vol: %s %s",
+    printout(debugReflections ? ALWAYS : lvl, "Geant4Converter",
+	     "+++ Placement: **** Reuse: OLD: %s vol: %s %s   NEW: %s vol: %s %s",
              old_node->GetName(), old_vol->GetName(), is_left_handed(old_tr) ? "    REFLECTED" : "NOT REFLECTED", 
              new_node->GetName(), new_vol->GetName(), is_left_handed(new_tr) ? "    REFLECTED" : "NOT REFLECTED");
   }
-  //g4 = nullptr;
+#endif
+  g4 = nullptr;
   if (!g4) {
     TGeoVolume* mot_vol = node->GetMotherVolume();
     TGeoMatrix* tr = node->GetMatrix();
@@ -861,7 +874,6 @@ void* Geant4Converter::handlePlacement(const string& name, const TGeoNode* node)
              node->IsA()->GetName(), vol);
     }
     else {
-      G4Transform3D Ta;
       int           copy               = node->GetNumber();
       bool          node_is_reflected  = is_left_handed(tr);
       bool          node_is_assembly   = vol->IsA() == TGeoVolumeAssembly::Class();
@@ -869,12 +881,6 @@ void* Geant4Converter::handlePlacement(const string& name, const TGeoNode* node)
       MyTransform3D transform(tr->GetTranslation(),tr->IsRotation() ? tr->GetRotationMatrix() : s_identity_rot);
       Geant4GeometryMaps::VolumeMap::const_iterator volIt = info.g4Volumes.find(mot_vol);
 
-      if ( node_is_reflected )   {
-        printout(ALWAYS, "Geant4Converter", "+++ Placement: **** : Placing reflected volume. dau:%s "
-                 "to mother %s Tr:x=%8.3f y=%8.3f z=%8.3f",
-                 vol->GetName(), mot_vol->GetName(),
-                 transform.dx(), transform.dy(), transform.dz());
-      }
       if ( mother_is_assembly )   {
         //
         // Mother is an assembly:
@@ -893,10 +899,16 @@ void* Geant4Converter::handlePlacement(const string& name, const TGeoNode* node)
         // Node is an assembly:
         // Imprint the assembly. The mother MUST already be transformed.
         //
-        printout(lvl, "Geant4Converter", "+++ Assembly: makeImprint: dau:%s in mother %s "
-                 "Tr:x=%8.3f y=%8.3f z=%8.3f",
-                 node->GetName(), mot_vol ? mot_vol->GetName() : "<unknown>",
-                 transform.dx(), transform.dy(), transform.dz());
+	G4Scale3D     scale;
+	G4Rotate3D    rot;
+	G4Translate3D trans;
+	transform.getDecomposition(scale, rot, trans);
+        printout(lvl, "Geant4Converter", "+++ Assembly: makeImprint: dau:%-12s %s in mother %-12s "
+                 "Tr:x=%8.1f y=%8.1f z=%8.1f   Scale:x=%4.2f y=%4.2f z=%4.2f",
+                 node->GetName(), node_is_reflected ? "(REFLECTED)" : "",
+		 mot_vol ? mot_vol->GetName() : "<unknown>",
+                 transform.dx(), transform.dy(), transform.dz(),
+		 scale.xx(), scale.yy(), scale.zz());
         Geant4AssemblyVolume* ass = (Geant4AssemblyVolume*)info.g4AssemblyVolumes[node];
         Geant4AssemblyVolume::Chain chain;
         chain.emplace_back(node);
@@ -906,6 +918,9 @@ void* Geant4Converter::handlePlacement(const string& name, const TGeoNode* node)
       else if ( node != info.manager->GetTopNode() && volIt == info.g4Volumes.end() )  {
         throw logic_error("Geant4Converter: Invalid mother volume found!");
       }
+      G4Scale3D     scale;
+      G4Rotate3D    rot;
+      G4Translate3D trans;
       G4LogicalVolume* g4vol = info.g4Volumes[vol];
       G4LogicalVolume* g4mot = info.g4Volumes[mot_vol];
       G4PhysicalVolumesPair pvPlaced =
@@ -916,6 +931,14 @@ void* Geant4Converter::handlePlacement(const string& name, const TGeoNode* node)
                                                false,     // no boolean operations
                                                copy,      // its copy number
                                                checkOverlaps);
+      transform.getDecomposition(scale, rot, trans);
+      printout(debugReflections ? ALWAYS : lvl, "Geant4Converter",
+	       "+++ Place %svolume %-12s in mother %-12s "
+	       "Tr:x=%8.1f y=%8.1f z=%8.1f   Scale:x=%4.2f y=%4.2f z=%4.2f",
+	       node_is_reflected ? "REFLECTED " : "", _v.name(),
+	       mot_vol ? mot_vol->GetName() : "<unknown>",
+	       transform.dx(), transform.dy(), transform.dz(),
+	       scale.xx(), scale.yy(), scale.zz());
       // First 2 cases can be combined.
       // Leave them separated for debugging G4ReflectionFactory for now...
       if ( node_is_reflected  && !pvPlaced.second )
@@ -1453,6 +1476,7 @@ Geant4Converter& Geant4Converter::create(DetElement top) {
   //setPrintLevel(VERBOSE);
   //debugMaterials  = true;
   //debugElements   = true;
+  debugReflections  = true;
   
 #if ROOT_VERSION_CODE >= ROOT_VERSION(6,17,0)
   handleArray(this, geo.manager->GetListOfGDMLMatrices(), &Geant4Converter::handleMaterialProperties);
diff --git a/DDG4/src/Geant4HierarchyDump.cpp b/DDG4/src/Geant4HierarchyDump.cpp
index 390d45204..190d3480f 100644
--- a/DDG4/src/Geant4HierarchyDump.cpp
+++ b/DDG4/src/Geant4HierarchyDump.cpp
@@ -67,19 +67,11 @@ static const char* _T(const std::string& str) {
   return str.c_str();
 }
 
-enum {
-  G4DUMP_ALL = 0xFFFFFFFF,
-  G4DUMP_LOGVOL = 1 << 0,
-  G4DUMP_SOLID = 1 << 1,
-  G4DUMP_SENSDET = 1 << 2,
-  G4DUMP_LIMITS = 1 << 3,
-  G4DUMP_REGION = 1 << 4,
-  G4DUMP_LAST
-};
-static unsigned long m_flags = ~0x0UL;
-
 /// Initializing Constructor
-Geant4HierarchyDump::Geant4HierarchyDump(Detector& description) : m_detDesc(description) {
+Geant4HierarchyDump::Geant4HierarchyDump(Detector& description, unsigned long flags)
+  : m_detDesc(description), m_flags(flags)
+{
+  m_flags &= ~G4DUMP_SOLID;
 }
 
 /// Standard destructor
@@ -87,24 +79,25 @@ Geant4HierarchyDump::~Geant4HierarchyDump() {
 }
 
 void Geant4HierarchyDump::dump(const string& indent, const G4VPhysicalVolume* v) const {
-  G4LogicalVolume* lv = v->GetLogicalVolume();
-  G4VSensitiveDetector* sd = lv->GetSensitiveDetector();
-  G4Material* mat = lv->GetMaterial();
-  G4VSolid* sol = lv->GetSolid();
-  G4Region* rg = lv->GetRegion();
-  G4UserLimits* ul = lv->GetUserLimits();
-  G4int ndau = lv->GetNoDaughters();
-  char text[32];
+  G4LogicalVolume*      lv   = v->GetLogicalVolume();
+  G4VSensitiveDetector* sd   = lv->GetSensitiveDetector();
+  G4RotationMatrix*     rot  = v->GetObjectRotation();
+  G4Material*           mat  = lv->GetMaterial();
+  G4VSolid*             sol  = lv->GetSolid();
+  G4Region*             rg   = lv->GetRegion();
+  G4UserLimits*         ul   = lv->GetUserLimits();
+  G4int                 ndau = lv->GetNoDaughters();
   stringstream str;
+  char text[32];
 
-  m_flags &= ~G4DUMP_SOLID;
-  printout(INFO, "Geant4Hierarchy", "%s -> Placement:%s LV:%s Material:%s Solid:%s # of Daughters:%d", indent.c_str(),
-           _T(v->GetName()), _T(lv->GetName()), _T(mat->GetName()), _T(sol->GetName()), ndau);
+  printout(INFO, "Geant4Hierarchy", "%s -> Placement:%s LV:%s Material:%s Solid:%s # of Daughters:%d CopyNo:%d",
+	   _T(indent), _T(v->GetName()), _T(lv->GetName()), _T(mat->GetName()),
+	   _T(sol->GetName()), ndau, v->GetCopyNo());
 
   if (sd && (m_flags & G4DUMP_SOLID)) {
     str.str("");
     sol->StreamInfo(str);
-    printout(INFO, "Geant4Hierarchy", "%s    Solid:%s", indent.c_str(), str.str().c_str());
+    printout(INFO, "Geant4Hierarchy", "%s    Solid:%s", _T(indent), str.str().c_str());
   }
   if (rg && (m_flags & G4DUMP_LIMITS)) {
     G4UserLimits* rg_limits = rg->GetUserLimits();
@@ -116,11 +109,20 @@ void Geant4HierarchyDump::dump(const string& indent, const G4VPhysicalVolume* v)
     printout(INFO, "Geant4Hierarchy", str.str().c_str());
   }
   if (sd && (m_flags & G4DUMP_SENSDET)) {
-    printout(INFO, "Geant4Hierarchy", "%s    Sens.det:%p %s path:%s Active:%-3s #Coll:%d", indent.c_str(), sd,
+    printout(INFO, "Geant4Hierarchy", "%s    Sens.det:%p %s path:%s Active:%-3s #Coll:%d", _T(indent), sd,
              _T(sd->GetName()), _T(sd->GetFullPathName()), yes_no(sd->isActive()), sd->GetNumberOfCollections());
   }
   if (ul && (m_flags & G4DUMP_LIMITS)) {
-    printout(INFO, "Geant4Hierarchy", "%s    Limits:%s ", indent.c_str(), _T(ul->GetType()));
+    printout(INFO, "Geant4Hierarchy", "%s    Limits:%s ", _T(indent), _T(ul->GetType()));
+  }
+  if (rot && (m_flags & G4DUMP_MATRIX)) {
+    const G4ThreeVector     t = v->GetTranslation();
+    const G4RotationMatrix& r = *rot;
+    double det =
+      r.xx()*r.yy()*r.zz() + r.xy()*r.yz()*r.zx() + r.xz()*r.yx()*r.zy() -
+      r.zx()*r.yy()*r.xz() - r.zy()*r.yz()*r.xx() - r.zz()*r.yx()*r.xy();
+    printout(INFO, "Geant4Hierarchy", "%s    Matrix: %sREFLECTED Tr: %8.3g %8.3g %8.3g [mm]",
+	     _T(indent), det > 0e0 ? "NOT " : "", t.x(), t.y(), t.z());
   }
   for (G4int idau = 0; idau < ndau; ++idau) {
     ::snprintf(text, sizeof(text), "  %-3d", idau);
diff --git a/DDG4/src/Geant4ParticleGenerator.cpp b/DDG4/src/Geant4ParticleGenerator.cpp
index f3002c529..898c2ac7d 100644
--- a/DDG4/src/Geant4ParticleGenerator.cpp
+++ b/DDG4/src/Geant4ParticleGenerator.cpp
@@ -130,16 +130,16 @@ void Geant4ParticleGenerator::operator()(G4Event*) {
     Particle* p = new Particle();
     direction = m_direction;
     getParticleDirection(i, direction, momentum);
-    unit_direction = direction.unit();
-    p->id         = inter->nextPID();
-    p->status    |= G4PARTICLE_GEN_STABLE;
-    p->mask       = m_mask;
-    p->pdgID      = m_particle->GetPDGEncoding();
-
-    p->psx        = unit_direction.X()*momentum;
-    p->psy        = unit_direction.Y()*momentum;
-    p->psz        = unit_direction.Z()*momentum;
-    p->mass       = m_particle->GetPDGMass();
+    unit_direction  = direction.unit();
+    p->id           = inter->nextPID();
+    p->status      |= G4PARTICLE_GEN_STABLE;
+    p->mask         = m_mask;
+    p->pdgID        = m_particle->GetPDGEncoding();
+
+    p->psx          = unit_direction.X()*momentum;
+    p->psy          = unit_direction.Y()*momentum;
+    p->psz          = unit_direction.Z()*momentum;
+    p->mass         = m_particle->GetPDGMass();
     p->charge       = m_particle->GetPDGCharge();
     p->spin[0]      = 0;
     p->spin[1]      = 0;
diff --git a/examples/ClientTests/CMakeLists.txt b/examples/ClientTests/CMakeLists.txt
index f77c57512..f5779e4fb 100644
--- a/examples/ClientTests/CMakeLists.txt
+++ b/examples/ClientTests/CMakeLists.txt
@@ -46,7 +46,7 @@ install(TARGETS multipleGeo RUNTIME DESTINATION bin)
 #
 #
 set(ClientTestsEx_INSTALL ${CMAKE_INSTALL_PREFIX}/examples/ClientTests)
-dd4hep_install_dir( compact scripts ref DESTINATION ${ClientTestsEx_INSTALL} )
+dd4hep_install_dir( compact scripts ref eve DESTINATION ${ClientTestsEx_INSTALL} )
 #--------------------------------------------------------------------------
 
 #--------------------------------------------------------------------------
diff --git a/examples/ClientTests/compact/NestedBoxReflection.xml b/examples/ClientTests/compact/NestedBoxReflection.xml
index de44bad6e..745c5bcc0 100644
--- a/examples/ClientTests/compact/NestedBoxReflection.xml
+++ b/examples/ClientTests/compact/NestedBoxReflection.xml
@@ -7,20 +7,17 @@
   </includes>
 
   <define>
-    <constant name="world_size" value="30*m"/>
+    <constant name="world_size" value="6*m"/>
     <constant name="world_x" value="world_size"/>
     <constant name="world_y" value="world_size"/>
     <constant name="world_z" value="world_size"/>
-    <constant name="HcalBarrel_rmin" value="300*cm"/>
-    <constant name="HcalBarrel_rmax" value="500*cm"/>
-    <constant name="HcalBarrel_zmax" value="600*cm"/>
   </define>
 
   <display>
     <vis name="Invisible" showDaughters="false" visible="false"/>
     <vis name="InvisibleWithChildren" showDaughters="true" visible="false"/>
-    <vis name="LightGrey"     alpha="0.3" r="0.7" g="0.7" b="0.7" showDaughters="true" visible="true"/>
-    <vis name="DarkGrey"      alpha="0.3" r="0.3" g="0.3" b="0.3" showDaughters="true" visible="true"/>
+    <vis name="VisibleGrey"   alpha="0.4" r="0.7" g="0.7" b="0.7" showDaughters="true" visible="true"/>
+    <vis name="DarkGrey"      alpha="0.4" r="0.3" g="0.3" b="0.3" showDaughters="true" visible="true"/>
     <vis name="VisibleRed"    alpha="0.6" r="1.0" g="0.0" b="0.0" showDaughters="true" visible="true"/>
     <vis name="VisibleBlue"   alpha="0.6" r="0.0" g="0.0" b="1.0" showDaughters="true" visible="true"/>
     <vis name="VisibleYellow" alpha="0.6" r="1.0" g="1.0" b="0.0" showDaughters="true" visible="true"/>
@@ -37,24 +34,53 @@
     <detector id="1" name="NestedBox" type="NestedBoxReflection" readout="NestedBoxHits" vis="VisibleGreen" limits="cal_limits">
       <comment>A box with 3 boxes inside spanning a coordinate system</comment>
       <assembly/>
-      <dimensions x="50*cm" y="70*cm" z="90*cm"/>
-      <xxxreflect_z/>
-      <no-reflect name="ReflectionY">
-	<rotation phiY="270.*deg" thetaY="90.*deg" phiX=" 0.*deg" thetaX="90.*deg" phiZ="0.*deg" thetaZ="0.*deg"/>
-	<position x="0" y="0" z="-130*cm"/>
-      </no-reflect>
+      <dimensions x="50*cm"   y="70*cm"   z="90*cm" level="2">
+	<position x="400*cm" y="0*cm" z="0*cm"/>
+      </dimensions>
       <reflect name="ReflectionX">
 	<rotation phiX="180.*deg" thetaX="90.*deg" phiY="90.*deg" thetaY="90.*deg" phiZ="0.*deg" thetaZ="0.*deg"/>
-	<position x="0" y="0" z="-130*cm"/>
+	<position x="200*cm" y="0*cm" z="0*cm"/>
       </reflect>
+      <reflect_x  x="-200*cm" y="0*cm"    z="0*cm"/>
 
-    </detector>
+      <reflect name="ReflectionY">
+	<rotation phiY="270.*deg" thetaY="90.*deg" phiX=" 0.*deg" thetaX="90.*deg" phiZ="0.*deg" thetaZ="0.*deg"/>
+	<position x="0*cm" y="200*cm" z="0*cm"/>
+      </reflect>
+      <reflect_y  x="0*cm"    y="-200*cm" z="0*cm"/>
+
+      <reflect_z  x="0*cm"    y="0*cm"    z="200*cm"/>
+      <reflect_z  x="0*cm"    y="0*cm"    z="-200*cm"/>
+<!--
+      <reflect_x  x="-200*cm" y="200*cm"    z="0*cm"/>
+      <reflect_x  x="-200*cm" y="200*cm"    z="200*cm"/>
+      <reflect_x  x="-200*cm" y="200*cm"    z="-200*cm"/>
+      <reflect_x  x="-200*cm" y="-200*cm"   z="200*cm"/>
+      <reflect_x  x="-200*cm" y="-200*cm"   z="-200*cm"/>
+      <reflect_x  x="-200*cm" y="-200*cm"   z="0*cm"/>
 
+      <reflect_y  x="0*cm"    y="200*cm"  z="200*cm"/>
+      <reflect_y  x="0*cm"    y="200*cm"  z="-200*cm"/>
+      <reflect_y  x="0*cm"    y="-200*cm" z="200*cm"/>
+      <reflect_y  x="0*cm"    y="-200*cm" z="-200*cm"/>
+      <reflect_y  x="200*cm"  y="0*cm"    z="200*cm"/>
+      <reflect_y  x="-200*cm" y="0*cm"    z="200*cm"/>
+      <reflect_y  x="200*cm"  y="0*cm"    z="-200*cm"/>
+      <reflect_y  x="-200*cm" y="0*cm"    z="-200*cm"/>
+      
+      <reflect_z  x="200*cm"  y="200*cm"  z="0*cm"/>
+      <reflect_z  x="200*cm"  y="200*cm"  z="200*cm"/>
+      <reflect_z  x="200*cm"  y="200*cm"  z="-200*cm"/>
+      <reflect_z  x="200*cm"  y="-200*cm" z="200*cm"/>
+      <reflect_z  x="200*cm"  y="-200*cm" z="-200*cm"/>
+      <reflect_z  x="200*cm"  y="-200*cm" z="0*cm"/>
+-->
+    </detector>
   </detectors>
   
   <readouts>
     <readout name="NestedBoxHits">
-      <id>system:8,lvl4:4,lvl3:4,lvl2:4,lvl1:4,lvl0:4</id> 
+      <id>system:8,lvl4:5,lvl3:5,lvl2:5,lvl1:5,lvl0:5</id> 
     </readout>
   </readouts>
 
diff --git a/examples/ClientTests/scripts/Check_reflection.py b/examples/ClientTests/scripts/Check_reflection.py
index 201073c17..21be799d8 100644
--- a/examples/ClientTests/scripts/Check_reflection.py
+++ b/examples/ClientTests/scripts/Check_reflection.py
@@ -7,10 +7,14 @@
 """
 from __future__ import absolute_import, unicode_literals
 import logging
+import time
 import sys
+import os
+from g4units import TeV, GeV, MeV, mm, cm, m
 from ddsix.moves import range
 
 logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.INFO)
+logger = logging.getLogger(__name__)
 
 
 def help():
@@ -23,7 +27,10 @@ def help():
 def run():
   geo = None
   vis = False
+  dump = False
   batch = False
+  install_dir = os.environ['DD4hepINSTALL']
+  #
   for i in list(range(len(sys.argv))):
     c = sys.argv[i].upper()
     if c.find('BATCH') < 2 and c.find('BATCH') >= 0:
@@ -32,6 +39,8 @@ def run():
       geo = sys.argv[i + 1]
     elif c[:4] == '-VIS':
       vis = True
+    elif c[:4] == '-DUM':
+      dump = True
 
   if not geo:
     help()
@@ -39,28 +48,102 @@ def run():
 
   import DDG4
   kernel = DDG4.Kernel()
+  description = kernel.detectorDescription()
+  DDG4.setPrintLevel(DDG4.OutputLevel.INFO)
+  DDG4.importConstants(description)
+  #
   # Configure UI
-  geant4 = DDG4.Geant4(kernel, tracker='Geant4TrackerCombineAction')
+  geant4 = DDG4.Geant4(kernel)
+  ui = None
   if batch:
     geant4.setupCshUI(ui=None, vis=None)
     kernel.UI = 'UI'
   else:
-    geant4.setupCshUI(vis=vis)
+    ui = geant4.setupCshUI(vis=vis)
   Output = DDG4.OutputLevel
+
   seq, act = geant4.addDetectorConstruction("Geant4DetectorGeometryConstruction/ConstructGeo")
+  act.DebugReflections = True
   act.DebugMaterials = False
   act.DebugElements = False
   act.DebugVolumes = False
   act.DebugShapes = False
-
+  if dump:
+    act.DumpHierarchy = ~0x0
+  #
   kernel.setOutputLevel(str('Geant4Converter'), Output.WARNING)
   kernel.loadGeometry(geo)
+  #
+  geant4.printDetectors()
   # Configure field
   geant4.setupTrackingField(prt=True)
+  logger.info("#  Setup random generator")
+  rndm = DDG4.Action(kernel, 'Geant4Random/Random')
+  rndm.Seed = 987654321
+  rndm.initialize()
+  #
+  # Setup detector
+  seq, act = geant4.setupCalorimeter('NestedBox')
+  #
+  # Configure I/O
+  geant4.setupROOTOutput('RootOutput', 'Reflections_' + time.strftime('%Y-%m-%d_%H-%M'), mc_truth=True)
+  #
+  # Setup particle gun
+  geant4.setupGun(name="Gun",
+                  particle='e-',
+                  energy=1000 * GeV,
+                  multiplicity=2,
+                  position=(0*m,0*m,0*m),
+                  PhiMin=0.0, PhiMax=3.141*2.0,
+                  ThetaMin=0.0, ThetaMax=3.141)
+
+  logger.info("#  ....and handle the simulation particles.")
+  part = DDG4.GeneratorAction(kernel, str('Geant4ParticleHandler/ParticleHandler'))
+  kernel.generatorAction().adopt(part)
+  part.MinimalKineticEnergy = 100 * MeV
+  part.SaveProcesses = ['Decay']
+  part.OutputLevel = 5  # generator_output_level
+  part.enableUI()
+  user = DDG4.Action(kernel, str('Geant4TCUserParticleHandler/UserParticleHandler'))
+  user.TrackingVolume_Rmax = 3.0 * m
+  user.TrackingVolume_Zmax = 2.0 * m
+  user.enableUI()
+  part.adopt(user)
+  #
+  #
+  prt = DDG4.EventAction(kernel, str('Geant4ParticlePrint/ParticlePrint'))
+  prt.OutputLevel = Output.INFO
+  prt.OutputType = 3  # Print both: table and tree
+  kernel.eventAction().adopt(prt)
+  #
   # Now build the physics list:
-  geant4.setupPhysics('')
-  kernel.physicsList().enableUI()
-  DDG4.setPrintLevel(DDG4.OutputLevel.INFO)
+  phys = geant4.setupPhysics(str('QGSP_BERT'))
+  ph = geant4.addPhysics(str('Geant4PhysicsList/Myphysics'))
+  ph.addPhysicsConstructor(str('G4StepLimiterPhysics'))
+  ph.addParticleConstructor(str('G4Geantino'))
+  ph.addParticleConstructor(str('G4BosonConstructor'))
+  #
+  # Add special particle types from specialized physics constructor
+  part = geant4.addPhysics('Geant4ExtraParticles/ExtraParticles')
+  part.pdgfile = os.path.join(install_dir, 'examples/DDG4/examples/particle.tbl')
+  #
+  # Add global range cut
+  rg = geant4.addPhysics('Geant4DefaultRangeCut/GlobalRangeCut')
+  rg.RangeCut = 0.7 * mm
+  #
+  phys.dump()
+  #
+  #
+  if ui and vis:
+    cmds = []
+    cmds.append('/control/verbose 2')
+    cmds.append('/run/initialize')
+    cmds.append('/vis/open OGL')
+    cmds.append('/vis/verbose errors')
+    cmds.append('/vis/drawVolume')
+    cmds.append('/vis/viewer/set/viewpointThetaPhi 55. 45.')
+    cmds.append('/vis/scene/add/axes 0 0 0 3 m')
+    ui.Commands = cmds
   kernel.NumEvents = 0
   kernel.configure()
   kernel.initialize()
diff --git a/examples/ClientTests/scripts/Check_shape_vis.mac b/examples/ClientTests/scripts/Check_shape_vis.mac
index bdd89275c..33ff74c4f 100644
--- a/examples/ClientTests/scripts/Check_shape_vis.mac
+++ b/examples/ClientTests/scripts/Check_shape_vis.mac
@@ -4,6 +4,8 @@
 /vis/verbose errors
 /vis/drawVolume
 /vis/viewer/set/viewpointThetaPhi 55. 45.
-/vis/scene/add/axes 0 0 0 1 m
+/vis/scene/add/axes 0 0 0 3 m
+
+
 /vis/viewer/zoom  2
 /vis/viewer/refresh
diff --git a/examples/ClientTests/scripts/SiliconBlock.py b/examples/ClientTests/scripts/SiliconBlock.py
index bdda06fa0..2f77739ea 100644
--- a/examples/ClientTests/scripts/SiliconBlock.py
+++ b/examples/ClientTests/scripts/SiliconBlock.py
@@ -75,9 +75,9 @@ def run():
 
   # Now build the physics list:
   phys = geant4.setupPhysics('QGSP_BERT')
-  ph = DDG4.PhysicsList(kernel, 'Geant4PhysicsList/Myphysics')
-  ph.addParticleConstructor('G4Geantino')
-  ph.addParticleConstructor('G4BosonConstructor')
+  ph = DDG4.PhysicsList(kernel, str('Geant4PhysicsList/Myphysics'))
+  ph.addParticleConstructor(str('G4Geantino'))
+  ph.addParticleConstructor(str('G4BosonConstructor'))
   ph.enableUI()
   phys.adopt(ph)
   phys.dump()
diff --git a/examples/ClientTests/src/NestedBoxReflection_geo.cpp b/examples/ClientTests/src/NestedBoxReflection_geo.cpp
index 937ab6c3b..1897890ab 100644
--- a/examples/ClientTests/src/NestedBoxReflection_geo.cpp
+++ b/examples/ClientTests/src/NestedBoxReflection_geo.cpp
@@ -13,8 +13,10 @@
 
 // Framework includes
 #include "DD4hep/Printout.h"
+#include "DD4hep/MatrixHelpers.h"
 #include "DD4hep/DetFactoryHelper.h"
 #include "XML/VolumeBuilder.h"
+#include "XML/Utilities.h"
 #include <cmath>
 
 using namespace std;
@@ -74,12 +76,12 @@ namespace   {
 
     void place_boxes(int level, Volume vol)    {
       if ( level >= 0 )   {
-        Box          box = vol.solid();
-        double       line= 0.015;
-        double       bx  = box.x();
-        double       by  = box.y();
-        double       bz  = box.z();
-        Material     mat = vol.material();
+        Box          box  = vol.solid();
+        double       line = 0.015;
+        double       bx   = box.x();
+        double       by   = box.y();
+        double       bz   = box.z();
+        Material     mat  = description.material("Si");
         Box          small_box(bx*0.2, by*0.2, bz*0.2);
         const char*  cols[4] = {"VisibleRed","VisibleBlue","VisibleGreen","VisibleYellow"};
         const char*  c;
@@ -146,63 +148,84 @@ namespace   {
         printout(INFO,"NestedBoxReflection","++ Volume: %s  Color: %s", v.name(), c);
       }
     }
+    
+    PlacedVolume place(Volume mother, Volume vol, xml_elt_t e, int level, int copyNo, char reflection)   {
+      Position    pos;
+      RotationZYX rot;
+      xml_dim_t   xpos = xml_dim_t(e).child(_U(position), false);
+      xml_dim_t   xrot = xml_dim_t(e).child(_U(rotation), false);
+      if ( !xpos.ptr() ) xpos = e;
+      if ( xpos.ptr()  ) pos = Position(xpos.x(0),xpos.y(0),xpos.z(0));
+      if ( xrot.ptr()  ) rot = RotationZYX(xrot.x(0),xrot.y(0),xrot.z(0));
+
+      TGeoHMatrix* mat = detail::matrix::_transform(pos, rot);
+      switch(reflection)  {
+      case 'X':
+	mat->ReflectX(kTRUE, kTRUE);
+	break;
+      case 'Y':
+	mat->ReflectY(kTRUE, kTRUE);
+	break;
+      case 'Z':
+      default:
+	mat->ReflectZ(kTRUE, kTRUE);
+	break;
+      }
+      PlacedVolume pv = mother.placeVolume(vol, mat);
+      pv.addPhysVolID(_toString(level,"lvl%d"), copyNo);
+      return pv;
+    }
 
     Ref_t create()    {
-      xml_dim_t  x_box(x_det.dimensions()); 
-      int        max_level = 3;
-      double     bx = x_box.x();
-      double     by = x_box.y();
-      double     bz = x_box.z();
-      Volume     v_det;
-      Box        box_solid(bx,by,bz);
-      Volume     box_vol(x_det.nameStr()+"_box",box_solid,description.air());  
+      xml_dim_t    x_box(x_det.dimensions()); 
+      int          levels = x_box.level(2);
+      double       bx = x_box.x();
+      double       by = x_box.y();
+      double       bz = x_box.z();
+      Volume       v_det;
+      Box          box_solid(bx,by,bz);
+      Volume       box_vol("nested_box",box_solid,description.air());  
       PlacedVolume pv;
-      int cnt = 1;
 
       sensitive.setType("tracker");
-      box_vol.setAttributes(description,x_det.regionStr(),x_det.limitsStr(),"VisibleGrey");
-
-      if ( x_det.hasChild(_U(assembly)) )
-        v_det = Assembly(x_det.nameStr()+"_det");
+      if ( levels != 0 && x_det.hasChild(_U(assembly)) )
+        v_det = Assembly("envelope");
       else
-        v_det = Volume(x_det.nameStr()+"_det",Box(2.5*bx,2.5*by,2.5*bz),description.air());
-
-      place_boxes(max_level-1, box_vol);
-      pv = v_det.placeVolume(box_vol, Position(0,0,1.1*bz));
-      pv.addPhysVolID(_toString(max_level,"lvl%d"), ++cnt);
-      pv = nullptr;
-      if ( x_det.hasChild(_U(reflect_x)) )   {
-        Volume   reflect_vol = box_vol.reflect(sensitive);
-        Position reflect_pos = Position(-1.1*bx,0,0);
-        pv = v_det.placeVolume(reflect_vol, reflect_pos);
-      }
-      else if ( x_det.hasChild(_U(reflect_y)) )   {
-        Volume   reflect_vol = box_vol.reflect(sensitive);
-        Position reflect_pos = Position(0,-1.1*by,0);
-        pv = v_det.placeVolume(reflect_vol, reflect_pos);
-      }
-      else if ( x_det.hasChild(_U(reflect_z)) )   {
-        Volume   reflect_vol = box_vol.reflect(sensitive);
-        Position reflect_pos = Position(0,0,-1.1*bz);
-        pv = v_det.placeVolume(reflect_vol, reflect_pos);
+        v_det = Volume("envelope",Box(4.5*bx,4.5*by,4.5*bz),description.air());
+
+      if ( levels == 0 )   {
+	v_det.setSensitiveDetector(sensitive);
       }
-      if ( pv.ptr() )   {
-        pv.addPhysVolID(_toString(max_level,"lvl%d"), ++cnt);
+      else if ( levels == 1 )   {
+	box_vol.setSensitiveDetector(sensitive);
+	box_vol.setAttributes(description,x_det.regionStr(),x_det.limitsStr(),"VisibleGrey");
       }
-      
-      if ( x_det.hasChild(_U(reflect)) )   {
-        Volume reflect_vol = box_vol;
-        for(xml_coll_t c(x_det,_U(reflect)); c; ++c)   {
-          TGeoCombiTrans* reflect_tr  = transform_reflect(c);
-          pv = v_det.placeVolume(reflect_vol.ptr(), reflect_tr);
-          pv.addPhysVolID(_toString(max_level,"lvl%d"), ++cnt);
-        }
+      else  {
+	int cnt = 1;
+	Transform3D tr = xml::createTransformation(x_box);
+	box_vol.setAttributes(description,x_det.regionStr(),x_det.limitsStr(),"VisibleGrey");
+	place_boxes(levels-1, box_vol);
+	pv = v_det.placeVolume(box_vol, tr);
+	pv.addPhysVolID(_toString(levels,"lvl%d"), ++cnt);
+	
+	for(xml_coll_t c(x_det,_U(reflect_x)); c; ++c)
+	  place(v_det, box_vol, c, levels, ++cnt, 'X');
+	for(xml_coll_t c(x_det,_U(reflect_y)); c; ++c)
+	  place(v_det, box_vol, c, levels, ++cnt, 'Y');
+	for(xml_coll_t c(x_det,_U(reflect_z)); c; ++c)
+	  place(v_det, box_vol, c, levels, ++cnt, 'Z');
+
+	if ( x_det.hasChild(_U(reflect)) )   {
+	  Volume reflect_vol = box_vol;
+	  for(xml_coll_t c(x_det,_U(reflect)); c; ++c)   {
+	    TGeoCombiTrans* reflect_tr = transform_reflect(c);
+	    pv = v_det.placeVolume(reflect_vol.ptr(), reflect_tr);
+	    pv.addPhysVolID(_toString(levels,"lvl%d"), ++cnt);
+	  }
+	}
       }
-  
       // Place the calo inside the world
-      pv = description.pickMotherVolume(detector).placeVolume(v_det);
-      pv.addPhysVolID("system",x_det.id());
-      detector.setPlacement(pv);
+      placeDetector(v_det, x_det).addPhysVolID("system",x_det.id());
       return detector;
     }
   };
-- 
GitLab