From 44e848c77aa26d76b313a2ea55dd4a2bd2e3c3ba Mon Sep 17 00:00:00 2001
From: Markus FRANK <Markus.Frank@cern.ch>
Date: Tue, 3 Nov 2020 09:08:19 +0100
Subject: [PATCH] Try to fix reflections for volumes and assemblies

---
 DDCore/include/DD4hep/GeoHandler.h            |  13 +-
 DDCore/src/DetectorImp.cpp                    |   9 +-
 DDCore/src/GeoHandler.cpp                     |  39 +++--
 DDCore/src/Volumes.cpp                        |   2 +
 DDCore/src/plugins/Compact2Objects.cpp        |  10 +-
 DDEve/DDEve/DDG4IO.C                          |  20 +--
 DDEve/include/DDEve/DDEveEventData.h          |   6 +-
 DDEve/include/DDEve/Display.h                 |  10 +-
 DDEve/include/DDEve/DisplayConfiguration.h    |   2 +-
 DDEve/include/DDEve/HitActors.h               |  13 +-
 DDEve/include/DDEve/ParticleActors.h          |  33 +++-
 DDEve/src/Display.cpp                         |  73 ++++----
 DDEve/src/DisplayConfigurationParser.cpp      |  21 +--
 DDEve/src/HitActors.cpp                       |  16 +-
 DDEve/src/ParticleActors.cpp                  |  65 +++++--
 DDG4/include/DDG4/Geant4Converter.h           |   1 +
 DDG4/include/DDG4/Geant4ParticleGun.h         |   5 +-
 DDG4/src/Geant4Converter.cpp                  | 159 +++++++++++++++---
 DDG4/src/Geant4IsotropeGenerator.cpp          |   2 +-
 DDG4/src/Geant4ParticleGenerator.cpp          |  13 +-
 DDG4/src/Geant4ParticleGun.cpp                |  24 +--
 .../compact/NestedBoxReflection.xml           |   2 +
 .../ClientTests/eve/NestedBoxReflection.xml   |   5 +-
 .../ClientTests/scripts/Check_reflection.py   |  16 +-
 .../src/NestedBoxReflection_geo.cpp           |  44 +++--
 25 files changed, 418 insertions(+), 185 deletions(-)

diff --git a/DDCore/include/DD4hep/GeoHandler.h b/DDCore/include/DD4hep/GeoHandler.h
index 4cba4d5ef..3f3bb964b 100644
--- a/DDCore/include/DD4hep/GeoHandler.h
+++ b/DDCore/include/DD4hep/GeoHandler.h
@@ -67,15 +67,15 @@ namespace dd4hep {
        */
       class GeometryInfo {
       public:
-        std::set<TGeoShape*>  solids;
-        std::set<Volume>      volumeSet;
-        std::vector<Volume>   volumes;
-        std::vector<std::pair<std::string, TGeoMatrix*> > trafos;
+        std::set<TGeoShape*>   solids;
+        std::set<Volume>       volumeSet;
+        std::vector<Volume>    volumes;
         std::set<VisAttr>      vis;
         std::set<Ref_t>        fields;
         std::set<Material>     materials;
         std::set<TGeoMedium*>  media;
         std::set<TGeoElement*> elements;
+        std::vector<std::pair<std::string, TGeoMatrix*> > trafos;
       };
     };
 
@@ -96,9 +96,12 @@ namespace dd4hep {
     protected:
       bool  m_propagateRegions;
       std::map<int, std::set<const TGeoNode*> >* m_data;
+      std::map<int, std::set<std::pair<const TGeoNode*,const TGeoNode*> > >* m_places;
 
       /// Internal helper to collect geometry information from traversal
-      GeoHandler& i_collect(const TGeoNode* node, int level, Region rg, LimitSet ls);
+      GeoHandler& i_collect(const TGeoNode* parent,
+			    const TGeoNode* node,
+			    int level, Region rg, LimitSet ls);
 
     private:
       /// Never call Copy constructor
diff --git a/DDCore/src/DetectorImp.cpp b/DDCore/src/DetectorImp.cpp
index 0d49b27aa..b02cf9efc 100644
--- a/DDCore/src/DetectorImp.cpp
+++ b/DDCore/src/DetectorImp.cpp
@@ -670,12 +670,17 @@ void DetectorImp::endDocument(bool close_geometry)    {
     add(trackingVis);
 #endif
     m_worldVol.solid()->ComputeBBox();
-    /// Since we allow now for anonymous shapes,
-    /// we will rename them to use the name of the volume they are assigned to
+    // Since we allow now for anonymous shapes,
+    // we will rename them to use the name of the volume they are assigned to
     mgr->CloseGeometry();
   }
+  // Patching shape names of anaonymous shapes
   ShapePatcher patcher(m_volManager, m_world);
   patcher.patchShapes();
+  // Propagating reflections
+  ReflectionBuilder rb(description);
+  rb.execute();
+
   mapDetectorTypes();
   m_state = READY;
 }
diff --git a/DDCore/src/GeoHandler.cpp b/DDCore/src/GeoHandler.cpp
index 6b4aae5c5..590c5db8d 100644
--- a/DDCore/src/GeoHandler.cpp
+++ b/DDCore/src/GeoHandler.cpp
@@ -30,12 +30,16 @@ using namespace dd4hep;
 using namespace std;
 
 namespace {
-  void collectSolid(GeoHandler::GeometryInfo& geo, const string& name, const string& node, TGeoShape* shape,
-                    TGeoMatrix* matrix) {
-    if (0 == ::strncmp(shape->GetName(), "TGeo", 4)) {
+  void collectSolid(GeoHandler::GeometryInfo& geo,
+		    const string& name,
+		    const string& node,
+		    TGeoShape* shape,
+                    TGeoMatrix* matrix)
+  {
+    if ( 0 == ::strncmp(shape->GetName(), "TGeo", 4) )  {
       shape->SetName(name.c_str());
     }
-    if (shape->IsA() == TGeoCompositeShape::Class()) {
+    if ( shape->IsA() == TGeoCompositeShape::Class() )  {
       const TGeoCompositeShape* s = (const TGeoCompositeShape*) shape;
       const TGeoBoolNode* boolean = s->GetBoolNode();
       collectSolid(geo, name + "_left", name + "_left", boolean->GetLeftShape(), boolean->GetLeftMatrix());
@@ -49,23 +53,28 @@ namespace {
 /// Default constructor
 GeoHandler::GeoHandler() : m_propagateRegions(false)  {
   m_data = new map<int,set<const TGeoNode*> >();
+  m_places = new map<int, set<pair<const TGeoNode*,const TGeoNode*> > >();
 }
 
 /// Initializing constructor
 GeoHandler::GeoHandler(map<int,set<const TGeoNode*> >* ptr)
   : m_propagateRegions(false), m_data(ptr) {
+  m_places = new map<int, set<pair<const TGeoNode*,const TGeoNode*> > >();
 }
 
 /// Default destructor
 GeoHandler::~GeoHandler() {
   if (m_data)
     delete m_data;
-  m_data = 0;
+  m_data = nullptr;
+  if ( m_places )
+    delete m_places;
+  m_places = nullptr;
 }
 
 map<int,set<const TGeoNode*> >* GeoHandler::release() {
   map<int,set<const TGeoNode*> >* d = m_data;
-  m_data = 0;
+  m_data = nullptr;
   return d;
 }
 
@@ -77,13 +86,19 @@ bool GeoHandler::setPropagateRegions(bool value)   {
 }
 
 GeoHandler& GeoHandler::collect(DetElement element) {
+  DetElement par = element.parent();
+  TGeoNode* par_node = par.isValid() ? par.placement().ptr() : nullptr;
   m_data->clear();
-  return i_collect(element.placement().ptr(), 0, Region(), LimitSet());
+  m_places->clear();
+  return i_collect(par_node, element.placement().ptr(), 0, Region(), LimitSet());
 }
 
 GeoHandler& GeoHandler::collect(DetElement element, GeometryInfo& info) {
+  DetElement par = element.parent();
+  TGeoNode* par_node = par.isValid() ? par.placement().ptr() : nullptr;
   m_data->clear();
-  i_collect(element.placement().ptr(), 0, Region(), LimitSet());
+  m_places->clear();
+  i_collect(par_node, element.placement().ptr(), 0, Region(), LimitSet());
   for (auto i = m_data->rbegin(); i != m_data->rend(); ++i) {
     const auto& mapped = (*i).second;
     for (const TGeoNode* n : mapped )  {
@@ -117,7 +132,10 @@ GeoHandler& GeoHandler::collect(DetElement element, GeometryInfo& info) {
   return *this;
 }
 
-GeoHandler& GeoHandler::i_collect(const TGeoNode* current, int level, Region rg, LimitSet ls) {
+GeoHandler& GeoHandler::i_collect(const TGeoNode* parent,
+				  const TGeoNode* current,
+				  int level, Region rg, LimitSet ls)
+{
   TGeoVolume* volume = current->GetVolume();
   TObjArray* nodes = volume->GetNodes();
   int num_children = nodes ? nodes->GetEntriesFast() : 0;
@@ -136,11 +154,12 @@ GeoHandler& GeoHandler::i_collect(const TGeoNode* current, int level, Region rg,
     }
   }
   (*m_data)[level].emplace(current);
+  (*m_places)[level].emplace(make_pair(parent,current));
   //printf("GeoHandler: collect level:%d %s\n",level,current->GetName());
   if (num_children > 0) {
     for (int i = 0; i < num_children; ++i) {
       TGeoNode* node = (TGeoNode*) nodes->At(i);
-      i_collect(node, level + 1, region, limits);
+      i_collect(current, node, level + 1, region, limits);
     }
   }
   return *this;
diff --git a/DDCore/src/Volumes.cpp b/DDCore/src/Volumes.cpp
index 69f246aba..dd23f31ea 100644
--- a/DDCore/src/Volumes.cpp
+++ b/DDCore/src/Volumes.cpp
@@ -208,12 +208,14 @@ namespace {
     v->CloneNodesAndConnect(vol);
     // The volume is now properly cloned, but with the same shape.
     // Reflect the shape (if any) and connect it.
+#if 0
     if (v->GetShape())   {
       TGeoScale* scale = new TGeoScale( 1., 1.,-1.);
       TGeoShape* reflected_shape =
         TGeoScaledShape::MakeScaledShape((nam+"_shape_refl").c_str(), v->GetShape(), scale);
       vol->SetShape(reflected_shape);
     }
+#endif
     // Reflect the daughters.
     Int_t nd = vol->GetNdaughters();
     if ( !nd ) return vol;
diff --git a/DDCore/src/plugins/Compact2Objects.cpp b/DDCore/src/plugins/Compact2Objects.cpp
index f5044b1c5..cceffd1c2 100644
--- a/DDCore/src/plugins/Compact2Objects.cpp
+++ b/DDCore/src/plugins/Compact2Objects.cpp
@@ -1474,8 +1474,8 @@ template <> void Converter<Compact>::operator()(xml_h element) const {
       open_geometry  = steer.attr<bool>(_U(open));
     if ( steer.hasAttr(_U(close)) )
       close_document = steer.attr<bool>(_U(close));
-    if ( steer.hasAttr(_U(close_geometry)) )
-      close_geometry = steer.attr<bool>(_U(close_geometry));
+    if ( steer.hasAttr(_U(reflect)) )
+      build_reflections = steer.attr<bool>(_U(reflect));
     for (xml_coll_t clr(steer, _U(clear)); clr; ++clr) {
       string nam = clr.hasAttr(_U(name)) ? clr.attr<string>(_U(name)) : string();
       if ( nam.substr(0,6) == "elemen" )   {
@@ -1563,12 +1563,6 @@ template <> void Converter<Compact>::operator()(xml_h element) const {
 }
 
 #ifdef _WIN32
-    void buildReflections();
-
-/// Build reflections the ROOT way. To be called once the geometry is closed
-void DetectorImp::buildReflections()    {
-}
-
   template Converter<Plugin>;
   template Converter<Constant>;
   template Converter<Material>;
diff --git a/DDEve/DDEve/DDG4IO.C b/DDEve/DDEve/DDG4IO.C
index 0d283807c..a9501f284 100644
--- a/DDEve/DDEve/DDG4IO.C
+++ b/DDEve/DDEve/DDG4IO.C
@@ -83,16 +83,16 @@ namespace {
   void* _convertParticleFunc(void* source, dd4hep::DDEveParticle* p)  {
     if (source )  {
       dd4hep::sim::Geant4Particle* s = (dd4hep::sim::Geant4Particle*)source;
-      p->id = s->id;
-      p->vsx = s->vsx;
-      p->vsy = s->vsy;
-      p->vsz = s->vsz;
-      p->vex = s->vex;
-      p->vey = s->vey;
-      p->vez = s->vez;
-      p->psx = s->psx;
-      p->psy = s->psy;
-      p->psz = s->psz;
+      p->id        = s->id;
+      p->vsx       = s->vsx;
+      p->vsy       = s->vsy;
+      p->vsz       = s->vsz;
+      p->vex       = s->vex;
+      p->vey       = s->vey;
+      p->vez       = s->vez;
+      p->psx       = s->psx;
+      p->psy       = s->psy;
+      p->psz       = s->psz;
       p->pdgID     = s->pdgID;
       p->parent    = s->parents.empty() ? -1 : *(s->parents.begin());
       p->energy    = std::sqrt(s->vsx*s->vsx + s->vsy*s->vsy + s->vsz*s->vsz + s->mass*s->mass);
diff --git a/DDEve/include/DDEve/DDEveEventData.h b/DDEve/include/DDEve/DDEveEventData.h
index cd9ca2107..7fb213d1e 100644
--- a/DDEve/include/DDEve/DDEveEventData.h
+++ b/DDEve/include/DDEve/DDEveEventData.h
@@ -29,11 +29,11 @@ namespace dd4hep {
   class DDEveHit   {
   public:
     /// Track/Particle, which produced this hit
-    int particle;
+    int particle {0};
     /// Hit position
-    float x,y,z; 
+    float x = 0e0, y = 0e0, z = 0e0; 
     /// Energy deposit
-    float deposit;
+    float deposit {0};
     /// Default constructor
     DDEveHit();
     /// Initializing constructor
diff --git a/DDEve/include/DDEve/Display.h b/DDEve/include/DDEve/Display.h
index c39513bc8..dc3eb505e 100644
--- a/DDEve/include/DDEve/Display.h
+++ b/DDEve/include/DDEve/Display.h
@@ -55,11 +55,11 @@ namespace dd4hep {
    */
   class Display : public EventConsumer {
   public:
-    typedef DisplayConfiguration::ViewConfig ViewConfig;
-    typedef DisplayConfiguration::Config DataConfig;
-    typedef std::set<View*> Views;
-    typedef std::set<DisplayConfiguration*> Configurations;
-    typedef std::set<PopupMenu*> Menus;
+    typedef DisplayConfiguration::ViewConfig         ViewConfig;
+    typedef DisplayConfiguration::Config             DataConfig;
+    typedef std::set<View*>                          Views;
+    typedef std::set<DisplayConfiguration*>          Configurations;
+    typedef std::set<PopupMenu*>                     Menus;
     typedef std::map<std::string, TEveElementList*>  Topics;
     typedef std::map<std::string, ViewConfig>        ViewConfigurations;
     typedef std::map<std::string, DataConfig>        DataConfigurations;
diff --git a/DDEve/include/DDEve/DisplayConfiguration.h b/DDEve/include/DDEve/DisplayConfiguration.h
index 4b38a86c2..81af0b57c 100644
--- a/DDEve/include/DDEve/DisplayConfiguration.h
+++ b/DDEve/include/DDEve/DisplayConfiguration.h
@@ -102,7 +102,7 @@ namespace dd4hep {
       } data;
       std::string name;
       std::string hits;
-      std::string use;
+      std::string use  {"true"};
       int type;
       /// Default constructor
       Config();
diff --git a/DDEve/include/DDEve/HitActors.h b/DDEve/include/DDEve/HitActors.h
index 2307f3cb6..599abba23 100644
--- a/DDEve/include/DDEve/HitActors.h
+++ b/DDEve/include/DDEve/HitActors.h
@@ -47,9 +47,10 @@ namespace dd4hep {
    *  \ingroup DD4HEP_EVE
    */
   struct PointsetCreator : public DDEveHitActor  {
-    TEvePointSet* pointset;
-    float deposit;
-    int count;
+    TEvePointSet* pointset {nullptr};
+    float threshold  {0};
+    float deposit {0};
+    int count {0};
     /// Standard initializing constructor
     PointsetCreator(const std::string& collection, size_t length);
     /// Standard initializing constructor
@@ -69,9 +70,9 @@ namespace dd4hep {
    *  \ingroup DD4HEP_EVE
    */
   struct BoxsetCreator : public DDEveHitActor  {
-    TEveBoxSet* boxset;
-    float emax, towerH, deposit;
-    int count;
+    TEveBoxSet* boxset {0};
+    float emax = 1e12, towerH = 1e12, deposit = 0e0;
+    int count {0};
     /// Standard initializing constructor
     BoxsetCreator(const std::string& collection, size_t length);
     /// Standard initializing constructor
diff --git a/DDEve/include/DDEve/ParticleActors.h b/DDEve/include/DDEve/ParticleActors.h
index 612e51c29..7655f0861 100644
--- a/DDEve/include/DDEve/ParticleActors.h
+++ b/DDEve/include/DDEve/ParticleActors.h
@@ -22,6 +22,7 @@
 
 // Forward declarations
 class TEveTrackPropagator;
+class TEvePointSet;
 class TEveCompound;
 class TEveElement;
 class TEveLine;
@@ -37,11 +38,13 @@ namespace dd4hep {
    */
   struct MCParticleCreator : public DDEveParticleActor  {
     typedef std::map<std::string,TEveCompound*> Compounds;
-    TEveTrackPropagator* propagator;
-    TEveCompound* particles;
+    TEveTrackPropagator* propagator {0};
+    TEveCompound* particles {0};
     Compounds types;
-    int count;
-    int lineWidth;
+    double threshold {10e0}; // 10 MeV
+    int count {0};
+    int lineWidth {4};
+    
     /// Standard initializing constructor
     MCParticleCreator(TEveTrackPropagator* p, TEveCompound* ps, const DisplayConfiguration::Config* cfg);
     /// Access sub-compound by name
@@ -54,6 +57,28 @@ namespace dd4hep {
     void close();
   };
 
+  /// Fill a 3D pointset with particle start vertices
+  /*
+   *  \author  M.Frank
+   *  \version 1.0
+   *  \ingroup DD4HEP_EVE
+   */
+  struct StartVertexCreator : public  DDEveParticleActor {
+    TEvePointSet* pointset;
+    float deposit;
+    int count;
+    /// Standard initializing constructor
+    StartVertexCreator(const std::string& collection, size_t length);
+    /// Standard initializing constructor
+    StartVertexCreator(const std::string& collection, size_t length, const DisplayConfiguration::Config& cfg);
+    /// Standard destructor
+    virtual ~StartVertexCreator();
+    /// Return eve element
+    TEveElement* element() const;
+    /// Action callback of this functor: 
+    virtual void operator()(const DDEveParticle& particle);
+  };
+
 } /* End namespace dd4hep   */
 
 
diff --git a/DDEve/src/Display.cpp b/DDEve/src/Display.cpp
index 7383a4919..1f98aa84c 100644
--- a/DDEve/src/Display.cpp
+++ b/DDEve/src/Display.cpp
@@ -368,34 +368,37 @@ void Display::OnNewEvent(EventHandler& handler )   {
     const Collections& colls = (*ityp).second;
     for(Collections::const_iterator j=colls.begin(); j!=colls.end(); ++j)   {
       size_t len = (*j).second;
-      const char* nam = (*j).first;
       if ( len > 0 )   {
+	const char* nam = (*j).first;
+	DataConfigurations::const_iterator icfg = m_collectionsConfigs.find(nam);
+	DataConfigurations::const_iterator cfgend = m_collectionsConfigs.end();
         EventHandler::CollectionType typ = handler.collectionType(nam);
         if ( typ == EventHandler::CALO_HIT_COLLECTION ||
              typ == EventHandler::TRACKER_HIT_COLLECTION )  {
-          const DataConfigurations::const_iterator i=m_collectionsConfigs.find(nam);
-          if ( i != m_collectionsConfigs.end() )  {
-            const DataConfig& cfg = (*i).second;
-            if ( cfg.hits == "PointSet" )  {
-              PointsetCreator cr(nam,len,cfg);
-              handler.collectionLoop((*j).first, cr);
-              ImportEvent(cr.element());
-            }
-            else if ( cfg.hits == "BoxSet" )  {
-              BoxsetCreator cr(nam,len,cfg);
-              handler.collectionLoop((*j).first, cr);
-              ImportEvent(cr.element());
-            }
-            else if ( cfg.hits == "TowerSet" )  {
-              TowersetCreator cr(nam,len,cfg);
-              handler.collectionLoop((*j).first, cr);
-              ImportEvent(cr.element());
-            }
-            else {  // Default is point set
-              PointsetCreator cr(nam,len);
-              handler.collectionLoop((*j).first, cr);
-              ImportEvent(cr.element());
-            }
+          if ( icfg != cfgend )  {
+            const DataConfig& cfg = (*icfg).second;
+	    if ( ::toupper(cfg.use[0]) == 'T' || ::toupper(cfg.use[0]) == 'Y' )  {
+	      if ( cfg.hits == "PointSet" )  {
+		PointsetCreator cr(nam,len,cfg);
+		handler.collectionLoop((*j).first, cr);
+		ImportEvent(cr.element());
+	      }
+	      else if ( cfg.hits == "BoxSet" )  {
+		BoxsetCreator cr(nam,len,cfg);
+		handler.collectionLoop((*j).first, cr);
+		ImportEvent(cr.element());
+	      }
+	      else if ( cfg.hits == "TowerSet" )  {
+		TowersetCreator cr(nam,len,cfg);
+		handler.collectionLoop((*j).first, cr);
+		ImportEvent(cr.element());
+	      }
+	      else {  // Default is point set
+		PointsetCreator cr(nam,len);
+		handler.collectionLoop((*j).first, cr);
+		ImportEvent(cr.element());
+	      }
+	    }
           }
           else  {
             PointsetCreator cr(nam,len);
@@ -409,13 +412,21 @@ void Display::OnNewEvent(EventHandler& handler )   {
           // last track is gone ie. when we re-initialize the event scene
 
           // $$$ Do not know exactly what the field parameters mean
-          const DataConfigurations::const_iterator i=m_collectionsConfigs.find(nam);
-          const DataConfig* cfg = (i==m_collectionsConfigs.end()) ? 0 : &((*i).second);
-          MCParticleCreator cr(new TEveTrackPropagator("","",new TEveMagFieldDuo(350, -3.5, 2.0)),
-                               new TEveCompound("MC_Particles","MC_Particles"),cfg);
-          handler.collectionLoop((*j).first, cr);
-          cr.close();
-          particles = cr.particles;
+	  if ( (icfg=m_collectionsConfigs.find("StartVertexPoints")) != cfgend )   {
+	    StartVertexCreator cr("StartVertexPoints", len, (*icfg).second);
+	    handler.collectionLoop((*j).first, cr);
+	    printout(INFO,"Display","+++ StartVertexPoints: Filled %d start vertex points.....",cr.count);
+	    ImportEvent(cr.element());
+	  }
+	  if ( (icfg=m_collectionsConfigs.find("MCParticles")) != cfgend )   {
+	    MCParticleCreator cr(new TEveTrackPropagator("","",new TEveMagFieldDuo(350, -3.5, 2.0)),
+				 new TEveCompound("MC_Particles","MC_Particles"),
+				 icfg == cfgend ? 0 : &((*icfg).second));
+	    handler.collectionLoop((*j).first, cr);
+	    printout(INFO,"Display","+++ StartVertexPoints: Filled %d patricle tracks.....",cr.count);
+	    cr.close();
+	    particles = cr.particles;
+	  }
         }
       }
     }
diff --git a/DDEve/src/DisplayConfigurationParser.cpp b/DDEve/src/DisplayConfigurationParser.cpp
index 07bdde59f..c2e39253e 100644
--- a/DDEve/src/DisplayConfigurationParser.cpp
+++ b/DDEve/src/DisplayConfigurationParser.cpp
@@ -128,10 +128,10 @@ template <> void Converter<collection_configs>::operator()(xml_h e)  const  {
   DisplayConfiguration::Config c;
   c.name = e.attr<string>(_U(name));
   c.type = DisplayConfiguration::COLLECTION;
-  c.data.hits.color     = e.hasAttr(_U(color)) ? e.attr<int>(_U(color)) : 0xBBBBBB;
+  c.data.hits.color     = e.hasAttr(_U(color)) ? e.attr<int>(_U(color))   : 0xBBBBBB;
   c.data.hits.alpha     = e.hasAttr(_U(alpha)) ? e.attr<float>(_U(alpha)) : -1.0;
-  c.data.hits.emax      = e.hasAttr(u_emax) ? e.attr<float>(u_emax) : 25.0;
-  c.data.hits.towerH    = e.hasAttr(u_towerH) ? e.attr<float>(u_towerH) : 25.0;
+  c.data.hits.emax      = e.hasAttr(u_emax)    ? e.attr<float>(u_emax)    : 25.0;
+  c.data.hits.towerH    = e.hasAttr(u_towerH)  ? e.attr<float>(u_towerH)  : 25.0;
   c.data.hits.threshold = e.hasAttr(_U(threshold)) ? e.attr<float>(_U(threshold)) : 0.0;
   if ( e.hasAttr(u_hits)   ) c.hits = e.attr<string>(u_hits);
   if ( e.hasAttr(u_use)    ) c.use = e.attr<string>(u_use);
@@ -153,10 +153,10 @@ template <> void Converter<view>::operator()(xml_h e)  const  {
   ViewConfigurations* configs = (ViewConfigurations*)param;
   DisplayConfiguration::ViewConfig c;
   extract(c,e,DisplayConfiguration::VIEW);
+  c.name  = e.attr<string>(_U(name));
   c.type  = e.attr<string>(_U(type));
   c.show_structure = e.hasAttr(_U(structure)) ? e.attr<bool>(_U(structure)) : true;
   c.show_sensitive = e.hasAttr(_U(sensitive)) ? e.attr<bool>(_U(sensitive)) : true;
-  c.name  = e.attr<string>(_U(name));
   printout(INFO,"DisplayConfiguration","+++ View: %s sensitive:%d structure:%d.",
            c.name.c_str(), c.show_sensitive, c.show_structure);
   xml_coll_t(e,_Unicode(panel)).for_each(Converter<panel>(description,&c.subdetectors));
@@ -180,10 +180,10 @@ template <> void Converter<view>::operator()(xml_h e)  const  {
 template <> void Converter<calodata>::operator()(xml_h e)  const  {
   Configurations* configs = (Configurations*)param;
   DisplayConfiguration::Config c;
-  c.name    = e.attr<string>(_U(name));
-  c.type    = DisplayConfiguration::CALODATA;
+  c.name = e.attr<string>(_U(name));
+  c.type = DisplayConfiguration::CALODATA;
   if ( e.hasAttr(u_use)    )   {
-    c.use = e.attr<string>(u_use);
+    c.use  = e.attr<string>(u_use);
     c.hits = e.attr<string>(u_hits);
   }
   else  {
@@ -220,8 +220,9 @@ template <> void Converter<collection>::operator()(xml_h e)  const  {
   Configurations* configs = (Configurations*)param;
   DisplayConfiguration::Config c;
   c.name = e.attr<string>(_U(name));
-  c.type = DisplayConfiguration::COLLECTION;
   c.hits = e.attr<string>(u_hits);
+  c.type = DisplayConfiguration::COLLECTION;
+  c.use  = e.hasAttr(u_use) ? e.attr<string>(u_use) : string("true");
   c.data.hits.size  = e.attr<float>(_U(size));
   c.data.hits.type  = e.attr<float>(_U(type));
   c.data.hits.color = e.hasAttr(_U(color))  ? e.attr<int>(_U(color)) : kRed;
@@ -269,9 +270,9 @@ template <> void Converter<include>::operator()(xml_h e)  const  {
  */
 template <> void Converter<display>::operator()(xml_h e)  const  {
   Display* d = (Display*)param;
-  if ( e.hasAttr(_Unicode(visLevel)) ) d->setVisLevel(e.attr<int>(_Unicode(visLevel)));
+  if ( e.hasAttr(_Unicode(visLevel))     ) d->setVisLevel(e.attr<int>(_Unicode(visLevel)));
   if ( e.hasAttr(_Unicode(eventHandler)) ) d->setEventHandlerName(e.attr<std::string>(_Unicode(eventHandler)));
-  if ( e.hasAttr(_Unicode(loadLevel)) ) d->setLoadLevel(e.attr<int>(_Unicode(loadLevel)));
+  if ( e.hasAttr(_Unicode(loadLevel))    ) d->setLoadLevel(e.attr<int>(_Unicode(loadLevel)));
 }
 
 /** Convert display configuration elements of tag type ddeve
diff --git a/DDEve/src/HitActors.cpp b/DDEve/src/HitActors.cpp
index 646cd1b83..dde055102 100644
--- a/DDEve/src/HitActors.cpp
+++ b/DDEve/src/HitActors.cpp
@@ -27,9 +27,11 @@ using namespace std;
 using namespace dd4hep;
 
 #ifdef HAVE_GEANT4_UNITS
-#define MM_2_CM 1.0
+#define MM_2_CM        1.0
+#define MEV_TO_GEV  1000.0
 #else
-#define MM_2_CM 0.1
+#define MM_2_CM        0.1
+#define MEV_TO_GEV     1.0
 #endif
 
 /// Action callback of this functor: 
@@ -40,7 +42,6 @@ void EtaPhiHistogramActor::operator()(const DDEveHit& hit)   {
 
 /// Standard initializing constructor
 PointsetCreator::PointsetCreator(const std::string& collection, size_t length) 
-  : pointset(0), deposit(0), count(0) 
 {
   pointset = new TEvePointSet(collection.c_str(),length);
   pointset->SetMarkerSize(0.2);
@@ -48,13 +49,13 @@ PointsetCreator::PointsetCreator(const std::string& collection, size_t length)
 
 /// Standard initializing constructor
 PointsetCreator::PointsetCreator(const std::string& collection, size_t length, const DisplayConfiguration::Config& cfg) 
-  : pointset(0), deposit(0), count(0) 
 {
   pointset = new TEvePointSet(collection.c_str(),length);
   pointset->SetMarkerSize(cfg.data.hits.size);
   pointset->SetMarkerStyle(cfg.data.hits.type);
   //pointset->SetMarkerAlpha(cfg.data.hits.alpha);
   pointset->SetMainColor(cfg.data.hits.color);
+  threshold = cfg.data.hits.threshold * MEV_TO_GEV;
 }
 /// Return eve element
 TEveElement* PointsetCreator::element() const   {
@@ -74,12 +75,14 @@ PointsetCreator::~PointsetCreator()   {
 
 /// Action callback of this functor: 
 void PointsetCreator::operator()(const DDEveHit& hit)   {
-  pointset->SetPoint(count++, hit.x*MM_2_CM, hit.y*MM_2_CM, hit.z*MM_2_CM); 
+  if ( hit.deposit > threshold )   {
+    deposit += hit.deposit;
+    pointset->SetPoint(count++, hit.x*MM_2_CM, hit.y*MM_2_CM, hit.z*MM_2_CM);
+  }
 }
 
 /// Standard initializing constructor
 BoxsetCreator::BoxsetCreator(const std::string& collection, size_t /*length */, const DisplayConfiguration::Config& cfg)
-  : boxset(0), emax(1e12), towerH(1e12), deposit(0.0), count(0)
 {
   emax   = cfg.data.hits.emax;
   towerH = cfg.data.hits.towerH;
@@ -94,7 +97,6 @@ BoxsetCreator::BoxsetCreator(const std::string& collection, size_t /*length */,
 
 /// Standard initializing constructor
 BoxsetCreator::BoxsetCreator(const std::string& collection, size_t /*length */)
-  : boxset(0), emax(1e12), towerH(1e12), deposit(0.0), count(0)
 {
   boxset = new TEveBoxSet(collection.c_str());
   boxset->SetMainTransparency(0);
diff --git a/DDEve/src/ParticleActors.cpp b/DDEve/src/ParticleActors.cpp
index 56aaea7d7..6bc62890a 100644
--- a/DDEve/src/ParticleActors.cpp
+++ b/DDEve/src/ParticleActors.cpp
@@ -13,11 +13,14 @@
 
 // Framework include files
 #include "DDEve/ParticleActors.h"
-#include "DD4hep/Objects.h"
 #include "DD4hep/DD4hepUnits.h"
+#include "DD4hep/Printout.h"
+#include "DD4hep/Objects.h"
 
-#include "TEveCompound.h"
 #include "TEveTrack.h"
+#include "TEveBoxSet.h"
+#include "TEvePointSet.h"
+#include "TEveCompound.h"
 #include "TEveTrackPropagator.h"
 
 #include "TParticle.h"
@@ -28,11 +31,13 @@ using namespace std;
 using namespace dd4hep;
 
 #ifdef HAVE_GEANT4_UNITS
-#define CM_2_MM 1.0
-#define MM_2_CM 1.0
+#define CM_2_MM     1.0
+#define MM_2_CM     1.0
+#define MEV_TO_GEV  1000.0
 #else
-#define CM_2_MM 10.0
-#define MM_2_CM 0.1
+#define CM_2_MM    10.0
+#define MM_2_CM     0.1
+#define MEV_TO_GEV  1.0
 #endif
 
 namespace {
@@ -43,7 +48,7 @@ namespace {
 
 /// Standard initializing constructor
 MCParticleCreator::MCParticleCreator(TEveTrackPropagator* p, TEveCompound* ps, const DisplayConfiguration::Config* cfg) 
-  : propagator(p), particles(ps), count(0), lineWidth(4)
+  : propagator(p), particles(ps)
 {
   propagator->SetName("Track propagator for charged particles");
   propagator->SetMaxR(1000);
@@ -55,8 +60,10 @@ MCParticleCreator::MCParticleCreator(TEveTrackPropagator* p, TEveCompound* ps, c
   propagator->RefPMAtt().SetMarkerSize(1.0);
   if ( cfg )  {
     lineWidth = cfg->data.hits.width;
+    threshold = cfg->data.hits.threshold * MEV_TO_GEV;
     propagator->RefPMAtt().SetMarkerSize(cfg->data.hits.size);
     propagator->RefPMAtt().SetMarkerStyle(cfg->data.hits.type);
+    printout(ALWAYS,"MCParticleCreator","+++ Minimal particle energy: %8.3g [GeV]",threshold);
   }
 }
 
@@ -119,16 +126,16 @@ void MCParticleCreator::operator()(const DDEveParticle& p)  {
   TEveVector dir = end-start;
 
   // Tracks longer than 100 micron and energy > 100 MeV
-  if ( dir.R()*CM_2_MM > 100e-3 && p.energy > 10e0 )  {
+  if ( p.energy > 10e0 && p.energy > threshold && dir.R()*CM_2_MM > 100e-3 )  {
     TDatabasePDG* db = TDatabasePDG::Instance();
     TParticlePDG* def = db->GetParticle(p.pdgID);
     TParticle part(p.pdgID,
                    0,0,0,0,0,
                    p.psx*MEV_2_GEV, p.psy*MEV_2_GEV, p.psz*MEV_2_GEV, p.energy*MEV_2_GEV,
                    p.vsx*MM_2_CM, p.vsy*MM_2_CM, p.vsz*MM_2_CM, p.time);
-  
-    TEveTrack* t = new TEveTrack(&part,p.id,propagator);
 
+    TEveTrack* t = new TEveTrack(&part,p.id,propagator);
+    ++count;
     // Add start-vertex as path mark
     //t->AddPathMark(TEvePathMark(TEvePathMark::kDecay,start));
     // Add end-vertex as path mark (kDecay)
@@ -149,7 +156,7 @@ void MCParticleCreator::operator()(const DDEveParticle& p)  {
                      p.vex*MM_2_CM, p.vey*MM_2_CM, p.vez*MM_2_CM,
                      dir.R(),
                      p.psx*MEV_2_GEV, p.psy*MEV_2_GEV, p.psz*MEV_2_GEV, p.energy*MEV_2_GEV));
-
+    
     // Add element to collection
     int pdg = abs(p.pdgID);
     if ( pdg == 11 )
@@ -170,9 +177,41 @@ void MCParticleCreator::operator()(const DDEveParticle& p)  {
       addCompound("Protons", t);
     else
       addCompound("Other", t);
-    //cout << "Add particle " << p.id << " to compound." << endl;
   }
   else  {
-    cout << "SKIP particle " << p.id << "." << endl;
+    printout(ALWAYS,"MCParticleCreator","+++ SKIP particle %4d. Energy: %8.3g [MeV]",p.id,p.energy);
   }
 }
+
+/// Standard initializing constructor
+StartVertexCreator::StartVertexCreator(const std::string& collection, size_t length) 
+  : pointset(0), deposit(0), count(0) 
+{
+  pointset = new TEvePointSet(collection.c_str(),length);
+  pointset->SetMarkerSize(0.2);
+}
+
+/// Standard initializing constructor
+StartVertexCreator::StartVertexCreator(const std::string& collection, size_t length, const DisplayConfiguration::Config& cfg) 
+  : pointset(0), deposit(0), count(0) 
+{
+  pointset = new TEvePointSet(collection.c_str(),length);
+  pointset->SetMarkerSize(cfg.data.hits.size);
+  pointset->SetMarkerStyle(cfg.data.hits.type);
+  //pointset->SetMarkerAlpha(cfg.data.hits.alpha);
+  pointset->SetMainColor(cfg.data.hits.color);
+}
+/// Return eve element
+TEveElement* StartVertexCreator::element() const   {
+  return pointset;
+}
+
+/// Standard destructor
+StartVertexCreator::~StartVertexCreator()   {
+}
+
+/// Action callback of this functor: 
+void StartVertexCreator::operator()(const DDEveParticle& p)  {
+  pointset->SetPoint(count++, p.vsx*MM_2_CM, p.vsy*MM_2_CM, p.vsz*MM_2_CM); 
+}
+
diff --git a/DDG4/include/DDG4/Geant4Converter.h b/DDG4/include/DDG4/Geant4Converter.h
index d5e097178..67f3d0989 100644
--- a/DDG4/include/DDG4/Geant4Converter.h
+++ b/DDG4/include/DDG4/Geant4Converter.h
@@ -101,6 +101,7 @@ namespace dd4hep {
 
       /// Convert the geometry type volume placement into the corresponding Geant4 object(s).
       virtual void* handlePlacement(const std::string& name, const TGeoNode* node) const;
+      virtual void* handlePlacement2(const std::pair<const TGeoNode*,const TGeoNode*>& node) const;
       virtual void* handleAssembly(const std::string& name, const TGeoNode* node) const;
 
       /// Convert the geometry type field into the corresponding Geant4 object(s).
diff --git a/DDG4/include/DDG4/Geant4ParticleGun.h b/DDG4/include/DDG4/Geant4ParticleGun.h
index 529d679e7..ff633b08a 100644
--- a/DDG4/include/DDG4/Geant4ParticleGun.h
+++ b/DDG4/include/DDG4/Geant4ParticleGun.h
@@ -64,10 +64,7 @@ namespace dd4hep {
       /// Shot number in sequence
       int m_shotNo;
       /// Particle modification. Caller presets defaults to: ( direction = m_direction, momentum = m_energy)
-      virtual void getParticleDirection(int, ROOT::Math::XYZVector& direction, double& momentum) const  {
-        direction = m_direction;
-        momentum = m_energy;
-      }
+      virtual void getParticleDirection(int, ROOT::Math::XYZVector& direction, double& momentum) const;
     public:
       /// Standard constructor
       Geant4ParticleGun(Geant4Context* context, const std::string& name);
diff --git a/DDG4/src/Geant4Converter.cpp b/DDG4/src/Geant4Converter.cpp
index 5fe2d9b87..dcb7a1a4d 100644
--- a/DDG4/src/Geant4Converter.cpp
+++ b/DDG4/src/Geant4Converter.cpp
@@ -847,31 +847,18 @@ 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;
-    TGeoVolume* old_vol  = old_node->GetVolume();
-    TGeoVolume* new_vol  = new_node->GetVolume();
-    TGeoMatrix* old_tr   = old_node->GetMatrix();
-    TGeoMatrix* new_tr   = new_node->GetMatrix();
-    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");
-  }
-#endif
   g4 = nullptr;
   if (!g4) {
     TGeoVolume* mot_vol = node->GetMotherVolume();
     TGeoMatrix* tr = node->GetMatrix();
     if (!tr) {
-      except("Geant4Converter", "++ Attempt to handle placement without transformation:%p %s of type %s vol:%p", node,
-             node->GetName(), node->IsA()->GetName(), vol);
+      except("Geant4Converter",
+	     "++ Attempt to handle placement without transformation:%p %s of type %s vol:%p",
+	     node, node->GetName(), node->IsA()->GetName(), vol);
     }
     else if (0 == vol) {
-      except("Geant4Converter", "++ Unknown G4 volume:%p %s of type %s ptr:%p", node, node->GetName(),
-             node->IsA()->GetName(), vol);
+      except("Geant4Converter", "++ Unknown G4 volume:%p %s of type %s ptr:%p",
+	     node, node->GetName(), node->IsA()->GetName(), vol);
     }
     else {
       int           copy               = node->GetNumber();
@@ -894,14 +881,14 @@ void* Geant4Converter::handlePlacement(const string& name, const TGeoNode* node)
                  transform.dx(), transform.dy(), transform.dz());
         return 0;
       }
-      else if ( node_is_assembly )   {
+      G4Scale3D        scale;
+      G4Rotate3D       rot;
+      G4Translate3D    trans;
+      if ( node_is_assembly )   {
         //
         // Node is an assembly:
         // Imprint the assembly. The mother MUST already be transformed.
         //
-	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",
@@ -918,9 +905,6 @@ 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 =
@@ -962,6 +946,120 @@ void* Geant4Converter::handlePlacement(const string& name, const TGeoNode* node)
   return g4;
 }
 
+void* Geant4Converter::handlePlacement2(const std::pair<const TGeoNode*,const TGeoNode*>& n) const   {
+  const TGeoNode* par_node = n.first;
+  const TGeoNode* node = n.second;
+  Geant4GeometryInfo& info = data();
+  PrintLevel lvl = debugPlacements ? ALWAYS : outputLevel;
+  Geant4GeometryMaps::PlacementMap::const_iterator g4it = info.g4Placements.find(node);
+  G4VPhysicalVolume* g4 = (g4it == info.g4Placements.end()) ? 0 : (*g4it).second;
+  TGeoVolume* vol = node->GetVolume();
+  Volume _v(vol);
+
+  if ( _v.testFlagBit(Volume::VETO_SIMU) )  {
+    printout(lvl, "Geant4Converter", "++ Placement %s not converted [Veto'ed for simulation]",node->GetName());
+    return 0;
+  }
+  g4 = nullptr;
+  if (!g4) {
+    TGeoVolume* mot_vol = par_node ? par_node->GetVolume() : node->GetMotherVolume();
+    TGeoMatrix* tr = node->GetMatrix();
+    if (!tr) {
+      except("Geant4Converter",
+	     "++ Attempt to handle placement without transformation:%p %s of type %s vol:%p",
+	     node, node->GetName(), node->IsA()->GetName(), vol);
+    }
+    else if (0 == vol) {
+      except("Geant4Converter", "++ Unknown G4 volume:%p %s of type %s ptr:%p",
+	     node, node->GetName(), node->IsA()->GetName(), vol);
+    }
+    else {
+      int           copy               = node->GetNumber();
+      bool          node_is_reflected  = is_left_handed(tr);
+      bool          node_is_assembly   = vol->IsA() == TGeoVolumeAssembly::Class();
+      bool          mother_is_assembly = mot_vol ? mot_vol->IsA() == TGeoVolumeAssembly::Class() : false;
+      MyTransform3D transform(tr->GetTranslation(),tr->IsRotation() ? tr->GetRotationMatrix() : s_identity_rot);
+      Geant4GeometryMaps::VolumeMap::const_iterator volIt = info.g4Volumes.find(mot_vol);
+
+      if ( mother_is_assembly )   {
+        //
+        // Mother is an assembly:
+        // Nothing to do here, because:
+        // -- placed volumes were already added before in "handleAssembly"
+        // -- imprint cannot be made, because this requires a logical volume as a mother
+        //
+        printout(lvl, "Geant4Converter", "+++ Assembly: **** : 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());
+        return 0;
+      }
+      G4Scale3D        scale;
+      G4Rotate3D       rot;
+      G4Translate3D    trans;
+      if ( node_is_assembly )   {
+        //
+        // Node is an assembly:
+        // Imprint the assembly. The mother MUST already be transformed.
+        //
+	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);
+        ass->imprint(info,node,chain,ass,(*volIt).second, transform, copy, checkOverlaps);
+        return 0;
+      }
+      else if ( node != info.manager->GetTopNode() && volIt == info.g4Volumes.end() )  {
+        throw logic_error("Geant4Converter: Invalid mother volume found!");
+      }
+      G4LogicalVolume* g4vol = info.g4Volumes[vol];
+      G4LogicalVolume* g4mot = info.g4Volumes[mot_vol];
+      G4PhysicalVolumesPair pvPlaced =
+        G4ReflectionFactory::Instance()->Place(transform, // no rotation
+                                               node->GetName(),      // its name
+                                               g4vol,     // its logical volume
+                                               g4mot,     // its mother (logical) volume
+                                               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 )
+        return info.g4Placements[node] = pvPlaced.first;
+      else if ( !node_is_reflected && !pvPlaced.second )
+        return info.g4Placements[node] = pvPlaced.first;
+      //G4LogicalVolume* g4refMoth = G4ReflectionFactory::Instance()->GetReflectedLV(g4mot);
+      // Now deal with valid pvPlaced.second ...
+      if ( node_is_reflected )
+        return info.g4Placements[node] = pvPlaced.first;
+      else if ( !node_is_reflected )
+        return info.g4Placements[node] = pvPlaced.first;
+      g4 = pvPlaced.second ? pvPlaced.second : pvPlaced.first;
+    }
+    info.g4Placements[node] = g4;
+    printout(ERROR, "Geant4Converter", "++ DEAD code. Should not end up here!");
+  }
+  else {
+    printout(ERROR, "Geant4Converter", "++ Attempt to DOUBLE-place physical volume: %s No:%d",
+	     node->GetName(), node->GetNumber());
+  }
+  return g4;
+}
+
 /// Convert the geometry type region into the corresponding Geant4 object(s).
 void* Geant4Converter::handleRegion(Region region, const set<const TGeoVolume*>& /* volumes */) const {
   G4Region* g4 = data().g4Regions[region];
@@ -1458,6 +1556,14 @@ namespace  {
       handle(o, (*i).second, pmf);
     }
   }
+  template <typename O, typename C, typename F> void handleRMap_(const O* o, const C& c, F pmf) {
+    for (typename C::const_iterator i = c.begin(); i != c.end(); ++i)  {
+      const auto& cc = (*i).second;
+      for (const auto& j : cc)   {
+	(o->*pmf)(j);
+      }
+    }
+  }
 }
 
 /// Create geometry conversion
@@ -1477,7 +1583,7 @@ Geant4Converter& Geant4Converter::create(DetElement top) {
   //debugMaterials  = true;
   //debugElements   = true;
   debugReflections  = true;
-  
+  debugPlacements   = true;
 #if ROOT_VERSION_CODE >= ROOT_VERSION(6,17,0)
   handleArray(this, geo.manager->GetListOfGDMLMatrices(), &Geant4Converter::handleMaterialProperties);
   handleArray(this, geo.manager->GetListOfOpticalSurfaces(), &Geant4Converter::handleOpticalSurface);
@@ -1497,6 +1603,7 @@ Geant4Converter& Geant4Converter::create(DetElement top) {
   handleRMap(this, *m_data,     &Geant4Converter::handleAssembly);
   // Now place all this stuff appropriately
   handleRMap(this, *m_data,     &Geant4Converter::handlePlacement);
+  //handleRMap_(this, *m_places,   &Geant4Converter::handlePlacement2);
 #if ROOT_VERSION_CODE >= ROOT_VERSION(6,17,0)
   /// Handle concrete surfaces
   handleArray(this, geo.manager->GetListOfSkinSurfaces(),   &Geant4Converter::handleSkinSurface);
diff --git a/DDG4/src/Geant4IsotropeGenerator.cpp b/DDG4/src/Geant4IsotropeGenerator.cpp
index 1a8aaddd8..54588aafd 100644
--- a/DDG4/src/Geant4IsotropeGenerator.cpp
+++ b/DDG4/src/Geant4IsotropeGenerator.cpp
@@ -133,5 +133,5 @@ void Geant4IsotropeGenerator::getParticleDirection(int num, ROOT::Math::XYZVecto
     break;
   }
   except("Unknown distribution densitiy: %s. Cannot generate primaries.",
-         m_distribution.c_str());
+	 m_distribution.c_str());
 }
diff --git a/DDG4/src/Geant4ParticleGenerator.cpp b/DDG4/src/Geant4ParticleGenerator.cpp
index 898c2ac7d..d16cf736c 100644
--- a/DDG4/src/Geant4ParticleGenerator.cpp
+++ b/DDG4/src/Geant4ParticleGenerator.cpp
@@ -42,8 +42,8 @@ Geant4ParticleGenerator::Geant4ParticleGenerator(Geant4Context* ctxt, const stri
   declareProperty("Energy",        m_energy = 50 * CLHEP::MeV);
   declareProperty("Multiplicity",  m_multiplicity = 1);
   declareProperty("Mask",          m_mask = 0);
-  declareProperty("Position",      m_position);
-  declareProperty("Direction",     m_direction);
+  declareProperty("Position",      m_position = ROOT::Math::XYZVector(0.,0.,0.));
+  declareProperty("Direction",     m_direction = ROOT::Math::XYZVector(1.,1.,1.));
 }
 
 /// Default destructor
@@ -117,7 +117,7 @@ void Geant4ParticleGenerator::operator()(G4Event*) {
 
   Geant4Vertex* vtx = new Geant4Vertex();
   int multiplicity = m_multiplicity;
-  ROOT::Math::XYZVector unit_direction, direction, position = m_position;
+  ROOT::Math::XYZVector unit_direction, position = m_position;
   getVertexPosition(position);
   getParticleMultiplicity(multiplicity);
   vtx->mask = m_mask;
@@ -127,8 +127,8 @@ void Geant4ParticleGenerator::operator()(G4Event*) {
   inter->vertices[m_mask].emplace_back( vtx );
   for(int i=0; i<m_multiplicity; ++i)   {
     double momentum = m_energy;
+    ROOT::Math::XYZVector direction = m_direction;
     Particle* p = new Particle();
-    direction = m_direction;
     getParticleDirection(i, direction, momentum);
     unit_direction  = direction.unit();
     p->id           = inter->nextPID();
@@ -155,8 +155,9 @@ void Geant4ParticleGenerator::operator()(G4Event*) {
     // p->vez        = vtx->z;
     inter->particles.emplace(p->id,p);
     vtx->out.insert(p->id);
-    printout(INFO,name(),"Particle [%d] %s %.3f GeV direction:(%6.3f %6.3f %6.3f)",
-             p->id, m_particleName.c_str(), momentum/CLHEP::GeV, 
+    printout(INFO,name(),"Particle [%d] %-12s Mom:%.3f GeV vertex:(%6.3f %6.3f %6.3f)[mm] direction:(%6.3f %6.3f %6.3f)",
+             p->id, m_particleName.c_str(), momentum/CLHEP::GeV,
+	     vtx->x/CLHEP::mm, vtx->y/CLHEP::mm, vtx->z/CLHEP::mm,
 	     direction.X(), direction.Y(), direction.Z());
 
   }
diff --git a/DDG4/src/Geant4ParticleGun.cpp b/DDG4/src/Geant4ParticleGun.cpp
index 1bfd9b11d..b4bdea577 100644
--- a/DDG4/src/Geant4ParticleGun.cpp
+++ b/DDG4/src/Geant4ParticleGun.cpp
@@ -32,10 +32,13 @@ Geant4ParticleGun::Geant4ParticleGun(Geant4Context* ctxt, const string& nam)
 {
   InstanceCount::increment(this);
   m_needsControl = true;
-  declareProperty("isotrop",      m_isotrop = false);
   declareProperty("Standalone",   m_standalone = true);
+  declareProperty("mask",         m_mask);
+  declareProperty("isotrop",      m_isotrop = false);
+  declareProperty("standalone",   m_standalone);
   // Backwards compatibility: Un-capitalize
   declareProperty("position",     m_position);
+  declareProperty("distribution", m_distribution);
   declareProperty("direction",    m_direction);
   declareProperty("energy",       m_energy);
   declareProperty("particle",     m_particleName);
@@ -48,17 +51,18 @@ Geant4ParticleGun::~Geant4ParticleGun() {
   InstanceCount::decrement(this);
 }
 
+/// Particle modification. Caller presets defaults to: ( direction = m_direction, momentum = m_energy)
+void Geant4ParticleGun::getParticleDirection(int num, ROOT::Math::XYZVector& direction, double& momentum) const  {
+  ( m_isotrop )
+    ? this->Geant4IsotropeGenerator::getParticleDirection(num, direction, momentum)
+    : this->Geant4ParticleGenerator::getParticleDirection(num, direction, momentum);
+}
+
 /// Callback to generate primary particles
 void Geant4ParticleGun::operator()(G4Event* event)   {
-  if ( m_isotrop )   {
-    double mom = 0.0;
-    this->Geant4IsotropeGenerator::getParticleDirection(0,m_direction,mom);
-  }
-  else  {
-    double r = m_direction.R(), eps = numeric_limits<float>::epsilon();
-    if ( r > eps )  {
-      m_direction.SetXYZ(m_direction.X()/r, m_direction.Y()/r, m_direction.Z()/r);
-    }
+  double r = m_direction.R(), eps = numeric_limits<float>::epsilon();
+  if ( r > eps )  {
+    m_direction.SetXYZ(m_direction.X()/r, m_direction.Y()/r, m_direction.Z()/r);
   }
 
   if ( m_standalone )  {
diff --git a/examples/ClientTests/compact/NestedBoxReflection.xml b/examples/ClientTests/compact/NestedBoxReflection.xml
index 745c5bcc0..af560b628 100644
--- a/examples/ClientTests/compact/NestedBoxReflection.xml
+++ b/examples/ClientTests/compact/NestedBoxReflection.xml
@@ -22,6 +22,7 @@
     <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"/>
     <vis name="VisibleGreen"  alpha="0.6" r="0.0" g="1.0" b="0.0" showDaughters="true" visible="true"/>
+    <vis name="VisibleCyan"   alpha="0.6" r="0.0" g="1.0" b="1.0" showDaughters="true" visible="true"/>
   </display>
 
   <limits>
@@ -30,6 +31,7 @@
     </limitset>
   </limits>
 
+  <geometry reflect="true"/>
   <detectors>
     <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>
diff --git a/examples/ClientTests/eve/NestedBoxReflection.xml b/examples/ClientTests/eve/NestedBoxReflection.xml
index 86b1fa628..264df55ec 100644
--- a/examples/ClientTests/eve/NestedBoxReflection.xml
+++ b/examples/ClientTests/eve/NestedBoxReflection.xml
@@ -1,7 +1,8 @@
 <ddeve>
   <display visLevel="7" loadLevel="3"/>
-  <collection name="NestedBoxHits" hits="PointSet" color="kMagenta" size="0.3" type="20"/>
-  <collection name="MCParticles"  hits="Particles" size="0.2" width="1" type="kCircle"/>
+  <collection name="NestedBoxHits"     hits="PointSet"  color="kMagenta" size="0.3"  type="20"      threshold="1000*eV"/>
+  <collectiona name="StartVertexPoints" hits="ParticleOrigin" color="kCyan"    size="2.3"  type="20"/>
+  <collectiona name="MCParticles"       hits="Particles" width="0.01"     size="0.01" type="kCircle" threshold="1.5*GeV" use="false"/>
 <!--
   <view name="3D Trackers R-Phi (Global)" type="RhoPhiProjection">
     <detelement name="NestedBox"    load_geo="-1" alpha="0.5"/>
diff --git a/examples/ClientTests/scripts/Check_reflection.py b/examples/ClientTests/scripts/Check_reflection.py
index 20f5184be..ab7681495 100644
--- a/examples/ClientTests/scripts/Check_reflection.py
+++ b/examples/ClientTests/scripts/Check_reflection.py
@@ -7,12 +7,13 @@
 """
 from __future__ import absolute_import, unicode_literals
 import logging
+import math
 import time
 import sys
 import os
 from g4units import rad, GeV, MeV, mm, m
 from ddsix.moves import range
-from math import pi
+
 
 logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.INFO)
 logger = logging.getLogger(__name__)
@@ -92,13 +93,14 @@ def run():
   # Setup particle gun
   geant4.setupGun(name="Gun",
                   particle='e-',
-                  energy=1000*GeV,
+                  energy=1000 * GeV,
+                  isotrop=True,
                   multiplicity=1,
-                  position=(0*m, 0*m, 0*m),
-                  PhiMin=0.0*rad,
-                  PhiMax=math.pi*2.0*rad,
-                  ThetaMin=0.0*rad,
-                  ThetaMax=math.pi*rad)
+                  position=(0 * m, 0 * m, 0 * m),
+                  PhiMin=0.0 * rad,
+                  PhiMax=math.pi * 2.0 * rad,
+                  ThetaMin=0.0 * rad,
+                  ThetaMax=math.pi * rad)
 
   logger.info("#  ....and handle the simulation particles.")
   part = DDG4.GeneratorAction(kernel, str('Geant4ParticleHandler/ParticleHandler'))
diff --git a/examples/ClientTests/src/NestedBoxReflection_geo.cpp b/examples/ClientTests/src/NestedBoxReflection_geo.cpp
index 1897890ab..c8cf2264d 100644
--- a/examples/ClientTests/src/NestedBoxReflection_geo.cpp
+++ b/examples/ClientTests/src/NestedBoxReflection_geo.cpp
@@ -82,28 +82,31 @@ namespace   {
         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"};
+	bool         sens = level == 2 || level == 0;
+        Box          long_box(bx*0.2, by*0.2, bz*0.4);
+        Box          flat_box(bx*1.0, by*1.0, bz*0.1);
+        Box          mini_box(bx*0.2, by*0.2, bz*0.2);
+        const char*  cols[5] = {"VisibleRed","VisibleBlue","VisibleGreen","VisibleYellow","VisibleCyan"};
         const char*  c;
         PlacedVolume pv;
         Volume       v;
 
-        c = cols[(0+level)%4];
-        v = Volume(_toString(1,"box%d"), small_box, mat);
+        c = cols[(0+level)%5];
+        v = Volume(_toString(1,"box%d"), mini_box, mat);
         v.setRegion(vol.region());
-        v.setSensitiveDetector(sensitive);
         v.setLimitSet(vol.limitSet());
+        if ( !sens ) v.setSensitiveDetector(sensitive);
         v.setVisAttributes(description, c);
         pv = vol.placeVolume(v, Position(0,0,0));
         pv.addPhysVolID(_toString(level,"lvl%d"), 1);
         printout(INFO,"NestedBoxReflection","++ Volume: %s  Color: %s", v.name(), c);
         place_boxes(level-1, v);
 
-        c = cols[(1+level)%4];
-        v = Volume(_toString(2,"box%d"), small_box, mat);
+        c = cols[(1+level)%5];
+        v = Volume(_toString(2,"box%d"), long_box, mat);
         v.setRegion(vol.region());
-        v.setSensitiveDetector(sensitive);
         v.setLimitSet(vol.limitSet());
+        if ( !sens ) v.setSensitiveDetector(sensitive);
         v.setVisAttributes(description, c);
         pv = vol.placeVolume(v, Position(0.8*bx,0,0));
         pv.addPhysVolID(_toString(level,"lvl%d"), 2);
@@ -115,11 +118,11 @@ namespace   {
         pv = vol.placeVolume(v, Position(0.4*bx,0,0));
         printout(INFO,"NestedBoxReflection","++ Volume: %s  Color: %s", v.name(), c);
 
-        c = cols[(2+level)%4];
-        v = Volume(_toString(3,"box%d"), small_box, mat);
+        c = cols[(2+level)%5];
+        v = Volume(_toString(3,"box%d"), mini_box, mat);
         v.setRegion(vol.region());
-        v.setSensitiveDetector(sensitive);
         v.setLimitSet(vol.limitSet());
+        if ( !sens ) v.setSensitiveDetector(sensitive);
         v.setVisAttributes(description, c);
         pv = vol.placeVolume(v, Position(0,0.8*by,0));
         pv.addPhysVolID(_toString(level,"lvl%d"), 3);
@@ -131,11 +134,11 @@ namespace   {
         pv = vol.placeVolume(v, Position(0,0.4*by,0));
         printout(INFO,"NestedBoxReflection","++ Volume: %s  Color: %s", v.name(), c);
 
-        c = cols[(3+level)%4];
-        v = Volume(_toString(4,"box%d"), small_box, mat);
+        c = cols[(3+level)%5];
+        v = Volume(_toString(4,"box%d"), mini_box, mat);
         v.setRegion(vol.region());
-        v.setSensitiveDetector(sensitive);
         v.setLimitSet(vol.limitSet());
+        if ( !sens ) v.setSensitiveDetector(sensitive);
         v.setVisAttributes(description, c);
         pv = vol.placeVolume(v, Position(0,0,0.8*bz));
         pv.addPhysVolID(_toString(level,"lvl%d"), 4);
@@ -146,6 +149,19 @@ namespace   {
         v.setVisAttributes(description, c);
         pv = vol.placeVolume(v, Position(0,0,0.4*bz));
         printout(INFO,"NestedBoxReflection","++ Volume: %s  Color: %s", v.name(), c);
+
+        c = cols[(4+level)%5];
+        v = Volume(_toString(5,"box%d"), flat_box, mat);
+        v.setRegion(vol.region());
+        v.setLimitSet(vol.limitSet());
+        v.setVisAttributes(description, c);
+        if ( !sens ) v.setSensitiveDetector(sensitive);
+	TGeoHMatrix* mtx = detail::matrix::_transform(Position(0,0,0.9*bz));
+	mtx->ReflectZ(kTRUE, kFALSE);
+        pv = vol.placeVolume(v, mtx);
+        pv.addPhysVolID(_toString(level,"lvl%d"), 5);
+        printout(INFO,"NestedBoxReflection","++ Volume: %s  Color: %s", v.name(), c);
+        place_boxes(level-1, v);
       }
     }
     
-- 
GitLab