From 94f51fae8f56684e72b483d9624ee32d7d536285 Mon Sep 17 00:00:00 2001
From: Markus Frank <Markus.Frank@cern.ch>
Date: Wed, 7 Mar 2018 12:19:51 +0100
Subject: [PATCH] Implement per particle limits in DDG4

---
 DDCore/include/DD4hep/IOV.h          |  15 ++--
 DDCore/include/DD4hep/Objects.h      |   6 ++
 DDCore/src/IOV.cpp                   |  12 +--
 DDG4/include/DDG4/Geant4UserLimits.h | 103 ++++++++++++++++++++++++++
 DDG4/src/Geant4Converter.cpp         |   9 ++-
 DDG4/src/Geant4UserLimits.cpp        | 107 +++++++++++++++++++++++++++
 6 files changed, 238 insertions(+), 14 deletions(-)
 create mode 100644 DDG4/include/DDG4/Geant4UserLimits.h
 create mode 100644 DDG4/src/Geant4UserLimits.cpp

diff --git a/DDCore/include/DD4hep/IOV.h b/DDCore/include/DD4hep/IOV.h
index fbcbeca03..8cdf334a2 100644
--- a/DDCore/include/DD4hep/IOV.h
+++ b/DDCore/include/DD4hep/IOV.h
@@ -71,12 +71,17 @@ namespace dd4hep {
     typedef long Key_second_type;
     typedef std::pair<Key_first_type,Key_second_type> Key;
 
-    const IOVType* iovType;
-    Key            keyData;
-    int            optData;
-    /// IOV buffer type: Must be a bitmap!
-    unsigned int   type;
+    enum { INVALID_KEY = 0 };
 
+    /// Reference to IOV type
+    const IOVType* iovType = 0;
+    /// IOV key (if second==first, discrete, otherwise range)
+    Key            keyData{INVALID_KEY,INVALID_KEY};
+    /// Optional user data
+    int            optData = 0;
+    /// IOV buffer type: Must be a bitmap!
+    unsigned int   type    = IOVType::UNKNOWN_IOV;
+    
     /// Initializing constructor
     explicit IOV(const IOVType* typ);
     /// Specialized copy constructor for range IOVs
diff --git a/DDCore/include/DD4hep/Objects.h b/DDCore/include/DD4hep/Objects.h
index d699a8753..5f207d2c7 100644
--- a/DDCore/include/DD4hep/Objects.h
+++ b/DDCore/include/DD4hep/Objects.h
@@ -362,11 +362,17 @@ namespace dd4hep {
    */
   class Limit {
   public:
+    /// Particle the limit should be applied to
     std::string particles;
+    /// Limit name
     std::string name;
+    /// Units
     std::string unit;
+    /// Content
     std::string content;
+    /// Double value
     double value = 0.0;
+  public:
     /// Default constructor
     Limit() = default;
     /// Copy constructor
diff --git a/DDCore/src/IOV.cpp b/DDCore/src/IOV.cpp
index e5be1dd33..f52c1a9ec 100644
--- a/DDCore/src/IOV.cpp
+++ b/DDCore/src/IOV.cpp
@@ -41,22 +41,22 @@ std::string IOVType::str()  const   {
 }
 
 /// Initializing constructor
-IOV::IOV(const IOVType* t) : iovType(t), keyData(0,0), optData(0)  {
-  type = t ? t->type : int(IOVType::UNKNOWN_IOV);
+IOV::IOV(const IOVType* t) : iovType(t)  {
+  if ( t ) type = t->type;
 }
 
 /// Specialized copy constructor for discrete IOVs
 IOV::IOV(const IOVType* t, Key_first_type iov_value)
-  : iovType(t), keyData(iov_value,iov_value), optData(0)
+  : iovType(t), keyData(iov_value,iov_value)
 {
-  type = t ? t->type : int(IOVType::UNKNOWN_IOV);
+  if ( t ) type = t->type;
 }
 
 /// Copy constructor
 IOV::IOV(const IOVType* t, const Key& k)
-  : iovType(t), keyData(k), optData(0)
+  : iovType(t), keyData(k)
 {
-  type = t ? t->type : int(IOVType::UNKNOWN_IOV);
+  if ( t ) type = t->type;
 }
 
 /// Set discrete IOV value
diff --git a/DDG4/include/DDG4/Geant4UserLimits.h b/DDG4/include/DDG4/Geant4UserLimits.h
new file mode 100644
index 000000000..48dc389c6
--- /dev/null
+++ b/DDG4/include/DDG4/Geant4UserLimits.h
@@ -0,0 +1,103 @@
+//==========================================================================
+//  AIDA Detector description implementation 
+//--------------------------------------------------------------------------
+// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
+// All rights reserved.
+//
+// For the licensing terms see $DD4hepINSTALL/LICENSE.
+// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
+//
+// Author     : M.Frank
+//
+//==========================================================================
+#ifndef DD4HEP_DDG4_GEANT4USERLIMITS_H
+#define DD4HEP_DDG4_GEANT4USERLIMITS_H
+
+// Framework include files
+#include "DD4hep/Objects.h"
+
+// Geant 4 include files
+#include "G4UserLimits.hh"
+
+// Forward declarations
+class G4ParticleDefinition;
+
+/// Namespace for the AIDA detector description toolkit
+namespace dd4hep {
+
+
+  /// Namespace for the Geant4 based simulation part of the AIDA detector description toolkit
+  namespace sim {
+
+    /// Helper to dump Geant4 volume hierarchy
+    /**
+     *  \author  M.Frank
+     *  \version 1.0
+     *  \ingroup DD4HEP_SIMULATION
+     */
+    class Geant4UserLimits : public  G4UserLimits {
+    public:
+      /// Helper class to one limit type
+      /**
+       *  \author  M.Frank
+       *  \version 1.0
+       *  \ingroup DD4HEP_SIMULATION
+       */
+      struct Handler  {
+      public:
+        /// Default value (either from base class or value if Limit.particles='*')
+        double                defaultValue = 0.0;
+        /// Handler particle ids for the limit (pdgID)
+        std::map<const G4ParticleDefinition*, double> particleLimits;
+      public:
+        /// Default constructor
+        Handler() = default;
+        /// Set the handler value(s)
+        void set(const std::string& particles, double val);
+        /// Access value according to track
+        double value(const G4Track& track) const;
+      };
+      /// Handle to the limitset to be applied.
+      LimitSet  limits;
+      /// Handler map for MaxStepLength limit
+      Handler   maxStepLength;
+      /// Handler map for MaxTrackLength limit
+      Handler   maxTrackLength;
+      /// Handler map for MaxTime limit
+      Handler   maxTime;
+      /// Handler map for MinEKine limit
+      Handler   minEKine;
+      /// Handler map for MinRange limit
+      Handler   minRange;
+
+    public:
+      /// Initializing Constructor
+      Geant4UserLimits(LimitSet ls);
+      /// Standard destructor
+      virtual ~Geant4UserLimits();
+      /// Access the user tracklength for a G4 track object
+      virtual G4double GetMaxAllowedStep(const G4Track& track)
+      {  return maxStepLength.value(track);    }
+      /// Access the user tracklength for a G4 track object
+      virtual G4double GetUserMaxTrackLength(const G4Track& track)
+      {  return maxTrackLength.value(track);   }
+      /// Access the proper time cut for a G4 track object
+      virtual G4double GetUserMaxTime (const G4Track& track)
+      {  return maxTime.value(track);          }
+      /// Access the kinetic energy cut for a G4 track object
+      virtual G4double GetUserMinEkine(const G4Track& track)
+      {  return minEKine.value(track);         }
+      /// Access the range cut for a G4 track object
+      virtual G4double GetUserMinRange(const G4Track& track)
+      {  return minRange.value(track);         }
+      /// Setters may not be called!
+      virtual void SetMaxAllowedStep(G4double ustepMax);    
+      virtual void SetUserMaxTrackLength(G4double utrakMax);
+      virtual void SetUserMaxTime(G4double utimeMax);
+      virtual void SetUserMinEkine(G4double uekinMin);
+      virtual void SetUserMinRange(G4double urangMin);
+    };
+  }
+}
+
+#endif  // DD4HEP_DDG4_GEANT4USERLIMITS_H
diff --git a/DDG4/src/Geant4Converter.cpp b/DDG4/src/Geant4Converter.cpp
index 154db9353..6fe49ace5 100644
--- a/DDG4/src/Geant4Converter.cpp
+++ b/DDG4/src/Geant4Converter.cpp
@@ -22,6 +22,7 @@
 
 #include "DDG4/Geant4Field.h"
 #include "DDG4/Geant4Converter.h"
+#include "DDG4/Geant4UserLimits.h"
 #include "DDG4/Geant4SensitiveDetector.h"
 
 // ROOT includes
@@ -856,11 +857,12 @@ void* Geant4Converter::handleRegion(Region region, const set<const TGeoVolume*>&
 void* Geant4Converter::handleLimitSet(LimitSet limitset, const set<const TGeoVolume*>& /* volumes */) const {
   G4UserLimits* g4 = data().g4Limits[limitset];
   if (!g4) {
+    g4 = new Geant4UserLimits(limitset);
+    /*
     LimitSet ls = limitset;
-    g4 = new G4UserLimits(limitset->GetName());
+    g4 = new G4UserLimits(limitset);
     const set<Limit>& limits = ls.limits();
-    for (LimitSet::Object::const_iterator i = limits.begin(); i != limits.end(); ++i) {
-      const Limit& l = *i;
+    for (const auto& l : limits)  {
       if (l.name == "step_length_max")
         g4->SetMaxAllowedStep(l.value*CLHEP::mm/units::mm);
       else if (l.name == "track_length_max")
@@ -874,6 +876,7 @@ void* Geant4Converter::handleLimitSet(LimitSet limitset, const set<const TGeoVol
       else
         throw runtime_error("Unknown Geant4 user limit: " + l.toString());
     }
+    */
     data().g4Limits[limitset] = g4;
   }
   return g4;
diff --git a/DDG4/src/Geant4UserLimits.cpp b/DDG4/src/Geant4UserLimits.cpp
new file mode 100644
index 000000000..659dc7e56
--- /dev/null
+++ b/DDG4/src/Geant4UserLimits.cpp
@@ -0,0 +1,107 @@
+//==========================================================================
+//  AIDA Detector description implementation 
+//--------------------------------------------------------------------------
+// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
+// All rights reserved.
+//
+// For the licensing terms see $DD4hepINSTALL/LICENSE.
+// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
+//
+// Author     : M.Frank
+//
+//==========================================================================
+
+// Framework include files
+#include "DDG4/Geant4UserLimits.h"
+#include "DDG4/Geant4Particle.h"
+#include "DD4hep/InstanceCount.h"
+#include "DD4hep/DD4hepUnits.h"
+#include "DD4hep/Primitives.h"
+
+// Geant 4 include files
+#include "G4Track.hh"
+#include "CLHEP/Units/SystemOfUnits.h"
+
+// C/C++ include files
+#include <stdexcept>
+
+using namespace std;
+using namespace dd4hep::sim;
+
+/// Access value according to track
+double Geant4UserLimits::Handler::value(const G4Track& track) const    {
+  if ( !particleLimits.empty() )  {
+    auto i = particleLimits.find(track.GetDefinition());
+    if ( i != particleLimits.end() )  {
+      return (*i).second;
+    }
+  }
+  return defaultValue;
+}
+
+/// Set the handler value(s)
+void Geant4UserLimits::Handler::set(const string& particles, double val)   {
+  if ( particles == "*" )   {
+    defaultValue = val;
+    return;
+  }
+  auto defs = Geant4ParticleHandle::g4DefinitionsRegEx(particles);
+  for(auto* d : defs)
+    particleLimits[d] = val;
+}
+
+/// Initializing Constructor
+Geant4UserLimits::Geant4UserLimits(LimitSet ls)
+  : G4UserLimits(ls.name()), limits(ls)
+{
+  const auto& lim = limits.limits();
+  InstanceCount::increment(this);
+  /// Set defaults
+  maxStepLength.defaultValue  = fMaxStep;
+  maxTrackLength.defaultValue = fMaxTrack;
+  maxTime.defaultValue        = fMaxTime;
+  minEKine.defaultValue       = fMinEkine;
+  minRange.defaultValue       = fMinRange;
+  /// Overwrite with values if present:
+  for(const Limit& l : lim)   {
+    if (l.name == "step_length_max")
+      maxStepLength.set(l.particles, l.value*CLHEP::mm/dd4hep::mm);
+    else if (l.name == "track_length_max")
+      maxTrackLength.set(l.particles, l.value*CLHEP::mm/dd4hep::mm);
+    else if (l.name == "time_max")
+      maxTime.set(l.particles, l.value*CLHEP::ns/dd4hep::ns);
+    else if (l.name == "ekin_min")
+      minEKine.set(l.particles, l.value*CLHEP::MeV/dd4hep::MeV);
+    else if (l.name == "range_min")
+      minRange.set(l.particles, l.value);
+    else
+      throw runtime_error("Unknown Geant4 user limit: " + l.toString());
+  }
+}
+
+/// Standard destructor
+Geant4UserLimits::~Geant4UserLimits()  {
+  InstanceCount::decrement(this);
+}
+
+/// Setters may not be called!
+void Geant4UserLimits::SetMaxAllowedStep(G4double /* ustepMax */)  {
+  dd4hep::notImplemented(string(__PRETTY_FUNCTION__)+" May not be called!");
+}
+
+void Geant4UserLimits::SetUserMaxTrackLength(G4double /* utrakMax */)  {
+  dd4hep::notImplemented(string(__PRETTY_FUNCTION__)+" May not be called!");
+}
+
+void Geant4UserLimits::SetUserMaxTime(G4double /* utimeMax */)  {
+  dd4hep::notImplemented(string(__PRETTY_FUNCTION__)+" May not be called!");
+}
+
+void Geant4UserLimits::SetUserMinEkine(G4double /* uekinMin */)  {
+  dd4hep::notImplemented(string(__PRETTY_FUNCTION__)+" May not be called!");
+}
+
+void Geant4UserLimits::SetUserMinRange(G4double /* urangMin */)  {
+  dd4hep::notImplemented(string(__PRETTY_FUNCTION__)+" May not be called!");
+}
+
-- 
GitLab