From 860de18f762ce6d299f45eb33ecedddb1218fdcc Mon Sep 17 00:00:00 2001
From: Markus Frank <Markus.Frank@cern.ch>
Date: Thu, 4 Jul 2019 13:42:01 +0200
Subject: [PATCH] Prepare DD4hep for Geant4 units in TGeo; Start digitization
 package

---
 DDCore/include/DD4hep/Handle.h                |   6 -
 DDCore/src/DetectorImp.cpp                    |   8 +-
 DDCore/src/MatrixHelpers.cpp                  |   8 +
 DDCore/src/Printout.cpp                       |   5 +
 DDCore/src/plugins/Compact2Objects.cpp        |  29 +-
 DDCore/src/plugins/LCDDConverter.cpp          |   3 +-
 DDDigi/CMakeLists.txt                         |  37 ++
 DDDigi/include/DDDigi/DigiAction.h            | 311 +++++++++++++++
 DDDigi/include/DDDigi/DigiActionSequence.h    |  81 ++++
 DDDigi/include/DDDigi/DigiContext.h           | 126 ++++++
 DDDigi/include/DDDigi/DigiData.h              | 149 +++++++
 DDDigi/include/DDDigi/DigiFactories.h         |  61 +++
 DDDigi/include/DDDigi/DigiHandle.h            | 120 ++++++
 DDDigi/include/DDDigi/DigiInputAction.h       |  59 +++
 DDDigi/include/DDDigi/DigiKernel.h            | 152 +++++++
 DDDigi/include/DDDigi/DigiLockedAction.h      |  66 ++++
 DDDigi/include/DDDigi/DigiSynchronize.h       |  61 +++
 DDDigi/plugins/DigiRandomNoise.cpp            | 107 +++++
 DDDigi/plugins/DigiTestAction.cpp             | 107 +++++
 DDDigi/plugins/dummy.cpp                      |  53 +++
 DDDigi/python/DDDigi.py                       | 372 ++++++++++++++++++
 DDDigi/python/DDDigiDict.C                    | 155 ++++++++
 DDDigi/src/DigiAction.cpp                     | 208 ++++++++++
 DDDigi/src/DigiActionSequence.cpp             |  50 +++
 DDDigi/src/DigiContext.cpp                    |  79 ++++
 DDDigi/src/DigiData.cpp                       |  44 +++
 DDDigi/src/DigiHandle.cpp                     | 190 +++++++++
 DDDigi/src/DigiInputAction.cpp                |  44 +++
 DDDigi/src/DigiKernel.cpp                     | 365 +++++++++++++++++
 DDDigi/src/DigiLockedAction.cpp               |  57 +++
 DDDigi/src/DigiSynchronize.cpp                |  71 ++++
 DDDigi/test_task_queue.cpp                    |  41 ++
 DDEve/src/HitActors.cpp                       |   6 +
 DDEve/src/ParticleActors.cpp                  |  17 +-
 DDG4/src/Geant4Converter.cpp                  |   2 +
 DDG4/src/Geant4SensDetAction.cpp              |   6 +
 DDG4/src/Geant4SensitiveDetector.cpp          |   6 +
 DDG4/src/Geant4StepHandler.cpp                |   4 +
 DDParsers/include/Evaluator/DD4hepUnits.h     | 316 ++++++++-------
 DDParsers/src/Evaluator/setSystemOfUnits.cpp  |   5 +
 .../ClientTests/src/MaterialTester_geo.cpp    |  39 +-
 41 files changed, 3447 insertions(+), 179 deletions(-)
 create mode 100644 DDDigi/CMakeLists.txt
 create mode 100644 DDDigi/include/DDDigi/DigiAction.h
 create mode 100644 DDDigi/include/DDDigi/DigiActionSequence.h
 create mode 100644 DDDigi/include/DDDigi/DigiContext.h
 create mode 100644 DDDigi/include/DDDigi/DigiData.h
 create mode 100644 DDDigi/include/DDDigi/DigiFactories.h
 create mode 100644 DDDigi/include/DDDigi/DigiHandle.h
 create mode 100644 DDDigi/include/DDDigi/DigiInputAction.h
 create mode 100644 DDDigi/include/DDDigi/DigiKernel.h
 create mode 100644 DDDigi/include/DDDigi/DigiLockedAction.h
 create mode 100644 DDDigi/include/DDDigi/DigiSynchronize.h
 create mode 100644 DDDigi/plugins/DigiRandomNoise.cpp
 create mode 100644 DDDigi/plugins/DigiTestAction.cpp
 create mode 100644 DDDigi/plugins/dummy.cpp
 create mode 100644 DDDigi/python/DDDigi.py
 create mode 100644 DDDigi/python/DDDigiDict.C
 create mode 100644 DDDigi/src/DigiAction.cpp
 create mode 100644 DDDigi/src/DigiActionSequence.cpp
 create mode 100644 DDDigi/src/DigiContext.cpp
 create mode 100644 DDDigi/src/DigiData.cpp
 create mode 100644 DDDigi/src/DigiHandle.cpp
 create mode 100644 DDDigi/src/DigiInputAction.cpp
 create mode 100644 DDDigi/src/DigiKernel.cpp
 create mode 100644 DDDigi/src/DigiLockedAction.cpp
 create mode 100644 DDDigi/src/DigiSynchronize.cpp
 create mode 100644 DDDigi/test_task_queue.cpp

diff --git a/DDCore/include/DD4hep/Handle.h b/DDCore/include/DD4hep/Handle.h
index e41635869..32ff10a3b 100644
--- a/DDCore/include/DD4hep/Handle.h
+++ b/DDCore/include/DD4hep/Handle.h
@@ -28,12 +28,6 @@
 #ifndef DEGREE_2_RAD
 #define DEGREE_2_RAD 0.0174532925199432957692369076848
 #endif
-#ifndef CM_2_MM
-#define CM_2_MM 10.0
-#endif
-#ifndef MM_2_CM
-#define MM_2_CM 0.1
-#endif
 
 #ifndef M_PI
 #define M_PI 3.14159265358979323846
diff --git a/DDCore/src/DetectorImp.cpp b/DDCore/src/DetectorImp.cpp
index 2416ed3dd..9ea6437be 100644
--- a/DDCore/src/DetectorImp.cpp
+++ b/DDCore/src/DetectorImp.cpp
@@ -32,6 +32,7 @@
 #include <mutex>
 
 // ROOT inlcude files
+#include "TGeant4SystemOfUnits.h"
 #include "TGeoCompositeShape.h"
 #include "TGeoBoolNode.h"
 #include "TGeoManager.h"
@@ -154,9 +155,10 @@ DetectorImp::DetectorImp()
 DetectorImp::DetectorImp(const string& name)
   : TNamed(), DetectorData(), DetectorLoad(this), m_buildType(BUILD_NONE)
 {
+  //TGeant4Unit::setUnitType(TGeant4Unit::kTGeant4Units);
   SetTitle("DD4hep detector description object");
-  set_unexpected( description_unexpected ) ;
-  set_terminate( description_unexpected ) ;
+  set_unexpected( description_unexpected );
+  set_terminate( description_unexpected );
   InstanceCount::increment(this);
   //if ( gGeoManager ) delete gGeoManager;
   m_manager = new TGeoManager(name.c_str(), "Detector Geometry");
@@ -167,7 +169,7 @@ DetectorImp::DetectorImp(const string& name)
     table->TGeoElementTable::~TGeoElementTable();
     new(table) TGeoElementTable();
     // This will initialize the table without filling:
-    table->AddElement("VACUUM","VACUUM"   ,0,   0, 0.0);
+    table->AddElement("VACUUM","VACUUM", 0, 0, 0.0);
     table->Print();
 #endif
   }
diff --git a/DDCore/src/MatrixHelpers.cpp b/DDCore/src/MatrixHelpers.cpp
index 8b16d136e..1a70ccac0 100644
--- a/DDCore/src/MatrixHelpers.cpp
+++ b/DDCore/src/MatrixHelpers.cpp
@@ -13,12 +13,20 @@
 
 // Framework include files
 #include "DD4hep/MatrixHelpers.h"
+#include "DD4hep/DD4hepUnits.h"
+
+#ifdef HAVE_GEANT4_UNITS
+#define MM_2_CM 1.0
+#else
+#define MM_2_CM 0.1
+#endif
 
 // ROOT includes
 #include "TGeoMatrix.h"
 
 using namespace dd4hep;
 
+
 TGeoIdentity* dd4hep::detail::matrix::_identity() {
   return gGeoIdentity;
 }
diff --git a/DDCore/src/Printout.cpp b/DDCore/src/Printout.cpp
index a9242f7d9..69ca75ae3 100644
--- a/DDCore/src/Printout.cpp
+++ b/DDCore/src/Printout.cpp
@@ -15,6 +15,7 @@
 #include "DD4hep/Printout.h"
 
 // C/C++ include files
+#include <mutex>
 #include <cstring>
 #include <cstdarg>
 #include <sstream>
@@ -27,6 +28,8 @@
 using namespace std;
 
 namespace {
+  std::mutex s_output_synchronization;
+
   size_t _the_printer_1(void*, dd4hep::PrintLevel lvl, const char* src, const char* text);
   size_t _the_printer_2(void* par, dd4hep::PrintLevel lvl, const char* src, const char* fmt, va_list& args);
 
@@ -54,6 +57,7 @@ namespace {
   }
 
   size_t _the_printer_1(void*, dd4hep::PrintLevel lvl, const char* src, const char* text) {
+    std::lock_guard<std::mutex> lock(s_output_synchronization);
     ::fflush(stdout);
     ::fflush(stderr);
     cout << flush;
@@ -66,6 +70,7 @@ namespace {
   size_t _the_printer_2(void* par, dd4hep::PrintLevel lvl, const char* src, const char* fmt, va_list& args) {
     if ( !print_func_1 )  {
       char text[4096];
+      std::lock_guard<std::mutex> lock(s_output_synchronization);
       ::fflush(stdout);
       ::fflush(stderr);
       cout << flush;
diff --git a/DDCore/src/plugins/Compact2Objects.cpp b/DDCore/src/plugins/Compact2Objects.cpp
index 1950d6f37..99b9fef8e 100644
--- a/DDCore/src/plugins/Compact2Objects.cpp
+++ b/DDCore/src/plugins/Compact2Objects.cpp
@@ -363,7 +363,8 @@ template <> void Converter<Header>::operator()(xml_h e) const {
   h.setComment(e.child(_U(comment)).text());
   description.setHeader(h);
 }
-
+#include "TGeoPhysicalConstants.h"
+#include "TMath.h"
 /** Convert compact material/element description objects
  *
  *  Materials:
@@ -413,16 +414,6 @@ template <> void Converter<Material>::operator()(xml_h e) const {
     }
     printout(s_debug.materials ? ALWAYS : DEBUG, "Compact",
              "++ Converting material %-16s  Density: %.3f.",matname, dens_val);
-#if 0
-    cout << "Gev    " << xml::_toDouble(_Unicode(GeV)) << endl;
-    cout << "sec    " << xml::_toDouble(_Unicode(second)) << endl;
-    cout << "nsec   " << xml::_toDouble(_Unicode(nanosecond)) << endl;
-    cout << "kilo   " << xml::_toDouble(_Unicode(kilogram)) << endl;
-    cout << "kilo   " << xml::_toDouble(_Unicode(joule*s*s/(m*m))) << endl;
-    cout << "meter  " << xml::_toDouble(_Unicode(meter)) << endl;
-    cout << "ampere " << xml::_toDouble(_Unicode(ampere)) << endl;
-    cout << "degree " << xml::_toDouble(_Unicode(degree)) << endl;
-#endif
     //throw 1;
     mat = mix = new TGeoMixture(matname, composites.size(), dens_val);
     size_t ifrac = 0;
@@ -462,7 +453,6 @@ template <> void Converter<Material>::operator()(xml_h e) const {
 #if ROOT_VERSION_CODE >= ROOT_VERSION(6,12,0)
     mix->ComputeDerivedQuantities();
 #endif
-
 #if ROOT_VERSION_CODE >= ROOT_VERSION(6,17,0)
     /// In case there were material properties specified: convert them here
     for(xml_coll_t properties(x_mat, _U(constant)); properties; ++properties) {
@@ -1439,6 +1429,21 @@ template <> void Converter<Compact>::operator()(xml_h element) const {
       }
     }
   }
+
+  if ( s_debug.materials || s_debug.elements )   {
+    printout(INFO,"Compact","+++ UNIT System:");
+    printout(INFO,"Compact","+++ Density:    %8.3g  Units:%8.3g",
+             xml::_toDouble(_Unicode(gram/cm3)), dd4hep::gram/dd4hep::cm3);
+    printout(INFO,"Compact","+++ GeV:        %8.3g  Units:%8.3g",xml::_toDouble(_Unicode(GeV)),dd4hep::GeV);
+    printout(INFO,"Compact","+++ sec:        %8.3g  Units:%8.3g",xml::_toDouble(_Unicode(second)),dd4hep::second);
+    printout(INFO,"Compact","+++ nanosecond: %8.3g  Units:%8.3g",xml::_toDouble(_Unicode(nanosecond)),dd4hep::nanosecond);
+    printout(INFO,"Compact","+++ kilo:       %8.3g  Units:%8.3g",xml::_toDouble(_Unicode(kilogram)),dd4hep::kilogram);
+    printout(INFO,"Compact","+++ kilo:       %8.3g  Units:%8.3g",xml::_toDouble(_Unicode(joule*s*s/(m*m))),
+             dd4hep::joule*dd4hep::s*dd4hep::s/(dd4hep::meter*dd4hep::meter));
+    printout(INFO,"Compact","+++ meter:      %8.3g  Units:%8.3g",xml::_toDouble(_Unicode(meter)),dd4hep::meter);
+    printout(INFO,"Compact","+++ ampere:     %8.3g  Units:%8.3g",xml::_toDouble(_Unicode(ampere)),dd4hep::ampere);
+    printout(INFO,"Compact","+++ degree:     %8.3g  Units:%8.3g",xml::_toDouble(_Unicode(degree)),dd4hep::degree);
+  }
   
   xml_coll_t(compact, _U(define)).for_each(_U(include), Converter<DetElementInclude>(description));
   xml_coll_t(compact, _U(define)).for_each(_U(constant), Converter<Constant>(description));
diff --git a/DDCore/src/plugins/LCDDConverter.cpp b/DDCore/src/plugins/LCDDConverter.cpp
index d1bdbb042..ecf007aec 100644
--- a/DDCore/src/plugins/LCDDConverter.cpp
+++ b/DDCore/src/plugins/LCDDConverter.cpp
@@ -16,6 +16,7 @@
 #include "DD4hep/Printout.h"
 #include "DD4hep/Volumes.h"
 #include "DD4hep/FieldTypes.h"
+#include "DD4hep/DD4hepUnits.h"
 #include "DD4hep/Segmentations.h"
 #include "DD4hep/detail/ObjectsInterna.h"
 #include "DD4hep/detail/DetectorInterna.h"
@@ -882,7 +883,7 @@ xml_h LCDDConverter::handleSegmentation(Segmentation seg) const {
       }
       // translate from TGeo units to Geant4 units if necessary
       if (v->unitType() == DDSegmentation::SegmentationParameter::LengthUnit) {
-        double value = _toDouble(v->value()) * CM_2_MM;
+        double value = _toDouble(v->value()) / dd4hep::mm;
         xml.setAttr(Unicode(v->name()), value);
       } else if (v->unitType() == DDSegmentation::SegmentationParameter::AngleUnit) {
         double value = _toDouble(v->value()) * DEGREE_2_RAD;
diff --git a/DDDigi/CMakeLists.txt b/DDDigi/CMakeLists.txt
new file mode 100644
index 000000000..68e494588
--- /dev/null
+++ b/DDDigi/CMakeLists.txt
@@ -0,0 +1,37 @@
+#==========================================================================
+#  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.
+#
+#==========================================================================
+dd4hep_package(    DDDigi
+  USES             DDCore
+                   [ROOT   REQUIRED COMPONENTS Geom GenVector RIO]
+		   TBB
+  INCLUDE_DIRS     include
+  INSTALL_INCLUDES include/DDDigi )
+
+#---Add Library---------------------------------------------------------------------
+dd4hep_add_package_library(DDDigi SOURCES src/*.cpp)
+target_compile_definitions(DDDigi PUBLIC DD4HEP_USE_TBB)
+message( STATUS "TBB_INCLUDE_DIR : ${TBB_INCLUDE_DIR}")
+message( STATUS "TBB_LIBRARY : ${TBB_LIBRARY}")
+
+#---------------------------  Legacy libraries -------------------------------------
+dd4hep_add_dictionary( G__DDDigi
+  SOURCES ${DDCore_INCLUDE_DIRS}/include/ROOT/Warnings.h python/DDDigiDict.C
+  LINKDEF ${DDCore_INCLUDE_DIRS}/include/ROOT/LinkDef.h
+  )
+#---------------------------  Plugin library for the digitization framework  -------
+dd4hep_add_plugin(DDDigiPlugins
+  GENERATED   G__DDDigi.cxx
+  SOURCES     plugins/*.cpp
+  )
+target_compile_definitions(DDDigiPlugins PUBLIC DD4HEP_USE_TBB)
+#---Package installation procedure(s) ----------------------------------------------
+#d4hep_install_dir(examples DESTINATION examples/DDDigi)
+dd4hep_install_files(FILES python/*.py python/*.C DESTINATION python)
diff --git a/DDDigi/include/DDDigi/DigiAction.h b/DDDigi/include/DDDigi/DigiAction.h
new file mode 100644
index 000000000..ff7b98976
--- /dev/null
+++ b/DDDigi/include/DDDigi/DigiAction.h
@@ -0,0 +1,311 @@
+//==========================================================================
+//  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_DDDIGI_DIGIACTION_H
+#define DD4HEP_DDDIGI_DIGIACTION_H
+
+// Framework include files
+#include "DD4hep/Printout.h"
+#include "DD4hep/Callback.h"
+#include "DD4hep/ComponentProperties.h"
+#include "DDDigi/DigiContext.h"
+
+// C/C++ include files
+#include <string>
+#include <cstdarg>
+
+/// Namespace for the AIDA detector description toolkit
+namespace dd4hep {
+
+  /// Namespace for the Digitization part of the AIDA detector description toolkit
+  namespace digi {
+
+    /// Cast operator
+    template <typename TO, typename FROM> TO fast_cast(FROM from) {
+#ifdef USE_FASTCAST
+      return static_cast<TO>(from);
+#else
+      return dynamic_cast<TO>(from);
+#endif
+    }
+
+    /// Helper class to handle strings of the format "type/name"
+    /**
+     *  \author  M.Frank
+     *  \version 1.0
+     *  \ingroup DD4HEP_DIGITIZATION
+     */
+    class TypeName : public std::pair<std::string, std::string> {
+    public:
+      /// Default constructor
+      TypeName() = default;
+      /// Copy constructor
+      TypeName(const TypeName& copy) = default;
+      /// Copy constructor from pair
+      TypeName(const std::pair<std::string, std::string>& c)
+        : std::pair<std::string, std::string>(c) {      }
+      /// Initializing constructor
+      TypeName(const std::string& typ, const std::string& nam)
+        : std::pair<std::string, std::string>(typ, nam) {      }
+      /// Assignment operator
+      TypeName& operator=(const TypeName& copy) = default;
+      /// Split string pair according to default delimiter ('/')
+      static TypeName split(const std::string& type_name);
+      /// Split string pair according to custom delimiter
+      static TypeName split(const std::string& type_name, const std::string& delim);
+    };
+
+    /// Default base class for all Digitizer actions and derivates thereof.
+    /**
+     *  This is a utility class supporting properties, output and access to
+     *  event and run objects through the context.
+     *
+     *  \author  M.Frank
+     *  \version 1.0
+     *  \ingroup DD4HEP_SIMULATION
+     */
+    class DigiAction {
+      friend class DigiKernel;
+
+    protected:
+      /// Reference to the Digi context
+      const DigiKernel&  m_kernel;
+      /// Action name
+      std::string        m_name;
+      /// Property pool
+      PropertyManager    m_properties;
+      /// Reference count. Initial value: 1
+      long               m_refCount    = 1;
+      /// Default property: Output level
+      int                m_outputLevel = 3;
+      ///
+      
+      /// Property: Support parallel execution
+      bool               m_parallel    = false;
+    protected:
+
+      /// Functor to access elements by name
+      struct FindByName  {
+        std::string _n;
+        FindByName(const std::string& n) : _n(n) {}
+        bool operator()(const DigiAction* a) { return a->name() == _n; }
+      };
+      /// Actor class to manipulate action groups
+      /**
+       *  \author  M.Frank
+       *  \version 1.0
+       *  \ingroup DD4HEP_SIMULATION
+       */
+      template <typename T> class Actors {
+      public:
+        typedef typename std::vector<T*> _V;
+        _V m_v;
+        Actors() = default;
+        ~Actors()  = default;
+        size_t size()    const        { return m_v.size();              }
+        void clear()                  { m_v.clear();                    }
+        void add(T* obj)              { m_v.push_back(obj);             }
+        void add_front(T* obj)        { m_v.insert(m_v.begin(), obj);   }
+        const typename _V::value_type& operator[](size_t i)  const
+        {  return m_v[i];}
+        typename _V::value_type& operator[](size_t i)  {  return m_v[i];}
+        operator const _V&() const    { return m_v;                     }
+        operator _V&()                { return m_v;                     }
+        const _V* operator->() const  { return &m_v;                    }
+        _V* operator->()              { return &m_v;                    }
+        typename _V::iterator begin() { return m_v.begin();             }
+        typename _V::iterator end()   { return m_v.end();               }
+        typename _V::const_iterator begin() const { return m_v.begin(); }
+        typename _V::const_iterator end()   const { return m_v.end();   }
+        
+        /// Context updates
+        void updateContext(DigiContext* ctxt)  {
+          (*this)(&T::updateContext,ctxt);
+        }
+        /// Element access by name
+        template <typename F> typename _V::value_type get(const F& f)  const   {
+          if (!m_v.empty())  {
+            typename _V::const_iterator i=std::find_if(m_v.begin(),m_v.end(),f);
+            return i==m_v.end() ? 0 : (*i);
+          }
+          return 0;
+        }
+        /// NON-CONST actions
+        template <typename R, typename Q> void operator()(R (Q::*pmf)()) {
+          if (m_v.empty())
+            return;
+          for (typename _V::iterator i = m_v.begin(); i != m_v.end(); ++i)
+            ((*i)->*pmf)();
+        }
+        template <typename R, typename Q, typename A0> void operator()(R (Q::*pmf)(A0&), A0& a0) {
+          if (m_v.empty())
+            return;
+          for (typename _V::iterator i = m_v.begin(); i != m_v.end(); ++i)
+            ((*i)->*pmf)(a0);
+        }
+        template <typename R, typename Q, typename A0, typename A1> void operator()(R (Q::*pmf)(A0, A1), A0 a0, A1 a1) {
+          if (m_v.empty())
+            return;
+          for (typename _V::iterator i = m_v.begin(); i != m_v.end(); ++i)
+            ((*i)->*pmf)(a0, a1);
+        }
+        /// CONST actions
+        template <typename R, typename Q> void operator()(R (Q::*pmf)() const) const {
+          if (m_v.empty())
+            return;
+          for (typename _V::const_iterator i = m_v.begin(); i != m_v.end(); ++i)
+            ((*i)->*pmf)();
+        }
+        template <typename R, typename Q, typename A0> void operator()(R (Q::*pmf)(A0&) const, A0& a0) const {
+          if (m_v.empty())
+            return;
+          for (typename _V::const_iterator i = m_v.begin(); i != m_v.end(); ++i)
+            ((*i)->*pmf)(a0);
+        }
+        template <typename R, typename Q, typename A0, typename A1> void operator()(R (Q::*pmf)(A0, A1) const, A0 a0,
+                                                                                    A1 a1) const {
+          if (m_v.empty())
+            return;
+          for (typename _V::const_iterator i = m_v.begin(); i != m_v.end(); ++i)
+            ((*i)->*pmf)(a0, a1);
+        }
+        /// CONST filters
+        template <typename Q> bool filter(bool (Q::*pmf)() const) const {
+          if (!m_v.empty())
+            return true;
+          for (typename _V::const_iterator i = m_v.begin(); i != m_v.end(); ++i)
+            if (!((*i)->*pmf)())
+              return false;
+          return true;
+        }
+        template <typename Q, typename A0> bool filter(bool (Q::*pmf)(A0) const, A0 a0) const {
+          if (m_v.empty())
+            return true;
+          for (typename _V::const_iterator i = m_v.begin(); i != m_v.end(); ++i)
+            if (!((*i)->*pmf)(a0))
+              return false;
+          return true;
+        }
+        template <typename Q, typename A0, typename A1> bool filter(bool (Q::*pmf)(A0, A1) const, A0 a0, A1 a1) const {
+          if (m_v.empty())
+            return true;
+          for (typename _V::const_iterator i = m_v.begin(); i != m_v.end(); ++i)
+            if (!((*i)->*pmf)(a0, a1))
+              return false;
+          return true;
+        }
+      };
+
+    protected:
+      /// Inhibit default constructor
+      DigiAction() = delete;
+      /// Inhibit copy constructor
+      DigiAction(const DigiAction& copy) = delete;
+      /// Inhibit move constructor
+      DigiAction(DigiAction&& copy) = delete;
+      /// Inhibit assignment operator
+      DigiAction& operator=(const DigiAction& copy) = delete;
+      /// Inhibit assignment operator
+      DigiAction& operator=(DigiAction&& copy) = delete;
+
+      /// Default destructor
+      virtual ~DigiAction();
+
+    public:
+      /// Standard constructor
+      DigiAction(const DigiKernel& kernel, const std::string& nam);
+      /// Increase reference count
+      long addRef();
+      /// Decrease reference count. Implicit destruction
+      long release();
+      /// Access name of the action
+      const std::string& name() const {
+        return m_name;
+      }
+      /// Access name of the action
+      const char* c_name() const {
+        return m_name.c_str();
+      }
+      /// Set the object name.
+      void setName(const std::string& new_name) {
+        m_name = new_name;
+      }
+      /// Access to the properties of the object
+      PropertyManager& properties() {
+        return m_properties;
+      }
+      /// Access the output level
+      PrintLevel outputLevel() const  {
+        return (PrintLevel)m_outputLevel;
+      }
+      /// Set the output level; returns previous value
+      PrintLevel setOutputLevel(PrintLevel new_level);
+      /// Access parallization flag
+      bool executeParallel()  const  {
+        return m_parallel;
+      }      
+      /// Set the parallization flag; returns previous value
+      bool setExecuteParallel(bool new_value);
+      
+      /// Declare property
+      template <typename T> DigiAction& declareProperty(const std::string& nam, T& val);
+      /// Declare property
+      template <typename T> DigiAction& declareProperty(const char* nam, T& val);
+      /// Check property for existence
+      bool hasProperty(const std::string& name) const;
+      /// Access single property
+      Property& property(const std::string& name);
+      /// Support for messages with variable output level using output level
+      void print(const char* fmt, ...) const;
+      /// Support for messages with variable output level using output level-1
+      void printM1(const char* fmt, ...) const;
+      /// Support for messages with variable output level using output level-2
+      void printM2(const char* fmt, ...) const;
+      /// Support for messages with variable output level using output level+1
+      void printP1(const char* fmt, ...) const;
+      /// Support for messages with variable output level using output level+2
+      void printP2(const char* fmt, ...) const;
+
+      /// Support of debug messages.
+      void debug(const char* fmt, ...) const;
+      /// Support of info messages.
+      void info(const char* fmt, ...) const;
+      /// Support of warning messages.
+      void warning(const char* fmt, ...) const;
+      /// Support of error messages.
+      void error(const char* fmt, ...) const;
+      /// Action to support error messages.
+      bool return_error(bool return_value, const char* fmt, ...) const;
+      /// Support of fatal messages. Throws exception
+      void fatal(const char* fmt, ...) const;
+      /// Support of exceptions: Print fatal message and throw runtime_error.
+      void except(const char* fmt, ...) const;
+
+      /// Main functional callback
+      virtual void execute(DigiContext& context)   const = 0;
+    };
+
+    /// Declare property
+    template <typename T> DigiAction& DigiAction::declareProperty(const std::string& nam, T& val) {
+      m_properties.add(nam, val);
+      return *this;
+    }
+
+    /// Declare property
+    template <typename T> DigiAction& DigiAction::declareProperty(const char* nam, T& val) {
+      m_properties.add(nam, val);
+      return *this;
+    }
+  }    // End namespace digi
+}      // End namespace dd4hep
+
+#endif // DD4HEP_DDDIGI_DIGIACTION_H
diff --git a/DDDigi/include/DDDigi/DigiActionSequence.h b/DDDigi/include/DDDigi/DigiActionSequence.h
new file mode 100644
index 000000000..50f43710e
--- /dev/null
+++ b/DDDigi/include/DDDigi/DigiActionSequence.h
@@ -0,0 +1,81 @@
+//==========================================================================
+//  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_DDDIGI_DIGIACTIONSEQUENCE_H
+#define DD4HEP_DDDIGI_DIGIACTIONSEQUENCE_H
+
+// Framework include files
+#include "DDDigi/DigiSynchronize.h"
+
+/// Namespace for the AIDA detector description toolkit
+namespace dd4hep {
+
+  /// Namespace for the Digitization part of the AIDA detector description toolkit
+  namespace digi {
+
+    // Forward declarations
+    class DigiAction;
+    class DigiActionSequence;
+
+    /// Concrete implementation of the Digitization event action sequence
+    /**
+     * The sequence dispatches the callbacks to all registered DigiAction 
+     * members and all registered callbacks.
+     *
+     * Note Multi-Threading issue:
+     * Neither callbacks not the action list is protected against multiple 
+     * threads calling the Digi callbacks!
+     * These must be protected in the user actions themselves.
+     *
+     *  \author  M.Frank
+     *  \version 1.0
+     *  \ingroup DD4HEP_DIGITIZATION
+     */
+    class DigiActionSequence : public DigiSynchronize {
+    protected:
+      /// Callback sequence before the digitization modules execute
+      CallbackSequence   m_begin;
+      /// Callback sequence after the digitization modules executed
+      CallbackSequence   m_end;
+
+    protected:
+      /// Inhibit copy constructor
+      DigiActionSequence() = default;
+      /// Inhibit copy constructor
+      DigiActionSequence(const DigiActionSequence& copy) = delete;
+      /// Inhibit assignment operator
+      DigiActionSequence& operator=(const DigiActionSequence& copy) = delete;
+
+    public:
+      /// Standard constructor
+      DigiActionSequence(const DigiKernel& kernel, const std::string& nam);
+      /// Default destructor
+      virtual ~DigiActionSequence();
+      /// Adopt a new action as part of the sequence. Sequence takes ownership.
+      void adopt(DigiAction* action);
+      /// Register external listener callbacks before starting the sequence
+      template <typename Q, typename T>
+      void begin(Q* p, void (T::*f)(DigiContext* context)) {
+        m_begin.add(p, f);
+      }
+      /// Register external listener callbacks after finishing the sequence
+      template <typename Q, typename T>
+      void end(Q* p, void (T::*f)(DigiContext* context))  {
+        m_end.add(p, f);
+      }
+      /// Begin-of-event callback
+      virtual void execute(DigiContext& context)  const override;
+    };
+
+  }    // End namespace digi
+}      // End namespace dd4hep
+#endif // DD4HEP_DDDIGI_DIGIACTIONSEQUENCE_H
diff --git a/DDDigi/include/DDDigi/DigiContext.h b/DDDigi/include/DDDigi/DigiContext.h
new file mode 100644
index 000000000..aac4561ac
--- /dev/null
+++ b/DDDigi/include/DDDigi/DigiContext.h
@@ -0,0 +1,126 @@
+//==========================================================================
+//  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_DDDIGI_DIGICONTEXT_H
+#define DD4HEP_DDDIGI_DIGICONTEXT_H
+
+// Framework incloude files
+#include "DD4hep/Primitives.h"
+#include "DDDigi/DigiData.h"
+
+/// Namespace for the AIDA detector description toolkit
+namespace dd4hep {
+
+  // Forward declarations
+  class Detector;
+  class DetElement;
+
+  /// Namespace for the Digitization part of the AIDA detector description toolkit
+  namespace digi {
+
+    /// Forward declarations
+    class DigiActionSequence;
+    class DigiKernel;
+
+    /// Generic context to extend user, run and event information
+    /**
+     *  A valid instance of the DigiContext is passed to every instance of a DigiAction at 
+     *  creation time.
+     *
+     *  The DigiContext is the main thread specific accessor to the dd4hep, DDG4 and
+     *  the user framework.
+     *  - The access to the dd4hep objects is via the DigiContext::detectorDescription() call,
+     *  - the access to DDG4 as a whole is supported via DigiContext::kernel() and
+     *  - the access to the user gframework using a specialized implementation of:
+     *  template <typename T> T& userFramework()  const;
+     *
+     *  A user defined implementations must be specialized somewhere in a compilation unit
+     *  of the user framework, not in a header file. The framework object could host
+     *  e.g. references for histogramming, logging, data access etc.
+     *
+     *  This way any experiment/user related data processing framework can exhibit
+     *  it's essential tools to DDG4 actions.
+     *
+     *  A possible specialized implementations would look like the following:
+     *
+     *  struct Gaudi  {
+     *    IMessageSvc*   msg;
+     *    IHistogramSvc* histos;
+     *    ....
+     *  };
+     *
+     *  template<> Gaudi& DigiContext::userFramework<Gaudi>()  const  {
+     *    UserFramework& fw = m_kernel->userFramework();
+     *    if ( fw.first && &typeid(T) == fw.second ) return *(T*)fw.first;
+     *    throw std::runtime_error("No user specified framework context present!");
+     *  }
+     *
+     *  To access the user framework then use the following call:
+     *  Gaudi* fw = context->userFramework<Gaudi>();
+     *
+     *  of course after having initialized it:
+     *  Gaudi * fw = ...;
+     *  GaudiKernel& kernel = ...;
+     *  kernel.setUserFramework(fw);
+     *
+     *  \author  M.Frank
+     *  \version 1.0
+     *  \ingroup DD4HEP_DIGITIZATION
+     */
+    class DigiContext  {
+      friend class DigiKernel;
+    public:
+      typedef std::pair<void*, const std::type_info*>   UserFramework;
+    protected:
+      /// Transient context variable - depending on the thread context: event reference
+      const DigiKernel* m_kernel = 0;
+      /// Reference to transient event
+      DigiEvent*        m_event  = 0;
+
+      /// Inhibit default constructor
+      DigiContext() = delete;
+      /// Inhibit move constructor
+      DigiContext(DigiContext&&) = delete;
+      /// Inhibit copy constructor
+      DigiContext(const DigiContext&) = delete;
+
+    public:
+      /// Initializing constructor
+      DigiContext(const DigiKernel* kernel_pointer, DigiEvent* event_pointer = 0);
+      /// Default destructor
+      virtual ~DigiContext();
+
+      /// Set the geant4 event reference
+      void setEvent(DigiEvent* new_event);
+      /// Access the geant4 event -- valid only between BeginEvent() and EndEvent()!
+      DigiEvent& event()  const;
+      /// Access the geant4 event by ptr. Must be checked by clients!
+      DigiEvent* eventPtr()  const     { return m_event; }
+
+      /// Access to the user framework. Specialized function to be implemented by the client
+      template <typename T> T& framework()  const;
+      /// Generic framework access
+      UserFramework& userFramework() const;
+      /// Access to detector description
+      Detector& detectorDescription() const;
+      /// Access to the main input action sequence from the kernel object
+      DigiActionSequence& inputAction() const;
+      /// Access to the main event action sequence from the kernel object
+      DigiActionSequence& eventAction() const;
+      /// Access to the main output action sequence from the kernel object
+      DigiActionSequence& outputAction() const;
+    };
+
+  }    // End namespace digi
+}      // End namespace dd4hep
+
+#endif // DD4HEP_DDDIGI_DIGICONTEXT_H
diff --git a/DDDigi/include/DDDigi/DigiData.h b/DDDigi/include/DDDigi/DigiData.h
new file mode 100644
index 000000000..cd4de7190
--- /dev/null
+++ b/DDDigi/include/DDDigi/DigiData.h
@@ -0,0 +1,149 @@
+//==========================================================================
+//  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_DDDIGI_DIGIDATA_H
+#define DD4HEP_DDDIGI_DIGIDATA_H
+
+/// Framework include files
+#include "DD4hep/Primitives.h"
+#include "DD4hep/ObjectExtensions.h"
+
+/// C/C++ include files
+#include <memory>
+
+/// Namespace for the AIDA detector description toolkit
+namespace dd4hep {
+
+  /// Namespace for the Digitization part of the AIDA detector description toolkit
+  namespace digi {
+
+    class DigiEvent;
+
+    /// Container class to host energy deposits from simulation or noise processing
+    /*
+     *
+     *  \author  M.Frank
+     *  \version 1.0
+     *  \ingroup DD4HEP_DIGITIZATION
+     */
+    template <typename T> class DigiContainer  {
+    public:
+      /// Default constructor
+      DigiContainer() = default;
+      /// Disable move constructor
+      DigiContainer(DigiContainer&& copy) = delete;
+      /// Disable copy constructor
+      DigiContainer(const DigiContainer& copy) = delete;      
+      /// Default destructor
+      virtual ~DigiContainer() = default;
+      /// Disable move assignment
+      DigiContainer& operator=(DigiContainer&& copy) = delete;
+      /// Disable copy assignment
+      DigiContainer& operator=(const DigiContainer& copy) = delete;      
+    };
+    
+
+    /// 
+    /*
+     *
+     *  \author  M.Frank
+     *  \version 1.0
+     *  \ingroup DD4HEP_DIGITIZATION
+     */
+    class DigiDeposit   {
+    public:
+      /// Default constructor
+      DigiDeposit() = default;
+      /// Disable move constructor
+      DigiDeposit(DigiDeposit&& copy) = delete;
+      /// Disable copy constructor
+      DigiDeposit(const DigiDeposit& copy) = delete;      
+      /// Default destructor
+      virtual ~DigiDeposit() = default;
+      /// Disable move assignment
+      DigiDeposit& operator=(DigiDeposit&& copy) = delete;
+      /// Disable copy assignment
+      DigiDeposit& operator=(const DigiDeposit& copy) = delete;      
+    };
+
+    /// 
+    /*
+     *
+     *  \author  M.Frank
+     *  \version 1.0
+     *  \ingroup DD4HEP_DIGITIZATION
+     */
+    class DigiCount   {
+    public:
+      /// Default constructor
+      DigiCount() = default;
+      /// Disable move constructor
+      DigiCount(DigiCount&& copy) = delete;
+      /// Disable copy constructor
+      DigiCount(const DigiCount& copy) = delete;      
+      /// Default destructor
+      virtual ~DigiCount() = default;
+      /// Disable move assignment
+      DigiCount& operator=(DigiCount&& copy) = delete;
+      /// Disable copy assignment
+      DigiCount& operator=(const DigiCount& copy) = delete;      
+    };
+
+    typedef DigiContainer<DigiDeposit> DigiEnergyDeposits;
+    typedef DigiContainer<DigiCount>   DigiCounts;
+
+    ///  User event data for DDDigi
+    /**
+     *
+     *  \author  M.Frank
+     *  \version 1.0
+     *  \ingroup DD4HEP_DIGITIZATION
+     */
+    class  DigiEvent : public ObjectExtensions  {
+    public:
+      std::map<unsigned long, std::shared_ptr<DigiEnergyDeposits> >  energyDeposits;
+      std::map<unsigned long, std::shared_ptr<DigiCounts> >          digitizations;
+      int eventNumber = 0;
+    public:
+#if defined(G__ROOT) || defined(__CLING__) || defined(__ROOTCLING__)
+      /// Inhibit default constructor
+      DigiEvent();
+#endif
+      /// Inhibit move constructor
+      DigiEvent(DigiEvent&& copy) = delete;
+      /// Inhibit copy constructor
+      DigiEvent(const DigiEvent& copy) = delete;
+      /// Intializing constructor
+      DigiEvent(int num);
+      /// Default destructor
+      virtual ~DigiEvent();
+      
+      /// Add an extension object to the detector element
+      void* addExtension(unsigned long long int k, ExtensionEntry* e)  {
+        return ObjectExtensions::addExtension(k, e);
+      }
+      /// Add user extension object. Ownership is transferred and object deleted at the end of the event.
+      template <typename T> T* addExtension(T* ptr, bool take_ownership=true)   {
+        ExtensionEntry* e = take_ownership
+          ? (ExtensionEntry*)new detail::DeleteExtension<T,T>(ptr)
+          : (ExtensionEntry*)new detail::SimpleExtension<T,T>(ptr);
+        return (T*)ObjectExtensions::addExtension(detail::typeHash64<T>(),e);
+      }
+      /// Access to type safe extension object. Exception is thrown if the object is invalid
+      template <typename T> T* extension(bool alert=true) {
+        return (T*)ObjectExtensions::extension(detail::typeHash64<T>(),alert);
+      }
+    };
+  }    // End namespace digi
+}      // End namespace dd4hep
+
+#endif // DD4HEP_DDDIGI_DIGIDATA_H
diff --git a/DDDigi/include/DDDigi/DigiFactories.h b/DDDigi/include/DDDigi/DigiFactories.h
new file mode 100644
index 000000000..e7254dfdc
--- /dev/null
+++ b/DDDigi/include/DDDigi/DigiFactories.h
@@ -0,0 +1,61 @@
+//==========================================================================
+//  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 DDG4_DIGI_DIGIFACTORIES_H
+#define DDG4_DIGI_DIGIFACTORIES_H
+
+// Framework include files
+#include "DD4hep/Plugins.h"
+#include "DD4hep/Detector.h"
+#include "DD4hep/Primitives.h"
+
+// C/C++ include files
+#include <string>
+#include <map>
+
+/// Namespace for the AIDA detector description toolkit
+namespace dd4hep {
+  class DetElement;
+  class Detector;
+
+  /// Namespace for the Digitization part of the AIDA detector description toolkit
+  namespace digi {
+    class DigiKernel;
+    class DigiAction;
+  }
+}
+
+namespace {
+
+  namespace DS = dd4hep::digi;
+  struct _ns {
+    typedef DS::DigiAction  DA;
+    typedef DS::DigiKernel  K;
+    typedef std::map<std::string,std::string> STRM;
+  };
+
+  /// Factory to create Digi action objects
+  DD4HEP_PLUGIN_FACTORY_ARGS_2(DS::DigiAction*,const _ns::K*, std::string)
+  {    return new P(*a0,a1);  }
+
+}
+
+/// Plugin defintion to create DigiAction objects
+#define DECLARE_DIGIACTION_NS(name_space,name)  namespace {\
+  using name_space::name;                                               \
+  DD4HEP_PLUGINSVC_FACTORY(name,name,dd4hep::digi::DigiAction*(const _ns::K*,std::string),__LINE__) \
+    }
+
+/// Plugin defintion to create DigiAction objects
+#define DECLARE_DIGIACTION(name)         DECLARE_DIGIACTION_NS(dd4hep::digi,name)
+
+#endif // DDG4_DIGI_DIGIFACTORIES_H
diff --git a/DDDigi/include/DDDigi/DigiHandle.h b/DDDigi/include/DDDigi/DigiHandle.h
new file mode 100644
index 000000000..13ec8cacd
--- /dev/null
+++ b/DDDigi/include/DDDigi/DigiHandle.h
@@ -0,0 +1,120 @@
+//==========================================================================
+//  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_DDDIGI_DIGIHANDLE_H
+#define DD4HEP_DDDIGI_DIGIHANDLE_H
+
+// Framework include files
+#include "DD4hep/ComponentProperties.h"
+#include "DD4hep/Detector.h"
+
+// C/C++ include files
+#include <string>
+#include <memory>
+
+/// Namespace for the AIDA detector description toolkit
+namespace dd4hep {
+
+  /// Namespace for the Digitization part of the AIDA detector description toolkit
+  namespace digi  {
+
+    /// Forward declarations
+    class DigiKernel;
+    class DigiAction;
+
+    /// Handle to Digi actions with built-in creation mechanism
+    /**
+     *  \author  M.Frank
+     *  \version 1.0
+     *  \ingroup DD4HEP_SIMULATION
+     */
+    template <typename TYPE> class DigiHandle {
+    protected:
+      void checked_assign(TYPE* p);
+      TYPE* null()  { return 0; }
+    public:
+      /// Pointer to referenced object
+      mutable TYPE* value = 0;
+      /// Default constructor
+      explicit DigiHandle() = default;
+      /// Construction initialized with object pointer
+      DigiHandle(TYPE* typ);
+      /// Cross type initialization
+      template <typename T> DigiHandle(T* typ) : value(0) {
+        checked_assign(dynamic_cast<TYPE*>(typ));
+      }
+      /// Copy constructor
+      DigiHandle(const DigiHandle& handle);
+      /// Move constructor
+      DigiHandle(DigiHandle&& handle);
+      /// Initializing constructor
+      DigiHandle(const DigiKernel&, const char* type_name);
+      /// Initializing constructor
+      DigiHandle(const DigiKernel&, const std::string& type_name);
+      /// Default destructor
+      ~DigiHandle();
+      /// Property accessor
+      Property& operator[](const std::string& property_name) const;
+      /// Assignment operator
+      DigiHandle& operator=(const DigiHandle& handle);
+      /// Move assignment operator
+      DigiHandle& operator=(DigiHandle&& handle);
+      /// Assignment operator
+      DigiHandle& operator=(TYPE* ptr);
+      /// Validity check
+      bool operator!() const;
+      /// Access to the underlying object
+      DigiAction* action() const;
+      /// Access to the underlying object
+      TYPE* operator->() const;
+      /// Conversion operator
+      operator TYPE*() const;
+      /// Access to the underlying object
+      TYPE* get() const;
+      /// Release the underlying object
+      TYPE* release();
+    };
+
+    /// Handle to Digi actions with built-in creation mechanism
+    /**
+     *  \author  M.Frank
+     *  \version 1.0
+     *  \ingroup DD4HEP_SIMULATION
+     */
+    class KernelHandle {
+    public:
+      /// Pointer to referenced object
+      mutable DigiKernel* value;
+      /// Default constructor
+      explicit KernelHandle();
+      /// Construction initialized with object pointer
+      explicit KernelHandle(DigiKernel* k);
+      /// Copy constructor
+      KernelHandle(const KernelHandle& k) : value(k.value) {}
+      /// Default destructor
+      ~KernelHandle()                  {               }
+      /// Conversion operator
+      operator DigiKernel*() const   { return value; }
+      /// Access to the underlying object
+      DigiKernel* get() const        { return value; }
+      /// Access to the underlying object
+      DigiKernel* operator->() const { return value; }
+      /// Access to worker thread
+      KernelHandle worker();
+      /// Destroy referenced object (program termination)
+      void destroy();
+    };
+
+  }    // End namespace digi
+}      // End namespace dd4hep
+
+#endif // DD4HEP_DDDIGI_DIGIHANDLE_H
diff --git a/DDDigi/include/DDDigi/DigiInputAction.h b/DDDigi/include/DDDigi/DigiInputAction.h
new file mode 100644
index 000000000..e43a17422
--- /dev/null
+++ b/DDDigi/include/DDDigi/DigiInputAction.h
@@ -0,0 +1,59 @@
+//==========================================================================
+//  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_DDDIGI_DIGIINPUTACTION_H
+#define DD4HEP_DDDIGI_DIGIINPUTACTION_H
+
+/// Framework include files
+#include "DDDigi/DigiAction.h"
+
+/// Namespace for the AIDA detector description toolkit
+namespace dd4hep {
+
+  /// Namespace for the Digitization part of the AIDA detector description toolkit
+  namespace digi {
+
+    // Forward declarations
+    class DigiAction;
+    class DigiInputAction;
+
+    /// Base class for input actions to the digitization
+    /**
+     *
+     *  \author  M.Frank
+     *  \version 1.0
+     *  \ingroup DD4HEP_DIGITIZATION
+     */
+    class DigiInputAction : public DigiAction {
+    protected:
+      std::vector<std::string> m_input;
+      
+    protected:
+      /// Inhibit copy constructor
+      DigiInputAction() = default;
+      /// Inhibit copy constructor
+      DigiInputAction(const DigiInputAction& copy) = delete;
+      /// Inhibit assignment operator
+      DigiInputAction& operator=(const DigiInputAction& copy) = delete;
+
+    public:
+      /// Standard constructor
+      DigiInputAction(const DigiKernel& kernel, const std::string& nam);
+      /// Default destructor
+      virtual ~DigiInputAction();
+      /// Callback to read event input
+      virtual void execute(DigiContext& context)  const override;
+    };
+
+  }    // End namespace digi
+}      // End namespace dd4hep
+#endif // DD4HEP_DDDIGI_DIGIINPUTACTION_H
diff --git a/DDDigi/include/DDDigi/DigiKernel.h b/DDDigi/include/DDDigi/DigiKernel.h
new file mode 100644
index 000000000..e6f265843
--- /dev/null
+++ b/DDDigi/include/DDDigi/DigiKernel.h
@@ -0,0 +1,152 @@
+//==========================================================================
+//  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_DDDIGI_DIGIKERNEL_H
+#define DD4HEP_DDDIGI_DIGIKERNEL_H
+
+// Framework include files
+#include "DDDigi/DigiAction.h"
+
+// C/C++ include files
+#include <map>
+#include <mutex>
+#include <atomic>
+#include <typeinfo>
+
+/// Namespace for the AIDA detector description toolkit
+namespace dd4hep {
+
+  /// Namespace for the Digitization part of the AIDA detector description toolkit
+  namespace digi {
+
+    /// Forward declarations
+    class DigiActionSequence;
+    
+    /// Class, which allows all DigiAction derivatives to access the DDG4 kernel structures.
+    /**
+     *  To implement access to a user specified framework please see class DigiContext.
+     *
+     *  \author  M.Frank
+     *  \version 1.0
+     *  \ingroup DD4HEP_DIGITIZATION
+     */
+    class DigiKernel  {
+    public:
+      typedef std::map<std::string,int>                 ClientOutputLevels;
+      typedef std::pair<void*, const std::type_info*>   UserFramework;
+
+    private:
+      class Internals;
+      class Processor;
+      class Wrapper;
+
+      /// Internal only data structures;
+      Internals*            internals = 0;
+      
+    protected:
+      /// Detector description object
+      Detector*             m_detDesc = 0;
+      /// Reference to the user framework
+      mutable UserFramework m_userFramework;
+      
+      /// Execute one single event
+      virtual void executeEvent(DigiContext* context);
+      /// Notify kernel that the execution of one single event finished
+      void notify(DigiContext* context);
+      /// Notify kernel that the execution of one single event finished
+      void notify(DigiContext* context, const std::exception& e);
+      
+    public:
+      /// Standard constructor for the master instance
+      DigiKernel(Detector& description);
+
+    public:
+      /// Default destructor
+      virtual ~DigiKernel();
+
+#ifndef __CINT__
+      /// Instance accessor
+      static DigiKernel& instance(Detector& description);
+#endif
+      /// Access to detector description
+      Detector& detectorDescription() const     {        return *m_detDesc;        }
+      /// Generic framework access
+      UserFramework& userFramework() const      {        return m_userFramework;   }
+      /// Set the framework context to the kernel object
+      template <typename T> void setUserFramework(T* object)   {
+        m_userFramework = UserFramework(object,&typeid(T));
+      }
+      
+      /** Property access                            */
+      /// Access to the properties of the object
+      PropertyManager& properties();
+      /// Print the property values
+      void printProperties() const;
+      /// Declare property
+      template <typename T> DigiKernel& declareProperty(const std::string& nam, T& val);
+      /// Declare property
+      template <typename T> DigiKernel& declareProperty(const char* nam, T& val);
+      /// Check property for existence
+      bool hasProperty(const std::string& name) const;
+      /// Access single property
+      Property& property(const std::string& name);
+
+      /** Output level settings                       */
+      /// Access the output level
+      PrintLevel outputLevel() const;
+      /// Set the global output level of the kernel object; returns previous value
+      PrintLevel setOutputLevel(PrintLevel new_level);
+      /// Fill cache with the global output level of a named object. Must be set before instantiation
+      void setOutputLevel(const std::string object, PrintLevel new_level);
+      /// Retrieve the global output level of a named object.
+      PrintLevel getOutputLevel(const std::string object) const;
+
+      /// Construct detector geometry using description plugin
+      virtual void loadGeometry(const std::string& compact_file);
+      /// Load XML file 
+      virtual void loadXML(const char* fname);
+
+      /// Run the simulation: Configure Digi
+      virtual int configure();
+      /// Run the simulation: Initialize Digi
+      virtual int initialize();
+      /// Run the simulation: Simulate the number of events given by the property "NumEvents"
+      virtual int run();
+      /// Run the simulation: Terminate Digi
+      virtual int terminate();
+
+      /// Access to the main input action sequence from the kernel object
+      DigiActionSequence& inputAction() const;
+      /// Access to the main event action sequence from the kernel object
+      DigiActionSequence& eventAction() const;
+      /// Access to the main output action sequence from the kernel object
+      DigiActionSequence& outputAction() const;
+      /// Submit a bunch of actions to be executed in parallel
+      virtual void submit (const DigiAction::Actors<DigiAction>& algorithms, DigiContext& context)  const;
+      /// Submit a bunch of actions to be executed serially
+      virtual void execute(const DigiAction::Actors<DigiAction>& algorithms, DigiContext& context)  const;
+      virtual void wait(DigiContext& context)   const;
+    };
+    /// Declare property
+    template <typename T> DigiKernel& DigiKernel::declareProperty(const std::string& nam, T& val) {
+      properties().add(nam, val);
+      return *this;
+    }
+
+    /// Declare property
+    template <typename T> DigiKernel& DigiKernel::declareProperty(const char* nam, T& val) {
+      properties().add(nam, val);
+      return *this;
+    }
+  }    // End namespace digi
+}      // End namespace dd4hep
+#endif // DD4HEP_DDDIGI_DIGIKERNEL_H
diff --git a/DDDigi/include/DDDigi/DigiLockedAction.h b/DDDigi/include/DDDigi/DigiLockedAction.h
new file mode 100644
index 000000000..59e331503
--- /dev/null
+++ b/DDDigi/include/DDDigi/DigiLockedAction.h
@@ -0,0 +1,66 @@
+//==========================================================================
+//  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_DDDIGI_DIGILOCKEDACTION_H
+#define DD4HEP_DDDIGI_DIGILOCKEDACTION_H
+
+/// Framework include files
+#include "DDDigi/DigiAction.h"
+
+/// C/C++ include files
+#include <mutex>
+
+/// Namespace for the AIDA detector description toolkit
+namespace dd4hep {
+
+  /// Namespace for the Digitization part of the AIDA detector description toolkit
+  namespace digi {
+
+    // Forward declarations
+    class DigiAction;
+    class DigiLockedAction;
+
+    /// Class to execute non-reentrant subaction in wrapped mode
+    /**
+     *
+     *  \author  M.Frank
+     *  \version 1.0
+     *  \ingroup DD4HEP_DIGITIZATION
+     */
+    class DigiLockedAction : public DigiAction {
+    protected:
+      /// Action lock to inhibit calling the non-reentrant underlying
+      std::mutex  m_lock;
+      /// Reference to underlying action
+      DigiAction* m_action = 0;
+    protected:
+      /// Inhibit copy constructor
+      DigiLockedAction() = default;
+      /// Inhibit copy constructor
+      DigiLockedAction(const DigiLockedAction& copy) = delete;
+      /// Inhibit assignment operator
+      DigiLockedAction& operator=(const DigiLockedAction& copy) = delete;
+
+    public:
+      /// Standard constructor
+      DigiLockedAction(const DigiKernel& kernel, const std::string& nam);
+      /// Default destructor
+      virtual ~DigiLockedAction();
+      /// Underlying object to be used during the locked execution
+      void use(DigiAction* action);
+      /// Callback to read event locked
+      virtual void execute(DigiContext& context)  const override;
+    };
+
+  }    // End namespace digi
+}      // End namespace dd4hep
+#endif // DD4HEP_DDDIGI_DIGILOCKEDACTION_H
diff --git a/DDDigi/include/DDDigi/DigiSynchronize.h b/DDDigi/include/DDDigi/DigiSynchronize.h
new file mode 100644
index 000000000..cf4216d67
--- /dev/null
+++ b/DDDigi/include/DDDigi/DigiSynchronize.h
@@ -0,0 +1,61 @@
+//==========================================================================
+//  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_DDDIGI_DIGISYNCHRONIZE_H
+#define DD4HEP_DDDIGI_DIGISYNCHRONIZE_H
+
+// Framework incloude files
+#include "DDDigi/DigiAction.h"
+
+/// Namespace for the AIDA detector description toolkit
+namespace dd4hep {
+
+  // Forward declarations
+
+  /// Namespace for the Digitization part of the AIDA detector description toolkit
+  namespace digi {
+
+    /// 
+    /**
+     *
+     *  \author  M.Frank
+     *  \version 1.0
+     *  \ingroup DD4HEP_DIGITIZATION
+     */
+    class DigiSynchronize : public DigiAction {
+    protected:
+      /// The list of action objects to be called
+      Actors<DigiAction> m_actors;
+
+    public:
+      /// Standard constructor
+      DigiSynchronize(const DigiKernel& kernel, const std::string& nam);
+      /// Default destructor
+      virtual ~DigiSynchronize();
+      /// Get an action member by name
+      DigiAction* get(const std::string& name) const;
+      /// Access the children
+      const Actors<DigiAction>& children()   const   {
+        return m_actors;
+      }
+      /// Adopt a new action as part of the sequence. Sequence takes ownership.
+      void adopt(DigiAction* action);
+      /// Begin-of-event callback
+      virtual void execute(DigiContext& context)  const override;
+      ///
+      void analyze();
+    };
+
+  }    // End namespace digi
+}      // End namespace dd4hep
+
+#endif // DD4HEP_DDDIGI_DIGISYNCHRONIZE_H
diff --git a/DDDigi/plugins/DigiRandomNoise.cpp b/DDDigi/plugins/DigiRandomNoise.cpp
new file mode 100644
index 000000000..f6cc0f8f4
--- /dev/null
+++ b/DDDigi/plugins/DigiRandomNoise.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
+//
+//==========================================================================
+#ifndef DD4HEP_DDDIGI_DIGIRANDOMNOISE_H
+#define DD4HEP_DDDIGI_DIGIRANDOMNOISE_H
+
+// Framework include files
+#include "DDDigi/DigiAction.h"
+
+/// Namespace for the AIDA detector description toolkit
+namespace dd4hep {
+
+  /// Namespace for the Digitization part of the AIDA detector description toolkit
+  namespace digi {
+
+    // Forward declarations
+    class DigiAction;
+    class DigiRandomNoise;
+
+    /// Class which applies random noise hits of a given amplitude
+    /**
+     *  Class which applies random noise hits of a given amplitude
+     *  to a segmented sensitive element.
+     *
+     *  \author  M.Frank
+     *  \version 1.0
+     *  \ingroup DD4HEP_DIGITIZATION
+     */
+    class DigiRandomNoise : public DigiAction {
+    protected:
+      double m_probability = 1.0;
+      double m_amplitude   = 1.0;
+      
+    protected:
+      /// Inhibit copy constructor
+      DigiRandomNoise() = default;
+      /// Inhibit copy constructor
+      DigiRandomNoise(const DigiRandomNoise& copy) = delete;
+      /// Inhibit assignment operator
+      DigiRandomNoise& operator=(const DigiRandomNoise& copy) = delete;
+
+    public:
+      /// Standard constructor
+      DigiRandomNoise(const DigiKernel& kernel, const std::string& nam);
+      /// Default destructor
+      virtual ~DigiRandomNoise();
+      /// Callback to read event input
+      virtual void execute(DigiContext& context)  const override;
+    };
+
+  }    // End namespace digi
+}      // End namespace dd4hep
+#endif // DD4HEP_DDDIGI_DIGIRANDOMNOISE_H
+
+//==========================================================================
+//  AIDA Detector description implementation 
+//--------------------------------------------------------------------------
+// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
+// All rights reserved.
+//
+// For the licensing terms see $DD4hepINSTALL/LICENSE.
+// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
+//
+// Author     : M.Frank
+//
+//==========================================================================
+
+// Framework include files
+#include "DD4hep/Printout.h"
+#include "DD4hep/InstanceCount.h"
+#include "DDDigi/DigiFactories.h"
+//#include "DDDigi/DigiRandomNoise.h"
+
+// C/C++ include files
+
+using namespace std;
+using namespace dd4hep::digi;
+
+DECLARE_DIGIACTION_NS(dd4hep::digi,DigiRandomNoise)
+
+/// Standard constructor
+DigiRandomNoise::DigiRandomNoise(const DigiKernel& kernel, const string& nam)
+  : DigiAction(kernel, nam)
+{
+  declareProperty("Probability", m_probability);
+  declareProperty("Amplitude",   m_amplitude);
+  InstanceCount::increment(this);
+}
+
+/// Default destructor
+DigiRandomNoise::~DigiRandomNoise() {
+  InstanceCount::decrement(this);
+}
+
+/// Pre-track action callback
+void DigiRandomNoise::execute(DigiContext& /* context */)  const   {
+  info("+++ Virtual method execute() MUST be overloaded!");
+}
diff --git a/DDDigi/plugins/DigiTestAction.cpp b/DDDigi/plugins/DigiTestAction.cpp
new file mode 100644
index 000000000..a9d404b95
--- /dev/null
+++ b/DDDigi/plugins/DigiTestAction.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
+//
+//==========================================================================
+#ifndef DD4HEP_DDDIGI_DIGITESTACTION_H
+#define DD4HEP_DDDIGI_DIGITESTACTION_H
+
+// Framework include files
+#include "DDDigi/DigiAction.h"
+
+/// Namespace for the AIDA detector description toolkit
+namespace dd4hep {
+
+  /// Namespace for the Digitization part of the AIDA detector description toolkit
+  namespace digi {
+
+    // Forward declarations
+    class DigiAction;
+    class DigiTestAction;
+
+    /// Class which applies random noise hits of a given amplitude
+    /**
+     *  Class which applies random noise hits of a given amplitude
+     *  to a segmented sensitive element.
+     *
+     *  \author  M.Frank
+     *  \version 1.0
+     *  \ingroup DD4HEP_DIGITIZATION
+     */
+    class DigiTestAction : public DigiAction {
+    protected:
+      /// Sleep period to fake execution [milliseconds]
+      int m_sleep = 0;
+    protected:
+      /// Inhibit copy constructor
+      DigiTestAction() = default;
+      /// Inhibit copy constructor
+      DigiTestAction(const DigiTestAction& copy) = delete;
+      /// Inhibit assignment operator
+      DigiTestAction& operator=(const DigiTestAction& copy) = delete;
+
+    public:
+      /// Standard constructor
+      DigiTestAction(const DigiKernel& kernel, const std::string& nam);
+      /// Default destructor
+      virtual ~DigiTestAction();
+      /// Callback to read event input
+      virtual void execute(DigiContext& context)  const override;
+    };
+
+  }    // End namespace digi
+}      // End namespace dd4hep
+#endif // DD4HEP_DDDIGI_DIGITESTACTION_H
+
+//==========================================================================
+//  AIDA Detector description implementation 
+//--------------------------------------------------------------------------
+// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
+// All rights reserved.
+//
+// For the licensing terms see $DD4hepINSTALL/LICENSE.
+// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
+//
+// Author     : M.Frank
+//
+//==========================================================================
+
+// Framework include files
+#include "DD4hep/Printout.h"
+#include "DD4hep/InstanceCount.h"
+#include "DDDigi/DigiFactories.h"
+//#include "DDDigi/DigiTestAction.h"
+
+// C/C++ include files
+
+using namespace std;
+using namespace dd4hep::digi;
+
+DECLARE_DIGIACTION_NS(dd4hep::digi,DigiTestAction)
+
+/// Standard constructor
+DigiTestAction::DigiTestAction(const DigiKernel& kernel, const string& nam)
+  : DigiAction(kernel, nam)
+{
+  declareProperty("sleep", m_sleep = 0);
+  InstanceCount::increment(this);
+}
+
+/// Default destructor
+DigiTestAction::~DigiTestAction() {
+  InstanceCount::decrement(this);
+}
+
+/// Pre-track action callback
+void DigiTestAction::execute(DigiContext& context)  const   {
+  debug("+++ Event: %8d (DigiTestAction)  %d msec",
+       context.event().eventNumber, m_sleep);
+  if ( m_sleep > 0 ) ::usleep(1000*m_sleep);
+}
diff --git a/DDDigi/plugins/dummy.cpp b/DDDigi/plugins/dummy.cpp
new file mode 100644
index 000000000..b34f3609e
--- /dev/null
+++ b/DDDigi/plugins/dummy.cpp
@@ -0,0 +1,53 @@
+//==========================================================================
+//  AIDA Detector description implementation 
+//--------------------------------------------------------------------------
+// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
+// All rights reserved.
+//
+// For the licensing terms see $DD4hepINSTALL/LICENSE.
+// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
+//
+// Author     : M.Frank
+//
+//==========================================================================
+
+// Framework include files
+#include "DD4hep/Printout.h"
+#include "DD4hep/Factories.h"
+#include "DDDigi/DigiFactories.h"
+
+// C/C++ include files
+#include <cerrno>
+#include <cstdlib>
+#include <sstream>
+
+#include "DDDigi/DigiInputAction.h"
+DECLARE_DIGIACTION_NS(dd4hep::digi,DigiInputAction)
+
+#include "DDDigi/DigiActionSequence.h"
+DECLARE_DIGIACTION_NS(dd4hep::digi,DigiActionSequence)
+
+#include "DDDigi/DigiSynchronize.h"
+DECLARE_DIGIACTION_NS(dd4hep::digi,DigiSynchronize)
+
+#include "DDDigi/DigiLockedAction.h"
+DECLARE_DIGIACTION_NS(dd4hep::digi,DigiLockedAction)
+
+using namespace std;
+using namespace dd4hep;
+using namespace dd4hep::detail;
+
+
+
+/// Basic entry point 
+/**
+ *  Factory: DD4hep_GeometryDisplay
+ *
+ *  \author  M.Frank
+ *  \version 1.0
+ *  \date    01/04/2014
+ */
+static long dummy(Detector&, int, char**) {
+  return 0;
+}
+DECLARE_APPLY(DDDigi_dummy,dummy)
diff --git a/DDDigi/python/DDDigi.py b/DDDigi/python/DDDigi.py
new file mode 100644
index 000000000..8f4879de9
--- /dev/null
+++ b/DDDigi/python/DDDigi.py
@@ -0,0 +1,372 @@
+#==========================================================================
+#  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.
+#
+#==========================================================================
+import logging
+from dd4hep_base import *
+
+logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.DEBUG)
+def loadDDDigi():
+  ## import ROOT ## done in import * above
+  from ROOT import gSystem
+
+  ## Try to load libglapi to avoid issues with TLS Static
+  ## Turn off all errors from ROOT about the library missing
+  orgLevel = ROOT.gErrorIgnoreLevel
+  ROOT.gErrorIgnoreLevel=6000
+  gSystem.Load("libglapi")
+  ROOT.gErrorIgnoreLevel=orgLevel
+
+  import platform
+  import os
+  if platform.system()=="Darwin":
+    gSystem.SetDynamicPath(os.environ['DD4HEP_LIBRARY_PATH'])
+
+  result = gSystem.Load("libDDDigiPlugins")
+  if result < 0:
+    raise Exception('DDDigi.py: Failed to load the DDDigi library libDDDigiPlugins: '+gSystem.GetErrorStr())
+  from ROOT import dd4hep as module
+  return module
+
+
+# We are nearly there ....
+current = __import__(__name__)
+def _import_class(ns,nam):  
+  scope = getattr(current,ns)
+  setattr(current,nam,getattr(scope,nam))
+
+#---------------------------------------------------------------------------
+#
+try:
+  dd4hep = loadDDDigi() 
+except Exception as X:
+  logging.info('+--%-100s--+',100*'-')
+  logging.info('|  %-100s  |','Failed to load DDDigi library:')
+  logging.info('|  %-100s  |',str(X))
+  logging.info('+--%-100s--+',100*'-')
+  exit(1)
+
+core       = dd4hep
+digi       = dd4hep.digi
+Kernel     = digi.KernelHandle
+Interface  = digi.DigiActionCreation
+Detector   = core.Detector
+#
+from   dd4hep_base import std, std_vector, std_list, std_map, std_pair
+#
+#---------------------------------------------------------------------------
+def _constant(self,name):
+  return self.constantAsString(name)
+
+Detector.globalVal = _constant
+#---------------------------------------------------------------------------
+
+"""
+  Import the Detector constants into the DDDigi namespace
+"""
+def importConstants(description,namespace=None,debug=False):
+  scope = current
+  ns = current
+  if namespace is not None and not hasattr(current,namespace):
+    import imp
+    m = imp.new_module('DDDigi.'+namespace)
+    setattr(current,namespace,m)
+    ns = m
+  evaluator = dd4hep.g4Evaluator()
+  cnt = 0
+  num = 0
+  todo = {}
+  strings = {}
+  for c in description.constants():
+    if c.second.dataType == 'string':
+      strings[c.first] = c.second.GetTitle()
+    else:
+      todo[c.first] = c.second.GetTitle().replace('(int)','')
+  while len(todo) and cnt<100:
+    cnt = cnt + 1
+    if cnt == 100:
+      logging.info('%s %d out of %d %s "%s": [%s]\n+++ %s',\
+            '+++ FAILED to import',
+            len(todo),len(todo)+num,
+            'global values into namespace',
+            ns.__name__,'Try to continue anyway',100*'=')
+      for k,v in todo.items():
+        if not hasattr(ns,k):
+          logging.info('+++ FAILED to import: "'+k+'" = "'+str(v)+'"')
+      logging.info('+++ %s',100*'=')
+
+    for k,v in todo.items():
+      if not hasattr(ns,k):
+        val = evaluator.evaluate(v)
+        status = evaluator.status()
+        if status == 0:
+          evaluator.setVariable(k,val)
+          setattr(ns,k,val)
+          if debug: logging.info('Imported global value: "'+k+'" = "'+str(val)+'" into namespace'+ns.__name__)
+          del todo[k]
+          num = num + 1
+  if cnt<100:
+    logging.info('+++ Imported %d global values to namespace:%s',num,ns.__name__,)
+
+#---------------------------------------------------------------------------
+def _getKernelProperty(self, name):
+  #logging.info('_getKernelProperty: %s  %s',str(type(self)),name)
+  ret = Interface.getPropertyKernel(self.get(),name)
+  if ret.status > 0:
+    return ret.data
+  elif hasattr(self.get(),name):
+    return getattr(self.get(),name)
+  elif hasattr(self,name):
+    return getattr(self,name)
+  msg = 'DigiKernel::GetProperty [Unhandled]: Cannot access Kernel.'+name
+  raise KeyError(msg)
+
+#---------------------------------------------------------------------------
+def _setKernelProperty(self, name, value):
+  #logging.info('_setKernelProperty: %s %s',name,str(value))
+  if Interface.setPropertyKernel(self.get(),name,str(value)):
+    return
+  msg = 'DigiKernel::SetProperty [Unhandled]: Cannot set Kernel.'+name+' = '+str(value)
+  raise KeyError(msg)
+
+#---------------------------------------------------------------------------
+def _kernel_terminate(self):         return self.get().terminate()
+#---------------------------------------------------------------------------
+Kernel.__getattr__ = _getKernelProperty
+Kernel.__setattr__ = _setKernelProperty
+Kernel.terminate   = _kernel_terminate
+#---------------------------------------------------------------------------
+ActionHandle = digi.ActionHandle
+#---------------------------------------------------------------------------
+def Action(kernel, nam, parallel=False):
+  obj = Interface.createAction(kernel,nam)
+  obj.parallel = parallel
+  return obj
+#---------------------------------------------------------------------------
+def TestAction(kernel, nam, sleep=0):
+  obj = Interface.createAction(kernel,'DigiTestAction/'+nam)
+  if sleep != 0:
+    obj.sleep = sleep
+  return obj
+#---------------------------------------------------------------------------
+def ActionSequence(kernel, nam, parallel=False):
+  obj = Interface.createSequence(kernel,nam)
+  obj.parallel = parallel
+  return obj
+#---------------------------------------------------------------------------
+def Synchronize(kernel, nam, parallel=False):
+  obj = Interface.createSync(kernel,nam)
+  obj.parallel = parallel
+  return obj
+#---------------------------------------------------------------------------
+def _setup(obj):
+  def _adopt(self,action):  self.__adopt(action.get())
+  _import_class('digi',obj)
+  o = getattr(current,obj)
+  setattr(o,'__adopt',getattr(o,'adopt'))
+  setattr(o,'adopt',_adopt)
+  #setattr(o,'add',_adopt)
+
+#---------------------------------------------------------------------------
+_setup('DigiActionSequence')
+_setup('DigiSynchronize')
+_import_class('digi','DigiKernel')
+_import_class('digi','DigiContext')
+_import_class('digi','DigiAction')
+
+#---------------------------------------------------------------------------
+def _get(self, name):
+  import traceback
+  #logging.info('_get: %s  %s',str(type(self)),name)
+  a = Interface.toAction(self)
+  ret = Interface.getProperty(a,name)
+  if ret.status > 0:
+    return ret.data
+  elif hasattr(self.action,name):
+    return getattr(self.action,name)
+  elif hasattr(a,name):
+    return getattr(a,name)
+  #elif hasattr(self,name):
+  #  return getattr(self,name)
+  #traceback.print_stack()
+  msg = 'DigiAction::GetProperty [Unhandled]: Cannot access property '+a.name()+'.'+name
+  raise KeyError(msg)
+
+def _set(self, name, value):
+  a = Interface.toAction(self)
+  if Interface.setProperty(a,name,str(value)):
+    return
+  msg = 'DigiAction::SetProperty [Unhandled]: Cannot set '+a.name()+'.'+name+' = '+str(value)
+  raise KeyError(msg)
+
+def _props(obj):
+  _import_class('digi',obj)
+  cl = getattr(current,obj)
+  cl.__getattr__ = _get
+  cl.__setattr__ = _set
+
+_props('ActionHandle')
+_props('ActionSequenceHandle')
+_props('SynchronizeHandle')
+
+"""
+   Helper object to perform stuff, which occurs very often.
+   I am sick of typing the same over and over again.
+   Hence, I grouped often used python fragments to this small
+   class to re-usage.
+
+   Long live laziness!
+
+
+   \author  M.Frank
+   \version 1.0
+
+"""
+class Digitize:
+  def __init__(self, kernel=None):
+    kernel.printProperties()
+    self._kernel = kernel
+    if kernel is None:
+      self._kernel = Kernel()
+    self.description = self._kernel.detectorDescription()
+
+  """
+     Access the worker kernel object.
+     
+     \author  M.Frank
+  """
+  def kernel(self):
+    return self._kernel
+
+  """
+     Execute the Geant 4 program with all steps.
+
+     \author  M.Frank
+  """
+  def execute(self):
+    self.kernel().configure()
+    self.kernel().initialize()
+    self.kernel().run()
+    self.kernel().terminate()
+    return self
+
+  def activeDetectors(self):
+    detectors = []
+    for i in self.description.detectors():
+      o = DetElement(i.second.ptr())
+      sd = self.description.sensitiveDetector(o.name())
+      if sd.isValid():
+        d = { 'name': o.name(), 'type': sd.type(), 'detector': o, 'sensitive': sd }
+        detectors.append(d)
+    return detectors
+
+  def printDetectors(self):
+    logging.info('+++  List of sensitive detectors:')
+    dets = self.activeDetectors()
+    for d in dets:
+      logging.info('+++  %-32s ---> type:%-12s', d['name'], d['type'])
+
+  def setupDetector(self,name,collections=None,modules=None):
+    parameterDict = {}
+    seq = ActionSequence(self.kernel(),'DigiActionSequence/'+name)
+    actions = []
+    if isinstance(modules,tuple) or isinstance(modules,list):
+      for m in modules:
+        if isinstance(m,str):
+          a = Action(self.kernel(), m)
+          actions.append(a)
+        elif isinstance(m,tuple) or isinstance(m,list):
+          a = Action(self.kernel(), m[0])
+          actions.append(a)
+          if len(m) > 1:
+            params = m[1]
+            for k,v in params.items():
+              setattr(a, k, v)
+        else:
+          ol = m.OutputLevel    # Check if the object is a DigiAction....
+          actions.append(m)
+    for a in actions:
+      seq.adopt(a)
+    return (seq,actions)
+
+  """
+     Configure ROOT output for the event digitization
+
+     \author  M.Frank
+  """
+  def setupROOTOutput(self,name,output,mc_truth=True):
+    evt_root = EventAction(self.kernel(),'DigiOutput2ROOT/'+name,True)
+    evt_root.HandleMCTruth = mc_truth
+    evt_root.Control = True
+    if not output.endswith('.root'):
+      output = output + '.root'
+    evt_root.Output = output
+    evt_root.enableUI()
+    self.kernel().eventAction().add(evt_root)
+    return evt_root
+
+  """
+     Generic build of the input stage with multiple input modules.
+
+     Actions executed are:
+     1) Register Generation initialization action
+     2) Append all modules to build the complete input record
+        These modules are readers/particle sources, boosters and/or smearing actions.
+     3) Merge all existing interaction records
+     4) Add the MC truth handler
+
+     \author  M.Frank
+  """
+  def buildInputStage(self, generator_input_modules, output_level=None, have_mctruth=True):
+    ga = self.kernel().generatorAction()
+    # Register Generation initialization action
+    gen = GeneratorAction(self.kernel(),"DigiGeneratorActionInit/GenerationInit")
+    if output_level is not None:
+      gen.OutputLevel = output_level
+    ga.adopt(gen)
+
+    # Now append all modules to build the complete input record
+    # These modules are readers/particle sources, boosters and/or smearing actions
+    for gen in generator_input_modules:
+      gen.enableUI()
+      if output_level is not None:
+        gen.OutputLevel = output_level
+      ga.adopt(gen)
+
+    # Merge all existing interaction records
+    gen = GeneratorAction(self.kernel(),"DigiInteractionMerger/InteractionMerger")
+    gen.enableUI()
+    if output_level is not None:
+      gen.OutputLevel = output_level
+    ga.adopt(gen)
+
+    # Finally generate Digi primaries
+    if have_mctruth:
+      gen = GeneratorAction(self.kernel(),"DigiPrimaryHandler/PrimaryHandler")
+      gen.RejectPDGs="{1,2,3,4,5,6,21,23,24}"
+      gen.enableUI()
+      if output_level is not None:
+        gen.OutputLevel = output_level
+      ga.adopt(gen)
+    # Puuuhh! All done.
+    return self
+
+  """
+     Execute the main Digi action
+     \author  M.Frank
+  """
+  def run(self):
+    #self.kernel().configure()
+    #self.kernel().initialize()
+    #self.kernel().run()
+    #self.kernel().terminate()
+    from ROOT import PyDDDigi
+    PyDDDigi.run(self.kernel().get())
+    return self
+
diff --git a/DDDigi/python/DDDigiDict.C b/DDDigi/python/DDDigiDict.C
new file mode 100644
index 000000000..7c4f8b9ad
--- /dev/null
+++ b/DDDigi/python/DDDigiDict.C
@@ -0,0 +1,155 @@
+//==========================================================================
+//  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.
+//
+//====================================================================
+//
+// Define the ROOT dictionaries for all data classes to be saved 
+// which are created by the DDG4 examples.
+//
+//  Author     : M.Frank
+//
+//====================================================================
+
+#if defined(__GNUC__)
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#pragma GCC diagnostic ignored "-Wdeprecated"
+#pragma GCC diagnostic ignored "-Wunused"
+#pragma GCC diagnostic ignored "-Woverlength-strings"
+
+#elif defined(__llvm__) || defined(__APPLE__)
+
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#pragma clang diagnostic ignored "-Wdeprecated"
+#pragma clang diagnostic ignored "-Wunused"
+#pragma clang diagnostic ignored "-Woverlength-strings"
+#endif
+
+#include "DDDigi/DigiData.h"
+#include "DDDigi/DigiHandle.h"
+#include "DDDigi/DigiKernel.h"
+#include "DDDigi/DigiContext.h"
+#include "DDDigi/DigiSynchronize.h"
+#include "DDDigi/DigiActionSequence.h"
+
+struct DDDigiDict  {};
+
+/// Namespace for the AIDA detector description toolkit
+namespace dd4hep {
+
+  /// Namespace for the Digitization part of the AIDA detector description toolkit
+  namespace digi {
+
+#define ACTIONHANDLE(x)                                                                   \
+    struct x##Handle  {                                                                   \
+      Digi##x* action;                                                                    \
+      explicit x##Handle(Digi##x* a) : action(a)       { if ( action ) action->addRef();} \
+      x##Handle(const x##Handle& h) : action(h.action) { if ( action ) action->addRef();} \
+      ~x##Handle()                                     { if ( action) action->release();} \
+      Digi##x* release()          { Digi##x* tmp = action; action=0; return tmp;        } \
+      operator dd4hep::digi::Digi##x* () const         { return action;                 } \
+      Digi##x* operator->() const                      { return action;                 } \
+      Digi##x* get() const                             { return action;                 } \
+    }
+
+    ACTIONHANDLE(Action);
+    ACTIONHANDLE(ActionSequence);
+    ACTIONHANDLE(Synchronize);
+
+    struct PropertyResult  {
+      std::string data;
+      int status;
+      PropertyResult() : status(0) {}
+      PropertyResult(const std::string& d, int s) : data(d), status(s) {}
+      PropertyResult(const PropertyResult& c) : data(c.data), status(c.status) {}
+      ~PropertyResult() {}
+    };
+
+    struct DigiActionCreation  {
+      template <typename H,typename T> static
+      H cr(KernelHandle& kernel, const std::string& name_type)  {
+        T action(*kernel.get(),name_type);
+        H handle(action.get());
+        return handle;
+      }
+      static ActionHandle createAction(KernelHandle& kernel, const std::string& name_type)   
+      { return cr<ActionHandle,DigiHandle<DigiAction> >(kernel,name_type);                           }
+      static ActionSequenceHandle createSequence(KernelHandle& kernel, const std::string& name_type)   
+      { return cr<ActionSequenceHandle,DigiHandle<DigiActionSequence> >(kernel,name_type);           }
+      static SynchronizeHandle createSync(KernelHandle& kernel, const std::string& name_type)
+      { return cr<SynchronizeHandle,DigiHandle<DigiSynchronize> >(kernel,name_type);                 }
+
+      static DigiAction* toAction(DigiAction* f)                   { return f;                       }
+      static DigiAction* toAction(DigiActionSequence* f)           { return f;                       }
+      static DigiAction* toAction(DigiSynchronize* f)              { return f;                       }
+
+      static DigiAction* toAction(ActionHandle f)                  { return f.action;                }
+      static DigiAction* toAction(ActionSequenceHandle f)          { return f.action;                }
+      static DigiAction* toAction(SynchronizeHandle f)             { return f.action;                }
+
+      static PropertyResult getProperty(DigiAction* action, const std::string& name)  {
+        if ( action->hasProperty(name) )  {
+          return PropertyResult(action->property(name).str(),1);
+        }
+        return PropertyResult("",0);
+      }
+      static int setProperty(DigiAction* action, const std::string& name, const std::string& value)  {
+        if ( action->hasProperty(name) )  {
+          action->property(name).str(value);
+          return 1;
+        }
+        return 0;
+      }
+      static PropertyResult getPropertyKernel(DigiKernel* kernel, const std::string& name)  {
+        if ( kernel->hasProperty(name) )  {
+          return PropertyResult(kernel->property(name).str(),1);
+        }
+        return PropertyResult("",0);
+      }
+      static int setPropertyKernel(DigiKernel* kernel, const std::string& name, const std::string& value)  {
+        if ( kernel->hasProperty(name) )  {
+          kernel->property(name).str(value);
+          return 1;
+        }
+        return 0;
+      }
+    };
+  }
+}
+
+// CINT configuration
+#if defined(__CINT__) || defined(__MAKECINT__) || defined(__CLING__) || defined(__ROOTCLING__)
+
+#pragma link off all globals;
+#pragma link off all classes;
+#pragma link off all functions;
+
+using namespace std;
+
+#pragma link C++ namespace dd4hep;
+#pragma link C++ namespace dd4hep::digi;
+
+#pragma link C++ class dd4hep::digi::DigiActionCreation;
+#pragma link C++ class dd4hep::digi::KernelHandle;
+#pragma link C++ class dd4hep::digi::DigiKernel;
+#pragma link C++ class dd4hep::digi::DigiContext;
+
+#pragma link C++ class dd4hep::digi::DigiAction;
+#pragma link C++ class dd4hep::digi::ActionHandle;
+
+#pragma link C++ class dd4hep::digi::DigiActionSequence;
+#pragma link C++ class dd4hep::digi::ActionSequenceHandle;
+
+#pragma link C++ class dd4hep::digi::DigiSynchronize;
+#pragma link C++ class dd4hep::digi::SynchronizeHandle;
+
+#pragma link C++ class dd4hep::digi::DigiEvent;
+#pragma link C++ class dd4hep::digi::DigiEnergyDeposits+;
+#pragma link C++ class dd4hep::digi::DigiCounts+;
+
+#endif
diff --git a/DDDigi/src/DigiAction.cpp b/DDDigi/src/DigiAction.cpp
new file mode 100644
index 000000000..adc16b1e2
--- /dev/null
+++ b/DDDigi/src/DigiAction.cpp
@@ -0,0 +1,208 @@
+//==========================================================================
+//  AIDA Detector description implementation 
+//--------------------------------------------------------------------------
+// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
+// All rights reserved.
+//
+// For the licensing terms see $DD4hepINSTALL/LICENSE.
+// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
+//
+// Author     : M.Frank
+//
+//==========================================================================
+
+// Framework include files
+#include "DD4hep/Printout.h"
+#include "DD4hep/InstanceCount.h"
+#include "DDDigi/DigiAction.h"
+
+// C/C++ include files
+#include <algorithm>
+
+using namespace std;
+using namespace dd4hep;
+using namespace dd4hep::digi;
+
+TypeName TypeName::split(const string& type_name, const string& delim) {
+  size_t idx = type_name.find(delim);
+  string typ = type_name, nam = type_name;
+  if (idx != string::npos) {
+    typ = type_name.substr(0, idx);
+    nam = type_name.substr(idx + 1);
+  }
+  return TypeName(typ, nam);
+}
+
+TypeName TypeName::split(const string& type_name) {
+  return split(type_name,"/");
+}
+
+/// Standard constructor
+DigiAction::DigiAction(const DigiKernel& krnl, const string& nam)
+  : m_kernel(krnl), m_name(nam), m_outputLevel(INFO)
+{
+  InstanceCount::increment(this);
+  declareProperty("Name", m_name);
+  declareProperty("name", m_name);
+  declareProperty("parallel", m_parallel);
+  declareProperty("OutputLevel", m_outputLevel);
+}
+
+/// Default destructor
+DigiAction::~DigiAction() {
+  InstanceCount::decrement(this);
+}
+
+/// Implicit destruction
+long DigiAction::addRef() {
+  return ++m_refCount;
+}
+
+/// Decrease reference count. Implicit destruction
+long DigiAction::release() {
+  long count = --m_refCount;
+  if (m_refCount <= 0) {
+    printM1("DigiAction: Deleting object %s of type %s Pointer:%p",
+            m_name.c_str(),typeName(typeid(*this)).c_str(),(void*)this);
+    delete this;
+  }
+  return count;
+}
+
+/// Set the output level; returns previous value
+PrintLevel DigiAction::setOutputLevel(PrintLevel new_level)  {
+  int old = m_outputLevel;
+  m_outputLevel = new_level;
+  return (PrintLevel)old;
+}
+
+/// Set the parallization flag; returns previous value
+bool DigiAction::setExecuteParallel(bool new_value)    {
+  bool old = m_parallel;
+  m_parallel = new_value;
+  return old;
+}
+
+/// Check property for existence
+bool DigiAction::hasProperty(const string& nam) const    {
+  return m_properties.exists(nam);
+}
+
+/// Access single property
+Property& DigiAction::property(const string& nam)   {
+  return properties()[nam];
+}
+
+/// Support for messages with variable output level using output level
+void DigiAction::print(const char* fmt, ...) const   {
+  int level = max(int(outputLevel()),(int)VERBOSE);
+  if ( level >= printLevel() )  {
+    va_list args;
+    va_start(args, fmt);
+    dd4hep::printout((PrintLevel)level, m_name.c_str(), fmt, args);
+    va_end(args);
+  }
+}
+
+/// Support for messages with variable output level using output level-1
+void DigiAction::printM1(const char* fmt, ...) const   {
+  int level = max(outputLevel()-1,(int)VERBOSE);
+  if ( level >= printLevel() )  {
+    va_list args;
+    va_start(args, fmt);
+    dd4hep::printout((PrintLevel)level, m_name.c_str(), fmt, args);
+    va_end(args);
+  }
+}
+
+/// Support for messages with variable output level using output level-2
+void DigiAction::printM2(const char* fmt, ...) const   {
+  int level = max(outputLevel()-2,(int)VERBOSE);
+  if ( level >= printLevel() )  {
+    va_list args;
+    va_start(args, fmt);
+    dd4hep::printout((PrintLevel)level, m_name.c_str(), fmt, args);
+    va_end(args);
+  }
+}
+
+/// Support for messages with variable output level using output level-1
+void DigiAction::printP1(const char* fmt, ...) const   {
+  int level = min(outputLevel()+1,(int)FATAL);
+  if ( level >= printLevel() )  {
+    va_list args;
+    va_start(args, fmt);
+    dd4hep::printout((PrintLevel)level, m_name.c_str(), fmt, args);
+    va_end(args);
+  }
+}
+
+/// Support for messages with variable output level using output level-2
+void DigiAction::printP2(const char* fmt, ...) const   {
+  int level = min(outputLevel()+2,(int)FATAL);
+  if ( level >= printLevel() )  {
+    va_list args;
+    va_start(args, fmt);
+    dd4hep::printout((PrintLevel)level, m_name.c_str(), fmt, args);
+    va_end(args);
+  }
+}
+
+/// Support of debug messages.
+void DigiAction::debug(const char* fmt, ...) const {
+  va_list args;
+  va_start(args, fmt);
+  dd4hep::printout(dd4hep::DEBUG, m_name, fmt, args);
+  va_end(args);
+}
+
+/// Support of info messages.
+void DigiAction::info(const char* fmt, ...) const {
+  va_list args;
+  va_start(args, fmt);
+  dd4hep::printout(dd4hep::INFO, m_name, fmt, args);
+  va_end(args);
+}
+
+/// Support of warning messages.
+void DigiAction::warning(const char* fmt, ...) const {
+  va_list args;
+  va_start(args, fmt);
+  dd4hep::printout(dd4hep::WARNING, m_name, fmt, args);
+  va_end(args);
+}
+
+/// Action to support error messages.
+void DigiAction::error(const char* fmt, ...) const {
+  va_list args;
+  va_start(args, fmt);
+  dd4hep::printout(dd4hep::ERROR, m_name, fmt, args);
+  va_end(args);
+}
+
+/// Action to support error messages.
+bool DigiAction::return_error(bool return_value, const char* fmt, ...) const {
+  va_list args;
+  va_start(args, fmt);
+  dd4hep::printout(dd4hep::ERROR, m_name, fmt, args);
+  va_end(args);
+  return return_value;
+}
+
+/// Support of fatal messages. Throws exception if required.
+void DigiAction::fatal(const char* fmt, ...) const {
+  va_list args;
+  va_start(args, fmt);
+  dd4hep::printout(dd4hep::FATAL, m_name, fmt, args);
+  va_end(args);
+}
+
+/// Support of exceptions: Print fatal message and throw runtime_error.
+void DigiAction::except(const char* fmt, ...) const {
+  va_list args;
+  va_start(args, fmt);
+  string err = dd4hep::format(m_name, fmt, args);
+  dd4hep::printout(dd4hep::FATAL, m_name, err.c_str());
+  va_end(args);
+  throw runtime_error(err);
+}
diff --git a/DDDigi/src/DigiActionSequence.cpp b/DDDigi/src/DigiActionSequence.cpp
new file mode 100644
index 000000000..31cf428d2
--- /dev/null
+++ b/DDDigi/src/DigiActionSequence.cpp
@@ -0,0 +1,50 @@
+//==========================================================================
+//  AIDA Detector description implementation 
+//--------------------------------------------------------------------------
+// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
+// All rights reserved.
+//
+// For the licensing terms see $DD4hepINSTALL/LICENSE.
+// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
+//
+// Author     : M.Frank
+//
+//==========================================================================
+
+// Framework include files
+#include "DD4hep/InstanceCount.h"
+#include "DDDigi/DigiActionSequence.h"
+
+// C/C++ include files
+#include <stdexcept>
+
+using namespace std;
+using namespace dd4hep::digi;
+
+/// Standard constructor
+DigiActionSequence::DigiActionSequence(const DigiKernel& kernel, const string& nam)
+  : DigiSynchronize(kernel, nam)
+{
+  InstanceCount::increment(this);
+}
+
+/// Default destructor
+DigiActionSequence::~DigiActionSequence() {
+  m_begin.clear();
+  m_end.clear();
+  InstanceCount::decrement(this);
+}
+
+/// Adopt a new action as part of the sequence. Sequence takes ownership.
+void DigiActionSequence::adopt(DigiAction* action)    {
+  this->DigiSynchronize::adopt(action);
+}
+
+/// Pre-track action callback
+void DigiActionSequence::execute(DigiContext& context)  const   {
+  m_begin(&context);
+  this->DigiSynchronize::execute(context);
+  debug("+++ Event: %8d (DigiActionSequence) Parallel: %s Done.",
+       context.event().eventNumber, yes_no(m_parallel));
+  m_end(&context);
+}
diff --git a/DDDigi/src/DigiContext.cpp b/DDDigi/src/DigiContext.cpp
new file mode 100644
index 000000000..3575def8f
--- /dev/null
+++ b/DDDigi/src/DigiContext.cpp
@@ -0,0 +1,79 @@
+//==========================================================================
+//  AIDA Detector description implementation 
+//--------------------------------------------------------------------------
+// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
+// All rights reserved.
+//
+// For the licensing terms see $DD4hepINSTALL/LICENSE.
+// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
+//
+// Author     : M.Frank
+//
+//==========================================================================
+
+// Framework include files
+#include "DD4hep/Printout.h"
+#include "DD4hep/InstanceCount.h"
+#include "DDDigi/DigiContext.h"
+#include "DDDigi/DigiKernel.h"
+
+// C/C++ include files
+#include <algorithm>
+
+using namespace std;
+using namespace dd4hep;
+using namespace dd4hep::digi;
+
+/// Default constructor
+DigiContext::DigiContext(const DigiKernel* k, DigiEvent* e)
+  : m_kernel(k), m_event(e)
+{
+  if ( !m_kernel )    {
+    except("DigiContext","Cannot initialize Digitization context with invalid DigiKernel!");
+  }
+  InstanceCount::increment(this);
+}
+
+/// Default destructor
+DigiContext::~DigiContext() {
+  // Do not delete run and event structures here. This is done outside in the framework
+  InstanceCount::decrement(this);
+}
+
+/// Set the geant4 event reference
+void DigiContext::setEvent(DigiEvent* new_event)   {
+  m_event = new_event;
+}
+
+/// Access the geant4 event -- valid only between BeginEvent() and EndEvent()!
+DigiEvent& DigiContext::event()  const   {
+  if ( m_event ) return *m_event;
+  invalidHandleError<DigiEvent>();
+  return *m_event;
+}
+
+/// Access to detector description
+Detector& DigiContext::detectorDescription()  const {
+  return m_kernel->detectorDescription();
+}
+
+/// Generic framework access
+DigiContext::UserFramework& DigiContext::userFramework()  const  {
+  return m_kernel->userFramework();
+}
+
+/// Access to the main input action sequence from the kernel object
+DigiActionSequence& DigiContext::inputAction() const    {
+  return m_kernel->inputAction();
+}
+
+/// Access to the main event action sequence from the kernel object
+DigiActionSequence& DigiContext::eventAction()  const  {
+  return m_kernel->eventAction();
+}
+
+/// Access to the main output action sequence from the kernel object
+DigiActionSequence& DigiContext::outputAction() const    {
+  return m_kernel->outputAction();
+}
+
diff --git a/DDDigi/src/DigiData.cpp b/DDDigi/src/DigiData.cpp
new file mode 100644
index 000000000..80c92748b
--- /dev/null
+++ b/DDDigi/src/DigiData.cpp
@@ -0,0 +1,44 @@
+//==========================================================================
+//  AIDA Detector description implementation 
+//--------------------------------------------------------------------------
+// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
+// All rights reserved.
+//
+// For the licensing terms see $DD4hepINSTALL/LICENSE.
+// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
+//
+// Author     : M.Frank
+//
+//==========================================================================
+
+// Framework include files
+#include "DD4hep/Printout.h"
+#include "DD4hep/InstanceCount.h"
+#define  G__ROOT
+#include "DDDigi/DigiData.h"
+
+// C/C++ include files
+
+using namespace std;
+using namespace dd4hep;
+using namespace dd4hep::digi;
+
+/// Intializing constructor
+DigiEvent::DigiEvent()
+  : ObjectExtensions(typeid(DigiEvent))
+{
+  InstanceCount::increment(this);
+}
+
+/// Intializing constructor
+DigiEvent::DigiEvent(int ev_num)
+  : ObjectExtensions(typeid(DigiEvent)), eventNumber(ev_num)
+{
+  InstanceCount::increment(this);
+}
+
+/// Default destructor
+DigiEvent::~DigiEvent()
+{
+  InstanceCount::decrement(this);
+}
diff --git a/DDDigi/src/DigiHandle.cpp b/DDDigi/src/DigiHandle.cpp
new file mode 100644
index 000000000..09500703d
--- /dev/null
+++ b/DDDigi/src/DigiHandle.cpp
@@ -0,0 +1,190 @@
+//==========================================================================
+//  AIDA Detector description implementation 
+//--------------------------------------------------------------------------
+// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
+// All rights reserved.
+//
+// For the licensing terms see $DD4hepINSTALL/LICENSE.
+// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
+//
+// Author     : M.Frank
+//
+//==========================================================================
+
+// Framework include files
+#include "DD4hep/Detector.h"
+#include "DD4hep/Plugins.h"
+#include "DD4hep/Printout.h"
+
+#include "DDDigi/DigiHandle.h"
+#include "DDDigi/DigiKernel.h"
+#include "DDDigi/DigiAction.h"
+
+// C/C++ include files
+#include <stdexcept>
+
+using namespace std;
+using namespace dd4hep;
+using namespace dd4hep::digi;
+
+/// Namespace for the AIDA detector description toolkit
+namespace dd4hep {
+  /// Namespace for the Digitization part of the AIDA detector description toolkit
+  namespace digi {
+ 
+    template <typename TYPE> static inline TYPE* checked_value(TYPE* p) {
+      if (p) {
+        return p;
+      }
+      except("DigiHandle","Attempt to access an invalid object of type:%s!",
+             typeName(typeid(TYPE)).c_str());
+      return 0;
+    }
+
+    template <typename TYPE> DigiHandle<TYPE>::DigiHandle(TYPE* typ) : value(typ)  {
+      if (value)
+        value->addRef();
+    }
+
+    template <typename TYPE> DigiHandle<TYPE>::DigiHandle(const DigiHandle<TYPE>& handle) : value(handle.get())
+    {
+      if (value)
+        value->addRef();
+    }
+
+    template <typename TYPE> DigiHandle<TYPE>::DigiHandle(DigiHandle<TYPE>&& handle) : value(handle.get())
+    {
+      handle.value = 0;
+    }
+
+    template <typename TYPE> TYPE* _create_object(const DigiKernel& kernel, const TypeName& typ)    {
+      DigiAction* object = PluginService::Create<DigiAction*>(typ.first, &kernel, typ.second);
+      if (!object && typ.first == typ.second) {
+        string _t = typeName(typeid(TYPE));
+        printout(DEBUG, "DigiHandle", "Object factory for %s not found. Try out %s",
+                 typ.second.c_str(), _t.c_str());
+        object = PluginService::Create<DigiAction*>(_t, &kernel, typ.second);
+        if (!object) {
+          size_t idx = _t.rfind(':');
+          if (idx != string::npos)
+            _t = string(_t.substr(idx + 1));
+          printout(DEBUG, "DigiHandle", "Try out object factory for %s",_t.c_str());
+          object = PluginService::Create<DigiAction*>(_t, &kernel, typ.second);
+        }
+      }
+      if (object)  {
+        TYPE* ptr = dynamic_cast<TYPE*>(object);
+        if (ptr)  {
+          return ptr;
+        }
+        except("DigiHandle", "Failed to convert object of type %s to handle of type %s!",
+               typ.first.c_str(),typ.second.c_str());
+      }
+      except("DigiHandle", "Failed to create object of type %s!", typ.first.c_str());
+      return 0;
+    }
+
+    template <typename TYPE> 
+    DigiHandle<TYPE>::DigiHandle(const DigiKernel& kernel, const string& type_name)  {
+      value = _create_object<TYPE>(kernel,TypeName::split(type_name));
+    }
+
+    template <typename TYPE> 
+    DigiHandle<TYPE>::DigiHandle(const DigiKernel& kernel, const char* type_name_char)  {
+      value = _create_object<TYPE>(kernel,TypeName::split(type_name_char ? type_name_char : "????"));
+    }
+
+    template <typename TYPE> DigiHandle<TYPE>::~DigiHandle() {
+      if (value)
+        value->release();
+      value = 0;
+    }
+
+    template <typename TYPE> TYPE* DigiHandle<TYPE>::release() {
+      TYPE* temp = value;
+      value = 0;
+      return temp;
+    }
+
+    template <typename TYPE> void DigiHandle<TYPE>::checked_assign(TYPE* p) {
+      if (value)
+        value->release();
+      value = checked_value(p);
+      if (value)
+        value->addRef();
+    }
+
+    template <typename TYPE> Property& DigiHandle<TYPE>::operator[](const string& property_name) const {
+      PropertyManager& pm = checked_value(value)->properties();
+      return pm[property_name];
+    }
+
+    template <typename TYPE> DigiHandle<TYPE>::operator TYPE*() const {
+      return checked_value(value);
+    }
+
+    template <typename TYPE> bool DigiHandle<TYPE>::operator!() const {
+      return 0 == value;
+    }
+
+    template <typename TYPE> TYPE* DigiHandle<TYPE>::get() const {
+      return checked_value(value);
+    }
+
+    template <typename TYPE> TYPE* DigiHandle<TYPE>::operator->() const {
+      return checked_value(value);
+    }
+
+    template <typename TYPE> DigiAction* DigiHandle<TYPE>::action() const {
+      return checked_value(value);
+    }
+
+    /// Assignment operator
+    template <typename TYPE> DigiHandle<TYPE>& DigiHandle<TYPE>::operator=(const DigiHandle& handle) {
+      if ( &handle != this )  {
+        TYPE* point = value;
+        value = handle.get();
+        if ( value ) value->addRef();
+        if ( point ) point->release();
+      }
+      return *this;
+    }
+
+    /// Assignment move operator
+    template <typename TYPE> DigiHandle<TYPE>& DigiHandle<TYPE>::operator=(DigiHandle&& handle) {
+      if ( value ) value->release();
+      value = handle.get();
+      handle.value = 0;
+      return *this;
+    }
+
+    template <typename TYPE> DigiHandle<TYPE>& DigiHandle<TYPE>::operator=(TYPE* pointer) {
+      if ( pointer != value )  {
+        TYPE* point = value;
+        value = pointer;
+        if ( value ) value->addRef();
+        if ( point ) point->release();
+      }
+      return *this;
+    }
+
+    KernelHandle::KernelHandle()  {
+      value = &DigiKernel::instance(Detector::getInstance());
+    }
+    KernelHandle::KernelHandle(DigiKernel* k) : value(k)  {
+    }
+  }
+}
+
+#include "DDDigi/DigiSynchronize.h"
+#include "DDDigi/DigiActionSequence.h"
+
+/// Namespace for the AIDA detector description toolkit
+namespace dd4hep {
+  /// Namespace for the Digitization part of the AIDA detector description toolkit
+  namespace digi {
+    template class DigiHandle<DigiAction>;
+    template class DigiHandle<DigiSynchronize>;
+    template class DigiHandle<DigiActionSequence>;
+  }
+}
diff --git a/DDDigi/src/DigiInputAction.cpp b/DDDigi/src/DigiInputAction.cpp
new file mode 100644
index 000000000..b3604b1f1
--- /dev/null
+++ b/DDDigi/src/DigiInputAction.cpp
@@ -0,0 +1,44 @@
+//==========================================================================
+//  AIDA Detector description implementation 
+//--------------------------------------------------------------------------
+// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
+// All rights reserved.
+//
+// For the licensing terms see $DD4hepINSTALL/LICENSE.
+// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
+//
+// Author     : M.Frank
+//
+//==========================================================================
+
+// Framework include files
+#include "DD4hep/InstanceCount.h"
+#include "DDDigi/DigiInputAction.h"
+
+// C/C++ include files
+#include <stdexcept>
+#include <unistd.h>
+
+using namespace std;
+using namespace dd4hep::digi;
+
+/// Standard constructor
+DigiInputAction::DigiInputAction(const DigiKernel& kernel, const string& nam)
+  : DigiAction(kernel, nam)
+{
+  declareProperty("Input", m_input);
+  InstanceCount::increment(this);
+}
+
+/// Default destructor
+DigiInputAction::~DigiInputAction()   {
+  InstanceCount::decrement(this);
+}
+
+/// Pre-track action callback
+void DigiInputAction::execute(DigiContext& /* context */)  const   {
+  ::sleep(1);
+  info("+++ Virtual method execute()");
+  return;
+  //except("DigiInputAction","+++ Virtual method execute() MUST be overloaded!");
+}
diff --git a/DDDigi/src/DigiKernel.cpp b/DDDigi/src/DigiKernel.cpp
new file mode 100644
index 000000000..a3aab4ca6
--- /dev/null
+++ b/DDDigi/src/DigiKernel.cpp
@@ -0,0 +1,365 @@
+//==========================================================================
+//  AIDA Detector description implementation 
+//--------------------------------------------------------------------------
+// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
+// All rights reserved.
+//
+// For the licensing terms see $DD4hepINSTALL/LICENSE.
+// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
+//
+// Author     : M.Frank
+//
+//==========================================================================
+
+// Framework include files
+#include "DD4hep/Detector.h"
+#include "DD4hep/Memory.h"
+#include "DD4hep/Plugins.h"
+#include "DD4hep/Printout.h"
+#include "DD4hep/Primitives.h"
+#include "DD4hep/InstanceCount.h"
+
+#include "DDDigi/DigiKernel.h"
+#include "DDDigi/DigiContext.h"
+#include "DDDigi/DigiActionSequence.h"
+
+#include "tbb/tbb.h"
+
+// C/C++ include files
+#include <stdexcept>
+#include <algorithm>
+#include <memory>
+#include <chrono>
+
+using namespace std;
+using namespace dd4hep;
+using namespace dd4hep::digi;
+
+/// DigiKernel herlp class: Container of instance variabled
+/*
+ *
+ *  \author  M.Frank
+ *  \version 1.0
+ *  \ingroup DD4HEP_DIGITIZATION
+ */
+class DigiKernel::Internals   {
+public:
+  /// Property pool
+  PropertyManager       properties;
+  /// Property: Client output levels
+  ClientOutputLevels    clientLevels;
+  /// Atomic counter: Number of events still to be processed in this run
+  std::atomic_int       eventsToDo;
+
+  /// The main data input action sequence
+  DigiActionSequence*   inputAction = 0;
+  /// The main event action sequence
+  DigiActionSequence*   eventAction = 0;
+  /// The main data output action sequence
+  DigiActionSequence*   outputAction = 0;
+  /// TBB initializer (If TBB is used)
+  void*                 tbbInit = 0;
+  /// Property: Output level
+  int                   outputLevel;
+  /// Property: maximum number of events to be processed (if < 0: infinite)
+  int                   numEvents;
+  /// Property: maximum number of events to be processed in parallel (if TBB)
+  int                   maxEventsParallel;
+  /// Property: maximum number of threads to be used (if TBB)
+  int                   numThreads;
+  /// Property: Allow to stop execution from interactive prompt
+  bool                  stop = false;
+  Internals() = default;
+  ~Internals() = default;
+};
+
+/// DigiKernel herlp class: TBB wrapper to execute DigiAction instances
+/*
+ *
+ *  \author  M.Frank
+ *  \version 1.0
+ *  \ingroup DD4HEP_DIGITIZATION
+ */
+class DigiKernel::Wrapper  {
+public:
+  DigiContext& context;
+  DigiAction*  action = 0;
+  Wrapper(DigiContext& c, DigiAction* a)
+    : context(c), action(a) {}
+  Wrapper(Wrapper&& copy) = default;
+  Wrapper(const Wrapper& copy) = default;
+  Wrapper& operator=(Wrapper&& copy) = default;
+  Wrapper& operator=(const Wrapper& copy) = default;
+  void operator()() const {
+    action->execute(context);
+  }
+};
+
+/// DigiKernel herlp class: TBB wrapper to execute a full event
+/*
+ *
+ *  \author  M.Frank
+ *  \version 1.0
+ *  \ingroup DD4HEP_DIGITIZATION
+ */
+class DigiKernel::Processor { 
+  DigiKernel& kernel;
+public: 
+  Processor(DigiKernel& k) : kernel(k) {}
+  Processor(Processor&& l) = default;
+  Processor(const Processor& l) = default;
+  void operator()()  const {
+    int todo;
+    while( !kernel.internals->stop &&
+           (todo = --kernel.internals->eventsToDo) >= 0 )    {
+      int ev_num = kernel.internals->numEvents - todo;
+      unique_ptr<DigiContext> c = make_unique<DigiContext>(&kernel);
+      unique_ptr<DigiEvent>   e = make_unique<DigiEvent>(ev_num);
+      c->setEvent(e.release());
+      kernel.executeEvent(c.release());
+    }
+  }
+};
+
+
+/// Standard constructor
+DigiKernel::DigiKernel(Detector& description_ref)
+  : m_detDesc(&description_ref)
+{
+  internals = new Internals();
+#ifdef DD4HEP_USE_TBB
+  internals->numThreads = tbb::task_scheduler_init::default_num_threads();
+#else
+  internals->numThreads = -1;
+#endif
+  declareProperty("maxEventsParallel",internals->maxEventsParallel = 1);
+  declareProperty("numThreads",       internals->numThreads);
+  declareProperty("numEvents",        internals->numEvents = 10);
+  declareProperty("stop",             internals->stop = false);
+  declareProperty("OutputLevel",      internals->outputLevel = DEBUG);
+  declareProperty("OutputLevels",     internals->clientLevels);
+  internals->inputAction  = new DigiActionSequence(*this, "InputAction");
+  internals->eventAction  = new DigiActionSequence(*this, "EventAction");
+  internals->outputAction = new DigiActionSequence(*this, "OutputAction");
+  internals->inputAction->setExecuteParallel(false);
+  internals->eventAction->setExecuteParallel(false);
+  internals->outputAction->setExecuteParallel(false);
+  InstanceCount::increment(this);
+}
+
+/// Default destructor
+DigiKernel::~DigiKernel() {
+#ifdef DD4HEP_USE_TBB
+  tbb::task_scheduler_init* init = (tbb::task_scheduler_init*)internals->tbbInit;
+  if ( init ) delete init;
+#endif
+  detail::releasePtr(internals->outputAction);
+  detail::releasePtr(internals->eventAction);
+  detail::releasePtr(internals->inputAction);
+  detail::deletePtr(internals);
+  InstanceCount::decrement(this);
+}
+
+/// Instance accessor
+DigiKernel& DigiKernel::instance(Detector& description) {
+  static dd4hep::dd4hep_ptr<DigiKernel> s_main_instance(0);
+  if ( 0 == s_main_instance.get() )   {
+    static std::mutex kernel_mutex;
+    std::lock_guard<std::mutex> lock(kernel_mutex);
+    if ( 0 == s_main_instance.get() )   { // Need to check again!
+      s_main_instance.adopt(new DigiKernel(description));
+    }
+  }
+  return *(s_main_instance.get());
+}
+
+/// Access to the properties of the object
+PropertyManager& DigiKernel::properties()   {
+  return internals->properties;
+}
+
+/// Print the property values
+void DigiKernel::printProperties()  const  {
+  printout(ALWAYS,"DigiKernel","OutputLevel:  %d", internals->outputLevel);
+  for(ClientOutputLevels::const_iterator i=internals->clientLevels.begin(); i!=internals->clientLevels.end();++i)  {
+    printout(ALWAYS,"DigiKernel","OutputLevel[%s]:  %d",(*i).first.c_str(),(*i).second);
+  }
+}
+
+/// Check property for existence
+bool DigiKernel::hasProperty(const std::string& name) const    {
+  return internals->properties.exists(name);
+}
+
+/// Access single property
+dd4hep::Property& DigiKernel::property(const std::string& name)   {
+  return internals->properties[name];
+}
+
+/// Access the output level
+PrintLevel DigiKernel::outputLevel() const  {
+  return (PrintLevel)internals->outputLevel;
+}
+
+/// Fill cache with the global output level of a named object. Must be set before instantiation
+void DigiKernel::setOutputLevel(const std::string object, PrintLevel new_level)   {
+  internals->clientLevels[object] = new_level;
+}
+
+/// Retrieve the global output level of a named object.
+dd4hep::PrintLevel DigiKernel::getOutputLevel(const std::string object) const   {
+  ClientOutputLevels::const_iterator i=internals->clientLevels.find(object);
+  if ( i != internals->clientLevels.end() ) return (PrintLevel)(*i).second;
+  return dd4hep::PrintLevel(dd4hep::printLevel()-1);
+}
+
+/// Set the output level; returns previous value
+dd4hep::PrintLevel DigiKernel::setOutputLevel(PrintLevel new_level)  {
+  int old = internals->outputLevel;
+  internals->outputLevel = new_level;
+  return (PrintLevel)old;
+}
+
+/// Construct detector geometry using description plugin
+void DigiKernel::loadGeometry(const std::string& compact_file) {
+  char* arg = (char*) compact_file.c_str();
+  m_detDesc->apply("DD4hep_XMLLoader", 1, &arg);
+}
+
+// Utility function to load XML files
+void DigiKernel::loadXML(const char* fname) {
+  const char* args[] = { fname, 0 };
+  m_detDesc->apply("DD4hep_XMLLoader", 1, (char**) args);
+}
+
+int DigiKernel::configure()   {
+  return 1;//DigiExec::configure(*this);
+}
+
+int DigiKernel::initialize()   {
+  return 1;//DigiExec::initialize(*this);
+}
+
+/// Access to the main input action sequence from the kernel object
+DigiActionSequence& DigiKernel::inputAction() const    {
+  return *internals->inputAction;
+}
+
+/// Access to the main event action sequence from the kernel object
+DigiActionSequence& DigiKernel::eventAction() const    {
+  return *internals->eventAction;
+}
+
+/// Access to the main output action sequence from the kernel object
+DigiActionSequence& DigiKernel::outputAction() const    {
+  return *internals->outputAction;
+}
+
+void DigiKernel::submit(const DigiAction::Actors<DigiAction>& actions, DigiContext& context)   const  {
+  chrono::system_clock::time_point start = chrono::system_clock::now();
+  bool parallel = 0 != internals->tbbInit && internals->numThreads>0;
+#ifdef DD4HEP_USE_TBB
+  if ( parallel )   {
+    tbb::task_group que;
+    for(auto i=actions.begin(); i!=actions.end(); ++i)
+      que.run(Wrapper(context, *i));
+    que.wait();
+    goto print_stamp;
+  }
+#endif
+  actions(&DigiAction::execute,context);
+
+ print_stamp:
+  chrono::duration<double> secs = chrono::system_clock::now() - start;
+  printout(DEBUG,"DigiKernel","+++ Event: %8d Executed %s task group with %3ld members [%8.3g sec]",
+           context.event().eventNumber, parallel ? "parallel" : "serial", actions.size(),
+           secs.count());
+}
+
+void DigiKernel::execute(const DigiAction::Actors<DigiAction>& actions, DigiContext& context)   const  {
+  actions(&DigiAction::execute,context);
+}
+
+void DigiKernel::wait(DigiContext& context)   const  {
+  if ( context.eventPtr() ) {}
+}
+
+/// Execute one single event
+void DigiKernel::executeEvent(DigiContext* context)    {
+  DigiContext& refContext = *context;
+  try {
+    inputAction().execute(refContext);
+    eventAction().execute(refContext);
+    outputAction().execute(refContext);
+    notify(context);
+  }
+  catch(const exception& e)   {
+    notify(context, e);
+  }
+}
+
+void DigiKernel::notify(DigiContext* context)   {
+  if ( context )   {
+    DigiEvent* event = context->eventPtr();
+    if ( event )    {
+      context->setEvent(0);
+      detail::deletePtr(event);
+    }
+    delete context;
+  }
+}
+
+void DigiKernel::notify(DigiContext* context, const std::exception& e)   {
+  internals->stop = true;
+  printout(ERROR,"DigiKernel","+++ Exception during event processing: %s. [%s]",
+           e.what(), "Shall stop the event loop!");
+  notify(context);
+}
+
+int DigiKernel::run()   {
+  chrono::system_clock::time_point start = chrono::system_clock::now();
+  internals->stop = false;
+  internals->eventsToDo = internals->numEvents;
+  printout(INFO,
+           "DigiKernel","+++ Total number of events:    %d",internals->numEvents);
+#ifdef DD4HEP_USE_TBB
+  if ( 0 == internals->tbbInit && internals->numThreads>=0 )   {
+    if ( 0 == internals->numThreads )
+      internals->numThreads = tbb::task_scheduler_init::default_num_threads();
+    printout(INFO,
+             "DigiKernel","+++ Number of TBB threads to:  %d",internals->numThreads);
+    printout(INFO,
+             "DigiKernel","+++ Number of parallel events: %d",internals->maxEventsParallel);
+    internals->tbbInit = new tbb::task_scheduler_init(internals->numThreads);
+    if ( internals->maxEventsParallel > 1 )   {
+      int todo_evt = internals->eventsToDo;
+      int num_proc = std::min(todo_evt,internals->maxEventsParallel);
+      tbb::task_group main_group;
+      for(int i=0; i < num_proc; ++i)
+        main_group.run(Processor(*this));
+      main_group.wait();
+      printout(DEBUG,"DigiKernel","+++ All event processing threads Synchronized --- Done!");
+    }
+  }
+#endif
+  if ( internals->eventsToDo > 0 )   {
+    for(int i=0; i<internals->numEvents; ++i)   {
+      unique_ptr<DigiContext> context = make_unique<DigiContext>(this);
+      ++internals->eventsToDo;
+      executeEvent(context.release());
+    }
+  }
+  chrono::duration<double> duration = chrono::system_clock::now() - start;
+  double sec = chrono::duration_cast<chrono::seconds>(duration).count();
+  printout(DEBUG,"DigiKernel","+++ Event processing finished. Total: %7.3f seconds %7.3f seconds/event",
+           sec, sec/double(std::max(1,internals->numEvents)));
+  return 1;
+}
+
+int DigiKernel::terminate() {
+  printout(INFO,"DigiKernel","++ Terminate Digi and delete associated actions.");
+  m_detDesc->destroyInstance();
+  m_detDesc = 0;
+  return 1;
+}
+
diff --git a/DDDigi/src/DigiLockedAction.cpp b/DDDigi/src/DigiLockedAction.cpp
new file mode 100644
index 000000000..21623e279
--- /dev/null
+++ b/DDDigi/src/DigiLockedAction.cpp
@@ -0,0 +1,57 @@
+//==========================================================================
+//  AIDA Detector description implementation 
+//--------------------------------------------------------------------------
+// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
+// All rights reserved.
+//
+// For the licensing terms see $DD4hepINSTALL/LICENSE.
+// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
+//
+// Author     : M.Frank
+//
+//==========================================================================
+
+// Framework include files
+#include "DD4hep/Printout.h"
+#include "DD4hep/InstanceCount.h"
+#include "DDDigi/DigiLockedAction.h"
+
+// C/C++ include files
+
+using namespace std;
+using namespace dd4hep::digi;
+
+
+/// Standard constructor
+DigiLockedAction::DigiLockedAction(const DigiKernel& kernel, const string& nam)
+  : DigiAction(kernel, nam)
+{
+  InstanceCount::increment(this);
+}
+
+/// Default destructor
+DigiLockedAction::~DigiLockedAction()   {
+  dd4hep::detail::releasePtr(m_action);
+  InstanceCount::decrement(this);
+}
+
+/// Underlying object to be used during the locked execution
+void DigiLockedAction::use(DigiAction* action)   {
+  if (action) {
+    action->addRef();
+    m_properties.adopt(action->properties());
+    m_action = action;
+    return;
+  }
+  fatal("DigiLockedAction: Attempt to use invalid actor!");
+}
+
+/// Pre-track action callback
+void DigiLockedAction::execute(DigiContext& context)  const   {
+  if (m_action) {
+    m_action->execute(context);
+    return;
+  }
+  fatal("DigiLockedAction: Attempt to use invalid actor! "
+        "Did you call DigiLockedAction::use?");
+}
diff --git a/DDDigi/src/DigiSynchronize.cpp b/DDDigi/src/DigiSynchronize.cpp
new file mode 100644
index 000000000..23ff00f05
--- /dev/null
+++ b/DDDigi/src/DigiSynchronize.cpp
@@ -0,0 +1,71 @@
+//==========================================================================
+//  AIDA Detector description implementation 
+//--------------------------------------------------------------------------
+// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
+// All rights reserved.
+//
+// For the licensing terms see $DD4hepINSTALL/LICENSE.
+// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
+//
+// Author     : M.Frank
+//
+//==========================================================================
+
+// Framework include files
+#include "DD4hep/InstanceCount.h"
+#include "DDDigi/DigiKernel.h"
+#include "DDDigi/DigiContext.h"
+#include "DDDigi/DigiSynchronize.h"
+
+// C/C++ include files
+#include <stdexcept>
+
+using namespace std;
+using namespace dd4hep::digi;
+
+/// Standard constructor
+DigiSynchronize::DigiSynchronize(const DigiKernel& kernel, const string& nam)
+  : DigiAction(kernel, nam)
+{
+  InstanceCount::increment(this);
+}
+
+/// Default destructor
+DigiSynchronize::~DigiSynchronize() {
+  m_actors(&DigiAction::release);
+  m_actors.clear();
+  InstanceCount::decrement(this);
+}
+
+/// Get an action sequence member by name
+DigiAction* DigiSynchronize::get(const string& nam) const   {
+  return m_actors.get(FindByName(TypeName::split(nam).second));
+}
+
+/// Pre-track action callback
+void DigiSynchronize::execute(DigiContext& context)  const   {
+  auto start = chrono::high_resolution_clock::now();
+  if ( m_parallel )
+    m_kernel.submit(m_actors, context);
+  else
+    m_kernel.execute(m_actors, context);
+  chrono::duration<double> secs = chrono::high_resolution_clock::now() - start;
+  debug("+++ Event: %8d (DigiSynchronize) Parallel: %-4s  %3ld actions [%8.3g sec]",
+        context.event().eventNumber, yes_no(m_parallel), m_actors.size(),
+        secs.count());
+}
+
+/// Add an actor responding to all callbacks. Sequence takes ownership.
+void DigiSynchronize::adopt(DigiAction* action) {
+  if (action)    {
+    action->addRef();
+    m_actors.add(action);
+    return;
+  }
+  except("DigiSynchronize","++ Attempt to add invalid actor!");
+}
+
+/// Add an actor responding to all callbacks. Sequence takes ownership.
+void DigiSynchronize::analyze() {
+  info("+++ Analyzing the algorithm sequence. Parallel: %s",yes_no(m_parallel));
+}
diff --git a/DDDigi/test_task_queue.cpp b/DDDigi/test_task_queue.cpp
new file mode 100644
index 000000000..345f1ebfb
--- /dev/null
+++ b/DDDigi/test_task_queue.cpp
@@ -0,0 +1,41 @@
+//==========================================================================
+//  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
+//
+//==========================================================================
+#include "tbb/tbb.h"
+#include <iostream>
+using namespace tbb;
+using namespace std;
+
+class say_hello {
+  int cnt = 0;
+  const char* message;
+public:
+  
+  say_hello(const char* str, int i) : message(str), cnt(i) {  }
+  void operator( ) ( ) const { 
+    cout << message << " " << cnt << endl;
+  }
+};
+
+int main( )
+{
+  task_scheduler_init init(2);
+  task_group tg1, tg2, tg3;
+  for(int i=0; i<200; ++i)  {
+    tg1.run(std::move(say_hello("child(1)",i)));
+    tg2.run(std::move(say_hello("child(2)",i)));
+    tg3.run(std::move(say_hello("child(3)",i)));
+  }
+  tg1.wait( ); // wait for tasks to complete
+  tg2.wait( ); // wait for tasks to complete
+  tg3.wait( ); // wait for tasks to complete
+}
diff --git a/DDEve/src/HitActors.cpp b/DDEve/src/HitActors.cpp
index f5b4b551b..646cd1b83 100644
--- a/DDEve/src/HitActors.cpp
+++ b/DDEve/src/HitActors.cpp
@@ -14,6 +14,7 @@
 // Framework include files
 #include "DDEve/HitActors.h"
 #include "DD4hep/Objects.h"
+#include "DD4hep/DD4hepUnits.h"
 
 // ROOT include files
 #include "TH2.h"
@@ -25,6 +26,11 @@
 using namespace std;
 using namespace dd4hep;
 
+#ifdef HAVE_GEANT4_UNITS
+#define MM_2_CM 1.0
+#else
+#define MM_2_CM 0.1
+#endif
 
 /// Action callback of this functor: 
 void EtaPhiHistogramActor::operator()(const DDEveHit& hit)   {
diff --git a/DDEve/src/ParticleActors.cpp b/DDEve/src/ParticleActors.cpp
index beb752b18..cd9b63176 100644
--- a/DDEve/src/ParticleActors.cpp
+++ b/DDEve/src/ParticleActors.cpp
@@ -14,6 +14,7 @@
 // Framework include files
 #include "DDEve/ParticleActors.h"
 #include "DD4hep/Objects.h"
+#include "DD4hep/DD4hepUnits.h"
 
 #include "TEveCompound.h"
 #include "TEveTrack.h"
@@ -26,9 +27,19 @@
 using namespace std;
 using namespace dd4hep;
 
-static Color_t Colors[] = {
-  kRed, kBlue, kYellow, kGreen, kPink, kAzure, kOrange, kTeal, kViolet, kSpring, kMagenta, kCyan
-};
+#ifdef HAVE_GEANT4_UNITS
+#define CM_2_MM 1.0
+#define MM_2_CM 1.0
+#else
+#define CM_2_MM 10.0
+#define MM_2_CM 0.1
+#endif
+
+namespace {
+  Color_t Colors[] = {
+    kRed, kBlue, kYellow, kGreen, kPink, kAzure, kOrange, kTeal, kViolet, kSpring, kMagenta, kCyan
+  };
+}
 
 /// Standard initializing constructor
 MCParticleCreator::MCParticleCreator(TEveTrackPropagator* p, TEveCompound* ps, const DisplayConfiguration::Config* cfg) 
diff --git a/DDG4/src/Geant4Converter.cpp b/DDG4/src/Geant4Converter.cpp
index 533587406..9de626bec 100644
--- a/DDG4/src/Geant4Converter.cpp
+++ b/DDG4/src/Geant4Converter.cpp
@@ -116,6 +116,8 @@ using namespace std;
 #include "G4VPhysicalVolume.hh"
 #include "G4ReflectionFactory.hh"
 
+static constexpr double CM_2_MM = (CLHEP::centimeter/dd4hep::centimeter);
+
 void Geant4AssemblyVolume::imprint(Geant4GeometryInfo& info,
                                    const TGeoNode*   parent,
                                    Chain chain,
diff --git a/DDG4/src/Geant4SensDetAction.cpp b/DDG4/src/Geant4SensDetAction.cpp
index a2fb4b546..401489015 100644
--- a/DDG4/src/Geant4SensDetAction.cpp
+++ b/DDG4/src/Geant4SensDetAction.cpp
@@ -30,6 +30,12 @@
 // C/C++ include files
 #include <stdexcept>
 
+#ifdef HAVE_GEANT4_UNITS
+#define MM_2_CM 1.0
+#else
+#define MM_2_CM 0.1
+#endif
+
 using namespace std;
 using namespace dd4hep;
 using namespace dd4hep::sim;
diff --git a/DDG4/src/Geant4SensitiveDetector.cpp b/DDG4/src/Geant4SensitiveDetector.cpp
index 2b0ecfbe0..f717d7ccf 100644
--- a/DDG4/src/Geant4SensitiveDetector.cpp
+++ b/DDG4/src/Geant4SensitiveDetector.cpp
@@ -16,6 +16,7 @@
 #include "DDG4/Geant4Converter.h"
 #include "DDG4/Geant4Hits.h"
 #include "DD4hep/Segmentations.h"
+
 #include "DD4hep/Printout.h"
 #include "DD4hep/Detector.h"
 
@@ -26,6 +27,11 @@
 // ROOT include files
 #include "TGeoNode.h"
 
+#include "DD4hep/DD4hepUnits.h"
+#include "CLHEP/Units/SystemOfUnits.h"
+
+static constexpr double MM_2_CM = (CLHEP::millimeter/dd4hep::millimeter);
+
 #define DEBUG 0
 
 // C/C++ include files
diff --git a/DDG4/src/Geant4StepHandler.cpp b/DDG4/src/Geant4StepHandler.cpp
index 3e8ed40af..79cff318c 100644
--- a/DDG4/src/Geant4StepHandler.cpp
+++ b/DDG4/src/Geant4StepHandler.cpp
@@ -15,6 +15,10 @@
 #include "DDG4/Geant4StepHandler.h"
 #include "DDSegmentation/Segmentation.h"
 #include "DD4hep/DD4hepUnits.h"
+#include "CLHEP/Units/SystemOfUnits.h"
+
+static constexpr double MM_2_CM = (CLHEP::millimeter/dd4hep::millimeter);
+
 namespace units = dd4hep;
 using namespace dd4hep;
 using namespace dd4hep::sim;
diff --git a/DDParsers/include/Evaluator/DD4hepUnits.h b/DDParsers/include/Evaluator/DD4hepUnits.h
index f744148ec..b64e6f48b 100644
--- a/DDParsers/include/Evaluator/DD4hepUnits.h
+++ b/DDParsers/include/Evaluator/DD4hepUnits.h
@@ -29,6 +29,10 @@
 
 #include "RVersion.h"
 
+#ifndef HAVE_GEANT4_UNITS
+// #define HAVE_GEANT4_UNITS
+#endif
+
 // We use the ROOT system units if they are avalible (FAILS SOME TESTS FOR NOW)
 #if 0
 /// ROOT_VERSION_CODE >= ROOT_VERSION(6,12,0)
@@ -46,245 +50,257 @@ namespace dd4hep {
     //
     // Length [L]
     //
-    static const double millimeter = 0.1;
-    static const double millimeter2 = millimeter * millimeter;
-    static const double millimeter3 = millimeter * millimeter * millimeter;
+#ifdef HAVE_GEANT4_UNITS
+    static constexpr double millimeter = 1.0;
+#else
+    static constexpr double millimeter = 0.1;
+#endif
+    static constexpr double millimeter2 = millimeter * millimeter;
+    static constexpr double millimeter3 = millimeter * millimeter * millimeter;
 
-    static const double centimeter = 10. * millimeter;
-    static const double centimeter2 = centimeter * centimeter;
-    static const double centimeter3 = centimeter * centimeter * centimeter;
+    static constexpr double centimeter = 10. * millimeter;
+    static constexpr double centimeter2 = centimeter * centimeter;
+    static constexpr double centimeter3 = centimeter * centimeter * centimeter;
 
-    static const double meter = 1000. * millimeter;
-    static const double meter2 = meter * meter;
-    static const double meter3 = meter * meter * meter;
+    static constexpr double meter = 1000. * millimeter;
+    static constexpr double meter2 = meter * meter;
+    static constexpr double meter3 = meter * meter * meter;
 
-    static const double kilometer = 1000. * meter;
-    static const double kilometer2 = kilometer * kilometer;
-    static const double kilometer3 = kilometer * kilometer * kilometer;
+    static constexpr double kilometer = 1000. * meter;
+    static constexpr double kilometer2 = kilometer * kilometer;
+    static constexpr double kilometer3 = kilometer * kilometer * kilometer;
 
-    static const double parsec = 3.0856775807e+16 * meter;
+    static constexpr double parsec = 3.0856775807e+16 * meter;
 
-    static const double micrometer = 1.e-6 * meter;
-    static const double nanometer = 1.e-9 * meter;
-    static const double angstrom = 1.e-10 * meter;
-    static const double fermi = 1.e-15 * meter;
+    static constexpr double micrometer = 1.e-6 * meter;
+    static constexpr double nanometer = 1.e-9 * meter;
+    static constexpr double angstrom = 1.e-10 * meter;
+    static constexpr double fermi = 1.e-15 * meter;
 
-    static const double barn = 1.e-28 * meter2;
-    static const double millibarn = 1.e-3 * barn;
-    static const double microbarn = 1.e-6 * barn;
-    static const double nanobarn = 1.e-9 * barn;
-    static const double picobarn = 1.e-12 * barn;
+    static constexpr double barn = 1.e-28 * meter2;
+    static constexpr double millibarn = 1.e-3 * barn;
+    static constexpr double microbarn = 1.e-6 * barn;
+    static constexpr double nanobarn = 1.e-9 * barn;
+    static constexpr double picobarn = 1.e-12 * barn;
 
     // symbols
-    static const double nm = nanometer;
-    static const double um = micrometer;
+    static constexpr double nm = nanometer;
+    static constexpr double um = micrometer;
 
-    static const double mm = millimeter;
-    static const double mm2 = millimeter2;
-    static const double mm3 = millimeter3;
+    static constexpr double mm = millimeter;
+    static constexpr double mm2 = millimeter2;
+    static constexpr double mm3 = millimeter3;
 
-    static const double cm = centimeter;
-    static const double cm2 = centimeter2;
-    static const double cm3 = centimeter3;
+    static constexpr double cm = centimeter;
+    static constexpr double cm2 = centimeter2;
+    static constexpr double cm3 = centimeter3;
 
-    static const double m = meter;
-    static const double m2 = meter2;
-    static const double m3 = meter3;
+    static constexpr double m = meter;
+    static constexpr double m2 = meter2;
+    static constexpr double m3 = meter3;
 
-    static const double km = kilometer;
-    static const double km2 = kilometer2;
-    static const double km3 = kilometer3;
+    static constexpr double km = kilometer;
+    static constexpr double km2 = kilometer2;
+    static constexpr double km3 = kilometer3;
 
-    static const double pc = parsec;
+    static constexpr double pc = parsec;
 
     //
     // Angle
     //
-    // static const double radian = 180. / 3.14159265358979323846;   // => degree=1
-    // static const double milliradian = 1.e-3 * radian;
-    // static const double degree = 1.;   //= (3.14159265358979323846/180.0)*radian;
+    // static constexpr double radian = 180. / 3.14159265358979323846;   // => degree=1
+    // static constexpr double milliradian = 1.e-3 * radian;
+    // static constexpr double degree = 1.;   //= (3.14159265358979323846/180.0)*radian;
 
     //fg: use radians as default unit as this is needed for all math functions
     //    and everywhere else, except in TGeo shapes -> this is taken care of in shape Handles ....
-    static const double radian = 1. ;
-    static const double milliradian = 1.e-3 * radian;
-    static const double degree = (3.14159265358979323846/180.0)*radian;
+    static constexpr double radian = 1. ;
+    static constexpr double milliradian = 1.e-3 * radian;
+    static constexpr double degree = (3.14159265358979323846/180.0)*radian;
 
-    static const double steradian = 1.;
+    static constexpr double steradian = 1.;
 
     // symbols
-    static const double rad = radian;
-    static const double mrad = milliradian;
-    static const double sr = steradian;
-    static const double deg = degree;
+    static constexpr double rad = radian;
+    static constexpr double mrad = milliradian;
+    static constexpr double sr = steradian;
+    static constexpr double deg = degree;
 
     //
     // Time [T]
     //
-    static const double nanosecond = 1.e-9;
-    static const double second = 1.e+9 * nanosecond;
-    static const double millisecond = 1.e-3 * second;
-    static const double microsecond = 1.e-6 * second;
-    static const double picosecond = 1.e-12 * second;
+#ifdef HAVE_GEANT4_UNITS
+    static constexpr double nanosecond = 1.0;
+#else
+    static constexpr double nanosecond = 1.e-9;
+#endif
+    static constexpr double second = 1.e+9 * nanosecond;
+    static constexpr double millisecond = 1.e-3 * second;
+    static constexpr double microsecond = 1.e-6 * second;
+    static constexpr double picosecond = 1.e-12 * second;
 
-    static const double hertz = 1. / second;
-    static const double kilohertz = 1.e+3 * hertz;
-    static const double megahertz = 1.e+6 * hertz;
+    static constexpr double hertz = 1. / second;
+    static constexpr double kilohertz = 1.e+3 * hertz;
+    static constexpr double megahertz = 1.e+6 * hertz;
 
     // symbols
-    static const double ns = nanosecond;
-    static const double s = second;
-    static const double ms = millisecond;
+    static constexpr double ns = nanosecond;
+    static constexpr double s = second;
+    static constexpr double ms = millisecond;
 
     //
     // Electric charge [Q]
     //
-    static const double eplus = 1.;   // positron charge
-    static const double e_SI = 1.602176487e-19;   // positron charge in coulomb
-    static const double coulomb = eplus / e_SI;   // coulomb = 6.24150 e+18 * eplus
+    static constexpr double eplus = 1.;   // positron charge
+    static constexpr double e_SI = 1.602176487e-19;   // positron charge in coulomb
+    static constexpr double coulomb = eplus / e_SI;   // coulomb = 6.24150 e+18 * eplus
 
     //
     // Energy [E]
     //
-    static const double megaelectronvolt = 1.e-3;
-    static const double electronvolt = 1.e-6 * megaelectronvolt;
-    static const double kiloelectronvolt = 1.e-3 * megaelectronvolt;
-    static const double gigaelectronvolt = 1.e+3 * megaelectronvolt;
-    static const double teraelectronvolt = 1.e+6 * megaelectronvolt;
-    static const double petaelectronvolt = 1.e+9 * megaelectronvolt;
+#ifdef HAVE_GEANT4_UNITS
+    static constexpr double megaelectronvolt = 1.0;
+#else
+    static constexpr double megaelectronvolt = 1.e-3;
+#endif
+    static constexpr double electronvolt = 1.e-6 * megaelectronvolt;
+    static constexpr double kiloelectronvolt = 1.e-3 * megaelectronvolt;
+    static constexpr double gigaelectronvolt = 1.e+3 * megaelectronvolt;
+    static constexpr double teraelectronvolt = 1.e+6 * megaelectronvolt;
+    static constexpr double petaelectronvolt = 1.e+9 * megaelectronvolt;
 
-    static const double joule = electronvolt / e_SI;   // joule = 6.24150 e+12 * MeV
+    static constexpr double joule = electronvolt / e_SI;   // joule = 6.24150 e+12 * MeV
 
     // symbols
-    static const double MeV = megaelectronvolt;
-    static const double eV = electronvolt;
-    static const double keV = kiloelectronvolt;
-    static const double GeV = gigaelectronvolt;
-    static const double TeV = teraelectronvolt;
-    static const double PeV = petaelectronvolt;
+    static constexpr double MeV = megaelectronvolt;
+    static constexpr double eV = electronvolt;
+    static constexpr double keV = kiloelectronvolt;
+    static constexpr double GeV = gigaelectronvolt;
+    static constexpr double TeV = teraelectronvolt;
+    static constexpr double PeV = petaelectronvolt;
 
     //
     // Mass [E][T^2][L^-2]
     //
-    static const double kilogram = joule * second * second / (meter * meter);
-    static const double gram = 1.e-3 * kilogram;
-    static const double milligram = 1.e-3 * gram;
+    static constexpr double kilogram = joule * second * second / (meter * meter);
+    static constexpr double gram = 1.e-3 * kilogram;
+    static constexpr double milligram = 1.e-3 * gram;
 
     // symbols
-    static const double kg = kilogram;
-    static const double g = gram;
-    static const double mg = milligram;
+    static constexpr double kg = kilogram;
+    static constexpr double g = gram;
+    static constexpr double mg = milligram;
 
     //
     // Power [E][T^-1]
     //
-    static const double watt = joule / second;   // watt = 6.24150 e+3 * MeV/ns
+    static constexpr double watt = joule / second;   // watt = 6.24150 e+3 * MeV/ns
 
     //
     // Force [E][L^-1]
     //
-    static const double newton = joule / meter;   // newton = 6.24150 e+9 * MeV/mm
+    static constexpr double newton = joule / meter;   // newton = 6.24150 e+9 * MeV/mm
 
     //
     // Pressure [E][L^-3]
     //
 #define pascal hep_pascal                          // a trick to avoid warnings
-    static const double hep_pascal = newton / m2;   // pascal = 6.24150 e+3 * MeV/mm3
-    static const double bar = 100000 * pascal;   // bar    = 6.24150 e+8 * MeV/mm3
-    static const double atmosphere = 101325 * pascal;   // atm    = 6.32420 e+8 * MeV/mm3
+    static constexpr double hep_pascal = newton / m2;   // pascal = 6.24150 e+3 * MeV/mm3
+    static constexpr double bar = 100000 * pascal;   // bar    = 6.24150 e+8 * MeV/mm3
+    static constexpr double atmosphere = 101325 * pascal;   // atm    = 6.32420 e+8 * MeV/mm3
 
     //
     // Electric current [Q][T^-1]
     //
-    static const double ampere = coulomb / second;   // ampere = 6.24150 e+9 * eplus/ns
-    static const double milliampere = 1.e-3 * ampere;
-    static const double microampere = 1.e-6 * ampere;
-    static const double nanoampere = 1.e-9 * ampere;
+    static constexpr double ampere = coulomb / second;   // ampere = 6.24150 e+9 * eplus/ns
+    static constexpr double milliampere = 1.e-3 * ampere;
+    static constexpr double microampere = 1.e-6 * ampere;
+    static constexpr double nanoampere = 1.e-9 * ampere;
 
     //
     // Electric potential [E][Q^-1]
     //
-    static const double megavolt = megaelectronvolt / eplus;
-    static const double kilovolt = 1.e-3 * megavolt;
-    static const double volt = 1.e-6 * megavolt;
+    static constexpr double megavolt = megaelectronvolt / eplus;
+    static constexpr double kilovolt = 1.e-3 * megavolt;
+    static constexpr double volt = 1.e-6 * megavolt;
 
     //
     // Electric resistance [E][T][Q^-2]
     //
-    static const double ohm = volt / ampere;   // ohm = 1.60217e-16*(MeV/eplus)/(eplus/ns)
+    static constexpr double ohm = volt / ampere;   // ohm = 1.60217e-16*(MeV/eplus)/(eplus/ns)
 
     //
     // Electric capacitance [Q^2][E^-1]
     //
-    static const double farad = coulomb / volt;   // farad = 6.24150e+24 * eplus/Megavolt
-    static const double millifarad = 1.e-3 * farad;
-    static const double microfarad = 1.e-6 * farad;
-    static const double nanofarad = 1.e-9 * farad;
-    static const double picofarad = 1.e-12 * farad;
+    static constexpr double farad = coulomb / volt;   // farad = 6.24150e+24 * eplus/Megavolt
+    static constexpr double millifarad = 1.e-3 * farad;
+    static constexpr double microfarad = 1.e-6 * farad;
+    static constexpr double nanofarad = 1.e-9 * farad;
+    static constexpr double picofarad = 1.e-12 * farad;
 
     //
     // Magnetic Flux [T][E][Q^-1]
     //
-    static const double weber = volt * second;   // weber = 1000*megavolt*ns
+    static constexpr double weber = volt * second;   // weber = 1000*megavolt*ns
 
     //
     // Magnetic Field [T][E][Q^-1][L^-2]
     //
-    static const double tesla = volt * second / meter2;   // tesla =0.001*megavolt*ns/mm2
+    static constexpr double tesla = volt * second / meter2;   // tesla =0.001*megavolt*ns/mm2
 
-    static const double gauss = 1.e-4 * tesla;
-    static const double kilogauss = 1.e-1 * tesla;
+    static constexpr double gauss = 1.e-4 * tesla;
+    static constexpr double kilogauss = 1.e-1 * tesla;
 
     //
     // Inductance [T^2][E][Q^-2]
     //
-    static const double henry = weber / ampere;   // henry = 1.60217e-7*MeV*(ns/eplus)**2
+    static constexpr double henry = weber / ampere;   // henry = 1.60217e-7*MeV*(ns/eplus)**2
 
     //
     // Temperature
     //
-    static const double kelvin = 1.;
+    static constexpr double kelvin = 1.;
 
     //
     // Amount of substance
     //
-    static const double mole = 1.;
+    static constexpr double mole = 1.;
 
     //
     // Activity [T^-1]
     //
-    static const double becquerel = 1. / second;
-    static const double curie = 3.7e+10 * becquerel;
+    static constexpr double becquerel = 1. / second;
+    static constexpr double curie = 3.7e+10 * becquerel;
 
     //
     // Absorbed dose [L^2][T^-2]
     //
-    static const double gray = joule / kilogram;
-    static const double kilogray = 1.e+3 * gray;
-    static const double milligray = 1.e-3 * gray;
-    static const double microgray = 1.e-6 * gray;
+    static constexpr double gray = joule / kilogram;
+    static constexpr double kilogray = 1.e+3 * gray;
+    static constexpr double milligray = 1.e-3 * gray;
+    static constexpr double microgray = 1.e-6 * gray;
 
     //
     // Luminous intensity [I]
     //
-    static const double candela = 1.;
+    static constexpr double candela = 1.;
 
     //
     // Luminous flux [I]
     //
-    static const double lumen = candela * steradian;
+    static constexpr double lumen = candela * steradian;
 
     //
     // Illuminance [I][L^-2]
     //
-    static const double lux = lumen / meter2;
+    static constexpr double lux = lumen / meter2;
 
     //
     // Miscellaneous
     //
-    static const double perCent = 0.01;
-    static const double perThousand = 0.001;
-    static const double perMillion = 0.000001;
+    static constexpr double perCent = 0.01;
+    static constexpr double perThousand = 0.001;
+    static constexpr double perMillion = 0.000001;
 
     // -*- C++ -*-
     // ----------------------------------------------------------------------
@@ -323,85 +339,85 @@ namespace dd4hep {
     // 29.04.08   use PDG 2006 values
     // 03.11.08   use PDG 2008 values
 
-    static const double pi = 3.14159265358979323846;
-    static const double twopi = 2 * pi;
-    static const double halfpi = pi / 2;
-    static const double pi2 = pi * pi;
+    static constexpr double pi = 3.14159265358979323846;
+    static constexpr double twopi = 2 * pi;
+    static constexpr double halfpi = pi / 2;
+    static constexpr double pi2 = pi * pi;
 
     //
     //
     //
-    static const double Avogadro = 6.02214179e+23 / mole;
+    static constexpr double Avogadro = 6.02214179e+23 / mole;
 
     //
     // c   = 299.792458 mm/ns
     // c^2 = 898.7404 (mm/ns)^2
     //
-    static const double c_light = 2.99792458e+8 * m / s;
-    static const double c_squared = c_light * c_light;
+    static constexpr double c_light = 2.99792458e+8 * m / s;
+    static constexpr double c_squared = c_light * c_light;
 
     //
     // h     = 4.13566e-12 MeV*ns
     // hbar  = 6.58212e-13 MeV*ns
     // hbarc = 197.32705e-12 MeV*mm
     //
-    static const double h_Planck = 6.62606896e-34 * joule * s;
-    static const double hbar_Planck = h_Planck / twopi;
-    static const double hbarc = hbar_Planck * c_light;
-    static const double hbarc_squared = hbarc * hbarc;
+    static constexpr double h_Planck = 6.62606896e-34 * joule * s;
+    static constexpr double hbar_Planck = h_Planck / twopi;
+    static constexpr double hbarc = hbar_Planck * c_light;
+    static constexpr double hbarc_squared = hbarc * hbarc;
 
     //
     //
     //
-    static const double electron_charge = -eplus;   // see SystemOfUnits.h
-    static const double e_squared = eplus * eplus;
+    static constexpr double electron_charge = -eplus;   // see SystemOfUnits.h
+    static constexpr double e_squared = eplus * eplus;
 
     //
     // amu_c2 - atomic equivalent mass unit
     //        - AKA, unified atomic mass unit (u)
     // amu    - atomic mass unit
     //
-    static const double electron_mass_c2 = 0.510998910 * MeV;
-    static const double proton_mass_c2 = 938.272013 * MeV;
-    static const double neutron_mass_c2 = 939.56536 * MeV;
-    static const double amu_c2 = 931.494028 * MeV;
-    static const double amu = amu_c2 / c_squared;
+    static constexpr double electron_mass_c2 = 0.510998910 * MeV;
+    static constexpr double proton_mass_c2 = 938.272013 * MeV;
+    static constexpr double neutron_mass_c2 = 939.56536 * MeV;
+    static constexpr double amu_c2 = 931.494028 * MeV;
+    static constexpr double amu = amu_c2 / c_squared;
 
     //
     // permeability of free space mu0    = 2.01334e-16 Mev*(ns*eplus)^2/mm
     // permittivity of free space epsil0 = 5.52636e+10 eplus^2/(MeV*mm)
     //
-    static const double mu0 = 4 * pi * 1.e-7 * henry / m;
-    static const double epsilon0 = 1. / (c_squared * mu0);
+    static constexpr double mu0 = 4 * pi * 1.e-7 * henry / m;
+    static constexpr double epsilon0 = 1. / (c_squared * mu0);
 
     //
     // electromagnetic coupling = 1.43996e-12 MeV*mm/(eplus^2)
     //
-    static const double elm_coupling = e_squared / (4 * pi * epsilon0);
-    static const double fine_structure_const = elm_coupling / hbarc;
-    static const double classic_electr_radius = elm_coupling / electron_mass_c2;
-    static const double electron_Compton_length = hbarc / electron_mass_c2;
-    static const double Bohr_radius = electron_Compton_length / fine_structure_const;
+    static constexpr double elm_coupling = e_squared / (4 * pi * epsilon0);
+    static constexpr double fine_structure_const = elm_coupling / hbarc;
+    static constexpr double classic_electr_radius = elm_coupling / electron_mass_c2;
+    static constexpr double electron_Compton_length = hbarc / electron_mass_c2;
+    static constexpr double Bohr_radius = electron_Compton_length / fine_structure_const;
 
-    static const double alpha_rcl2 = fine_structure_const * classic_electr_radius * classic_electr_radius;
+    static constexpr double alpha_rcl2 = fine_structure_const * classic_electr_radius * classic_electr_radius;
 
-    static const double twopi_mc2_rcl2 = twopi * electron_mass_c2 * classic_electr_radius * classic_electr_radius;
+    static constexpr double twopi_mc2_rcl2 = twopi * electron_mass_c2 * classic_electr_radius * classic_electr_radius;
     //
     //
     //
-    static const double k_Boltzmann = 8.617343e-11 * MeV / kelvin;
+    static constexpr double k_Boltzmann = 8.617343e-11 * MeV / kelvin;
 
     //
     //
     //
-    static const double STP_Temperature = 273.15 * kelvin;
-    static const double STP_Pressure = 1. * atmosphere;
-    static const double kGasThreshold = 10. * mg / cm3;
+    static constexpr double STP_Temperature = 273.15 * kelvin;
+    static constexpr double STP_Pressure = 1. * atmosphere;
+    static constexpr double kGasThreshold = 10. * mg / cm3;
 
     //
     //
     //
-    static const double universe_mean_density = 1.e-25 * g / cm3;
+    static constexpr double universe_mean_density = 1.e-25 * g / cm3;
   //}
 }
 #endif
diff --git a/DDParsers/src/Evaluator/setSystemOfUnits.cpp b/DDParsers/src/Evaluator/setSystemOfUnits.cpp
index 487849da3..57820eb76 100644
--- a/DDParsers/src/Evaluator/setSystemOfUnits.cpp
+++ b/DDParsers/src/Evaluator/setSystemOfUnits.cpp
@@ -29,6 +29,7 @@ namespace dd4hep  {
       const double micro_ = 1.e-06; // micro (Latin) or mikros (Greek) "small"
       const double nano_  = 1.e-09; // nanus (Latin) or nanos  (Greek) "dwarf"
       const double pico_  = 1.e-12; // pico (Spanish) "bit"
+      const double femto_ = 1.e-15; // femto
 
       // ======================================================================
       //
@@ -260,13 +261,17 @@ namespace dd4hep  {
 
       setVariable("micrometer", micro_ * m);
       setVariable("micron",     micro_ * m);
+      setVariable("mum",        micro_ * m);
       setVariable("nanometer",  nano_  * m);
+      setVariable("nm",         nano_  * m);
 
       // ---  honors Anders Jonas Angstrom (1814-1874) of Sweden
       setVariable("angstrom",   1.e-10 * m);
 
       // ---  honors Enrico Fermi (1901-1954) of Italy
       setVariable("fermi",      1.e-15 * m);
+      setVariable("femtometer", femto_ * m);
+      setVariable("fm",         femto_ * m);
 
       // Length^2
 
diff --git a/examples/ClientTests/src/MaterialTester_geo.cpp b/examples/ClientTests/src/MaterialTester_geo.cpp
index 67b210cd1..2e29cff97 100644
--- a/examples/ClientTests/src/MaterialTester_geo.cpp
+++ b/examples/ClientTests/src/MaterialTester_geo.cpp
@@ -11,13 +11,19 @@
 //
 //==========================================================================
 
+
 // Framework include files
 #include "DD4hep/DetFactoryHelper.h"
+#include "DD4hep/DD4hepUnits.h"
 #include "DD4hep/Printout.h"
 
 // ROOT include file
 #include "TGeoElement.h"
+#include "TGeoPhysicalConstants.h"
+#include "TGeant4PhysicalConstants.h"
+#include "TMath.h"
 
+namespace units = dd4hep;
 using namespace std;
 using namespace dd4hep;
 using namespace dd4hep::detail;
@@ -33,10 +39,12 @@ static Ref_t create_element(Detector& description, xml_h xml_det, SensitiveDetec
     Material mat = description.material(c.nameStr());
     TGeoMaterial* material = mat->GetMaterial();
     printout(INFO,det_name,"+++ Material:%s [%p, %p] Z=%6.2f A=%6.2f D=%9.4f [g/cm3]",
-             material->GetName(), mat.ptr(), m, material->GetZ(),
+             material->GetName(), mat.ptr(), material, material->GetZ(),
              material->GetA(), material->GetDensity());
-    printout(INFO,det_name,"+++          Radiation Length:%9.4f Interaction length:%9.4f Mixture:%s",
-             material->GetRadLen(), material->GetIntLen(),
+    
+    printout(INFO,det_name,"+++          Radiation Length:%9.4f [cm] Interaction length:%9.4f [cm] Mixture:%s",
+             material->GetRadLen()/TGeant4Unit::mm*units::cm, material->GetIntLen()/TGeant4Unit::mm*units::cm,
+             //material->GetRadLen(), material->GetIntLen(),
              yes_no(material->IsMixture()));
     printout(INFO,det_name,"+++          Elements:%d Index:%d",
              material->GetNelements(), material->GetIndex());
@@ -57,7 +65,30 @@ static Ref_t create_element(Detector& description, xml_h xml_det, SensitiveDetec
     }
   }
 
-
+  printout(INFO,det_name,"+++ Basic units:");
+  printout(INFO,det_name,"+++ Length: mm:         %12.3f  Geant4: %8.3f mm    dd4hep: %8.3f mm    TGeo: %8.3g",
+           units::mm, units::mm/TGeant4Unit::mm, units::mm/units::mm, units::mm/TGeoUnit::mm);
+  printout(INFO,det_name,"+++ Time:   s:          %12.0g  Geant4: %8.3f s     dd4hep: %8.3f s     TGeo: %8.3g",
+           units::s , units::s /TGeant4Unit::s , units::s /units::s,  units::s /TGeoUnit::s );
+  printout(INFO,det_name,"+++ Energy: eV:         %12.3g  Geant4: %8.3f eV    dd4hep: %8.3f eV    TGeo: %8.3g",
+           units::eV, units::eV/TGeant4Unit::eV, units::eV/units::eV, units::eV/TGeoUnit::eV);
+  printout(INFO,det_name,"+++ Energy: MeV:        %12.3f  Geant4: %8.3f MeV   dd4hep: %8.3f MeV   TGeo: %8.3g",
+           units::MeV, units::MeV/TGeant4Unit::MeV, units::MeV /units::MeV, units::MeV /TGeoUnit::MeV);
+  printout(INFO,det_name,"+++ 1./Fine structure:  %12.3f  Geant4: %8.3f       dd4hep: %8.3f       TGeo: %8.3f",
+           1./units::fine_structure_const, 1./TGeant4Unit::fine_structure_const,
+           1./units::fine_structure_const, 1./TGeoUnit::fine_structure_const);
+  printout(INFO,det_name,"+++ Universe density:   %12.3g  Geant4: %8.3g g/cm3 dd4hep: %8.3g g/cm3 TGeo: %8.3g",
+           units::universe_mean_density,
+           units::universe_mean_density/TGeant4Unit::g*TGeant4Unit::cm3,
+           units::universe_mean_density/units::g*units::cm3,
+           units::universe_mean_density/TGeoUnit::g*TGeoUnit::cm3);
+  printout(INFO,det_name,"+++ STP_temperature:    %12.3f  Geant4: %8.3f K     dd4hep: %8.3f K     TGeo: %8.3f K",
+           STP_temperature, STP_temperature/TGeant4Unit::kelvin,
+           STP_temperature/units::kelvin, STP_temperature/TGeoUnit::kelvin);
+  printout(INFO,det_name,"+++ STP_pressure:       %12.0f  Geant4: %8.3f hPa   dd4hep: %8.3f hPa   TGeo: %8.3f hPa",
+           STP_pressure, STP_pressure/TGeant4Unit::pascal/1e2,
+           STP_pressure/units::pascal/1e2,STP_pressure/TGeoUnit::pascal/1e2);
+  
   PlacedVolume pv = description.pickMotherVolume(det).placeVolume(assembly);
   pv.addPhysVolID("system",x_det.id());
   det.setPlacement(pv);
-- 
GitLab