diff --git a/DDCore/include/DD4hep/Factories.h b/DDCore/include/DD4hep/Factories.h
index 7be5a22c5b8372983cb178c16cd6ae0b6c8b4333..069fd2c0363d401587425a0904abefef723524a0 100644
--- a/DDCore/include/DD4hep/Factories.h
+++ b/DDCore/include/DD4hep/Factories.h
@@ -54,6 +54,10 @@ namespace dd4hep {
    *  \date    2012/07/31
    *  \ingroup DD4HEP_CORE
    */
+  template <typename T> class SimpleConstructionFactory {
+  public:
+    static void* create();
+  };
   template <typename T> class ConstructionFactory {
   public:
     static void* create(const char* arg);
@@ -206,6 +210,9 @@ namespace {
     typedef dd4hep::DDSegmentation::BitFieldCoder   BitFieldCoder;
   }
 
+  DD4HEP_PLUGIN_FACTORY_ARGS_0(void*)  
+  {    return dd4hep::SimpleConstructionFactory<P>::create();                           }
+
   DD4HEP_PLUGIN_FACTORY_ARGS_1(void*,const char*)  
   {    return dd4hep::ConstructionFactory<P>::create(a0);                               }
 
@@ -265,6 +272,11 @@ namespace {
     DD4HEP_PLUGINSVC_FACTORY(name,segmentation_constructor__##name,     \
                              SegmentationObject*(const DDSegmentation::BitFieldCoder*),__LINE__)}
 
+// Call function of the type [void* (*func)()]
+#define DECLARE_CREATE(name,func)        DD4HEP_OPEN_PLUGIN(dd4hep,name)   { \
+    template <> void* SimpleConstructionFactory<name>::create() { return func(); } \
+    DD4HEP_PLUGINSVC_FACTORY(name,name,void*(),__LINE__)}
+
 // Call function of the type [long (*func)(const char* arg)]
 #define DECLARE_APPLY(name,func)        DD4HEP_OPEN_PLUGIN(dd4hep,name)   { \
     template <> long ApplyFactory<name>::create(dd4hep::Detector& l,int n,char** a) {return func(l,n,a);} \
diff --git a/DDCore/include/Parsers/Primitives.h b/DDCore/include/Parsers/Primitives.h
index 3494b4e0d05ded2fa7901b905506d35a6271ab6a..20afb2b27b169093466400cb6ad41c91efeb541a 100644
--- a/DDCore/include/Parsers/Primitives.h
+++ b/DDCore/include/Parsers/Primitives.h
@@ -143,6 +143,17 @@ namespace dd4hep {
       return reverse_num; 
     }
 
+    /// C++ version to convert a string to lower case
+    std::string str_lower(const std::string& str);
+    /// C++ version to convert a string to upper case
+    std::string str_upper(const std::string& str);
+    /// Replace all occurrencies of a string
+    std::string str_replace(const std::string& source, const std::string& pattern, const std::string& replacement);
+    /// Replace all occurrencies of a string
+    std::string str_replace(const std::string& source, char pattern, const std::string& replacement);
+    /// Replace all occurrencies of a string
+    std::string str_replace(const std::string& source, char pattern, char replacement);
+
     /// Convert date into epoch time (seconds since 1970)
     long int makeTime(int year, int month, int day,
                       int hour=0, int minutes=0, int seconds=0);
diff --git a/DDCore/python/dd4hep_base.py b/DDCore/python/dd4hep_base.py
index 9985f4e91390a8748282e7a1d46b8f4f59c7fe8f..d2d8aaa75375e4feb9f571f4897f380a309922d9 100644
--- a/DDCore/python/dd4hep_base.py
+++ b/DDCore/python/dd4hep_base.py
@@ -72,7 +72,6 @@ def import_namespace_item(ns, nam):
 def import_root(nam):
   setattr(name_space, nam, getattr(ROOT, nam))
 
-
 # ---------------------------------------------------------------------------
 #
 try:
@@ -97,6 +96,29 @@ class _Levels:
     self.FATAL = 6
     self.ALWAYS = 7
 
+# ---------------------------------------------------------------------------
+def unicode_2_string(value):
+  """Turn any unicode literal into str, needed when passing to c++.
+
+  Recursively transverses dicts, lists, sets, tuples
+
+  :return: always a str
+  """
+  import ddsix as six
+  if isinstance(value, (bool, float, six.integer_types)):
+    value = value
+  elif isinstance(value, six.string_types):
+    value = str(value)
+  elif isinstance(value, (list, set, tuple)):
+    value = [unicode_2_string(x) for x in value]
+  elif isinstance(value, dict):
+    tempDict = {}
+    for key, val in value.items():
+      key = unicode_2_string(key)
+      val = unicode_2_string(val)
+      tempDict[key] = val
+    value = tempDict
+  return str(value)
 
 OutputLevel = _Levels()
 # ------------------------Generic STL stuff can be accessed using std:  -----
@@ -125,21 +147,30 @@ import_namespace_item('core', 'run_interpreter')
 #
 import_namespace_item('detail', 'interp')
 import_namespace_item('detail', 'eval')
+
 # ---------------------------------------------------------------------------
 # def run_interpreter(name):   detail.interp.run(name)
 # def evaluator():     return eval.instance()
 # def g4Evaluator():   return eval.g4instance()
-# ---------------------------------------------------------------------------
-
 
+# ---------------------------------------------------------------------------
 def import_detail():
   import_namespace_item('detail', 'DD4hepUI')
 
-
+# ---------------------------------------------------------------------------
 def import_geometry():
   import_namespace_item('core', 'setPrintLevel')
   import_namespace_item('core', 'setPrintFormat')
   import_namespace_item('core', 'printLevel')
+  import_namespace_item('core', 'PrintLevel')
+
+  import_namespace_item('core', 'debug')
+  import_namespace_item('core', 'info')
+  import_namespace_item('core', 'warning')
+  import_namespace_item('core', 'error')
+  import_namespace_item('core', 'fatal')
+  import_namespace_item('core', 'exception')
+
   import_namespace_item('core', 'Detector')
   import_namespace_item('core', 'evaluator')
   import_namespace_item('core', 'g4Evaluator')
@@ -157,10 +188,16 @@ def import_geometry():
   import_namespace_item('core', 'VisAttr')
   import_namespace_item('core', 'Limit')
   import_namespace_item('core', 'LimitSet')
+  import_namespace_item('core', 'LimitSetObject')
   import_namespace_item('core', 'Region')
+  import_namespace_item('core', 'RegionObject')
+  import_namespace_item('core', 'HitCollection')
 
   # // Readout.h
+  import_namespace_item('core', 'Segmentation')
+  import_namespace_item('core', 'SegmentationObject')
   import_namespace_item('core', 'Readout')
+  import_namespace_item('core', 'ReadoutObject')
 
   # // Alignments.h
   import_namespace_item('core', 'Alignment')
@@ -206,7 +243,7 @@ def import_geometry():
   import_namespace_item('core', 'UnionSolid')
   import_namespace_item('core', 'IntersectionSolid')
 
-
+# ---------------------------------------------------------------------------
 def import_tgeo():
   import_root('TGeoManager')
   import_root('TGeoNode')
@@ -259,6 +296,55 @@ def import_tgeo():
 import_tgeo()
 import_geometry()
 import_detail()
+
+# ---------------------------------------------------------------------------
+class Logger:
+  """
+  Helper class to use the dd4hep printout functions from python
+  
+  \author  M.Frank
+  \version 1.0
+  """
+
+  def __init__(self, name):
+    "Logger constructor"
+    self.name = name
+
+  def always(self, msg):
+    "Call dd4hep printout function with level ALWAYS"
+    dd4hep.always(self.name, msg)
+
+  def verbose(self, msg):
+    "Call dd4hep printout function with level VERBOSE"
+    dd4hep.verbose(self.name, msg)
+
+  def debug(self, msg):
+    "Call dd4hep printout function with level DEBUG"
+    dd4hep.debug(self.name, msg)
+
+  def info(self, msg):
+    "Call dd4hep printout function with level INFO"
+    dd4hep.info(self.name, msg)
+
+  def warning(self, msg):
+    "Call dd4hep printout function with level WARNING"
+    dd4hep.warning(self.name, msg)
+
+  def error(self, msg):
+    "Call dd4hep printout function with level ERROR"
+    dd4hep.error(self.name, msg)
+
+  def fatal(self, msg):
+    "Call dd4hep printout function with level FATAL"
+    dd4hep.fatal(self.name, msg)
+
+  def exception(self, msg):
+    "Call dd4hep exception function"
+    dd4hep.exception(self.name, msg)
+
+dd4hep_logger = Logger
+
+# ---------------------------------------------------------------------------
 #
 #  Import units from TGeo.
 #  Calling import_units makes all the units local to the dd4hep module.
diff --git a/DDCore/src/InstanceCount.cpp b/DDCore/src/InstanceCount.cpp
index f4632ee54a53ace9d170862bf580ba31586e827c..9b8fda016003352556d8e3c4acb464ff10091752 100644
--- a/DDCore/src/InstanceCount.cpp
+++ b/DDCore/src/InstanceCount.cpp
@@ -21,6 +21,7 @@
 #include <cstdio>
 #include <cstdlib>
 #include <cstring>
+#include <mutex>
 #include <map>
 
 using namespace std;
@@ -45,6 +46,7 @@ namespace {
   }
   int s_global = 1;
   struct _Global {
+    std::mutex lock;
     _Global() {}
     ~_Global() { s_global = 0; }
   } s_globalObj;
@@ -97,34 +99,44 @@ InstanceCount::Counter* InstanceCount::getCounter(const std::string& typ) {
   return (0 != cnt) ? cnt : strings()[&typ] = new Counter();
 }
 
+#define COUNTER_LOCK std::lock_guard<std::mutex> _counter_lock(s_globalObj.lock);
+
 /// Increment count according to string information
 void InstanceCount::increment(const std::string& typ) {
-  if ( s_global )
+  if ( s_global )   {
+    COUNTER_LOCK
     getCounter(typ)->increment();
+  }
   else
     on_exit_destructors();
 }
 
 /// Decrement count according to string information
 void InstanceCount::decrement(const std::string& typ) {
-  if ( s_global )
+  if ( s_global )   {
+    COUNTER_LOCK
     getCounter(typ)->decrement();
+  }
   else
     on_exit_destructors();
 }
 
 /// Increment count according to type information
 void InstanceCount::increment(const std::type_info& typ) {
-  if ( s_global )
+  if ( s_global )    {
+    COUNTER_LOCK
     getCounter(typ)->increment();
+  }
   else
     on_exit_destructors();
 }
 
 /// Decrement count according to type information
 void InstanceCount::decrement(const std::type_info& typ) {
-  if ( s_global )
+  if ( s_global )   {
+    COUNTER_LOCK
     getCounter(typ)->decrement();
+  }
   else
     on_exit_destructors();
 }
diff --git a/DDCore/src/Primitives.cpp b/DDCore/src/Primitives.cpp
index eea237cfd8a90df605b0369194a892e98cd15dd5..29773362dc91cd9932f8d6dfa2eb866444d6c5ba 100644
--- a/DDCore/src/Primitives.cpp
+++ b/DDCore/src/Primitives.cpp
@@ -165,6 +165,50 @@ unsigned long long int dd4hep::detail::hash64(const std::string& key)  {
   return std::accumulate(begin(key),end(key),FNV1a_64::hashinit,FNV1a_64::doByte);
 }
 
+/// Replace all occurrencies of a string
+std::string dd4hep::detail::str_replace(const std::string& str,
+					const std::string& pattern,
+					const std::string& replacement)   {
+  std::string res = str;
+  for(size_t id=res.find(pattern); id != std::string::npos; id = res.find(pattern) )
+    res.replace(id, pattern.length(), replacement);
+  return res;
+}
+
+/// Replace all occurrencies of a string
+std::string dd4hep::detail::str_replace(const std::string& str,
+					char  pattern,
+					const std::string& replacement)   {
+  std::string res = str;
+  for(size_t id=res.find(pattern); id != std::string::npos; id = res.find(pattern) )
+    res.replace(id, 1, replacement);
+  return res;
+}
+
+/// Replace all occurrencies of a string
+std::string dd4hep::detail::str_replace(const std::string& str,
+					char  pattern,
+				        char  replacement)   {
+  std::string res = str;
+  for(size_t id=res.find(pattern); id != std::string::npos; id = res.find(pattern) )
+    res.replace(id, 1, 1, replacement);
+  return res;
+}
+
+/// C++ version to convert a string to lower case
+std::string dd4hep::detail::str_lower(const std::string& str) {
+  std::string res = str.c_str();
+  std::transform(res.begin(), res.end(), res.begin(), ::tolower);
+  return res;
+}
+
+/// C++ version to convert a string to upper case
+std::string dd4hep::detail::str_upper(const std::string& str) {
+  std::string res = str.c_str();
+  std::transform(res.begin(), res.end(), res.begin(), ::toupper);
+  return res;
+}
+
 long int dd4hep::detail::makeTime(int year, int month, int day,
                           int hour, int minutes, int seconds)
 {
diff --git a/DDCore/src/Printout.cpp b/DDCore/src/Printout.cpp
index 69ca75ae3f8bce7288dd4ed10769bfe6406ea982..d0a6bfd15799d22127fd09dfd014d63af3dcb79f 100644
--- a/DDCore/src/Printout.cpp
+++ b/DDCore/src/Printout.cpp
@@ -371,7 +371,8 @@ string dd4hep::format(const string& src, const string& fmt, va_list& args) {
  */
 string dd4hep::format(const char* src, const char* fmt, va_list& args) {
   char str[4096];
-  size_t len1 = ::snprintf(str, sizeof(str), "%s: ", src);
+  size_t len1 = 0;
+  if ( src && *src ) ::snprintf(str, sizeof(str), "%s: ", src);
   size_t len2 = ::vsnprintf(str + len1, sizeof(str) - len1, fmt, args);
   if ( len2 > sizeof(str) - len1 )  {
     len2 = sizeof(str) - len1 - 1;
diff --git a/DDCore/src/RootDictionary.h b/DDCore/src/RootDictionary.h
index 02f28ec439083122078542afd1cb94127b350610..937dd746d3bfddacb952c9c71dd4d0e7ee3521b1 100644
--- a/DDCore/src/RootDictionary.h
+++ b/DDCore/src/RootDictionary.h
@@ -58,6 +58,15 @@ namespace dd4hep {
   tools::Evaluator& evaluator();
   tools::Evaluator& g4Evaluator();
 
+  std::size_t always (const std::string& src, const std::string& msg) { return printout(ALWAYS,  src, msg); }
+  std::size_t verbose(const std::string& src, const std::string& msg) { return printout(VERBOSE, src, msg); }
+  std::size_t debug  (const std::string& src, const std::string& msg) { return printout(DEBUG,   src, msg); }
+  std::size_t info   (const std::string& src, const std::string& msg) { return printout(INFO,    src, msg); }
+  std::size_t warning(const std::string& src, const std::string& msg) { return printout(WARNING, src, msg); }
+  std::size_t error  (const std::string& src, const std::string& msg) { return printout(ERROR,   src, msg); }
+  std::size_t fatal  (const std::string& src, const std::string& msg) { return printout(FATAL,   src, msg); }
+  void        exception(const std::string& src, const std::string& msg) { except(src, "%s", msg.c_str()); }
+
   namespace detail {
     /// Helper to invoke the ROOT interpreter
     struct interp  {
@@ -111,6 +120,16 @@ namespace dd4hep   {   namespace Parsers   {
 #pragma link C++ namespace dd4hep::DDSegmentation;
 
 #pragma link C++ enum dd4hep::PrintLevel;
+#pragma link C++ function dd4hep::always;
+#pragma link C++ function dd4hep::verbose;
+#pragma link C++ function dd4hep::debug;
+#pragma link C++ function dd4hep::info;
+#pragma link C++ function dd4hep::warning;
+#pragma link C++ function dd4hep::error;
+#pragma link C++ function dd4hep::fatal;
+#pragma link C++ function dd4hep::except;
+#pragma link C++ function dd4hep::printout;
+#pragma link C++ function dd4hep::exception;
 
 #ifndef __ROOTCLING__
 template std::pair<unsigned int, std::string>;
diff --git a/DDDigi/CMakeLists.txt b/DDDigi/CMakeLists.txt
index 7f7c82d09fed7844d9c2de72866faf6c69842519..cc08ec210e03aaa5a2b66eb8ef7c1f9bcb3b1554 100644
--- a/DDDigi/CMakeLists.txt
+++ b/DDDigi/CMakeLists.txt
@@ -64,4 +64,3 @@ install(TARGETS DDDigi DDDigiPlugins EXPORT DD4hep
   LIBRARY DESTINATION lib
   )
 install(DIRECTORY include/DDDigi DESTINATION include)
-
diff --git a/DDDigi/include/DDDigi/DigiAction.h b/DDDigi/include/DDDigi/DigiAction.h
index d775da63fd537062eb53bbce0fc784bef0be1677..8559bc353928eb79fbe2ab851f7a40920c0b2096 100644
--- a/DDDigi/include/DDDigi/DigiAction.h
+++ b/DDDigi/include/DDDigi/DigiAction.h
@@ -99,6 +99,11 @@ namespace dd4hep {
       /// Reference to the Digi context
 #if defined(G__ROOT) || defined(__CLING__) || defined(__ROOTCLING__)
       const DigiKernel*  m_kernel;
+    public:
+      const DigiKernel*  kernel()  const   {
+	return m_kernel;
+      }
+    protected:
 #else
       const DigiKernel&  m_kernel;
 #endif
@@ -282,6 +287,8 @@ namespace dd4hep {
       /// Support for messages with variable output level using output level+2
       void printP2(const char* fmt, ...) const;
 
+      /// Support for building formatted messages
+      std::string format(const char* fmt, ...) const;
       /// Support of debug messages.
       void debug(const char* fmt, ...) const;
       /// Support of info messages.
diff --git a/DDDigi/include/DDDigi/DigiActionSequence.h b/DDDigi/include/DDDigi/DigiActionSequence.h
index fed3b8bbf16d6b17596ea46bb9b1eddffe6e85bc..de1d9e08e353e958928ff1210eacedfed62b0192 100644
--- a/DDDigi/include/DDDigi/DigiActionSequence.h
+++ b/DDDigi/include/DDDigi/DigiActionSequence.h
@@ -72,6 +72,36 @@ namespace dd4hep {
       virtual void execute(DigiContext& context)  const override;
     };
 
+    /// Definitiaon of the sequential action sequence
+    /** Definitiaon of the sequential action sequence
+     *
+     *  \author  M.Frank
+     *  \version 1.0
+     *  \ingroup DD4HEP_DIGITIZATION
+     */
+    class DigiSequentialActionSequence : public DigiActionSequence {
+    public:
+      /// Standard constructor
+      DigiSequentialActionSequence(const DigiKernel& kernel, const std::string& nam);
+      /// Default destructor
+      virtual ~DigiSequentialActionSequence();
+    };
+
+    /// Definitiaon of the parallel action sequence
+    /** Definitiaon of the parallel action sequence
+     *
+     *  \author  M.Frank
+     *  \version 1.0
+     *  \ingroup DD4HEP_DIGITIZATION
+     */
+    class DigiParallelActionSequence : public DigiActionSequence {
+    public:
+      /// Standard constructor
+      DigiParallelActionSequence(const DigiKernel& kernel, const std::string& nam);
+      /// Default destructor
+      virtual ~DigiParallelActionSequence();
+    };
+
   }    // End namespace digi
 }      // End namespace dd4hep
 #endif // DDDIGI_DIGIACTIONSEQUENCE_H
diff --git a/DDDigi/include/DDDigi/DigiContainerCombine.h b/DDDigi/include/DDDigi/DigiContainerCombine.h
new file mode 100644
index 0000000000000000000000000000000000000000..76cda89f1176b057281b671f12d91a646db3d3c7
--- /dev/null
+++ b/DDDigi/include/DDDigi/DigiContainerCombine.h
@@ -0,0 +1,65 @@
+//==========================================================================
+//  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 DDDIGI_DIGICONTAINERCOMBINE_H
+#define DDDIGI_DIGICONTAINERCOMBINE_H
+
+// Framework include files
+#include <DDDigi/DigiEventAction.h>
+
+/// Namespace for the AIDA detector description toolkit
+namespace dd4hep {
+
+  /// Namespace for the Digitization part of the AIDA detector description toolkit
+  namespace digi {
+
+    /// 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 DigiContainerCombine : public DigiEventAction   {
+    protected:
+      /// Implementation declaration
+      class internals_t;
+
+      /// Reference to the implementation
+      std::unique_ptr<internals_t> internals;
+
+    protected:
+      /// Define standard assignments and constructors
+      DDDIGI_DEFINE_ACTION_CONSTRUCTORS(DigiContainerCombine);
+
+      /// Default destructor
+      virtual ~DigiContainerCombine();
+
+      /// Combine selected containers to one single deposit container
+      template <typename PREDICATE> 
+	std::size_t combine_containers(DigiEvent& event,
+				       DigiEvent::container_map_t& inputs,
+				       DigiEvent::container_map_t& outputs,
+				       const PREDICATE& predicate)  const;
+
+    public:
+      /// Standard constructor
+      DigiContainerCombine(const DigiKernel& kernel, const std::string& name);
+
+      /// Main functional callback
+      virtual void execute(DigiContext& context)  const;
+    };
+  }    // End namespace digi
+}      // End namespace dd4hep
+#endif // DDDIGI_DIGICONTAINERCOMBINE_H
diff --git a/DDDigi/include/DDDigi/DigiContext.h b/DDDigi/include/DDDigi/DigiContext.h
index cfbd7e2e9c5eafe96b8273e0eef41288cbb3cf88..2a9150bfde32669cd1f4a09f9ad1bdb0645a76d6 100644
--- a/DDDigi/include/DDDigi/DigiContext.h
+++ b/DDDigi/include/DDDigi/DigiContext.h
@@ -20,6 +20,7 @@
 
 /// C/C++ include files
 #include <memory>
+#include <mutex>
 
 /// Namespace for the AIDA detector description toolkit
 namespace dd4hep {
@@ -84,13 +85,19 @@ namespace dd4hep {
       friend class DigiKernel;
     public:
       typedef std::pair<void*, const std::type_info*>   UserFramework;
-    protected:
+
+    public:
+      /// Reference to the thread context
+      const DigiKernel&           kernel;
       /// Transient context variable - depending on the thread context: event reference
-      const DigiKernel*                 m_kernel = 0;
-      /// Reference to transient event
-      DigiEvent*                        m_event  = 0;
+      std::unique_ptr<DigiEvent>  event  { };
+
+    protected:
       /// Reference to the random engine for this event
       std::shared_ptr<DigiRandomGenerator> m_random;
+
+
+    protected:
       /// Inhibit default constructor
       DigiContext() = delete;
       /// Inhibit move constructor
@@ -99,17 +106,19 @@ namespace dd4hep {
       DigiContext(const DigiContext&) = delete;
 
     public:
+
       /// Initializing constructor
-      DigiContext(const DigiKernel* kernel_pointer, DigiEvent* event_pointer = 0);
+      DigiContext(const DigiKernel& kernel, std::unique_ptr<DigiEvent>&& event);
       /// 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;   }
+      /// Have a shared initializer lock
+      std::mutex& initializer_lock()   const;
+      /// Have a global I/O lock (e.g. for ROOT)
+      std::mutex& global_io_lock()   const;
+      /// Have a global output log lock
+      std::mutex& global_output_lock()   const;
+
       /// Access to the random engine for this event
       DigiRandomGenerator& randomGenerator()  const  { return *m_random; }
       /// Access to the user framework. Specialized function to be implemented by the client
diff --git a/DDDigi/include/DDDigi/DigiData.h b/DDDigi/include/DDDigi/DigiData.h
index d56781aca62634473bb6a869e63174094d85562f..f12ae3a035cab67b398a5f7d03dfa33c66490641 100644
--- a/DDDigi/include/DDDigi/DigiData.h
+++ b/DDDigi/include/DDDigi/DigiData.h
@@ -25,7 +25,12 @@
 #include <stdexcept>
 #include <cstdint>
 #include <memory>
+#include <mutex>
 #include <map>
+#include <set>
+#include <unordered_map>
+#include <unordered_set>
+#include <any>
 
 /// Namespace for the AIDA detector description toolkit
 namespace dd4hep {
@@ -33,227 +38,201 @@ namespace dd4hep {
   /// Namespace for the Digitization part of the AIDA detector description toolkit
   namespace digi {
 
+    /// Forward declarations
     class DigiEvent;
+    class Particle;
+    class ParticleMapping;
+    class EnergyDeposit;
+    class DepositMapping;
 
-    /// Container class to host energy deposits from simulation or noise processing
-    /*
+    ///  Key defintion to access the event data
+    /**
+     *  Helper to convert item and mask to a 64 bit integer
      *
      *  \author  M.Frank
      *  \version 1.0
      *  \ingroup DD4HEP_DIGITIZATION
      */
-    template <typename T> class DigiContainer : public std::vector<T>    {
-      /// Unique name within the event
-      std::string    name;
-
-    public:
-      /// Default constructor
-      DigiContainer() = default;
-      /// Disable move constructor
-      DigiContainer(DigiContainer&& copy) = default;
-      /// Disable copy constructor
-      DigiContainer(const DigiContainer& copy) = default;      
-      /// Default constructor
-      DigiContainer(const std::string& nam) : name(nam) {}
-      /// Default destructor
-      virtual ~DigiContainer() = default;
-      /// Disable move assignment
-      DigiContainer& operator=(DigiContainer&& copy) = delete;
-      /// Disable copy assignment
-      DigiContainer& operator=(const DigiContainer& copy) = delete;      
+    union Key   {
+      typedef std::uint64_t key_type;
+      typedef std::uint32_t itemkey_type;
+      typedef std::uint16_t mask_type;
+      
+      key_type key;
+      struct {
+        itemkey_type item;
+        mask_type    mask;
+        mask_type    spare;
+      } values;
+      Key();
+      Key(const Key&);
+      Key(key_type full_mask);
+      Key(mask_type mask, const std::string& item);
+      Key& operator=(const Key&);
+      key_type toLong()  const  {  return key; }
+      void set(const std::string& name, int mask);
+      /// Project the mask part of the key
+      static itemkey_type item(key_type k)  {
+	return Key(k).values.item;
+      }
+      /// Project the item part of the key
+      static mask_type mask(key_type k)  {
+	return Key(k).values.mask;
+      }
+      /// Access key name (if registered properly)
+      static std::string key_name(const Key& key);
     };
-    
-    /// 
-    /*
+
+    /// Particle definition for digitization
+    /** Particle definition for digitization
      *
      *  \author  M.Frank
      *  \version 1.0
      *  \ingroup DD4HEP_DIGITIZATION
      */
-    class EnergyDeposit   {
+    class Particle   {
     public:
-      class FunctionTable   {
-        friend class EnergyDeposit;
-      public:
-        std::function<long long int(const void*)> cellID;
-        std::function<long(const void*)>          flag;
-        FunctionTable() = default;
-        ~FunctionTable() = default;
-      };
-      template <typename Q, typename T> static const Q* vtable();
-      std::pair<const void*, const FunctionTable*> object;
+      /// Source contributing
+      std::any history;
 
     public:
       /// Initializing constructor
-      template <typename T> EnergyDeposit(const T* object);
+      Particle(std::any&& history);
       /// Default constructor
-      EnergyDeposit() = delete;
+      Particle() = default;
       /// Disable move constructor
-      EnergyDeposit(EnergyDeposit&& copy) = default;
+      Particle(Particle&& copy) = default;
       /// Disable copy constructor
-      EnergyDeposit(const EnergyDeposit& copy) = default;      
+      Particle(const Particle& copy) = default;
       /// Default destructor
-      virtual ~EnergyDeposit() = default;
+      virtual ~Particle() = default;
       /// Disable move assignment
-      EnergyDeposit& operator=(EnergyDeposit&& copy) = default;
+      Particle& operator=(Particle&& copy) = default;
       /// Disable copy assignment
-      EnergyDeposit& operator=(const EnergyDeposit& copy) = default;      
-
-      long long int cellID()  const    {   return object.second->cellID(object.first);     }
-      long          flag()  const      {   return object.second->flag(object.first);       }
+      Particle& operator=(const Particle& copy) = default;
     };
 
-    template <typename T> inline EnergyDeposit::EnergyDeposit(const T* ptr)
-      : object(ptr, vtable<EnergyDeposit::FunctionTable,T>())
+    /// Initializing constructor
+    inline Particle::Particle(std::any&& h)
+      : history(h)
     {
     }
 
-    /// 
-    /*
+    /// Particle mapping definition for digitization
+    /** Particle mapping definition for digitization
      *
      *  \author  M.Frank
      *  \version 1.0
      *  \ingroup DD4HEP_DIGITIZATION
      */
-    class TrackerDeposit : public EnergyDeposit   {
+    class ParticleMapping : public std::map<Key::key_type, Particle>   {
     public:
-      class FunctionTable : public  EnergyDeposit::FunctionTable  {
-        friend class TrackerDeposit;
-        friend class EnergyDeposit;
-      public:
-        std::function<const Position& (const void*)>  position;
-        std::function<const Direction& (const void*)> momentum;
-        std::function<double(const void*)>            deposit;
-        std::function<double(const void*)>            length;
-        FunctionTable() = default;
-        ~FunctionTable() = default;
-      };
-      std::pair<const void*, const FunctionTable*> object;
+      std::string      name { };
+      Key::mask_type   mask { 0x0 };
 
-    public:
+    public: 
       /// Initializing constructor
-      template <typename T> TrackerDeposit(const T* object);
+      ParticleMapping(const std::string& name, Key::mask_type mask);
       /// Default constructor
-      TrackerDeposit() = delete;
+      ParticleMapping() = default;
       /// Disable move constructor
-      TrackerDeposit(TrackerDeposit&& copy) = default;
+      ParticleMapping(ParticleMapping&& copy) = default;
       /// Disable copy constructor
-      TrackerDeposit(const TrackerDeposit& copy) = default;      
+      ParticleMapping(const ParticleMapping& copy) = default;
       /// Default destructor
-      virtual ~TrackerDeposit() = default;
+      virtual ~ParticleMapping() = default;
       /// Disable move assignment
-      TrackerDeposit& operator=(TrackerDeposit&& copy) = default;
+      ParticleMapping& operator=(ParticleMapping&& copy) = default;
       /// Disable copy assignment
-      TrackerDeposit& operator=(const TrackerDeposit& copy) = default;      
+      ParticleMapping& operator=(const ParticleMapping& copy) = default;
 
-      const Position&  position()  const  {   return object.second->position(object.first);     }
-      const Direction& momentum()  const  {   return object.second->momentum(object.first);     }
-      double           deposit()  const   {   return object.second->deposit(object.first);      }
-      double           length()  const    {   return object.second->length(object.first);       }
+      /// Merge new deposit map onto existing map
+      std::size_t merge(ParticleMapping&& updates);
+      void push(Key::key_type key, Particle&& particle);
     };
 
-    template <typename T> inline TrackerDeposit::TrackerDeposit(const T* ptr)
-      : object(ptr, vtable<TrackerDeposit::FunctionTable,T>())
+    /// Initializing constructor
+    inline ParticleMapping::ParticleMapping(const std::string& n, Key::mask_type m)
+      : name(n), mask(m)
     {
     }
 
-    /// 
-    /*
+    /// Energy deposit definition for digitization
+    /** Energy deposit definition for digitization
      *
      *  \author  M.Frank
      *  \version 1.0
      *  \ingroup DD4HEP_DIGITIZATION
      */
-    class CaloDeposit : public EnergyDeposit   {
+    class EnergyDeposit   {
     public:
-      class FunctionTable : public  EnergyDeposit::FunctionTable  {
-        friend class CaloDeposit;
-        friend class EnergyDeposit;
-      public:
-        std::function<const Position& (const void*)>  position;
-        std::function<double(const void*)>            deposit;
-        FunctionTable() = default;
-        ~FunctionTable() = default;
-      };
-      std::pair<const void*, const FunctionTable*> object;
+      /// Total energy deposit
+      double deposit  { 0 };
+      /// Sources contributing to this deposit
+      std::vector<std::pair<std::any, Key::mask_type> > history;
 
     public:
       /// Initializing constructor
-      template <typename T> CaloDeposit(const T* object);
+      EnergyDeposit(double ene);
       /// Default constructor
-      CaloDeposit() = delete;
+      EnergyDeposit() = default;
       /// Disable move constructor
-      CaloDeposit(CaloDeposit&& copy) = default;
+      EnergyDeposit(EnergyDeposit&& copy) = default;
       /// Disable copy constructor
-      CaloDeposit(const CaloDeposit& copy) = default;      
+      EnergyDeposit(const EnergyDeposit& copy) = default;      
       /// Default destructor
-      virtual ~CaloDeposit() = default;
+      virtual ~EnergyDeposit() = default;
       /// Disable move assignment
-      CaloDeposit& operator=(CaloDeposit&& copy) = default;
+      EnergyDeposit& operator=(EnergyDeposit&& copy) = default;
       /// Disable copy assignment
-      CaloDeposit& operator=(const CaloDeposit& copy) = default;      
-
-      const Position& position()  const {   return object.second->position(object.first);    }
-      double          deposit()  const  {   return object.second->deposit(object.first);     }
+      EnergyDeposit& operator=(const EnergyDeposit& copy) = default;      
     };
 
-    template <typename T> inline CaloDeposit::CaloDeposit(const T* ptr)
-      : object(ptr, vtable<CaloDeposit::FunctionTable,T>())
+
+    /// Initializing constructor
+    inline EnergyDeposit::EnergyDeposit(double ene)
+      : deposit(ene)
     {
     }
-    
-    /// 
-    /*
+
+    /// Energy deposit mapping definition for digitization
+    /** Energy deposit mapping definition for digitization
      *
      *  \author  M.Frank
      *  \version 1.0
      *  \ingroup DD4HEP_DIGITIZATION
      */
-    class DigiCount   {
-    public:
+    class DepositMapping : public std::map<CellID, EnergyDeposit>   {
+    public: 
+      std::string    name { };
+      Key::mask_type mask { 0x0 };
+
+    public: 
+      /// Initializing constructor
+      DepositMapping(const std::string& name, Key::mask_type mask);
       /// Default constructor
-      DigiCount() = default;
-      /// Default move constructor
-      DigiCount(DigiCount&& copy) = default;
-      /// Default copy constructor
-      DigiCount(const DigiCount& copy) = default;
+      DepositMapping() = default;
+      /// Disable move constructor
+      DepositMapping(DepositMapping&& copy) = default;
+      /// Disable copy constructor
+      DepositMapping(const DepositMapping& copy) = default;      
       /// Default destructor
-      virtual ~DigiCount() = default;
-      /// Default move assignment
-      DigiCount& operator=(DigiCount&& copy) = delete;
-      /// Default copy assignment
-      DigiCount& operator=(const DigiCount& copy) = delete;      
+      virtual ~DepositMapping() = default;
+      /// Disable move assignment
+      DepositMapping& operator=(DepositMapping&& copy) = default;
+      /// Disable copy assignment
+      DepositMapping& operator=(const DepositMapping& copy) = default;      
+
+      /// Merge new deposit map onto existing map
+      std::size_t merge(DepositMapping&& updates);
     };
 
-    typedef DigiContainer<EnergyDeposit*> DigiEnergyDeposits;
-    typedef DigiContainer<DigiCount*>     DigiCounts;
+    /// Initializing constructor
+    inline DepositMapping::DepositMapping(const std::string& n, Key::mask_type m)
+      : name(n), mask(m)
+    {
+    }
 
-    ///  Key defintion to access the event data
-    /**
-     *  Helper to convert item and mask to a 64 bit integer
-     *
-     *  \author  M.Frank
-     *  \version 1.0
-     *  \ingroup DD4HEP_DIGITIZATION
-     */
-    union Key   {
-      typedef std::uint64_t key_type;
-      typedef std::uint32_t itemkey_type;
-      typedef std::uint8_t  mask_type;
-      key_type key;
-      struct {
-        itemkey_type item;
-        mask_type    mask;
-        mask_type    spare[3];
-      } values;
-      Key();
-      Key(const Key&);
-      Key(mask_type mask, itemkey_type item);
-      Key(mask_type mask, const std::string& item);
-      Key& operator=(const Key&);
-      key_type toLong()  const  {  return key; }
-      void set(const std::string& name, int mask);
-    };
   }    // End namespace digi
 }      // End namespace dd4hep
     
@@ -278,17 +257,24 @@ namespace dd4hep {
      *  \ingroup DD4HEP_DIGITIZATION
      */
     class  DigiEvent : public ObjectExtensions  {
+    private:
+      std::mutex  m_lock;
+      std::string m_id;
     public:
       /// Forward definition of the key type
       typedef Key::key_type key_type;
-      std::map<unsigned long, std::shared_ptr<DigiEnergyDeposits> >  energyDeposits;
-      std::map<unsigned long, std::shared_ptr<DigiCounts> >          digitizations;
 
       int eventNumber = 0;
 #if defined(DD4HEP_INTERPRETER_MODE)
       std::map<key_type, long>  data;
+      std::map<key_type, long>  inputs;
+      std::map<key_type, long>  deposits;
 #else
-      std::map<key_type, dd4hep::any>  data;
+      typedef std::map<key_type, dd4hep::any> container_map_t;
+    protected:
+      container_map_t data;
+      container_map_t inputs;
+      container_map_t deposits;
 #endif
     public:
 #if defined(DD4HEP_INTERPRETER_MODE) || defined(G__ROOT)
@@ -304,10 +290,22 @@ namespace dd4hep {
       /// Default destructor
       virtual ~DigiEvent();
 
+      /// String identifier of this event
+      const char* id()   const    {   return this->m_id.c_str();   }
+
 #if !defined(DD4HEP_INTERPRETER_MODE)
+      /// Add item by key to the data segment
+      bool put_data(unsigned long key, std::any&& object);
+
+      /// Add item by key to the input segment
+      bool put_input(unsigned long key, std::any&& object);
+
+      /// Retrieve data segment from the event structure
+      container_map_t& get_segment(const std::string& name);
+
       /// Add item by key to the data 
       template<typename T> bool put(const Key& key, T&& object)     {
-        bool ret = data.emplace(key.toLong(),make_any<T>(object)).second;
+        bool ret = this->inputs.emplace(key.toLong(),make_any<T>(object)).second;
         if ( ret ) return ret;
         except("DigiEvent","Invalid requested to store data in event container. Key:%ld",key.toLong());
         throw std::runtime_error("DigiEvent"); // Will never get here!
diff --git a/DDDigi/include/DDDigi/DigiEventAction.h b/DDDigi/include/DDDigi/DigiEventAction.h
index f787ed286f8abcc9b64abeec53df5667ac168325..9611312e48565fe1634db13ad13e4c3cd886c690 100644
--- a/DDDigi/include/DDDigi/DigiEventAction.h
+++ b/DDDigi/include/DDDigi/DigiEventAction.h
@@ -14,8 +14,7 @@
 #define DDDIGI_DIGIEVENTACTION_H
 
 // Framework include files
-#include "DDDigi/DigiAction.h"
-
+#include <DDDigi/DigiAction.h>
 
 /// Namespace for the AIDA detector description toolkit
 namespace dd4hep {
@@ -23,6 +22,9 @@ namespace dd4hep {
   /// Namespace for the Digitization part of the AIDA detector description toolkit
   namespace digi {
 
+    /// Forward declarations
+    class DigiEvent;
+
     /// Default base class for all Digitizer actions and derivates thereof.
     /**
      *  This is a utility class supporting properties, output and access to
diff --git a/DDDigi/include/DDDigi/DigiGrammars.h b/DDDigi/include/DDDigi/DigiGrammars.h
new file mode 100644
index 0000000000000000000000000000000000000000..89e46dbef12911fc2bc67214eeabded270091632
--- /dev/null
+++ b/DDDigi/include/DDDigi/DigiGrammars.h
@@ -0,0 +1,25 @@
+//==========================================================================
+//  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 DDDIGI_GRAMMARS_H
+#define DDDIGI_GRAMMARS_H
+
+/// Namespace for the AIDA detector description toolkit
+namespace dd4hep {
+
+  /// Namespace for the Digitization part of the AIDA detector description toolkit
+  namespace digi {
+
+
+  }    // End namespace digi
+}      // End namespace dd4hep
+#endif // DDDIGI_GRAMMARS_H
diff --git a/DDDigi/include/DDDigi/DigiHandle.h b/DDDigi/include/DDDigi/DigiHandle.h
index 05359087f6bb1488a034a4fd52b64211850ae3c6..dbafaaeb3fe057c1d130c6199b7a26d72945be58 100644
--- a/DDDigi/include/DDDigi/DigiHandle.h
+++ b/DDDigi/include/DDDigi/DigiHandle.h
@@ -33,6 +33,36 @@ namespace dd4hep {
     class DigiEventAction;
     class DigiSignalProcessor;
 
+    /// 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();
+    };
+
     /// Handle to Digi actions with built-in creation mechanism
     /**
      *  \author  M.Frank
@@ -86,36 +116,6 @@ namespace dd4hep {
       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
 
diff --git a/DDDigi/include/DDDigi/DigiHitAttenuatorExp.h b/DDDigi/include/DDDigi/DigiHitAttenuatorExp.h
new file mode 100644
index 0000000000000000000000000000000000000000..d4281fe7531e91090671fd0d6d7b3e80b2fcc721
--- /dev/null
+++ b/DDDigi/include/DDDigi/DigiHitAttenuatorExp.h
@@ -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
+//
+//==========================================================================
+#ifndef DDDIGI_DIGIHITATTENUATOREXP_H
+#define DDDIGI_DIGIHITATTENUATOREXP_H
+
+// Framework include files
+#include "DDDigi/DigiEventAction.h"
+
+
+/// Namespace for the AIDA detector description toolkit
+namespace dd4hep {
+
+  /// Namespace for the Digitization part of the AIDA detector description toolkit
+  namespace digi {
+
+    /// 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 DigiHitAttenuatorExp : public DigiEventAction   {
+    protected:
+      /// Implementation declaration
+      class internals_t;
+      /// Reference to the actual implementation
+      std::unique_ptr<internals_t> internals;
+
+    protected:
+      /// Define standard assignments and constructors
+      DDDIGI_DEFINE_ACTION_CONSTRUCTORS(DigiHitAttenuatorExp);
+
+      /// Default destructor
+      virtual ~DigiHitAttenuatorExp();
+
+    public:
+      /// Standard constructor
+      DigiHitAttenuatorExp(const DigiKernel& kernel, const std::string& nam);
+      /// Main functional callback
+      virtual void execute(DigiContext& context)  const;
+    };
+  }    // End namespace digi
+}      // End namespace dd4hep
+#endif // DDDIGI_DIGIHITATTENUATOREXP_H
diff --git a/DDDigi/include/DDDigi/DigiInputAction.h b/DDDigi/include/DDDigi/DigiInputAction.h
index 73d545b0d86349f32aadbda26e9ac37e3ef2f7e6..ab41c5e2bd2911be65e63078dee31dad701c5112 100644
--- a/DDDigi/include/DDDigi/DigiInputAction.h
+++ b/DDDigi/include/DDDigi/DigiInputAction.h
@@ -14,7 +14,10 @@
 #define DDDIGI_DIGIINPUTACTION_H
 
 /// Framework include files
-#include "DDDigi/DigiEventAction.h"
+#include <DDDigi/DigiEventAction.h>
+
+/// C/C++ include files
+#include <limits>
 
 /// Namespace for the AIDA detector description toolkit
 namespace dd4hep {
@@ -34,9 +37,16 @@ namespace dd4hep {
      *  \ingroup DD4HEP_DIGITIZATION
      */
     class DigiInputAction : public DigiEventAction {
+    public:
+      enum { INPUT_START = -1  };
+      enum { NO_MASK     = 0x0 };
+
     protected:
-      /// Input data specification
-      std::vector<std::string> m_input;
+      /// Property: Input data specification
+      std::vector<std::string> m_inputs { };
+      /// Property: Mask to flag input source items
+      int                      m_mask   { NO_MASK };
+
     protected:
       /// Define standard assignments and constructors
       DDDIGI_DEFINE_ACTION_CONSTRUCTORS(DigiInputAction);
diff --git a/DDDigi/include/DDDigi/DigiKernel.h b/DDDigi/include/DDDigi/DigiKernel.h
index 74e282847b834b04409cc6fe202af33a393705d8..edd680220eefb361977bc585f5096dae662423b4 100644
--- a/DDDigi/include/DDDigi/DigiKernel.h
+++ b/DDDigi/include/DDDigi/DigiKernel.h
@@ -18,7 +18,7 @@
 
 // C/C++ include files
 #include <mutex>
-#include <atomic>
+#include <memory>
 
 /// Namespace for the AIDA detector description toolkit
 namespace dd4hep {
@@ -48,20 +48,20 @@ namespace dd4hep {
       class Wrapper;
 
       /// Internal only data structures;
-      Internals*            internals = 0;
+      Internals*            internals   { nullptr };
       
     protected:
       /// Detector description object
-      Detector*             m_detDesc = 0;
+      Detector*             m_detDesc         { nullptr };
       /// Reference to the user framework
       mutable UserFramework m_userFramework;
       
       /// Execute one single event
-      virtual void executeEvent(DigiContext* context);
+      virtual void executeEvent(std::unique_ptr<DigiContext>&& context);
       /// Notify kernel that the execution of one single event finished
-      void notify(DigiContext* context);
+      void notify(std::unique_ptr<DigiContext>&& context);
       /// Notify kernel that the execution of one single event finished
-      void notify(DigiContext* context, const std::exception& e);
+      void notify(std::unique_ptr<DigiContext>&&, const std::exception& e);
       
     protected:
       /// Define standard assignments and constructors
@@ -87,6 +87,15 @@ namespace dd4hep {
       template <typename T> void setUserFramework(T* object)   {
         m_userFramework = UserFramework(object,&typeid(T));
       }
+
+      /// Have a shared initializer lock
+      std::mutex& initializer_lock()  const;
+
+      /// Have a global I/O lock (e.g. for ROOT)
+      std::mutex& global_io_lock()   const;
+
+      /// Have a global output log lock
+      std::mutex& global_output_lock()   const;
       
       /** Property access                            */
       /// Access to the properties of the object
@@ -112,6 +121,13 @@ namespace dd4hep {
       /// Retrieve the global output level of a named object.
       PrintLevel getOutputLevel(const std::string object) const;
 
+      /// Access current number of events still to process
+      std::size_t events_todo()  const;
+      /// Access current number of events already processed
+      std::size_t events_done()  const;
+      /// Access current number of events processing (events in flight)
+      std::size_t events_processing()  const;
+
       /// Construct detector geometry using description plugin
       virtual void loadGeometry(const std::string& compact_file);
       /// Load XML file 
diff --git a/DDDigi/include/DDDigi/DigiDDG4Input.h b/DDDigi/include/DDDigi/DigiROOTInput.h
similarity index 57%
rename from DDDigi/include/DDDigi/DigiDDG4Input.h
rename to DDDigi/include/DDDigi/DigiROOTInput.h
index 5c19d3a3874beec277be94a4b967a254087d812c..da30a24056ef59f53bd3d88274b5a73ac3ecb357 100644
--- a/DDDigi/include/DDDigi/DigiDDG4Input.h
+++ b/DDDigi/include/DDDigi/DigiROOTInput.h
@@ -10,16 +10,18 @@
 // Author     : M.Frank
 //
 //==========================================================================
-#ifndef DDDIGI_DIGIDDG4INPUT_H
-#define DDDIGI_DIGIDDG4INPUT_H
+#ifndef DDDIGI_DIGIROOTINPUT_H
+#define DDDIGI_DIGIROOTINPUT_H
 
 /// Framework include files
-#include "DDDigi/DigiInputAction.h"
+#include <DDDigi/DigiInputAction.h>
+
+// C/C++ include files
+#include <memory>
+#include <mutex>
 
 // Forward declarations
-class TFile;
-class TTree;
-class TBranch;
+class TClass;
 
 /// Namespace for the AIDA detector description toolkit
 namespace dd4hep {
@@ -28,7 +30,7 @@ namespace dd4hep {
   namespace digi {
 
     // Forward declarations
-    class DigiDDG4Input;
+    class DigiROOTInput;
 
     /// Base class for input actions to the digitization
     /**
@@ -37,26 +39,36 @@ namespace dd4hep {
      *  \version 1.0
      *  \ingroup DD4HEP_DIGITIZATION
      */
-    class DigiDDG4Input : public DigiInputAction {
+    class DigiROOTInput : public DigiInputAction {
+
     protected:
-      /// Reference to the current ROOT file to be read
-      TFile*                   m_current   { nullptr };
-      /// List of input sources to be worked down
-      std::vector<std::string> m_todo      {  };
+      /// Helper classes
+      class internals_t;
+      /// Property: Name of the tree to connect to
+      std::string                    m_tree_name   { };
+      /// Property: Container names to be loaded
+      std::vector<std::string>       m_containers  { };
+
+      mutable int                    m_curr_input  { 0 };
+      /// Connection parameters to the "current" input source
+      mutable std::unique_ptr<internals_t>   imp    { };
+
+      /// Open new input file
+      void open_new_file()  const;
 
     protected:
       /// Define standard assignments and constructors
-      DDDIGI_DEFINE_ACTION_CONSTRUCTORS(DigiDDG4Input);
+      DDDIGI_DEFINE_ACTION_CONSTRUCTORS(DigiROOTInput);
 
     public:
       /// Standard constructor
-      DigiDDG4Input(const DigiKernel& kernel, const std::string& nam);
+      DigiROOTInput(const DigiKernel& kernel, const std::string& nam);
       /// Default destructor
-      virtual ~DigiDDG4Input();
+      virtual ~DigiROOTInput();
       /// Callback to read event input
       virtual void execute(DigiContext& context)  const override;
     };
 
   }    // End namespace digi
 }      // End namespace dd4hep
-#endif // DDDIGI_DIGIDDG4INPUT_H
+#endif // DDDIGI_DIGIROOTINPUT_H
diff --git a/DDDigi/include/DDDigi/DigiSegmentation.h b/DDDigi/include/DDDigi/DigiSegmentation.h
index 3f4f82ff4a39ff31450bc9dcf660ceb4d8741630..3507a2b9a7a8981e756b84c6d368aa61df3e5b48 100644
--- a/DDDigi/include/DDDigi/DigiSegmentation.h
+++ b/DDDigi/include/DDDigi/DigiSegmentation.h
@@ -31,7 +31,7 @@ namespace dd4hep {
     class DigiContext;
     class DigiSegmentation;
     template <typename SEGMENTATION> class cell_data;
-    template <typename SEGMENTATION> class segmentation_data;    
+    template <typename SEGMENTATION> class segmentation_data;
     
     /// 
     /*
@@ -59,7 +59,7 @@ namespace dd4hep {
       /// Default move assignment
       DigiCellData& operator=(DigiCellData&& copy) = delete;
       /// Default copy assignment
-      DigiCellData& operator=(const DigiCellData& copy) = delete;      
+      DigiCellData& operator=(const DigiCellData& copy) = delete;
     };
 
     template <typename SEGMENTATION> 
diff --git a/DDDigi/include/DDDigi/DigiSegmentationSplitter.h b/DDDigi/include/DDDigi/DigiSegmentationSplitter.h
new file mode 100644
index 0000000000000000000000000000000000000000..fac34979d1f14c533f1f546a84938a6e6fdd106a
--- /dev/null
+++ b/DDDigi/include/DDDigi/DigiSegmentationSplitter.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 DDDIGI_DIGISEGMENTATIONSPLITTER_H
+#define DDDIGI_DIGISEGMENTATIONSPLITTER_H
+
+// Framework include files
+#include <DDDigi/DigiEventAction.h>
+
+/// Namespace for the AIDA detector description toolkit
+namespace dd4hep {
+
+  /// Namespace for the Digitization part of the AIDA detector description toolkit
+  namespace digi {
+
+    /// 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 DigiSegmentationSplitter : public DigiEventAction   {
+    protected:
+      /// Implementation declaration
+      class internals_t;
+
+      /// Reference to the implementation
+      std::unique_ptr<internals_t> internals;
+
+    protected:
+      /// Define standard assignments and constructors
+      DDDIGI_DEFINE_ACTION_CONSTRUCTORS(DigiSegmentationSplitter);
+
+      /// Default destructor
+      virtual ~DigiSegmentationSplitter();
+
+      /// Split actions according to the segmentation
+      void split_segments(DigiEvent& event, DigiEvent::container_map_t& data)  const;
+
+    public:
+      /// Standard constructor
+      DigiSegmentationSplitter(const DigiKernel& kernel, const std::string& name);
+
+      /// Main functional callback
+      virtual void execute(DigiContext& context)  const;
+    };
+  }    // End namespace digi
+}      // End namespace dd4hep
+#endif // DDDIGI_DIGISEGMENTATIONSPLITTER_H
diff --git a/DDDigi/include/DDDigi/DigiStoreDump.h b/DDDigi/include/DDDigi/DigiStoreDump.h
new file mode 100644
index 0000000000000000000000000000000000000000..2cbf1e89ab9fdc45096dbf6dab294aaa82f611bf
--- /dev/null
+++ b/DDDigi/include/DDDigi/DigiStoreDump.h
@@ -0,0 +1,64 @@
+//==========================================================================
+//  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 DDDIGI_DIGISTOREDUMP_H
+#define DDDIGI_DIGISTOREDUMP_H
+
+/// Framework include files
+#include "DDDigi/DigiEventAction.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 {
+
+    /// 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 DigiStoreDump : public DigiEventAction   {
+    protected:
+      /// Property: Flag to check history record
+      bool m_dump_history     { false };
+      /// Property: Data segments to be dumped
+      std::vector<std::string> m_data_segments { };
+
+    protected:
+      /// Define standard assignments and constructors
+      DDDIGI_DEFINE_ACTION_CONSTRUCTORS(DigiStoreDump);
+
+      /// Default destructor
+      virtual ~DigiStoreDump();
+
+      /// Dump hit container
+      template <typename CONTAINER> void dump(const std::string& tag,
+					      const DigiEvent& event,
+					      const CONTAINER& cont)  const;
+
+    public:
+      /// Standard constructor
+      DigiStoreDump(const DigiKernel& kernel, const std::string& nam);
+      /// Main functional callback
+      virtual void execute(DigiContext& context)  const;
+    };
+  }    // End namespace digi
+}      // End namespace dd4hep
+#endif // DDDIGI_DIGISTOREDUMP_H
diff --git a/DDDigi/plugins/Components.cpp b/DDDigi/plugins/Components.cpp
index e7080658446eaa3408a9b452b5503079dc8dda48..b36856ca8ccbbcbeb9e908990657f1e03e3c6cb2 100644
--- a/DDDigi/plugins/Components.cpp
+++ b/DDDigi/plugins/Components.cpp
@@ -24,14 +24,16 @@
 #include "DDDigi/DigiInputAction.h"
 DECLARE_DIGIEVENTACTION_NS(dd4hep::digi,DigiInputAction)
 
-#include "DDDigi/DigiDDG4Input.h"
-DECLARE_DIGIEVENTACTION_NS(dd4hep::digi,DigiDDG4Input)
+#include "DDDigi/DigiROOTInput.h"
+DECLARE_DIGIEVENTACTION_NS(dd4hep::digi,DigiROOTInput)
 
 #include "DDDigi/DigiSynchronize.h"
 DECLARE_DIGIEVENTACTION_NS(dd4hep::digi,DigiSynchronize)
 
 #include "DDDigi/DigiActionSequence.h"
 DECLARE_DIGIEVENTACTION_NS(dd4hep::digi,DigiActionSequence)
+DECLARE_DIGIEVENTACTION_NS(dd4hep::digi,DigiParallelActionSequence)
+DECLARE_DIGIEVENTACTION_NS(dd4hep::digi,DigiSequentialActionSequence)
 
 #include "DDDigi/DigiSubdetectorSequence.h"
 DECLARE_DIGIEVENTACTION_NS(dd4hep::digi,DigiSubdetectorSequence)
@@ -42,6 +44,19 @@ DECLARE_DIGIEVENTACTION_NS(dd4hep::digi,DigiLockedAction)
 #include "DDDigi/DigiSignalProcessorSequence.h"
 DECLARE_DIGISIGNALPROCESSOR_NS(dd4hep::digi,DigiSignalProcessorSequence)
 
+#include "DDDigi/DigiStoreDump.h"
+DECLARE_DIGIEVENTACTION_NS(dd4hep::digi,DigiStoreDump)
+
+#include "DDDigi/DigiHitAttenuatorExp.h"
+DECLARE_DIGIEVENTACTION_NS(dd4hep::digi,DigiHitAttenuatorExp)
+
+#include "DDDigi/DigiContainerCombine.h"
+DECLARE_DIGIEVENTACTION_NS(dd4hep::digi,DigiContainerCombine)
+
+#include "DDDigi/DigiSegmentationSplitter.h"
+DECLARE_DIGIEVENTACTION_NS(dd4hep::digi,DigiSegmentationSplitter)
+
+
 
 using namespace std;
 using namespace dd4hep;
diff --git a/DDDigi/plugins/DigiDDG4Input.cpp b/DDDigi/plugins/DigiDDG4Input.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a50fbdaa0564e9c1a2826eea760c5e60dda16f76
--- /dev/null
+++ b/DDDigi/plugins/DigiDDG4Input.cpp
@@ -0,0 +1,103 @@
+//==========================================================================
+//  AIDA Detector description implementation 
+//--------------------------------------------------------------------------
+// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
+// All rights reserved.
+//
+// For the licensing terms see $DD4hepINSTALL/LICENSE.
+// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
+//
+// Author     : M.Frank
+//
+//==========================================================================
+
+// Framework include files
+#include <DD4hep/Printout.h>
+#include <DD4hep/Factories.h>
+#include <DD4hep/DD4hepUnits.h>
+#include <DDG4/Geant4Data.h>
+#include <DDG4/Geant4Particle.h>
+#include <DDDigi/DigiData.h>
+#include <CLHEP/Units/SystemOfUnits.h>
+
+// ROOT include files
+
+// C/C++ include files
+#include <stdexcept>
+#include <any>
+
+using namespace dd4hep;
+
+typedef std::function<std::any(int, const char*, void*)> func_t;
+
+namespace  {
+
+  template <typename T> union input_data  {
+    const void*      raw;
+    std::vector<T*>* items;
+    input_data(const void* p)   { this->raw = p; }
+  };
+
+  template <typename T> void* ddg4_hit_convert_function(const char* desc)   {
+    std::string tag = desc;
+    func_t* cnv = new func_t([tag] (int mask, const char* name, void* ptr)  {
+	using wrap_t = std::shared_ptr<sim::Geant4HitData>;
+	std::size_t len = 0;
+	digi::DepositMapping out(name, mask);
+	if ( ptr )   {
+	  input_data<T> data(ptr);
+	  digi::Key::mask_type msk = digi::Key::mask_type(mask);
+	  for( auto* p : *data.items )   {
+	    auto it = out.find(p->cellID);
+	    if ( it == out.end() )   {
+	      digi::EnergyDeposit dep(p->energyDeposit);
+	      dep.history.emplace_back(std::any(wrap_t(p)), msk);
+	      out.emplace(p->cellID, std::move(dep));
+	      continue;
+	    }
+	    (*it).second.history.emplace_back(std::any(wrap_t(p)), msk);
+	    (*it).second.deposit += p->energyDeposit;
+	  }
+	  len = data.items->size();
+	  data.items->clear();
+	}
+	printout(DEBUG,"DDG4Converter","++ Converted %ld %s to %ld cell deposits",
+		 len, tag.c_str(), out.size());
+	return std::make_any<digi::DepositMapping>(std::move(out));
+      });
+    return cnv;
+  }
+}
+
+static void* convert_sim_geant4calorimeter_hits()     {
+  return ddg4_hit_convert_function<sim::Geant4Calorimeter::Hit>("DDG4 calorimeter hits");
+}
+DECLARE_CREATE(DD4hep_DDDigiConverter_vector_dd4hep_sim_Geant4Calorimeter_Hit_,convert_sim_geant4calorimeter_hits);
+
+static void* convert_sim_geant4tracker_hits()     {
+  return ddg4_hit_convert_function<sim::Geant4Tracker::Hit>("DDG4 tracker hits");
+}
+DECLARE_CREATE(DD4hep_DDDigiConverter_vector_dd4hep_sim_Geant4Tracker_Hit_,convert_sim_geant4tracker_hits);
+
+static void* convert_sim_geant4particles()     {
+  func_t* cnv = new func_t([] (int mask, const char* name, void* ptr)  {
+      std::any res = std::make_any<digi::ParticleMapping>(name, mask);
+      digi::ParticleMapping* out = std::any_cast<digi::ParticleMapping>(&res);
+      if ( ptr )   {
+	using wrap_t = std::shared_ptr<sim::Geant4Particle>;
+	auto* items = (std::vector<sim::Geant4Particle*>*)ptr;
+	for( auto* p : *items )   {
+	  digi::Key key(0);
+	  key.values.mask = mask;
+	  key.values.item = out->size();
+	  p->mask = mask;
+	  out->push(key.key, {std::make_any<wrap_t>(p)});
+	}
+	items->clear();
+      }
+      printout(DEBUG,"DDG4Converter","++ Converted %ld DDG4 particles", out->size());
+      return res;
+    });
+  return cnv;
+}
+DECLARE_CREATE(DD4hep_DDDigiConverter_vector_dd4hep_sim_Geant4Particle_,convert_sim_geant4particles);
diff --git a/DDDigi/plugins/DigiHitHistoryDrop.cpp b/DDDigi/plugins/DigiHitHistoryDrop.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..04d1e694cdf6c76f915324ababf0649bdc7a3c7b
--- /dev/null
+++ b/DDDigi/plugins/DigiHitHistoryDrop.cpp
@@ -0,0 +1,88 @@
+//==========================================================================
+//  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/DigiData.h"
+#include "DDDigi/DigiContext.h"
+#include "DDDigi/DigiEventAction.h"
+
+
+/// Namespace for the AIDA detector description toolkit
+namespace dd4hep {
+
+  /// Namespace for the Digitization part of the AIDA detector description toolkit
+  namespace digi {
+
+    /// 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 DigiHitHistoryDrop : public DigiEventAction   {
+    protected:
+      /// Property: Masks to act on
+      std::vector<int> m_masks  { };
+      /// Property: Input data segment name
+      std::string      m_input  { };
+
+    protected:
+      /// Define standard assignments and constructors
+      DDDIGI_DEFINE_ACTION_CONSTRUCTORS(DigiHitHistoryDrop);
+
+      /// Default destructor
+      virtual ~DigiHitHistoryDrop()  {
+	InstanceCount::decrement(this);
+      }
+
+    public:
+      /// Standard constructor
+      DigiHitHistoryDrop(const DigiKernel& krnl, const std::string& nam)
+	: DigiEventAction(krnl, nam)
+      {
+	declareProperty("masks", m_masks);
+	declareProperty("input", m_input = "inputs");
+	InstanceCount::increment(this);
+      }
+
+      /// Main functional callback
+      virtual void execute(DigiContext& context)  const  final  {
+	auto& inputs = context.event->get_segment(m_input);
+	std::size_t num_drop = 0;
+	for ( auto& i : inputs )     {
+	  Key key(i.first);
+	  auto im = std::find(m_masks.begin(), m_masks.end(), key.values.mask);
+	  if ( im != m_masks.end() )   {
+	    std::any& obj = i.second;
+	    DepositMapping* m = std::any_cast<DepositMapping>(&obj);
+	    if ( m )    {
+	      for( auto& c : *m )    {
+		num_drop += c.second.history.size();
+		c.second.history.clear();
+	      }
+	    }
+	  }
+	}
+	info("%s+++ Dropped history of %6ld hits", context.event->id(), num_drop);
+      }
+    };
+  }    // End namespace digi
+}      // End namespace dd4hep
+
+
+#include "DDDigi/DigiFactories.h"
+DECLARE_DIGIEVENTACTION_NS(dd4hep::digi,DigiHitHistoryDrop)
diff --git a/DDDigi/plugins/DigiRandomNoise.cpp b/DDDigi/plugins/DigiRandomNoise.cpp
index 93427ae893aa097efbcbc89cc744652349df3e39..a0b013a91ca0b87010793b1769404cea36047b36 100644
--- a/DDDigi/plugins/DigiRandomNoise.cpp
+++ b/DDDigi/plugins/DigiRandomNoise.cpp
@@ -14,7 +14,7 @@
 #define DD4HEP_DDDIGI_DIGIRANDOMNOISE_H
 
 // Framework include files
-#include "DDDigi/DigiEventAction.h"
+#include <DDDigi/DigiEventAction.h>
 
 /// Namespace for the AIDA detector description toolkit
 namespace dd4hep {
diff --git a/DDDigi/python/DDDigiDict.C b/DDDigi/python/DDDigiDict.C
index 3edc28d41c1fd8d2779bee82646cf5cf8d4fa41e..7b39474324e4e1aebdf58a4326f53015f41fb12b 100644
--- a/DDDigi/python/DDDigiDict.C
+++ b/DDDigi/python/DDDigiDict.C
@@ -35,7 +35,10 @@
 #include "DDDigi/DigiHandle.h"
 #include "DDDigi/DigiKernel.h"
 #include "DDDigi/DigiContext.h"
+#include "DDDigi/DigiAction.h"
 #include "DDDigi/DigiSynchronize.h"
+#include "DDDigi/DigiEventAction.h"
+#include "DDDigi/DigiInputAction.h"
 #include "DDDigi/DigiActionSequence.h"
 #include "DDDigi/DigiSignalProcessor.h"
 
@@ -57,11 +60,16 @@ namespace dd4hep {
       operator dd4hep::digi::Digi##x* () const         { return action;                 } \
       Digi##x* operator->() const                      { return action;                 } \
       Digi##x* get() const                             { return action;                 } \
+      KernelHandle kernel()  const                     {		\
+	auto* k = const_cast<DigiKernel*>(action->kernel());		\
+	return KernelHandle(k);						\
+      }									\
     }
 
     ACTIONHANDLE(SignalProcessor);
     ACTIONHANDLE(Action);
     ACTIONHANDLE(EventAction);
+    ACTIONHANDLE(InputAction);
     ACTIONHANDLE(ActionSequence);
     ACTIONHANDLE(Synchronize);
 
@@ -81,21 +89,35 @@ namespace dd4hep {
         H handle(action.get());
         return handle;
       }
+      static KernelHandle createKernel(DigiAction* action)   {
+	auto* k = const_cast<DigiKernel*>(action->kernel());
+	return KernelHandle(k);
+      }
       static ActionHandle createAction(KernelHandle& kernel, const std::string& name_type)   
       { return cr<ActionHandle,DigiHandle<DigiAction> >(kernel,name_type);                           }
+
       static EventActionHandle createEventAction(KernelHandle& kernel, const std::string& name_type)   
       { return cr<EventActionHandle,DigiHandle<DigiEventAction> >(kernel,name_type);                 }
+
+      static InputActionHandle createInputAction(KernelHandle& kernel, const std::string& name_type)   
+      { return cr<InputActionHandle,DigiHandle<DigiInputAction> >(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(DigiEventAction* f)              { return f;                       }
+      static DigiAction* toAction(DigiInputAction* f)              { return f;                       }
       static DigiAction* toAction(DigiActionSequence* f)           { return f;                       }
       static DigiAction* toAction(DigiSynchronize* f)              { return f;                       }
       static DigiAction* toAction(DigiSignalProcessor* f)          { return f;                       }
 
       static DigiAction* toAction(ActionHandle f)                  { return f.action;                }
+      static DigiAction* toAction(EventActionHandle f)             { return f.action;                }
+      static DigiAction* toAction(InputActionHandle f)             { return f.action;                }
       static DigiAction* toAction(ActionSequenceHandle f)          { return f.action;                }
       static DigiAction* toAction(SynchronizeHandle f)             { return f.action;                }
       static DigiAction* toAction(SignalProcessorHandle f)         { return f.action;                }
@@ -154,6 +176,9 @@ using namespace std;
 #pragma link C++ class dd4hep::digi::DigiEventAction;
 #pragma link C++ class dd4hep::digi::EventActionHandle;
 
+#pragma link C++ class dd4hep::digi::DigiInputAction;
+#pragma link C++ class dd4hep::digi::InputActionHandle;
+
 #pragma link C++ class dd4hep::digi::DigiActionSequence;
 #pragma link C++ class dd4hep::digi::ActionSequenceHandle;
 
@@ -165,7 +190,7 @@ using namespace std;
 
 /// Digi data item wrappers
 #pragma link C++ class dd4hep::digi::DigiEvent;
-#pragma link C++ class dd4hep::digi::DigiEnergyDeposits+;
-#pragma link C++ class dd4hep::digi::DigiCounts+;
+#pragma link C++ class dd4hep::digi::EnergyDeposit+;
+#pragma link C++ class dd4hep::digi::DepositMapping+;
 
 #endif
diff --git a/DDDigi/python/DDDigi.py b/DDDigi/python/dddigi.py
similarity index 55%
rename from DDDigi/python/DDDigi.py
rename to DDDigi/python/dddigi.py
index d78afcff9e4bfa694c840d2b3a9501789de4caf1..f5d111c7aa605e5182f6b024883a4de951929759 100644
--- a/DDDigi/python/DDDigi.py
+++ b/DDDigi/python/dddigi.py
@@ -9,11 +9,9 @@
 #
 # ==========================================================================
 from __future__ import absolute_import, unicode_literals
-import logging
 from dd4hep_base import *  # noqa: F403
 
-logger = logging.getLogger(__name__)
-
+logger = dd4hep_logger('dddigi')
 
 def loadDDDigi():
   import ROOT
@@ -27,27 +25,29 @@ def loadDDDigi():
     gSystem.Load("libglapi")
     ROOT.gErrorIgnoreLevel = orgLevel
 
-  import platform
   import os
+  import platform
   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())
+  logger.info('DDDigi.py: Successfully loaded DDDigi plugin library libDDDigiPlugins!')
+  result = gSystem.Load("libDDG4Plugins")
+  if result < 0:
+    raise Exception('DDDigi.py: Failed to load the DDG4 library libDDG4Plugins: ' + gSystem.GetErrorStr())
+  logger.info('DDDigi.py: Successfully loaded DDG4 plugin library libDDG4Plugins!')
   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:
@@ -63,29 +63,24 @@ core = dd4hep
 digi = dd4hep.digi
 Kernel = digi.KernelHandle
 Interface = digi.DigiActionCreation
-Detector = core.Detector
+Detector  = core.Detector
 #
 #
 # ---------------------------------------------------------------------------
-
-
 def _constant(self, name):
   return self.constantAsString(name)
 
-
 Detector.globalVal = _constant
 # ---------------------------------------------------------------------------
 
 """
-  Import the Detector constants into the DDDigi namespace
+  Import the Detector constants into the dddigi namespace
 """
-
-
 def importConstants(description, namespace=None, debug=False):
   ns = current
   if namespace is not None and not hasattr(current, namespace):
     import imp
-    m = imp.new_module('DDDigi.' + namespace)
+    m = imp.new_module('dddigi.' + namespace)
     setattr(current, namespace, m)
     ns = m
   evaluator = dd4hep.g4Evaluator()
@@ -126,8 +121,6 @@ def importConstants(description, namespace=None, debug=False):
     logger.info('+++ Imported %d global values to namespace:%s', num, ns.__name__,)
 
 # ---------------------------------------------------------------------------
-
-
 def _getKernelProperty(self, name):
   ret = Interface.getPropertyKernel(self.get(), name)
   if ret.status > 0:
@@ -140,8 +133,6 @@ def _getKernelProperty(self, name):
   raise KeyError(msg)
 
 # ---------------------------------------------------------------------------
-
-
 def _setKernelProperty(self, name, value):
   if Interface.setPropertyKernel(self.get(), str(name), str(value)):
     return
@@ -149,8 +140,6 @@ def _setKernelProperty(self, name, value):
   raise KeyError(msg)
 
 # ---------------------------------------------------------------------------
-
-
 def _kernel_terminate(self):
   return self.get().terminate()
 
@@ -162,8 +151,6 @@ Kernel.terminate = _kernel_terminate
 # ---------------------------------------------------------------------------
 ActionHandle = digi.ActionHandle
 # ---------------------------------------------------------------------------
-
-
 def Action(kernel, nam, parallel=False):
   obj = Interface.createAction(kernel, str(nam))
   obj.parallel = parallel
@@ -204,23 +191,13 @@ 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')
-
+  cls = getattr(current, obj)
+  setattr(cls, '__adopt', getattr(cls, 'adopt'))
+  setattr(cls, 'adopt', _adopt)
+  # setattr(cls,'add',_adopt)
+  return cls
 
-# ---------------------------------------------------------------------------
 def _get(self, name):
-  # import traceback
   a = Interface.toAction(self)
   ret = Interface.getProperty(a, name)
   if ret.status > 0:
@@ -229,188 +206,55 @@ def _get(self, 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
+  msg = 'DDDigiAction::GetProperty [Unhandled]: Cannot access property ' + a.name() + '.' + name
   raise KeyError(msg)
 
-
 def _set(self, name, value):
+  """This function is called when properties are passed to the c++ objects."""
   a = Interface.toAction(self)
-  if Interface.setProperty(a, name, str(value)):
+  name  = unicode_2_string(name)
+  value = unicode_2_string(value)
+  if Interface.setProperty(a, name, value):
     return
-  msg = 'DigiAction::SetProperty [Unhandled]: Cannot set ' + a.name() + '.' + name + ' = ' + str(value)
+  msg = 'DDDigiAction::SetProperty [Unhandled]: Cannot set ' + a.name() + '.' + name + ' = ' + value
   raise KeyError(msg)
 
-
-def _props(obj):
+def _props(obj, **extensions):
   _import_class('digi', obj)
-  cl = getattr(current, obj)
-  cl.__getattr__ = _get
-  cl.__setattr__ = _set
+  cls = getattr(current, obj)
+  for extension in extensions.items():
+    setattr(cls, extension[0], extension[1])
+  cls.__getattr__ = _get
+  cls.__setattr__ = _set
+  return cls
 
+_setup('DigiActionSequence')
+_setup('DigiSynchronize')
+
+_import_class('digi', 'DigiKernel')
+_import_class('digi', 'DigiContext')
+_import_class('digi', 'DigiAction')
+_import_class('digi', 'DigiEventAction')
+_import_class('digi', 'DigiInputAction')
 
 _props('ActionHandle')
+_props('EventActionHandle')
+_props('InputActionHandle')
 _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())  # noqa: F405
-      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):
-    logger.info('+++  List of sensitive detectors:')
-    dets = self.activeDetectors()
-    for d in dets:
-      logger.info('+++  %-32s ---> type:%-12s', d['name'], d['type'])
-
-  def setupDetector(self, name, collections=None, modules=None):
-    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:
-          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)  # noqa: F405
-    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")  # noqa: F405
-    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")  # noqa: F405
-    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")  # noqa: F405
-      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
+def adopt_sequence_action(self, name, **options):
+  kernel = Interface.createKernel(Interface.toAction(self))
+  action = EventAction(kernel, name)
+  for option in options.items():
+    setattr(action, option[0], option[1])
+  self.adopt(action)
+  return action
+
+_props('DigiSynchronize')
+_props('DigiActionSequence', adopt_action = adopt_sequence_action)
+_props('DigiParallelActionSequence', adopt_action = adopt_sequence_action)
+_props('DigiSequentialActionSequence', adopt_action = adopt_sequence_action)
+
+import digitize
+Digitize = digitize.Digitize
diff --git a/DDDigi/python/digitize.py b/DDDigi/python/digitize.py
new file mode 100644
index 0000000000000000000000000000000000000000..a6511e30910cab6ac63f1610fe20b70ad67a96f0
--- /dev/null
+++ b/DDDigi/python/digitize.py
@@ -0,0 +1,201 @@
+# ==========================================================================
+#  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 dd4hep
+import dddigi
+
+"""
+   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
+
+    #import pdb
+    #pdb.set_trace()
+
+"""
+class Digitize(dd4hep.Logger):
+  def __init__(self, kernel=None):
+    dd4hep.Logger.__init__(self, 'dddigi')
+    self._kernel = kernel
+    self._main_processor = None
+    self._input_processor = None
+    self._event_processor = None
+    self._parallel = True
+    self.description = self._kernel.detectorDescription()
+
+  """
+     Access the worker kernel object.
+
+     \author  M.Frank
+  """
+
+  def kernel(self):
+    return self._kernel
+
+  def main_sequencer(self):
+    if not self._main_processor:
+      self._main_processor = dddigi.Synchronize(self._kernel, 'DigiSynchronize/MainDigitizer', self._parallel)
+      self._main_processor.parallel = self._parallel
+    return self._main_processor
+
+  def new_action(self, name, **options):
+    action = dddigi.EventAction(self._kernel, name)
+    for option in options.items():
+      setattr(action, option[0], option[1])
+    return action
+
+  def input_action(self, name=None, **options):
+    """
+    Append a new action to the kernel's main input action sequence
+    """
+    if not self._input_processor:
+      self._input_processor = self._kernel.inputAction()
+      self._input_processor.parallel = self._parallel
+
+    if not name:
+      return self._input_processor
+
+    act = self.new_action(name, **options)
+    self._input_processor.adopt(act)
+    return act
+
+  def event_action(self, name=None, **options):
+    """
+    Append a new action to the kernel's main event action sequence
+    """
+    if not self._event_processor:
+      self._event_processor = self._kernel.eventAction()
+      self._event_processor.parallel = self._parallel
+
+    if not name:
+      return self._event_processor
+
+    action = self.new_action(name, **options)
+    self._event_processor.adopt(action)
+    return action
+
+  def output_action(self, name=None, **options):
+    """
+    Append a new action to the kernel's main output action sequence
+    """
+    if not self._output_processor:
+      self._output_processor = self._kernel.outputAction()
+      self._output_processor.parallel = self._parallel
+
+    if not name:
+      return self._output_processor
+
+    act = self.new_action(name, **options)
+    self._output_processor.adopt(act)
+    return act
+
+  def events_done(self):
+    """
+    Access the number of events which finished processing
+    """
+    return self.kernel().events_done()
+
+  def events_submitted(self):
+    """
+    Access the number of submitted events
+    """
+    return self.kernel().events_submitted()
+
+  def events_processing(self):
+    """
+    Access the currently number of processing events (events in-flight)
+    """
+    return self.kernel().events_processing()
+
+  
+
+  """
+     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())  # noqa: F405
+      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):
+    logger.info('+++  List of sensitive detectors:')
+    dets = self.activeDetectors()
+    for d in dets:
+      logger.info('+++  %-32s ---> type:%-12s', d['name'], d['type'])
+
+  def setupDetector(self, name, collections=None, modules=None):
+    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:
+          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)  # noqa: F405
+    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
+
+  """
+     Execute the main Digi action
+     \author  M.Frank
+  """
+  def run(self, num_events, num_threads, parallel):
+    krnl = self.kernel()
+    krnl.numEvents = num_events
+    krnl.numThreads = num_threads   # = number of concurrent threads
+    krnl.maxEventsParallel = parallel
+    krnl.run()
+    return krnl.events_done()
diff --git a/DDDigi/src/DigiAction.cpp b/DDDigi/src/DigiAction.cpp
index 401e27fe8e95ece6924295e8839954997ea20e2d..4e1aaee7ab5492ed41a7c64bb8c7440d94fc6cee 100644
--- a/DDDigi/src/DigiAction.cpp
+++ b/DDDigi/src/DigiAction.cpp
@@ -12,33 +12,31 @@
 //==========================================================================
 
 // Framework include files
-#include "DD4hep/Printout.h"
-#include "DD4hep/InstanceCount.h"
-#include "DDDigi/DigiAction.h"
+#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) {
+TypeName TypeName::split(const std::string& type_name, const std::string& delim) {
+  std::size_t idx = type_name.find(delim);
+  std::string typ = type_name, nam = type_name;
+  if (idx != std::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) {
+TypeName TypeName::split(const std::string& type_name) {
   return split(type_name,"/");
 }
 
 /// Standard constructor
-DigiAction::DigiAction(const DigiKernel& krnl, const string& nam)
+DigiAction::DigiAction(const DigiKernel& krnl, const std::string& nam)
   : m_kernel(krnl), m_name(nam), m_outputLevel(INFO)
 {
   InstanceCount::increment(this);
@@ -69,25 +67,25 @@ long DigiAction::release() {
 }
 
 /// Set the output level; returns previous value
-PrintLevel DigiAction::setOutputLevel(PrintLevel new_level)  {
+dd4hep::PrintLevel DigiAction::setOutputLevel(PrintLevel new_level)  {
   int old = m_outputLevel;
   m_outputLevel = new_level;
   return (PrintLevel)old;
 }
 
 /// Check property for existence
-bool DigiAction::hasProperty(const string& nam) const    {
+bool DigiAction::hasProperty(const std::string& nam) const    {
   return m_properties.exists(nam);
 }
 
 /// Access single property
-Property& DigiAction::property(const string& nam)   {
+dd4hep::Property& DigiAction::property(const std::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);
+  int level = std::max(int(outputLevel()),(int)VERBOSE);
   if ( level >= printLevel() )  {
     va_list args;
     va_start(args, fmt);
@@ -98,7 +96,7 @@ void DigiAction::print(const char* fmt, ...) const   {
 
 /// 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);
+  int level = std::max(outputLevel()-1,(int)VERBOSE);
   if ( level >= printLevel() )  {
     va_list args;
     va_start(args, fmt);
@@ -109,7 +107,7 @@ void DigiAction::printM1(const char* fmt, ...) const   {
 
 /// 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);
+  int level = std::max(outputLevel()-2,(int)VERBOSE);
   if ( level >= printLevel() )  {
     va_list args;
     va_start(args, fmt);
@@ -120,7 +118,7 @@ void DigiAction::printM2(const char* fmt, ...) const   {
 
 /// 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);
+  int level = std::min(outputLevel()+1,(int)FATAL);
   if ( level >= printLevel() )  {
     va_list args;
     va_start(args, fmt);
@@ -131,7 +129,7 @@ void DigiAction::printP1(const char* fmt, ...) const   {
 
 /// 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);
+  int level = std::min(outputLevel()+2,(int)FATAL);
   if ( level >= printLevel() )  {
     va_list args;
     va_start(args, fmt);
@@ -140,6 +138,15 @@ void DigiAction::printP2(const char* fmt, ...) const   {
   }
 }
 
+/// Support of debug messages.
+std::string DigiAction::format(const char* fmt, ...) const {
+  va_list args;
+  va_start(args, fmt);
+  std::string str = dd4hep::format(nullptr, fmt, args);
+  va_end(args);
+  return str;
+}
+
 /// Support of debug messages.
 void DigiAction::debug(const char* fmt, ...) const {
   va_list args;
@@ -193,10 +200,10 @@ void DigiAction::fatal(const char* fmt, ...) const {
 void DigiAction::except(const char* fmt, ...) const {
   va_list args;
   va_start(args, fmt);
-  string err = dd4hep::format(m_name, fmt, args);
+  std::string err = dd4hep::format(m_name, fmt, args);
   dd4hep::printout(dd4hep::FATAL, m_name, err.c_str());
   va_end(args);
-  throw runtime_error(err);
+  throw std::runtime_error(err);
 }
 
 /// Optional action initialization if required
diff --git a/DDDigi/src/DigiActionSequence.cpp b/DDDigi/src/DigiActionSequence.cpp
index b98370dcf4d598a25fe4dc94b777df9e9eff9312..b705e4953ff8841088ecb3e6c507ae84d126e64f 100644
--- a/DDDigi/src/DigiActionSequence.cpp
+++ b/DDDigi/src/DigiActionSequence.cpp
@@ -45,6 +45,32 @@ 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));
+       context.event->eventNumber, yes_no(m_parallel));
   m_end(&context);
 }
+
+/// Standard constructor
+DigiSequentialActionSequence::DigiSequentialActionSequence(const DigiKernel& kernel, const string& nam)
+  : DigiActionSequence(kernel, nam)
+{
+  this->m_parallel = false;
+  InstanceCount::increment(this);
+}
+
+/// Default destructor
+DigiSequentialActionSequence::~DigiSequentialActionSequence() {
+  InstanceCount::decrement(this);
+}
+
+/// Standard constructor
+DigiParallelActionSequence::DigiParallelActionSequence(const DigiKernel& kernel, const string& nam)
+  : DigiActionSequence(kernel, nam)
+{
+  this->m_parallel = true;
+  InstanceCount::increment(this);
+}
+
+/// Default destructor
+DigiParallelActionSequence::~DigiParallelActionSequence() {
+  InstanceCount::decrement(this);
+}
diff --git a/DDDigi/src/DigiContainerCombine.cpp b/DDDigi/src/DigiContainerCombine.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d5d4065d53302337c98e32d27eaa5aaba3399dd2
--- /dev/null
+++ b/DDDigi/src/DigiContainerCombine.cpp
@@ -0,0 +1,194 @@
+//==========================================================================
+//  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/DigiData.h"
+#include "DDDigi/DigiContext.h"
+#include "DDDigi/DigiContainerCombine.h"
+
+using dd4hep::digi::DigiContainerCombine;
+
+class DigiContainerCombine::internals_t   {
+public:
+  /// Property: Container names to be loaded
+  std::vector<std::string>       containers { };
+  /// Property: event masks to be handled
+  std::vector<int>               masks  { };
+  /// Property: Output container dressing
+  std::string                    output_name_flag;
+  /// Property: Input data segment name
+  std::string                    input;
+  /// Property: Output data segment name
+  std::string                    output;
+  /// Property: mask of the deposit
+  int                            deposit_mask { 0 };
+  /// Property: Flag to erase already combined containers (not thread-safe!!!)
+  bool                           erase_combined { false };
+
+  /// Fully qualified keys of all containers to be manipulated
+  std::set<Key::key_type>        keys  { };
+  /// Container keys of all containers to be manipulated
+  std::set<Key::key_type>        cont_keys  { };
+  /// Predicate function to select containers for merging
+  std::function<bool(Key::key_type)>  container_selector;
+  /// Flag to check the initialization
+  bool inited  { false };
+  /// Initializing function: compute values which depend on properties
+  void initialize(DigiContext& context)   {
+    if ( !this->inited )   {
+      std::lock_guard<std::mutex> lock(context.initializer_lock());
+      if ( !this->inited )   {
+	this->inited = true;
+
+	this->container_selector = [this](Key::key_type k)  {
+	  const auto& m = this->masks;
+	  bool use = m.empty() || this->keys.empty();
+	  if ( !use )  {
+	    use = std::find(m.begin(), m.end(), Key::mask(k)) != m.end();
+	    if ( !use )   {
+	      return this->cont_keys.find(Key::item(k)) != this->cont_keys.end();
+	    }
+	  }
+	  return true;
+	};
+	for ( const auto& c : this->containers )   {
+	  Key key(0x0, c);
+	  this->cont_keys.emplace(key.key);
+	  if ( this->masks.empty() )   {
+	    this->keys.emplace(key.key);
+	    continue;
+	  }
+	  for ( int m : this->masks )    {
+	    key.values.mask = m;
+	    this->keys.emplace(key.key);
+	  }
+	}
+      }
+    }
+  }
+};
+
+/// Standard constructor
+dd4hep::digi::DigiContainerCombine::DigiContainerCombine(const DigiKernel& krnl, const std::string& nam)
+  : DigiEventAction(krnl, nam)
+{
+  this->internals = std::make_unique<internals_t>();
+  this->declareProperty("containers",       this->internals->containers);
+  this->declareProperty("masks",            this->internals->masks);
+  this->declareProperty("input_segment",    this->internals->input  = "inputs");
+  this->declareProperty("output_segment",   this->internals->output = "deposits");
+  this->declareProperty("deposit_mask",     this->internals->deposit_mask);
+  this->declareProperty("output_name_flag", this->internals->output_name_flag);
+  this->declareProperty("erase_combined",   this->internals->erase_combined);
+  InstanceCount::increment(this);
+}
+
+/// Default destructor
+dd4hep::digi::DigiContainerCombine::~DigiContainerCombine() {
+  InstanceCount::decrement(this);
+}
+
+/// Combine selected containers to one single deposit container
+template <typename PREDICATE> std::size_t 
+dd4hep::digi::DigiContainerCombine::combine_containers(DigiEvent& event,
+						       DigiEvent::container_map_t& inputs,
+						       DigiEvent::container_map_t& outputs,
+						       const PREDICATE& predicate)  const
+{
+  std::size_t cnt_depos = 0;
+  std::size_t cnt_parts = 0;
+  std::size_t cnt_conts = 0;
+  std::vector<Key::key_type> to_erase;
+
+  for( auto& i : inputs )   {
+    if ( predicate(i.first) )   {
+      Key depo_key(i.first);
+      Key input_key(i.first);
+      DepositMapping* din = std::any_cast<DepositMapping>(&i.second);
+      if ( din )   {
+	depo_key.values.mask = internals->deposit_mask;
+	cnt_depos += din->size();
+	cnt_conts++;
+	auto iter = outputs.find(depo_key.key);
+	if ( iter == outputs.end() )   {
+	  this->info("%s+++ %-32s Mask: %06X Input: %06X Merged %6ld deposits",
+		     event.id(), din->name.c_str(), depo_key.values.mask, 
+		     input_key.values.mask, din->size()); 
+	  if ( !internals->output_name_flag.empty() )   {
+	    din->name = din->name+"/"+internals->output_name_flag;
+	  }
+	  outputs.emplace(depo_key.key, std::move(i.second));
+	  to_erase.emplace_back(i.first);
+	  continue;
+	}
+	DepositMapping* out = std::any_cast<DepositMapping>(&iter->second);
+	std::size_t cnt = out->merge(std::move(*din));
+	this->info("%s+++ %-32s Mask: %06X Input: %06X Merged %6ld deposits",
+		   event.id(), out->name.c_str(), depo_key.values.mask, 
+		   input_key.values.mask, cnt); 
+	i.second.reset();
+	to_erase.emplace_back(i.first);
+	continue;
+      }
+      ParticleMapping* pin = std::any_cast<ParticleMapping>(&i.second);
+      if ( pin )   {
+	depo_key.values.mask = internals->deposit_mask;
+	cnt_parts += pin->size();
+	cnt_conts++;
+	auto iter = outputs.find(depo_key.key);
+	if ( iter == outputs.end() )   {
+	  this->info("%s+++ %-32s Mask: %06X Input: %06X Merged %6ld particles",
+		     event.id(), pin->name.c_str(), depo_key.values.mask, 
+		     input_key.values.mask, pin->size()); 
+	  if ( !internals->output_name_flag.empty() )   {
+	    pin->name = pin->name+"/"+internals->output_name_flag;
+	  }
+	  outputs.emplace(depo_key.key, std::move(i.second));
+	  to_erase.emplace_back(i.first);
+	  continue;
+	}
+	ParticleMapping* out = std::any_cast<ParticleMapping>(&iter->second);
+	std::size_t cnt = out->merge(std::move(*pin));
+	this->info("%s+++ %-32s Mask: %06X Input: %06X Merged %6ld particles",
+		   event.id(), out->name.c_str(), depo_key.values.mask, 
+		   input_key.values.mask, cnt); 
+	i.second.reset();
+	to_erase.emplace_back(i.first);
+	continue;
+      }      
+    }
+  }
+  if ( this->internals->erase_combined )   {
+    for(auto key : to_erase)   {
+      auto iter = inputs.find(key);
+      if ( iter != inputs.end() )   {
+	inputs.erase(iter);
+      }
+    }
+  }
+  this->info("%s+++ Merged %ld particles and %ld deposits from %ld containers",
+	     event.id(), cnt_parts, cnt_depos, cnt_conts);
+  return cnt_depos;
+}
+
+/// Main functional callback
+void dd4hep::digi::DigiContainerCombine::execute(DigiContext& context)  const    {
+  this->internals->initialize(context);
+  auto& event    = *context.event;
+  auto& inputs   = event.get_segment(this->internals->input);
+  auto& outputs  = event.get_segment(this->internals->output);
+  auto& selector = this->internals->container_selector;
+  this->combine_containers(event, inputs, outputs, selector);
+}
diff --git a/DDDigi/src/DigiContext.cpp b/DDDigi/src/DigiContext.cpp
index 3575def8f6db8c9b8051e87658bf418401fdb415..84f659f49a2519268c37e5555b51daf1a284a665 100644
--- a/DDDigi/src/DigiContext.cpp
+++ b/DDDigi/src/DigiContext.cpp
@@ -12,25 +12,20 @@
 //==========================================================================
 
 // Framework include files
-#include "DD4hep/Printout.h"
-#include "DD4hep/InstanceCount.h"
-#include "DDDigi/DigiContext.h"
-#include "DDDigi/DigiKernel.h"
+#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)
+DigiContext::DigiContext(const DigiKernel& k, std::unique_ptr<DigiEvent>&& e)
+  : kernel(k), event(std::move(e))
 {
-  if ( !m_kernel )    {
-    except("DigiContext","Cannot initialize Digitization context with invalid DigiKernel!");
-  }
   InstanceCount::increment(this);
 }
 
@@ -40,40 +35,43 @@ DigiContext::~DigiContext() {
   InstanceCount::decrement(this);
 }
 
-/// Set the geant4 event reference
-void DigiContext::setEvent(DigiEvent* new_event)   {
-  m_event = new_event;
+/// Have a shared initializer lock
+std::mutex& DigiContext::initializer_lock()  const  {
+  return kernel.initializer_lock();
 }
 
-/// 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;
+/// Have a global I/O lock (e.g. for ROOT)
+std::mutex& DigiContext::global_io_lock()   const  {
+  return kernel.global_io_lock();
+}
+
+/// Have a global output log lock
+std::mutex& DigiContext::global_output_lock()   const  {
+  return kernel.global_output_lock();
 }
 
 /// Access to detector description
-Detector& DigiContext::detectorDescription()  const {
-  return m_kernel->detectorDescription();
+dd4hep::Detector& DigiContext::detectorDescription()  const {
+  return kernel.detectorDescription();
 }
 
 /// Generic framework access
 DigiContext::UserFramework& DigiContext::userFramework()  const  {
-  return m_kernel->userFramework();
+  return kernel.userFramework();
 }
 
 /// Access to the main input action sequence from the kernel object
 DigiActionSequence& DigiContext::inputAction() const    {
-  return m_kernel->inputAction();
+  return kernel.inputAction();
 }
 
 /// Access to the main event action sequence from the kernel object
 DigiActionSequence& DigiContext::eventAction()  const  {
-  return m_kernel->eventAction();
+  return kernel.eventAction();
 }
 
 /// Access to the main output action sequence from the kernel object
 DigiActionSequence& DigiContext::outputAction() const    {
-  return m_kernel->outputAction();
+  return kernel.outputAction();
 }
 
diff --git a/DDDigi/src/DigiDDG4Input.cpp b/DDDigi/src/DigiDDG4Input.cpp
deleted file mode 100644
index c39ed2ba1c4c753945bf6dc109f181d6550d154d..0000000000000000000000000000000000000000
--- a/DDDigi/src/DigiDDG4Input.cpp
+++ /dev/null
@@ -1,43 +0,0 @@
-//==========================================================================
-//  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/DigiDDG4Input.h"
-
-// C/C++ include files
-#include <stdexcept>
-#include <unistd.h>
-
-using namespace std;
-using namespace dd4hep::digi;
-
-/// Standard constructor
-DigiDDG4Input::DigiDDG4Input(const DigiKernel& kernel, const string& nam)
-  : DigiInputAction(kernel, nam)
-{
-  InstanceCount::increment(this);
-}
-
-/// Default destructor
-DigiDDG4Input::~DigiDDG4Input()   {
-  InstanceCount::decrement(this);
-}
-
-/// Pre-track action callback
-void DigiDDG4Input::execute(DigiContext& /* context */)  const   {
-  ::sleep(1);
-  info("+++ Virtual method execute()");
-  return;
-  //except("DigiDDG4Input","+++ Virtual method execute() MUST be overloaded!");
-}
diff --git a/DDDigi/src/DigiData.cpp b/DDDigi/src/DigiData.cpp
index dc70a2aef7e18ae626e6a323b4b2fa614e2da993..b3586757e2f6983a8bc79d1a2650ef4af10d94bc 100644
--- a/DDDigi/src/DigiData.cpp
+++ b/DDDigi/src/DigiData.cpp
@@ -21,61 +21,167 @@
 // C/C++ include files
 #include <mutex>
 
-using namespace std;
-using namespace dd4hep;
-using namespace dd4hep::digi;
+namespace   {
+  struct digi_keys   {
+    std::mutex  lock;
+    std::map<unsigned long, std::string> map;
+  };
+  digi_keys& keys()  {
+    static digi_keys k;
+    return k;
+  }
+}
 
-Key::Key()    {
-  key = 0;
+dd4hep::digi::Key::Key()    {
+  this->key = 0;
 }
 
-Key::Key(const Key& copy)   {
-  key = copy.key;
+dd4hep::digi::Key::Key(const Key& copy)   {
+  this->key = copy.key;
 }
 
-Key::Key(mask_type mask, itemkey_type item)   {
-  key = 0;
-  values.mask = mask;
-  values.item = item;
+dd4hep::digi::Key::Key(key_type full_mask)   {
+  this->key = full_mask;
 }
 
-Key::Key(mask_type mask, const std::string& item)  {
-  key = 0;
-  values.mask = mask;
-  values.item = detail::hash32(item);
+dd4hep::digi::Key::Key(mask_type mask, const std::string& item)  {
+  auto& _k = keys();
+  this->key = 0;
+  this->values.mask = mask;
+  this->values.item = detail::hash32(item);
+  std::lock_guard<std::mutex> lock(_k.lock);
+  _k.map[key] = item;
 }
 
-Key& Key::operator=(const Key& copy)   {
-  key = copy.key;
+dd4hep::digi::Key& dd4hep::digi::Key::operator=(const Key& copy)   {
+  this->key = copy.key;
   return *this;
 }
 
-void Key::set(const std::string& name, int mask)    {
-  static std::mutex mtx;
-  std::lock_guard<std::mutex> lock(mtx);
+void dd4hep::digi::Key::set(const std::string& name, int mask)    {
+  auto& _k = keys();
   if ( name.empty() )   {
+    std::lock_guard<std::mutex> lock(_k.lock);
     except("DDDigi::Key", "+++ No key name was specified  --  this is illegal!");
   }
-  values.mask = (unsigned char)(0xFF&mask);
-  values.item = detail::hash32(name);
+  this->values.mask = (unsigned char)(0xFF&mask);
+  this->values.item = detail::hash32(name);
+  std::lock_guard<std::mutex> lock(_k.lock);
+  _k.map[this->key] = name;
+}
+
+/// Access key name (if registered properly)
+std::string dd4hep::digi::Key::key_name(const Key& k)    {
+  auto& _k = keys();
+  std::lock_guard<std::mutex> lock(_k.lock);
+  std::map<unsigned long, std::string>::const_iterator it = _k.map.find(k.key);
+  if ( it != _k.map.end() ) return it->second;
+  Key kk;
+  kk.values.item = ~0x0;
+  for( const auto& e : _k.map )   {
+    if ( (e.first & kk.key) == k.values.item )
+      return e.second;
+  }
+  return "UNKNOWN";
+}
+
+/// Merge new deposit map onto existing map
+std::size_t dd4hep::digi::DepositMapping::merge(DepositMapping&& updates)    {
+  std::size_t update_size = updates.size();
+  for( auto& c : updates )    {
+    CellID         cell = c.first;
+    EnergyDeposit& depo = c.second;
+    auto iter = this->find(cell);
+    if ( iter == this->end() )   {
+      this->emplace(cell, std::move(depo));
+      continue;
+    }
+    auto& to_update = iter->second;
+    to_update.deposit += depo.deposit;
+    to_update.history.insert(to_update.history.end(), depo.history.begin(), depo.history.end());
+  }
+  return update_size;
+}
+
+/// Merge new deposit map onto existing map
+std::size_t dd4hep::digi::ParticleMapping::merge(ParticleMapping&& updates)    {
+  std::size_t update_size = updates.size();
+  for( ParticleMapping::value_type& c : updates )    {
+    Particle part(std::move(c.second));
+    this->push(c.first, std::move(part));
+  }
+  return update_size;
+}
+
+void dd4hep::digi::ParticleMapping::push(Key::key_type k, Particle&& part)  {
+  auto ret = this->emplace(k, std::move(part)).second;
+  if ( !ret )   {
+    Key key(k);
+    except("ParticleMapping","Error in particle map. Duplicate ID: mask:%04X Number:%d",
+	   key.values.mask, key.values.item);
+  }
 }
 
 /// Intializing constructor
-DigiEvent::DigiEvent()
+dd4hep::digi::DigiEvent::DigiEvent()
   : ObjectExtensions(typeid(DigiEvent))
 {
   InstanceCount::increment(this);
 }
 
 /// Intializing constructor
-DigiEvent::DigiEvent(int ev_num)
+dd4hep::digi::DigiEvent::DigiEvent(int ev_num)
   : ObjectExtensions(typeid(DigiEvent)), eventNumber(ev_num)
 {
+  char text[32];
+  ::snprintf(text, sizeof(text), "Ev:%06d ", ev_num);
+  m_id = text;
   InstanceCount::increment(this);
 }
 
 /// Default destructor
-DigiEvent::~DigiEvent()
+dd4hep::digi::DigiEvent::~DigiEvent()
 {
   InstanceCount::decrement(this);
 }
+
+/// Retrieve data segment from the event structure
+dd4hep::digi::DigiEvent::container_map_t& 
+dd4hep::digi::DigiEvent::get_segment(const std::string& name)   {
+  switch(::toupper(name[0]))   {
+  case 'I':
+    return this->inputs;
+  case 'D':
+    return this->deposits;
+  case 'O':
+    return this->data;
+  }
+  throw std::runtime_error("Invalid segment name: "+name);
+}
+
+/// Add item by key to the data 
+bool dd4hep::digi::DigiEvent::put_data(unsigned long key, std::any&& object)     {
+  std::lock_guard<std::mutex> lock(m_lock);
+  bool ret = data.emplace(key,object).second;
+  if ( ret ) return ret;
+
+  std::string name = Key::key_name(key);
+  uint32_t    mask = Key::mask(key);
+  except("DigiEvent","%s+++ Invalid requested to store object in data  container [key present]."
+	 " Key:%ld [Mask:%04X, name:%s]", this->id(), key, mask, name.c_str());
+  throw std::runtime_error("DigiEvent"); // Will never get here!
+}
+
+/// Add item by key to the data 
+bool dd4hep::digi::DigiEvent::put_input(unsigned long key, std::any&& object)     {
+  std::lock_guard<std::mutex> lock(m_lock);
+  bool ret = inputs.emplace(key,object).second;
+  if ( ret ) return ret;
+
+  std::string name = Key::key_name(key);
+  uint32_t    mask = Key::mask(key);
+  except("DigiEvent","%s+++ Invalid requested to store object in input container [key present]."
+	 " Key:%ld [Mask:%04X, name:%s]", this->id(), key, mask, name.c_str());
+  throw std::runtime_error("DigiEvent"); // Will never get here!
+}
+
diff --git a/DDDigi/src/DigiHandle.cpp b/DDDigi/src/DigiHandle.cpp
index 4dc7bf3eb37eecfa37609e226af4bd7fd492f295..2b6156331ef7416c074341d76583873b4ac54be9 100644
--- a/DDDigi/src/DigiHandle.cpp
+++ b/DDDigi/src/DigiHandle.cpp
@@ -18,6 +18,7 @@
 
 #include "DDDigi/DigiHandle.h"
 #include "DDDigi/DigiKernel.h"
+#include "DDDigi/DigiInputAction.h"
 #include "DDDigi/DigiEventAction.h"
 #include "DDDigi/DigiSignalProcessor.h"
 
@@ -62,12 +63,15 @@ namespace dd4hep {
       DigiEventAction* object = PluginService::Create<DigiEventAction*>(t, &kernel, n);
       return object ? dynamic_cast<T*>(object) : nullptr;
     }
+
     template <> DigiAction* _raw_create<DigiAction>(const std::string& t, const DigiKernel& kernel, const std::string& n)    {
       return PluginService::Create<DigiAction*>(t, &kernel, n);
     }
+
     template <> DigiSignalProcessor* _raw_create<DigiSignalProcessor>(const std::string& t, const DigiKernel& kernel, const std::string& n)    {
       return PluginService::Create<DigiSignalProcessor*>(t, &kernel, n);
     }
+
     template <typename TYPE> TYPE* _create_object(const DigiKernel& kernel, const TypeName& typ)    {
       TYPE* object = _raw_create<TYPE>(typ.first, kernel, typ.second);
       if (!object && typ.first == typ.second) {
@@ -177,6 +181,7 @@ namespace dd4hep {
     KernelHandle::KernelHandle()  {
       value = &DigiKernel::instance(Detector::getInstance());
     }
+
     KernelHandle::KernelHandle(DigiKernel* k) : value(k)  {
     }
   }
@@ -190,6 +195,7 @@ namespace dd4hep {
   /// Namespace for the Digitization part of the AIDA detector description toolkit
   namespace digi {
     template class DigiHandle<DigiAction>;
+    template class DigiHandle<DigiInputAction>;
     template class DigiHandle<DigiEventAction>;
     template class DigiHandle<DigiSynchronize>;
     template class DigiHandle<DigiActionSequence>;
diff --git a/DDDigi/src/DigiHitAttenuatorExp.cpp b/DDDigi/src/DigiHitAttenuatorExp.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8b88fa2e22c92a1ebff298091249de499315f4f4
--- /dev/null
+++ b/DDDigi/src/DigiHitAttenuatorExp.cpp
@@ -0,0 +1,96 @@
+//==========================================================================
+//  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/DigiData.h"
+#include "DDDigi/DigiContext.h"
+#include "DDDigi/DigiHitAttenuatorExp.h"
+
+class dd4hep::digi::DigiHitAttenuatorExp::internals_t   {
+public:
+  /// Property: Input data segment name
+  std::string                    input  { };
+  /// Property: Container names to be loaded
+  std::map<std::string, double>  container_attenuation  { };
+  /// Property: event masks to be handled
+  std::vector<int>               masks  { };
+  /// Property: T0 with respect to central crossing
+  double                         t0     { 0e0 };
+
+  /// Keys of all containers to be manipulated
+  std::map<unsigned long, double> attenuation  { };
+
+  void initialize(DigiContext& context)   {
+    if ( this->attenuation.empty() )   {
+      std::lock_guard<std::mutex> lock(context.initializer_lock());
+      if ( this->attenuation.empty() )   {
+	for ( const auto& c : this->container_attenuation )   {
+	  Key key(0x0, c.first);
+	  for ( int m : this->masks )    {
+	    double factor = std::exp(-1e0 * this->t0/c.second);
+	    key.values.mask = m;
+	    this->attenuation.emplace(key.key, factor);
+	  }
+	}
+      }
+    }
+  }
+};
+
+/// Standard constructor
+dd4hep::digi::DigiHitAttenuatorExp::DigiHitAttenuatorExp(const DigiKernel& krnl, const std::string& nam)
+  : DigiEventAction(krnl, nam)
+{
+  internals = std::make_unique<internals_t>();
+  declareProperty("input",      internals->input = "inputs");
+  declareProperty("containers", internals->container_attenuation);
+  declareProperty("masks",      internals->masks);
+  declareProperty("t0",         internals->t0);
+  InstanceCount::increment(this);
+}
+
+/// Default destructor
+dd4hep::digi::DigiHitAttenuatorExp::~DigiHitAttenuatorExp() {
+  InstanceCount::decrement(this);
+}
+
+/// Main functional callback
+void dd4hep::digi::DigiHitAttenuatorExp::execute(DigiContext& context)  const    {
+  internals->initialize(context);
+  std::size_t count = 0;
+  auto& event  = context.event;
+  auto& inputs = event->get_segment(internals->input);
+  for ( const auto& k : internals->attenuation )     {
+    auto iter = inputs.find(k.first);
+    if ( iter != inputs.end() )   {
+      std::any& obj = (*iter).second;
+      DepositMapping* m = std::any_cast<DepositMapping>(&obj);
+      double factor = k.second;
+      if ( m )    {
+	for( auto& c : *m )    {
+	  c.second.deposit *= factor;
+	}
+	count += m->size();
+	std::string nam = Key::key_name(k.first)+":";
+	debug("%s+++ %-32s Mask: %06X Attenuated exponentially %6ld hits by %8.5f",
+	      event->id(), nam.c_str(), m->mask, m->size(), factor); 
+	continue;
+      }
+      error("Invalid data type in container");
+    }
+  }
+  info("%s+++ Attenuated exponentially %6ld hits", event->id(), count);
+}
+
diff --git a/DDDigi/src/DigiInputAction.cpp b/DDDigi/src/DigiInputAction.cpp
index 98b1589a5e3fffb0b4e17e7b8e77b31e35826384..2352bed75e12d793e1aaa22484e39bd2c435d5ec 100644
--- a/DDDigi/src/DigiInputAction.cpp
+++ b/DDDigi/src/DigiInputAction.cpp
@@ -26,7 +26,8 @@ using namespace dd4hep::digi;
 DigiInputAction::DigiInputAction(const DigiKernel& kernel, const string& nam)
   : DigiEventAction(kernel, nam)
 {
-  declareProperty("Input", m_input);
+  declareProperty("input",  m_inputs);
+  declareProperty("mask",   m_mask);
   InstanceCount::increment(this);
 }
 
@@ -37,8 +38,6 @@ DigiInputAction::~DigiInputAction()   {
 
 /// Pre-track action callback
 void DigiInputAction::execute(DigiContext& /* context */)  const   {
+  info("+++ Virtual method execute() --- Should not be called");
   ::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
index f168ef9b6998d4f5b90bdde925ee89fe72521121..995f054596daf18c3607a3d5015d9c1f65075ad9 100644
--- a/DDDigi/src/DigiKernel.cpp
+++ b/DDDigi/src/DigiKernel.cpp
@@ -33,7 +33,6 @@
 #include <memory>
 #include <chrono>
 
-using namespace std;
 using namespace dd4hep;
 using namespace dd4hep::digi;
 namespace  {
@@ -55,6 +54,22 @@ public:
   ClientOutputLevels    clientLevels;
   /// Atomic counter: Number of events still to be processed in this run
   std::atomic_int       eventsToDo;
+  /// Atomic counter: Number of events still to be processed in this run
+  std::atomic_int       eventsFinished;
+  /// Atomic counter: Number of events still to be processed in this run
+  std::size_t           eventsSubmitted;
+
+  /// Lock to ensure counter safety
+  std::mutex            counter_lock        { };
+
+  /// Lock to ensure initialization safetyp
+  std::mutex            initializer_lock    { };
+
+  /// Lock for global I/O dependencies
+  std::mutex            global_io_lock      { };
+
+  /// Lock for global output logging
+  std::mutex            global_output_lock  { };
 
   /// The main data input action sequence
   DigiActionSequence*   inputAction = 0;
@@ -118,16 +133,15 @@ public:
     while( todo >= 0 )   {
       todo = -1;
       {
-        std::lock_guard<std::mutex> lock(kernel_mutex);
+        std::lock_guard<std::mutex> lock(kernel.internals->counter_lock);
         if( !kernel.internals->stop && kernel.internals->eventsToDo > 0)
           todo = --kernel.internals->eventsToDo;
       }
       if ( todo >= 0 )   {
         int ev_num = kernel.internals->numEvents - todo;
-        unique_ptr<DigiContext> c(new DigiContext(&kernel));
-        unique_ptr<DigiEvent>   e(new DigiEvent(ev_num));
-        c->setEvent(e.release());
-        kernel.executeEvent(c.release());
+	std::unique_ptr<DigiContext> context = 
+	  std::make_unique<DigiContext>(this->kernel,std::make_unique<DigiEvent>(ev_num));
+        kernel.executeEvent(std::move(context));
       }
     }
   }
@@ -161,6 +175,7 @@ DigiKernel::DigiKernel(Detector& description_ref)
 
 /// Default destructor
 DigiKernel::~DigiKernel() {
+  std::lock_guard<std::mutex> lock(kernel_mutex);
 #ifdef DD4HEP_USE_TBB
   tbb::task_scheduler_init* init = (tbb::task_scheduler_init*)internals->tbbInit;
   if ( init ) delete init;
@@ -184,6 +199,21 @@ DigiKernel& DigiKernel::instance(Detector& description) {
   return *(s_main_instance.get());
 }
 
+/// Have a shared initializer lock
+std::mutex& DigiKernel::initializer_lock()   const  {
+  return internals->initializer_lock;
+}
+
+/// Have a global output log lock
+std::mutex& DigiKernel::global_output_lock()   const   {
+  return internals->global_output_lock;
+}
+
+/// Have a global I/O lock (e.g. for ROOT)
+std::mutex& DigiKernel::global_io_lock()   const  {
+  return internals->global_io_lock;
+}
+
 /// Access to the properties of the object
 PropertyManager& DigiKernel::properties()   {
   return internals->properties;
@@ -191,9 +221,9 @@ PropertyManager& DigiKernel::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);
+  printout(ALWAYS, "DigiKernel", "OutputLevel:  %d", internals->outputLevel);
+  for( const auto& cl : internals->clientLevels )  {
+    printout(ALWAYS, "DigiKernel", "OutputLevel[%s]:  %d", cl.first.c_str(), cl.second);
   }
 }
 
@@ -231,6 +261,27 @@ dd4hep::PrintLevel DigiKernel::setOutputLevel(PrintLevel new_level)  {
   return (PrintLevel)old;
 }
 
+/// Access current number of events still to process
+std::size_t DigiKernel::events_todo()  const   {
+  std::lock_guard<std::mutex> lock(this->internals->counter_lock);
+  std::size_t evts = this->internals->eventsToDo;
+  return evts;
+}
+
+/// Access current number of events already processed
+std::size_t DigiKernel::events_done()  const   {
+  std::lock_guard<std::mutex> lock(this->internals->counter_lock);
+  std::size_t evts = this->internals->numEvents - this->internals->eventsToDo;
+  return evts;
+}
+
+/// Access current number of events processing (events in flight)
+std::size_t DigiKernel::events_processing()  const   {
+  std::lock_guard<std::mutex> lock(this->internals->counter_lock);
+  std::size_t evts = this->internals->eventsSubmitted - this->internals->eventsFinished;
+  return evts;
+}
+
 /// Construct detector geometry using description plugin
 void DigiKernel::loadGeometry(const std::string& compact_file) {
   char* arg = (char*) compact_file.c_str();
@@ -267,7 +318,7 @@ DigiActionSequence& DigiKernel::outputAction() const    {
 }
 
 void DigiKernel::submit(const DigiAction::Actors<DigiEventAction>& actions, DigiContext& context)   const  {
-  chrono::system_clock::time_point start = chrono::system_clock::now();
+  std::chrono::system_clock::time_point start = std::chrono::system_clock::now();
   bool parallel = 0 != internals->tbbInit && internals->numThreads>0;
 #ifdef DD4HEP_USE_TBB
   if ( parallel )   {
@@ -282,9 +333,9 @@ void DigiKernel::submit(const DigiAction::Actors<DigiEventAction>& actions, Digi
   goto print_stamp;
 
  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(),
+  std::chrono::duration<double> secs = std::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());
 }
 
@@ -293,44 +344,43 @@ void DigiKernel::execute(const DigiAction::Actors<DigiEventAction>& actions, Dig
 }
 
 void DigiKernel::wait(DigiContext& context)   const  {
-  if ( context.eventPtr() ) {}
+  if ( context.event ) {}
 }
 
 /// Execute one single event
-void DigiKernel::executeEvent(DigiContext* context)    {
+void DigiKernel::executeEvent(std::unique_ptr<DigiContext>&& context)    {
   DigiContext& refContext = *context;
   try {
     inputAction().execute(refContext);
     eventAction().execute(refContext);
     outputAction().execute(refContext);
-    notify(context);
+    notify(std::move(context));
   }
-  catch(const exception& e)   {
-    notify(context, e);
+  catch(const std::exception& e)   {
+    notify(std::move(context), e);
   }
 }
 
-void DigiKernel::notify(DigiContext* context)   {
+void DigiKernel::notify(std::unique_ptr<DigiContext>&& context)   {
   if ( context )   {
-    DigiEvent* event = context->eventPtr();
-    if ( event )    {
-      context->setEvent(0);
-      detail::deletePtr(event);
-    }
-    delete context;
+    context->event.reset();
   }
+  context.reset();
+  ++internals->eventsFinished;
 }
 
-void DigiKernel::notify(DigiContext* context, const std::exception& e)   {
+void DigiKernel::notify(std::unique_ptr<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);
+  printout(ERROR,"DigiKernel","+++ Exception during event processing [Shall stop the event loop]");
+  printout(ERROR,"DigiKernel"," -> %s", e.what());
+  notify(std::move(context));
 }
 
 int DigiKernel::run()   {
-  chrono::system_clock::time_point start = chrono::system_clock::now();
+  std::chrono::system_clock::time_point start = std::chrono::system_clock::now();
   internals->stop = false;
+  internals->eventsFinished = 0;
+  internals->eventsSubmitted = 0;
   internals->eventsToDo = internals->numEvents;
   printout(INFO,
            "DigiKernel","+++ Total number of events:    %d",internals->numEvents);
@@ -338,10 +388,8 @@ int DigiKernel::run()   {
   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);
+    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;
@@ -350,25 +398,26 @@ int DigiKernel::run()   {
       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!");
+      printout(DEBUG, "DigiKernel", "+++ All event processing threads Synchronized --- Done!");
     }
   }
 #endif
   while ( internals->eventsToDo > 0 && !internals->stop )   {
     Processor proc(*this);
     proc();
+    ++internals->eventsSubmitted;
   }
-  chrono::duration<double> duration = chrono::system_clock::now() - start;
-  double sec = chrono::duration_cast<chrono::seconds>(duration).count();
-  printout(DEBUG,"DigiKernel","+++ %d Events out of %d processed. "
+  std::chrono::duration<double> duration = std::chrono::system_clock::now() - start;
+  double sec = std::chrono::duration_cast<std::chrono::seconds>(duration).count();
+  printout(DEBUG, "DigiKernel", "+++ %d Events out of %d processed. "
            "Total: %7.1f seconds %7.3f seconds/event",
-           internals->numEvents, internals->numEvents-int(internals->eventsToDo),
+           internals->numEvents-int(internals->eventsToDo), internals->numEvents,
            sec, sec/double(std::max(1,internals->numEvents)));
   return 1;
 }
 
 int DigiKernel::terminate() {
-  printout(INFO,"DigiKernel","++ Terminate Digi and delete associated actions.");
+  printout(INFO, "DigiKernel", "++ Terminate Digi and delete associated actions.");
   m_detDesc->destroyInstance();
   m_detDesc = 0;
   return 1;
diff --git a/DDDigi/src/DigiROOTInput.cpp b/DDDigi/src/DigiROOTInput.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..670bce10118903e3174019f3b589d7166764d751
--- /dev/null
+++ b/DDDigi/src/DigiROOTInput.cpp
@@ -0,0 +1,207 @@
+//==========================================================================
+//  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/DigiROOTInput.h>
+#include <DD4hep/Printout.h>
+#include <DD4hep/Factories.h>
+
+// ROOT include files
+#include <TROOT.h>
+#include <TFile.h>
+#include <TTree.h>
+
+// C/C++ include files
+#include <stdexcept>
+#include <map>
+
+using namespace dd4hep::digi;
+
+/// Helper class to hide connection parameters
+/**
+ *
+ *  \author  M.Frank
+ *  \version 1.0
+ *  \ingroup DD4HEP_DIGITIZATION
+ */
+class DigiROOTInput::internals_t   {
+public:
+  typedef std::function<std::any(int, const char*, void*)> func_t;
+
+  class converter_t   {
+  public:
+    TBranch* branch   { nullptr };
+    TClass*  cls      { nullptr };
+    std::unique_ptr<func_t>   call     { };
+  };
+
+  /// Mutex to allow re-use of a single source for multiple input streams
+  std::mutex m_lock        { };
+  std::map<unsigned long, converter_t>  branches;
+  /// Reference to the current ROOT file to be read
+  TFile*     file   { };
+  /// Reference to the ROOT tree to be read
+  TTree*     tree   { nullptr };
+  /// Pointer to current input source
+  int        input  { INPUT_START };
+  /// Current entry inside the current input source
+  Long64_t   entry  { -1 };
+
+public:
+  /// Default constructor
+  internals_t () = default;
+  /// Default destructor
+  ~internals_t ()   {
+    if ( file )    {
+      file->Close();
+      delete file;
+      file = nullptr;
+    }
+  }
+  /// Coverter function from input data to DDDige data
+  std::unique_ptr<func_t> input_converter(TClass* cl)  const   {
+    using detail::str_replace;
+    std::string cln = str_replace(cl->GetName(),"::","_");
+    cln = str_replace(str_replace(str_replace(cln,'<','_'),'>','_'),'*',"");
+    std::string factory = "DD4hep_DDDigiConverter_"+cln;
+    func_t *fptr = (func_t*)PluginService::Create<void*>(factory.c_str());
+    if ( 0 == fptr )   {
+      dd4hep::except("DigiROOTInput","Failed to access function pointer to read ROOT datatype: %s",cl->GetName());
+    }
+    return std::unique_ptr<func_t>(fptr);
+  }
+};
+
+
+/// Standard constructor
+DigiROOTInput::DigiROOTInput(const DigiKernel& kernel, const std::string& nam)
+  : DigiInputAction(kernel, nam)
+{
+  declareProperty("tree", m_tree_name = "EVENT");
+  declareProperty("containers", m_containers);
+  InstanceCount::increment(this);
+}
+
+/// Default destructor
+DigiROOTInput::~DigiROOTInput()   {
+  InstanceCount::decrement(this);
+}
+
+/// Open new input file
+void DigiROOTInput::open_new_file()   const  {
+  int len = this->m_inputs.size();
+  imp = std::make_unique<internals_t>();
+  if ( this->m_inputs.empty() ) imp->input = 0;
+  while ( (imp->input+1) < len )   {
+    const auto& fname = m_inputs[++imp->input];
+    imp->file = TFile::Open(fname.c_str());
+    if ( imp->file && imp->file->IsZombie() )  {
+      delete imp->file;
+      imp->file = nullptr;
+      error("OpenInput ++ Failed to open input source %s", fname.c_str());
+    }
+    else if ( imp->file )  {
+      imp->tree = (TTree*)imp->file->Get(this->m_tree_name.c_str());
+      if ( !imp->tree )   {
+	error("OpenInput ++ Failed to access tree: %s in input: %s", 
+	      this->m_tree_name.c_str(), fname.c_str());
+	continue;
+      }
+      imp->branches.clear();
+      auto* branches = imp->tree->GetListOfBranches();
+      TObjArrayIter it(branches);
+      for(Int_t i=0; i<branches->GetEntriesFast(); ++i)   {
+	TBranch*  b = (TBranch*)branches->At(i);
+	TClass* cls = gROOT->GetClass( b->GetClassName(), kTRUE );
+	/// If there are no required branches, we convert everything
+	if ( this->m_containers.empty() )    {
+	  Key key(this->m_mask, b->GetName());
+	  b->SetAutoDelete( kFALSE );
+	  imp->branches[key.key] = {b, cls, imp->input_converter(cls)};
+	  continue;
+	}
+	/// Otherwise only the entities asked for
+	for( const auto& bname : this->m_containers )    {
+	  if ( bname == b->GetName() )   {
+	    Key key(this->m_mask, b->GetName());
+	    b->SetAutoDelete( kFALSE );
+	    imp->branches[key.key] = {b, cls, imp->input_converter(cls)};
+	    break;
+	  }
+	}
+      }
+      break;
+    }
+    else   {
+      error("OpenInput ++ Failed to open input source %s", fname.c_str());
+    }
+    imp->file = nullptr;
+  }
+  if ( imp->input >= len )   {
+    imp.reset();
+    except("OpenInput ++ Failed to open NEW input source");
+  }
+}
+
+/// Pre-track action callback
+void DigiROOTInput::execute(DigiContext& context)  const   {
+  if ( imp )   {
+    std::lock_guard<std::mutex> lock(context.global_io_lock());
+    Int_t total = imp->tree->GetEntries();
+    if ( (1+imp->entry) >= total )   {
+      imp.reset();
+    }
+  }
+  /// If necessary open a new file
+  if ( !imp )   {
+    std::lock_guard<std::mutex> lock(context.global_io_lock());
+    open_new_file();
+  }
+  
+  if ( nullptr == imp->file )    {
+    except("+++ No open file present. Configuration error?");
+  }
+  if ( imp->branches.empty() )    {
+    except("+++ No branches to be loaded. Configuration error!");
+  }
+  std::size_t input_len = 0;
+  //
+  //  We have to lock all ROOT based actions. Consequences are SEGV otherwise.
+  //
+  auto& event = context.event;
+  std::lock_guard<std::mutex> lock(context.global_io_lock());
+  ++imp->entry;
+  imp->tree->LoadTree( imp->entry );
+
+  /// We only get here with a valid input
+  for( const auto& br : imp->branches )    {
+    void* obj = br.second.cls->New();
+    br.second.branch->SetAddress(&obj);
+  }
+  for( const auto& br : imp->branches )    {
+    TBranch* b = br.second.branch;
+    int nb = b->GetEntry( imp->entry );
+    if ( nb < 0 ) { // This is definitely an error...ROOT says if reads fail, -1 is issued.
+      continue;
+    }
+    debug("%s+++ Loaded %8d bytes from branch %s", event->id(), nb, b->GetName());
+    input_len += nb;
+    const auto&  func = *br.second.call;
+    void** addr = (void**)b->GetAddress();
+    auto data = func(this->m_mask, b->GetName(), *addr);
+    event->put_input(br.first, std::move(data));
+  }
+  info("%s+++ Read event %6ld [%ld bytes] from tree %s file: %s",
+       event->id(), imp->entry, input_len, imp->tree->GetName(), imp->file->GetName());
+}
diff --git a/DDDigi/src/DigiSegmentationSplitter.cpp b/DDDigi/src/DigiSegmentationSplitter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b94a2556bc5dc9457151c7280eacdf1e570df01b
--- /dev/null
+++ b/DDDigi/src/DigiSegmentationSplitter.cpp
@@ -0,0 +1,74 @@
+//==========================================================================
+//  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/DigiData.h"
+#include "DDDigi/DigiContext.h"
+#include "DDDigi/DigiSegmentationSplitter.h"
+
+using dd4hep::digi::DigiSegmentationSplitter;
+
+class DigiSegmentationSplitter::internals_t   {
+public:
+  /// Property: Identifier of the input repository
+  std::string input_id;
+  /// Property: Subdetector to handle
+  std::string detector_name;
+  /// Property: Input masks in the repository
+  std::vector<int> masks;
+
+  /// Flag to check the initialization
+  bool inited  { false };
+
+  /// Initializing function: compute values which depend on properties
+  void initialize(DigiContext& context)   {
+    if ( !this->inited )   {
+      std::lock_guard<std::mutex> lock(context.initializer_lock());
+      if ( !this->inited )   {
+	this->inited = true;
+      }
+    }
+  }
+};
+
+/// Standard constructor
+dd4hep::digi::DigiSegmentationSplitter::DigiSegmentationSplitter(const DigiKernel& krnl, const std::string& nam)
+  : DigiEventAction(krnl, nam)
+{
+  this->internals = std::make_unique<internals_t>();
+  declareProperty("input",    this->internals->input_id = "deposits");
+  declareProperty("detector", this->internals->detector_name);
+  declareProperty("masks",    this->internals->masks);
+  InstanceCount::increment(this);
+}
+
+/// Default destructor
+dd4hep::digi::DigiSegmentationSplitter::~DigiSegmentationSplitter() {
+  InstanceCount::decrement(this);
+}
+
+/// Split actions according to the segmentation
+void dd4hep::digi::DigiSegmentationSplitter::split_segments(DigiEvent& event,
+							    DigiEvent::container_map_t& data)  const
+{
+
+}
+
+/// Main functional callback
+void dd4hep::digi::DigiSegmentationSplitter::execute(DigiContext& context)  const    {
+  this->internals->initialize(context);
+  auto& data = context.event->get_segment(this->internals->input_id);
+  this->split_segments(*context.event, data);
+}
diff --git a/DDDigi/src/DigiStoreDump.cpp b/DDDigi/src/DigiStoreDump.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e15199e9ce6152fdce6af02c5889b89b650c08ff
--- /dev/null
+++ b/DDDigi/src/DigiStoreDump.cpp
@@ -0,0 +1,86 @@
+//==========================================================================
+//  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/DigiData.h"
+#include "DDDigi/DigiKernel.h"
+#include "DDDigi/DigiContext.h"
+#include "DDDigi/DigiStoreDump.h"
+
+/// Standard constructor
+dd4hep::digi::DigiStoreDump::DigiStoreDump(const DigiKernel& krnl, const std::string& nam)
+  : DigiEventAction(krnl, nam)
+{
+  declareProperty("history",       this->m_dump_history  = false);
+  declareProperty("data_segments", this->m_data_segments);
+  this->m_data_segments.push_back("input");
+  this->m_data_segments.push_back("deposits");
+  this->m_data_segments.push_back("data");
+  InstanceCount::increment(this);
+}
+
+/// Default destructor
+dd4hep::digi::DigiStoreDump::~DigiStoreDump() {
+  InstanceCount::decrement(this);
+}
+
+/// Dump hit container
+template <typename CONTAINER> 
+void dd4hep::digi::DigiStoreDump::dump(const std::string& tag,
+				       const DigiEvent& event,
+				       const CONTAINER& data_segment)  const
+{
+  std::string str;
+  std::vector<std::string> records;
+  using detail::str_replace;
+  info("%s+---- %s segment: %ld entries", event.id(), tag.c_str(), data_segment.size());
+  for ( const auto& e : data_segment )     {
+    Key key {e.first};
+    const std::any& data = e.second;
+    std::string nam = Key::key_name(key);
+    std::string typ = typeName(data.type());
+    std::size_t idx = typ.find(", std::less<long long>, std::allocator<std::pair");
+    if ( idx != std::string::npos ) typ = str_replace(typ, typ.substr(idx), ">");
+    typ = str_replace(str_replace(typ,"std::",""),"dd4hep::digi::","");
+    if ( const auto* hits = std::any_cast<DepositMapping>(&data) )   {
+      str = this->format("%s|---- %4X %08X %-32s: %6ld hits      [%s]", 
+			 event.id(), key.values.mask, key.values.item,
+			 nam.c_str(), hits->size(), typ.c_str());
+    }
+    else if ( const auto* parts = std::any_cast<ParticleMapping>(&data) )   {
+      str = this->format("%s|---- %4X %08X %-32s: %6ld particles [%s]", 
+			 event.id(), key.values.mask, key.values.item,
+			 nam.c_str(), parts->size(), typ.c_str());
+    }
+    else   {
+      str = this->format("%s|---- %4X %08X %-32s: %s", 
+			 event.id(), key.values.mask, key.values.item, 
+			 nam.c_str(), typ.c_str());
+    }
+    records.push_back(str);
+  }
+  std::lock_guard<std::mutex> record_lock(m_kernel.global_output_lock());
+  for(const auto& s : records)
+    this->info(s.c_str());
+}
+
+/// Main functional callback
+void dd4hep::digi::DigiStoreDump::execute(DigiContext& context)  const    {
+  const auto& event = context.event;
+  for(const auto& segment : this->m_data_segments)   {
+    std::string seg = detail::str_upper(segment);
+    this->dump(seg, *event, event->get_segment(segment));
+  }
+}
diff --git a/DDDigi/src/DigiSubdetectorSequence.cpp b/DDDigi/src/DigiSubdetectorSequence.cpp
index d2018ac2bf91ecc5fa6d62bff8a8a67d94fc5fe6..5ca83e495bddcc3b4cf318938a3b08cac9429493 100644
--- a/DDDigi/src/DigiSubdetectorSequence.cpp
+++ b/DDDigi/src/DigiSubdetectorSequence.cpp
@@ -159,7 +159,7 @@ void DigiSubdetectorSequence::execute(DigiContext& context)  const   {
   }
   this->DigiSynchronize::execute(context);
   debug("+++ Event: %8d (DigiSubdetectorSequence) Parallel: %s Done.",
-        context.event().eventNumber, yes_no(m_parallel));
+        context.event->eventNumber, yes_no(m_parallel));
 }
 
 /// Access subdetector from the detector description
diff --git a/DDDigi/src/DigiSynchronize.cpp b/DDDigi/src/DigiSynchronize.cpp
index 49a9660fe696bdbd85e4d484127a6a1d8d9bfe62..bc836d85f04bb970fa8b3789bc2bfafa66d83af8 100644
--- a/DDDigi/src/DigiSynchronize.cpp
+++ b/DDDigi/src/DigiSynchronize.cpp
@@ -51,7 +51,7 @@ void DigiSynchronize::execute(DigiContext& context)  const   {
     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(),
+        context.event->eventNumber, yes_no(m_parallel), m_actors.size(),
         secs.count());
 }
 
diff --git a/DDEve/src/DDG4EventHandler.cpp b/DDEve/src/DDG4EventHandler.cpp
index dc61e5f3f20ce379fdd6ea43be6c15ea4ee900e3..2268fe25f802d4e436143d328b63494ec508c162 100644
--- a/DDEve/src/DDG4EventHandler.cpp
+++ b/DDEve/src/DDG4EventHandler.cpp
@@ -12,14 +12,14 @@
 //==========================================================================
 
 // Framework include files
-#include "DDEve/DDG4EventHandler.h"
-#include "DD4hep/Printout.h"
-#include "DD4hep/Objects.h"
-#include "DD4hep/Factories.h"
-
-#include "TFile.h"
-#include "TTree.h"
-#include "TBranch.h"
+#include <DDEve/DDG4EventHandler.h>
+#include <DD4hep/Printout.h>
+#include <DD4hep/Objects.h>
+#include <DD4hep/Factories.h>
+
+#include <TFile.h>
+#include <TTree.h>
+#include <TBranch.h>
 
 // C/C++ include files
 #include <stdexcept>
diff --git a/DDG4/include/DDG4/Geant4Data.h b/DDG4/include/DDG4/Geant4Data.h
index f2d53e14c961ba7ea511a7a959367492e7c65d0c..7e88e7aac384b22a6d9aeac94f42122b8aecf7c4 100644
--- a/DDG4/include/DDG4/Geant4Data.h
+++ b/DDG4/include/DDG4/Geant4Data.h
@@ -234,6 +234,8 @@ namespace dd4hep {
        */
       class Hit : public Geant4HitData {
       public:
+        typedef Geant4HitData base_t;
+
         /// Hit position
         Position      position;
         /// Hit direction
@@ -290,6 +292,8 @@ namespace dd4hep {
        */
       class Hit : public Geant4HitData {
       public:
+        typedef Geant4HitData base_t;
+
         /// Hit position
         Position      position;
         /// Hit contributions by individual particles
diff --git a/DDG4/python/DDG4.py b/DDG4/python/DDG4.py
index eefe6b9c6351706183182f61b3666d4970ec4d3c..6e4edad150da2e9919122d947293ebdc51095361 100644
--- a/DDG4/python/DDG4.py
+++ b/DDG4/python/DDG4.py
@@ -279,7 +279,6 @@ _import_class('Sim', 'Geant4Random')
 _import_class('CLHEP', 'HepRandom')
 _import_class('CLHEP', 'HepRandomEngine')
 
-
 def _get(self, name):
   a = Interface.toAction(self)
   ret = Interface.getProperty(a, name)
@@ -292,48 +291,22 @@ def _get(self, name):
   msg = 'Geant4Action::GetProperty [Unhandled]: Cannot access property ' + a.name() + '.' + name
   raise KeyError(msg)
 
-
-def _deUnicode(value):
-  """Turn any unicode literal into str, needed when passing to c++.
-
-  Recursively transverses dicts, lists, sets, tuples
-
-  :return: always a str
-  """
-  if isinstance(value, (bool, float, six.integer_types)):
-    value = value
-  elif isinstance(value, six.string_types):
-    value = str(value)
-  elif isinstance(value, (list, set, tuple)):
-    value = [_deUnicode(x) for x in value]
-  elif isinstance(value, dict):
-    tempDict = {}
-    for key, val in value.items():
-      key = _deUnicode(key)
-      val = _deUnicode(val)
-      tempDict[key] = val
-    value = tempDict
-  return str(value)
-
-
 def _set(self, name, value):
   """This function is called when properties are passed to the c++ objects."""
   a = Interface.toAction(self)
-  name = _deUnicode(name)
-  value = _deUnicode(value)
+  name  = unicode_2_string(name)
+  value = unicode_2_string(value)
   if Interface.setProperty(a, name, value):
     return
   msg = 'Geant4Action::SetProperty [Unhandled]: Cannot set ' + a.name() + '.' + name + ' = ' + value
   raise KeyError(msg)
 
-
 def _props(obj):
   _import_class('Sim', obj)
   cl = getattr(current, obj)
   cl.__getattr__ = _get
   cl.__setattr__ = _set
 
-
 _props('FilterHandle')
 _props('ActionHandle')
 _props('PhaseActionHandle')
diff --git a/examples/DDDigi/scripts/DigiTest.py b/examples/DDDigi/scripts/DigiTest.py
new file mode 100644
index 0000000000000000000000000000000000000000..290acb45c3e8238f044913d3655d2f25acda27ff
--- /dev/null
+++ b/examples/DDDigi/scripts/DigiTest.py
@@ -0,0 +1,82 @@
+# ==========================================================================
+#  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 dddigi
+import logging
+from g4units import ns
+logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.INFO)
+logger = logging.getLogger(__name__)
+
+"""
+  00C7A3C1 SiVertexEndcapHits               : map<long long, EnergyDeposit>
+  00D16F45 EcalBarrelHits                   : map<long long, EnergyDeposit>
+  0D3C3803 MCParticles                      : vector<shared_ptr<dd4hep::sim::Geant4Particle>, allocator<shared_ptr<dd4hep::sim::Geant4Particle> > >
+  2E9082A9 HcalPlugHits                     : map<long long, EnergyDeposit>
+  3A89E02E HcalEndcapHits                   : map<long long, EnergyDeposit>
+  569C1C49 HcalBarrelHits                   : map<long long, EnergyDeposit>
+  62AD0218 EcalEndcapHits                   : map<long long, EnergyDeposit>
+  7FBC6131 SiTrackerBarrelHits              : map<long long, EnergyDeposit>
+  A239CB2E LumiCalHits                      : map<long long, EnergyDeposit>
+  B5CD88D8 MuonBarrelHits                   : map<long long, EnergyDeposit>
+  BDB9AD3E SiVertexBarrelHits               : map<long long, EnergyDeposit>
+  C84DE2C2 MuonEndcapHits                   : map<long long, EnergyDeposit>
+  CB57C6D0 SiTrackerForwardHits             : map<long long, EnergyDeposit>
+  D108063E BeamCalHits                      : map<long long, EnergyDeposit>
+  F4183035 SiTrackerEndcapHits              : map<long long, EnergyDeposit>
+"""
+
+attenuation = { 'SiVertexEndcapHits': 15 * ns,
+                'SiVertexBarrelHits': 15 * ns,
+                'SiTrackerForwardHits': 15 * ns,
+                'SiTrackerEndcapHits': 15 * ns,
+                'SiTrackerBarrelHits': 15 * ns,
+                'HcalPlugHits': 15 * ns,
+                'HcalEndcapHits': 15 * ns,
+                'HcalBarrelHits': 15 * ns,
+                'EcalEndcapHits': 15 * ns,
+                'MuonEndcapHits': 15 * ns,
+                'MuonBarrelHits': 15 * ns,
+                'BeamCalHits': 15 * ns,
+                'LumiCalHits': 15 * ns,
+}
+
+
+class Test(dddigi.Digitize):
+
+  def __init__(self, geometry=None):
+    global attenuation
+    dddigi.Digitize.__init__(self, dddigi.Kernel())
+    dddigi.setPrintFormat(str('%-32s %5s %s'))
+    dddigi.setPrintLevel(dddigi.OutputLevel.INFO)
+    self.kernel().printProperties()
+    self.geometry = geometry
+    self.input = None
+    self.main_sequencer()
+    self.attenuation = attenuation
+    self.inputs = [
+        'CLICSiD_2022-10-05_13-21.root',
+        'CLICSiD_2022-10-05_13-52.root',
+        'CLICSiD_2022-10-05_14-16.root',
+        'CLICSiD_2022-10-05_14-40.root'
+    ]
+    self.used_inputs = []
+
+  def declare_input(self, name, input, parallel=True):
+    if not self.input:
+      self.input = dddigi.Synchronize(self.kernel(), 'DigiParallelActionSequence/READER')
+      self.input.parallel = True
+
+  def next_input(self):
+    if len(self.used_inputs) == len(self.inputs):
+      self.used_inputs = []
+    next = self.inputs[len(self.used_inputs)]
+    self.used_inputs.append(next)
+    return next
diff --git a/examples/DDDigi/scripts/TestFramework.py b/examples/DDDigi/scripts/TestFramework.py
index 78fc46a747eba91410e89a928baebea05e6c9635..1ff0a061f309a15660190d7df3a48f217338833b 100644
--- a/examples/DDDigi/scripts/TestFramework.py
+++ b/examples/DDDigi/scripts/TestFramework.py
@@ -9,15 +9,14 @@
 #
 # ==========================================================================
 from __future__ import absolute_import, unicode_literals
+import dddigi
 import os
-import DDDigi
-
 
 def make_input(kernel):
-  input_1 = DDDigi.TestAction(kernel, 'input_01', 100)
-  input_2 = DDDigi.TestAction(kernel, 'input_02', 200)
-  input_3 = DDDigi.TestAction(kernel, 'input_03', 150)
-  input_4 = DDDigi.TestAction(kernel, 'input_04', 60)
+  input_1 = dddigi.TestAction(kernel, 'input_01', 100)
+  input_2 = dddigi.TestAction(kernel, 'input_02', 200)
+  input_3 = dddigi.TestAction(kernel, 'input_03', 150)
+  input_4 = dddigi.TestAction(kernel, 'input_04', 60)
   seq = kernel.inputAction()
   seq.adopt(input_1)
   seq.adopt(input_2)
@@ -27,12 +26,12 @@ def make_input(kernel):
 
 
 def make_subdetector(kernel, name):
-  action_1 = DDDigi.TestAction(kernel, name + '_deposits', 150)
-  action_2 = DDDigi.TestAction(kernel, name + '_rndmNoise', 100)
-  action_3 = DDDigi.TestAction(kernel, name + '_deadChan', 100)
-  action_4 = DDDigi.TestAction(kernel, name + '_noiseChan', 50)
-  action_5 = DDDigi.TestAction(kernel, name + '_merge', 200)
-  seq = DDDigi.ActionSequence(kernel, 'DigiActionSequence/' + name + '_sequence', True)
+  action_1 = dddigi.TestAction(kernel, name + '_deposits', 150)
+  action_2 = dddigi.TestAction(kernel, name + '_rndmNoise', 100)
+  action_3 = dddigi.TestAction(kernel, name + '_deadChan', 100)
+  action_4 = dddigi.TestAction(kernel, name + '_noiseChan', 50)
+  action_5 = dddigi.TestAction(kernel, name + '_merge', 200)
+  seq = dddigi.ActionSequence(kernel, 'DigiActionSequence/' + name + '_sequence', True)
   seq.adopt(action_1)
   seq.adopt(action_2)
   seq.adopt(action_3)
@@ -44,16 +43,16 @@ def make_subdetector(kernel, name):
 def run():
   # import pdb
   # pdb.set_trace()
-  DDDigi.setPrintFormat(str('%-32s %5s %s'))
-  kernel = DDDigi.Kernel()
+  dddigi.setPrintFormat(str('%-32s %5s %s'))
+  kernel = dddigi.Kernel()
   install_dir = os.environ['DD4hepExamplesINSTALL']
   fname = "file:" + install_dir + "/examples/ClientTests/compact/MiniTel.xml"
   kernel.loadGeometry(str(fname))
   kernel.printProperties()
-  digi = DDDigi.Digitize(kernel)
+  digi = dddigi.Digitize(kernel)
   digi.printDetectors()
 
-  event_processor = DDDigi.Synchronize(kernel, 'DigiSynchronize/MainDigitizer', True)
+  event_processor = dddigi.Synchronize(kernel, 'DigiSynchronize/MainDigitizer', True)
   event_processor.parallel = True
   # input
   make_input(kernel)
@@ -64,15 +63,15 @@ def run():
     event_processor.adopt(seq)
   kernel.eventAction().adopt(event_processor)
   # Output
-  output = DDDigi.TestAction(kernel, 'output_01', 200)
+  output = dddigi.TestAction(kernel, 'output_01', 200)
   kernel.outputAction().adopt(output)
 
-  DDDigi.setPrintLevel(DDDigi.OutputLevel.DEBUG)
+  dddigi.setPrintLevel(dddigi.OutputLevel.DEBUG)
   kernel.numThreads = 0   # = number of concurrent threads
   kernel.numEvents = 10
   kernel.maxEventsParallel = 3
   kernel.run()
-  DDDigi.setPrintLevel(DDDigi.OutputLevel.INFO)
+  dddigi.setPrintLevel(dddigi.OutputLevel.INFO)
 
 
 if __name__ == '__main__':
diff --git a/examples/DDDigi/scripts/TestInput.py b/examples/DDDigi/scripts/TestInput.py
new file mode 100644
index 0000000000000000000000000000000000000000..9cf47bb900e7f94041015c42499f7e4e6f1a9dbb
--- /dev/null
+++ b/examples/DDDigi/scripts/TestInput.py
@@ -0,0 +1,20 @@
+# ==========================================================================
+#  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.
+#
+# ==========================================================================
+
+def run():
+  import DigiTest
+  digi = DigiTest.Test(geometry=None)
+  reader = digi.input_action('DigiROOTInput/SignalReader', mask=0x1, input=['CLICSiD_2022-10-05_13-21.root'])
+  dump = digi.event_action('DigiStoreDump/StoreDump')
+  digi.run(num_events = 5, num_threads = 5, parallel = 3)
+
+if __name__ == '__main__':
+  run()
diff --git a/examples/DDDigi/scripts/TestMultiInteractions.py b/examples/DDDigi/scripts/TestMultiInteractions.py
new file mode 100644
index 0000000000000000000000000000000000000000..18cf7ebbfc4f7156ba27330b8da0368d5a79f7e7
--- /dev/null
+++ b/examples/DDDigi/scripts/TestMultiInteractions.py
@@ -0,0 +1,55 @@
+# ==========================================================================
+#  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.
+#
+# ==========================================================================
+from g4units import ns
+
+def run():
+  import DigiTest
+  digi = DigiTest.Test(geometry=None)
+  attenuation = digi.attenuation
+
+  input  = digi.input_action('DigiParallelActionSequence/READER')
+  #========================================================================================================
+  digi.info('Created SIGNAL input')
+  signal = input.adopt_action('DigiROOTInput/SignalReader', mask=0x0, input = [digi.next_input()])
+  #========================================================================================================
+  digi.info('Creating collision overlays....')
+  #========================================================================================================
+  overlay = input.adopt_action('DigiSequentialActionSequence/Overlay-1')
+  evtreader = overlay.adopt_action('DigiROOTInput/Reader-1', mask=0x1, input = [digi.next_input()])
+  hist_drop = overlay.adopt_action('DigiHitHistoryDrop/Drop-1', masks = [evtreader.mask])
+  digi.info('Created input.overlay25')
+  #========================================================================================================
+  overlay = input.adopt_action('DigiSequentialActionSequence/Overlay-2')
+  evtreader = overlay.adopt_action('DigiROOTInput/Reader-2', mask=0x2, input = [digi.next_input()])
+  hist_drop = overlay.adopt_action('DigiHitHistoryDrop/Drop-2', masks = [evtreader.mask])
+  digi.info('Created input.overlay50')
+  #========================================================================================================
+  overlay = input.adopt_action('DigiSequentialActionSequence/Overlay-3')
+  evtreader = overlay.adopt_action('DigiROOTInput/Reader-3', mask=0x3, input = [digi.next_input()])
+  hist_drop = overlay.adopt_action('DigiHitHistoryDrop/Drop-3', masks = [evtreader.mask])
+  digi.info('Created input.overlay75')
+  #========================================================================================================
+
+  event = digi.event_action('DigiSequentialActionSequence/EventAction')
+  combine = event.adopt_action('DigiContainerCombine/Combine', masks=[0x0, 0x1, 0x2, 0x3], deposit_mask=0xFEED)
+  combine.erase_combined = True  # Not thread-safe! only do in SequentialActionSequence
+  dump = event.adopt_action('DigiStoreDump/StoreDump')
+  digi.info('Created event.dump')
+  #========================================================================================================
+  evt_todo = 5
+  evt_done = digi.run(num_events = evt_todo, num_threads = 5, parallel = 3)
+  if evt_done == evt_todo: result = "PASSED"
+  else: result = "FAILED"
+  digi.always('%s Test finished after processing %d events.'%(result, digi.events_done(),))
+  digi.always('Test done. Exiting')
+
+if __name__ == '__main__':
+  run()
diff --git a/examples/DDDigi/scripts/TestSegmentationSplit.py b/examples/DDDigi/scripts/TestSegmentationSplit.py
new file mode 100644
index 0000000000000000000000000000000000000000..a72f728e73f007c9d38f709dcb67bbbb09333717
--- /dev/null
+++ b/examples/DDDigi/scripts/TestSegmentationSplit.py
@@ -0,0 +1,43 @@
+# ==========================================================================
+#  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.
+#
+# ==========================================================================
+from g4units import ns
+
+def run():
+  import DigiTest
+  digi = DigiTest.Test(geometry=None)
+  attenuation = digi.attenuation
+
+  input  = digi.input_action('DigiParallelActionSequence/READER')
+  #========================================================================================================
+  digi.info('Created SIGNAL input')
+  signal = input.adopt_action('DigiROOTInput/SignalReader', mask=0x0, input = [digi.next_input()])
+  #========================================================================================================
+  event = digi.event_action('DigiSequentialActionSequence/EventAction')
+  combine = event.adopt_action('DigiContainerCombine/Combine', masks=[0x0, 0x1, 0x2, 0x3], deposit_mask=0xFEED)
+  combine.erase_combined = True  # Not thread-safe! only do in SequentialActionSequence
+  dump = event.adopt_action('DigiStoreDump/StoreDump')
+
+  splitter = event.adopt_action('DigiSegmentationSplitter/Splitter', 
+                                input='deposits',
+                                masks=[0xFEED],
+                                detector='SiTrackerBarrel');
+
+  digi.info('Created event.dump')
+  #========================================================================================================
+  evt_todo = 5
+  evt_done = digi.run(num_events = evt_todo, num_threads = 5, parallel = 3)
+  if evt_done == evt_todo: result = "PASSED"
+  else: result = "FAILED"
+  digi.always('%s Test finished after processing %d events.'%(result, digi.events_done(),))
+  digi.always('Test done. Exiting')
+
+if __name__ == '__main__':
+  run()
diff --git a/examples/DDDigi/scripts/TestSpillover.py b/examples/DDDigi/scripts/TestSpillover.py
new file mode 100644
index 0000000000000000000000000000000000000000..cf86dfd8ff0a517df94ac8ce35ac5601986b96c7
--- /dev/null
+++ b/examples/DDDigi/scripts/TestSpillover.py
@@ -0,0 +1,83 @@
+# ==========================================================================
+#  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.
+#
+# ==========================================================================
+from g4units import ns
+
+def run():
+  import DigiTest
+  digi = DigiTest.Test(geometry=None)
+  attenuation = digi.attenuation
+
+  input  = digi.input_action('DigiParallelActionSequence/READER')
+  #========================================================================================================
+  signal = input.adopt_action('DigiROOTInput/SignalReader', mask=0x0, input = [digi.next_input()])
+  digi.info('Created input.signal')
+  #========================================================================================================
+  digi.info('Creating spillover sequence for EARLIER bunch crossings.....')
+  #========================================================================================================
+  spillover = input.adopt_action('DigiSequentialActionSequence/Spillover-25')
+  evtreader = spillover.adopt_action('DigiROOTInput/Reader-25ns', mask=0x1, input = [digi.next_input()])
+  attenuate = spillover.adopt_action('DigiHitAttenuatorExp/Attenuator-25ns',
+                                     t0 = -25 * ns, masks = [evtreader.mask], containers = attenuation)
+  hist_drop = spillover.adopt_action('DigiHitHistoryDrop/Drop-25ns', masks = [evtreader.mask])
+  digi.info('Created input.spillover25')
+  #========================================================================================================
+  spillover = input.adopt_action('DigiSequentialActionSequence/Spillover-50')
+  evtreader = spillover.adopt_action('DigiROOTInput/Reader-50ns', mask=0x2, input = [digi.next_input()])
+  attenuate = spillover.adopt_action('DigiHitAttenuatorExp/Attenuator-50ns',
+                                     t0 = -50 * ns, masks = [evtreader.mask], containers = attenuation)
+  hist_drop = spillover.adopt_action('DigiHitHistoryDrop/Drop-50ns', masks = [evtreader.mask])
+  digi.info('Created input.spillover50')
+  #========================================================================================================
+  spillover = input.adopt_action('DigiSequentialActionSequence/Spillover-75')
+  evtreader = spillover.adopt_action('DigiROOTInput/Reader-75ns', mask=0x3, input = [digi.next_input()])
+  attenuate = spillover.adopt_action('DigiHitAttenuatorExp/Attenuator-75ns',
+                                     t0 = -75 * ns, masks = [evtreader.mask], containers = attenuation)
+  hist_drop = spillover.adopt_action('DigiHitHistoryDrop/Drop-75ns', masks = [evtreader.mask])
+  digi.info('Created input.spillover75')
+  #========================================================================================================
+  digi.info('Creating spillover sequence for LATER bunch crossings.....')
+  #========================================================================================================
+  spillover = input.adopt_action('DigiSequentialActionSequence/Spillover+25')
+  evtreader = spillover.adopt_action('DigiROOTInput/Reader+25ns', mask=0x4, input = [digi.next_input()])
+  attenuate = spillover.adopt_action('DigiHitAttenuatorExp/Attenuator+25ns',
+                                     t0 = 25 * ns, masks = [evtreader.mask], containers = attenuation)
+  hist_drop = spillover.adopt_action('DigiHitHistoryDrop/Drop+25ns', masks = [evtreader.mask])
+  digi.info('Created input.spillover25')
+  #========================================================================================================
+  spillover = input.adopt_action('DigiSequentialActionSequence/Spillover+50')
+  evtreader = spillover.adopt_action('DigiROOTInput/Reader+50ns', mask=0x5, input = [digi.next_input()])
+  attenuate = spillover.adopt_action('DigiHitAttenuatorExp/Attenuator+50ns',
+                                     t0 = 50 * ns, masks = [evtreader.mask], containers = attenuation)
+  hist_drop = spillover.adopt_action('DigiHitHistoryDrop/Drop_50ns', masks = [evtreader.mask])
+  digi.info('Created input.spillover50')
+  #========================================================================================================
+  spillover = input.adopt_action('DigiSequentialActionSequence/Spillover+75')
+  evtreader = spillover.adopt_action('DigiROOTInput/Reader+75ns', mask=0x6, input = [digi.next_input()])
+  attenuate = spillover.adopt_action('DigiHitAttenuatorExp/Attenuator+75ns',
+                                     t0 = 75 * ns, masks = [evtreader.mask], containers = attenuation)
+  hist_drop = spillover.adopt_action('DigiHitHistoryDrop/Drop+75ns', masks = [evtreader.mask])
+  digi.info('Created input.spillover75')
+  #========================================================================================================
+  event = digi.event_action('DigiSequentialActionSequence/EventAction')
+  combine = event.adopt_action('DigiContainerCombine/Combine', masks=[0x0, 0x1, 0x2, 0x3], deposit_mask=0xFEED)
+  combine.erase_combined = True  # Not thread-safe! only do in SequentialActionSequence
+  evtdump = event.adopt_action('DigiStoreDump/StoreDump')
+  digi.info('Created event.dump')
+  #========================================================================================================
+  evt_todo = 5
+  evt_done = digi.run(num_events = evt_todo, num_threads = 5, parallel = 3)
+  if evt_done == evt_todo: result = "PASSED"
+  else: result = "FAILED"
+  digi.always('%s Test finished after processing %d events.'%(result, digi.events_done(),))
+  digi.always('Test done. Exiting')
+
+if __name__ == '__main__':
+  run()
diff --git a/examples/DDDigi/src/DigiTestAction.cpp b/examples/DDDigi/src/DigiTestAction.cpp
index b7888f99a77acb0578caa0bd4e2b7971056b9cd2..b798cf74ef7286d991d9587229e42177efee8984 100644
--- a/examples/DDDigi/src/DigiTestAction.cpp
+++ b/examples/DDDigi/src/DigiTestAction.cpp
@@ -103,6 +103,6 @@ DigiTestAction::~DigiTestAction() {
 /// Pre-track action callback
 void DigiTestAction::execute(DigiContext& context)  const   {
   debug("+++ Event: %8d (DigiTestAction)  %d msec",
-       context.event().eventNumber, m_sleep);
+       context.event->eventNumber, m_sleep);
   if ( m_sleep > 0 ) ::usleep(1000*m_sleep);
 }