diff --git a/DDDigi/ddg4/DigiDDG4Input.cpp b/DDDigi/ddg4/DigiDDG4Input.cpp
index f887b0a4183ed30d5c63513420bd4d8a6c25aac0..6efa7a77dff450c6d4bc12573711db26737dd396 100644
--- a/DDDigi/ddg4/DigiDDG4Input.cpp
+++ b/DDDigi/ddg4/DigiDDG4Input.cpp
@@ -50,6 +50,7 @@ namespace  {
 	if ( ptr )   {
 	  Key history_key;
 	  input_data<T> data(ptr);
+	  history_key.set_segment(segment.id);
 	  history_key.set_mask(Key::mask_type(mask));
 	  for(size_t i=0; i < data.items->size(); ++i)   {
 	    auto* p = (*data.items)[i];
@@ -57,11 +58,10 @@ namespace  {
 	    dep.flag = p->flag;
 	    dep.deposit = p->energyDeposit;
 	    dep.position = p->position;
-
 	    history_key.set_item(i);
-	    dep.hit_history.emplace_back(history_key, 1.0);
+	    dep.history.hits.emplace_back(history_key, 1.0);
 	    history_key.set_item(p->g4ID);
-	    dep.particle_history.emplace_back(history_key, 1.0);
+	    dep.history.particles.emplace_back(history_key, 1.0);
 	    out.emplace(p->cellID, std::move(dep));
 	    particles.emplace_back(wrap_t(p));
 	  }
@@ -97,18 +97,17 @@ static void* convert_sim_geant4particles()     {
 	using wrap_t = std::shared_ptr<sim::Geant4Particle>;
 	auto* items = (std::vector<sim::Geant4Particle*>*)ptr;
 	for( auto* p : *items )   {
-	  Key key(0);
+	  Key key;
 	  Particle part;
-	  key.set_mask(mask);
-	  key.set_item(out->size());
-	  p->mask = mask;
+	  key.set_mask(mask).set_item(out->size()).set_segment(segment.id);
+	  p->mask             = mask;
 	  part.start_position = Position(p->vsx, p->vsy, p->vsz);
 	  part.end_position   = Position(p->vex, p->vey, p->vez);
 	  part.momentum       = Direction(p->psx, p->psy, p->psz);
 	  part.charge         = p->charge;
 	  part.mass           = p->mass;
 	  part.history        = std::make_any<wrap_t>(p);
-	  out->push(key.key, std::move(part));
+	  out->push(key, std::move(part));
 	}
 	items->clear();
       }
diff --git a/DDDigi/include/DDDigi/DigiContainerDrop.h b/DDDigi/include/DDDigi/DigiContainerDrop.h
new file mode 100644
index 0000000000000000000000000000000000000000..5f4305bde067b2b3248bfbbbd10f52a03369bf14
--- /dev/null
+++ b/DDDigi/include/DDDigi/DigiContainerDrop.h
@@ -0,0 +1,79 @@
+//==========================================================================
+//  AIDA Detector description implementation 
+//--------------------------------------------------------------------------
+// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
+// All rights reserved.
+//
+// For the licensing terms see $DD4hepINSTALL/LICENSE.
+// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
+//
+// Author     : M.Frank
+//
+//==========================================================================
+#ifndef DDDIGI_DIGICONTAINERDROP_H
+#define DDDIGI_DIGICONTAINERDROP_H
+
+/// Framework include files
+#include <DDDigi/DigiEventAction.h>
+#include <DDDigi/DigiParallelWorker.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_DIGITIZATION
+     */
+    class DigiContainerDrop : public DigiEventAction   {
+    public:
+      class work_definition_t;
+      using self_t  = DigiContainerDrop;
+      using Worker  = DigiParallelWorker<self_t,work_definition_t>;
+      using Workers = DigiParallelWorkers<Worker>;
+
+    protected:
+      /// Property: Container names to be loaded
+      std::vector<std::string>       m_containers   { };
+      /// Property: Input data segment name
+      std::string                    m_input;
+      /// Property: event masks to be handled
+      std::vector<int>               m_input_masks  { };
+      /// Fully qualified keys of all containers to be manipulated
+      std::set<Key::key_type>        m_keys  { };
+      /// Container keys of all containers to be manipulated
+      std::set<Key::key_type>        m_cont_keys  { };
+
+      /// Worker objects to be submitted to TBB each performing part of the job
+      Workers m_workers;
+
+    protected:
+      /// Define standard assignments and constructors
+      DDDIGI_DEFINE_ACTION_CONSTRUCTORS(DigiContainerDrop);
+
+      /// Default destructor
+      virtual ~DigiContainerDrop();
+
+      /// Initializing function: compute values which depend on properties
+      void initialize();
+
+      /// Decide if a continer is to merged based on the properties
+      virtual bool use_key(Key key)  const;
+
+    public:
+      /// Standard constructor
+      DigiContainerDrop(const DigiKernel& kernel, const std::string& name);
+
+      /// Main functional callback
+      virtual void execute(DigiContext& context)  const;
+    };
+  }    // End namespace digi
+}      // End namespace dd4hep
+#endif // DDDIGI_DIGICONTAINERDROP_H
diff --git a/DDDigi/include/DDDigi/DigiContainerProcessor.h b/DDDigi/include/DDDigi/DigiContainerProcessor.h
index c615e70fee9ea1a3abec44add3deeaefae2e40c1..a414ebbe7768182b8190d235caf84cb5112e5987 100644
--- a/DDDigi/include/DDDigi/DigiContainerProcessor.h
+++ b/DDDigi/include/DDDigi/DigiContainerProcessor.h
@@ -171,8 +171,8 @@ namespace dd4hep {
       };
       using worker_t         = DigiParallelWorker<processor_t, work_t>;
       using workers_t        = DigiParallelWorkers<worker_t>;
-      using reg_workers_t    = std::map<Key::itemkey_type, worker_t*>;
-      using reg_processors_t = std::map<Key::itemkey_type, processor_t*>;
+      using reg_workers_t    = std::map<Key, worker_t*>;
+      using reg_processors_t = std::map<Key, processor_t*>;
       friend class DigiParallelWorker<processor_t, work_t>;
 
       /// Array of sub-workers
@@ -255,12 +255,18 @@ namespace dd4hep {
       /// Property: event mask for output data
       int                m_output_mask  { 0x0 };
 
+      /// Set of container names to be used by this processor
+      std::map<std::string, std::vector<processor_t*> >    m_processors;
+      std::map<Key::itemkey_type, std::vector<worker_t*> > m_worker_map;
+
       /// Set of work items to be processed and passed to clients
-      std::set<Key>      m_work_items;
+      std::set<Key>             m_work_items;
       /// Set of keys required by each worker
-      worker_keys_t      m_worker_keys;
+      worker_keys_t             m_worker_keys;
+      /// Ordered list of actions registered
+      std::vector<processor_t*> m_actions;
       /// Lock for output merging
-      mutable std::mutex m_output_lock;
+      mutable std::mutex        m_output_lock;
 
       /// Array of sub-workers
       workers_t          m_workers;
@@ -270,6 +276,8 @@ namespace dd4hep {
       DDDIGI_DEFINE_ACTION_CONSTRUCTORS(DigiMultiContainerProcessor);
       /// Default destructor
       virtual ~DigiMultiContainerProcessor();
+      /// Initialize action object
+      void initialize();
 
     public:
       /// Standard constructor
diff --git a/DDDigi/include/DDDigi/DigiData.h b/DDDigi/include/DDDigi/DigiData.h
index 17ae58f52a281a70dcd771587960296101f562f9..936028d79c6c33b364633214823e51255bca1bd9 100644
--- a/DDDigi/include/DDDigi/DigiData.h
+++ b/DDDigi/include/DDDigi/DigiData.h
@@ -53,7 +53,10 @@ namespace dd4hep {
       typedef std::uint64_t key_type;
       typedef std::uint32_t itemkey_type;
       typedef std::uint16_t mask_type;
-      
+      typedef std::uint8_t  segment_type;
+      typedef std::uint8_t  submask_type;
+
+    private:      
       /// First union entry used for fast initialization
       key_type key;
       /// Second union entry to use for discrimination
@@ -61,11 +64,12 @@ namespace dd4hep {
 	// Ordering is important here: 
 	// We want to group the containers by item ie. by container name
 	// and not by mask
-        itemkey_type item;
+	segment_type segment;
+	submask_type submask;
         mask_type    mask;
-        mask_type    spare;
+        itemkey_type item;
       } values;
-
+    public:
       /// Default constructor
       Key();
       /// Move constructor
@@ -73,11 +77,13 @@ namespace dd4hep {
       /// Copy constructor
       Key(const Key&);
       /// Initializaing constructor (fast)
-      Key(key_type full_mask);
+      Key(key_type full_mask) = delete;
       /// Initializing constructor with key generation using hash algorithm
-      Key(const char* item, mask_type mask);
+      explicit Key(const char* item, mask_type mask);
       /// Initializing constructor with key generation using hash algorithm
-      Key(const std::string& item, mask_type mask);
+      explicit Key(const std::string& item, mask_type mask);
+      /// Assignment operator
+      Key& operator = (const Key::key_type) = delete;
       /// Assignment operator
       Key& operator = (const Key&);
       /// Move assignment operator
@@ -92,48 +98,52 @@ namespace dd4hep {
       /// Generate key using hash algorithm
       void set(const std::string& name, int mask);
 
-      /// Conversion to uint64
-      key_type toLong()  const  {
-	return key;
+      /// Set key mask
+      Key& set_mask(mask_type m)  {
+	this->values.mask = m;
+	return *this;
       }
-
-      /// Project the item part of the key
-      mask_type mask()  const {
-	return this->values.mask;
+      /// Set key submask
+      Key& set_submask(submask_type m)  {
+	this->values.submask = m;
+	return *this;
       }
-      /// Set key mask
-      void set_mask(Key k)  {
-	this->values.mask = k.values.mask;
+      /// Set key submask
+      Key& set_submask(const char* opt_tag);
+      /// Set key item identifier
+      Key& set_item(itemkey_type i)  {
+	this->values.item = i;
+	return *this;
       }
       /// Set key mask
-      void set_mask(mask_type m)  {
-	this->values.mask = m;
-      }
-      /// Project the item part of the key
-      static mask_type mask(key_type k)  {
-	return Key(k).values.mask;
+      Key& set_segment(segment_type seg)  {
+	this->values.segment = seg;
+	return *this;
       }
       /// Project the item part of the key
-      static mask_type mask(Key k)  {
-	return k.values.mask;
+      mask_type mask()  const {
+	return this->values.mask;
       }
-
       /// Project the mask part of the key
       itemkey_type item()  const  {
 	return this->values.item;
       }
-      /// Set key item identifier
-      void set_item(itemkey_type i)  {
-	this->values.item = i;
+      /// Project the segment part of the key
+      segment_type segment()  const  {
+        return this->values.segment;
       }
-      /// Project the mask part of the key
-      static itemkey_type item(key_type k)  {
-	return Key(k).values.item;
+      /// Access key as long integer
+      key_type value()  const {
+	return this->key;
       }
       /// Project the mask part of the key
       static itemkey_type item(Key k)  {
 	return k.values.item;
       }
+      /// Project the item part of the key
+      static mask_type mask(Key k)  {
+	return k.values.mask;
+      }
       /// Access key name (if registered properly)
       static std::string key_name(const Key& key);
     };
@@ -152,12 +162,6 @@ namespace dd4hep {
     inline Key::Key(const Key& copy)   {
       this->key = copy.key;
     }
-
-    /// Initializaing constructor (fast)
-    inline Key::Key(key_type full_mask)   {
-      this->key = full_mask;
-    }
-
     /// Initializaing constructor with key generation using hash algorithm
     inline Key::Key(const char* item, mask_type mask)  {
       this->set(item, mask);
@@ -198,7 +202,7 @@ namespace dd4hep {
     class SegmentEntry   {
     public:
       std::string      name { };
-      Key              key  { 0x0 };
+      Key              key  { };
     public:
       /// Initializing constructor
       SegmentEntry(const std::string& name, Key::mask_type mask);
@@ -238,7 +242,7 @@ namespace dd4hep {
       double    mass           { 0e0 };
       char      charge         { 0 };
       /// Source contributing
-      std::any history;
+      std::any  history;
 
     public:
       /// Initializing constructor
@@ -264,18 +268,18 @@ namespace dd4hep {
     }
 
     /// Particle mapping definition for digitization
-    /** Particle mapping definition for digitization
+    /**
      *
      *  \author  M.Frank
      *  \version 1.0
      *  \ingroup DD4HEP_DIGITIZATION
      */
     class ParticleMapping : public SegmentEntry   {
-      using container_t = std::map<Key::key_type, Particle>;
-      using value_type = container_t::value_type;
-      using mapped_type = container_t::mapped_type;
-      using key_type = container_t::key_type;
-      using iterator = container_t::iterator;
+      using container_t    = std::map<Key, Particle>;
+      using value_type     = container_t::value_type;
+      using mapped_type    = container_t::mapped_type;
+      using key_type       = container_t::key_type;
+      using iterator       = container_t::iterator;
       using const_iterator = container_t::const_iterator;
 
       container_t data;
@@ -301,6 +305,11 @@ namespace dd4hep {
       /// Add new entry to the particle mapping (not thread safe!)
       void push(Key key, Particle&& particle);
 
+      /// Merge new deposit map onto existing map (not thread safe!) (CONST)
+      std::size_t insert(const ParticleMapping& updates);
+      /// Add new entry to the particle mapping (not thread safe!) (CONST)
+      void insert(Key key, const Particle& particle);
+
       /// Access container size
       std::size_t size()  const           { return this->data.size();        }
       /// Check container if empty
@@ -326,8 +335,56 @@ namespace dd4hep {
     {
     }
 
+    ///  Class to hold the processing history of the detector response
+    /**
+     *
+     *  \author  M.Frank
+     *  \version 1.0
+     *  \ingroup DD4HEP_DIGITIZATION
+     */
+    class History   {
+    public:
+      struct hist_entry_t   {
+	Key    source { };
+	double weight { 0e0 };
+	hist_entry_t(Key s, double w);
+	hist_entry_t() = default;
+	hist_entry_t(hist_entry_t&& copy) = default;
+	hist_entry_t(const hist_entry_t& copy) = default;
+	hist_entry_t& operator=(hist_entry_t&& copy) = default;
+	hist_entry_t& operator=(const hist_entry_t& copy) = default;
+	~hist_entry_t() = default;
+      };
+      /// Sources contributing to the deposit indexed by the cell identifier
+      std::vector<hist_entry_t> hits;
+      std::vector<hist_entry_t> particles;
+
+    public:
+      /// Default constructor
+      History() = default;
+      /// Disable move constructor
+      History(History&& copy) = default;
+      /// Disable copy constructor
+      History(const History& copy) = default;
+      /// Default destructor
+      virtual ~History() = default;
+      /// Disable move assignment
+      History& operator=(History&& copy) = default;
+      /// Disable copy assignment
+      History& operator=(const History& copy) = default;
+
+      /// Update history
+      void update(const History& upda);
+      /// Drop history information
+      std::pair<std::size_t,std::size_t> drop();
+    };
+
+    inline History::hist_entry_t::hist_entry_t(Key s, double w)
+      : source(s), weight(w)  {
+    }
+
     /// Energy deposit definition for digitization
-    /** Energy deposit definition for digitization
+    /**
      *
      *  \author  M.Frank
      *  \version 1.0
@@ -349,8 +406,7 @@ namespace dd4hep {
       Key::mask_type mask        { 0 };
 
       /// Sources contributing to this deposit
-      std::vector<std::pair<Key, double> > hit_history;
-      std::vector<std::pair<Key, double> > particle_history;
+      History        history;
 
     public:
       /// Default constructor
@@ -373,7 +429,7 @@ namespace dd4hep {
 
 
     /// Energy deposit vector definition for digitization
-    /** Energy deposit vector definition for digitization
+    /**
      *
      *  \author  M.Frank
      *  \version 1.0
@@ -404,8 +460,12 @@ namespace dd4hep {
       DepositVector& operator=(const DepositVector& copy) = default;      
       /// Merge new deposit map onto existing vector (destroys inputs. not thread safe!)
       std::size_t merge(DepositVector&& updates);
+      /// Merge new deposit map onto existing vector (destroys inputs. not thread safe!)
+      std::size_t merge(const DepositVector& updates);
       /// Merge new deposit map onto existing map (destroys inputs. not thread safe!)
       std::size_t merge(DepositMapping&& updates);
+      /// Merge new deposit map onto existing map (destroys inputs. not thread safe!)
+      std::size_t merge(const DepositMapping& updates);
       /// Merge new deposit map onto existing vector (keep inputs. not thread safe!)
       std::size_t insert(const DepositVector& updates);
       /// Merge new deposit map onto existing map (keep inputs. not thread safe!)
@@ -441,7 +501,7 @@ namespace dd4hep {
     }
 
     /// Energy deposit mapping definition for digitization
-    /** Energy deposit mapping definition for digitization
+    /**
      *
      *  \author  M.Frank
      *  \version 1.0
@@ -470,12 +530,14 @@ namespace dd4hep {
       DepositMapping& operator=(DepositMapping&& copy) = default;
       /// Disable copy assignment
       DepositMapping& operator=(const DepositMapping& copy) = default;      
+
       /// Merge new deposit map onto existing map (not thread safe!)
       std::size_t merge(DepositMapping&& updates);
       /// Merge new deposit map onto existing map (not thread safe!)
-      std::size_t merge(DepositVector&& updates);
-      /// Merge new deposit map onto existing map (not thread safe!)
       std::size_t insert(const DepositMapping& updates);
+
+      /// Merge new deposit map onto existing map (not thread safe!)
+      std::size_t merge(DepositVector&& updates);
       /// Merge new deposit map onto existing map (not thread safe!)
       std::size_t insert(const DepositVector& updates);
 
@@ -510,8 +572,8 @@ namespace dd4hep {
       address_t  address;
     };
     
-    /// Energy deposit vector definition for digitization
-    /** Energy deposit vector definition for digitization
+    /// Detector response vector definition for digitization
+    /**
      *
      *  \author  M.Frank
      *  \version 1.0
@@ -540,6 +602,11 @@ namespace dd4hep {
       DetectorResponse& operator=(DetectorResponse&& copy) = default;
       /// Disable copy assignment
       DetectorResponse& operator=(const DetectorResponse& copy) = default;      
+
+      /// Merge new deposit map onto existing map (not thread safe!)
+      std::size_t merge(DetectorResponse&& updates);
+      /// Merge new deposit map onto existing map (not thread safe!)
+      std::size_t insert(const DetectorResponse& updates);
       /// Emplace entry
       void emplace(CellID cell, ADCValue&& value);
 
@@ -571,6 +638,80 @@ namespace dd4hep {
       this->data.emplace_back(cell, std::move(value));
     }
 
+    /// Detector history vector definition for digitization
+    /**
+     *
+     *  \author  M.Frank
+     *  \version 1.0
+     *  \ingroup DD4HEP_DIGITIZATION
+     */
+    class DetectorHistory : public SegmentEntry  {
+    public: 
+      using container_t    = std::vector<std::pair<CellID, History> >;
+      using iterator       = container_t::iterator;
+      using const_iterator = container_t::const_iterator;
+
+      container_t    data { };
+
+    public: 
+      /// Initializing constructor
+      DetectorHistory(const std::string& name, Key::mask_type mask);
+      /// Default constructor
+      DetectorHistory() = default;
+      /// Disable move constructor
+      DetectorHistory(DetectorHistory&& copy) = default;
+      /// Disable copy constructor
+      DetectorHistory(const DetectorHistory& copy) = default;      
+      /// Default destructor
+      virtual ~DetectorHistory() = default;
+      /// Disable move assignment
+      DetectorHistory& operator=(DetectorHistory&& copy) = default;
+      /// Disable copy assignment
+      DetectorHistory& operator=(const DetectorHistory& copy) = default;      
+
+      /// Merge new deposit map onto existing map (not thread safe!)
+      std::size_t merge(DetectorHistory&& updates);
+      /// Merge new deposit map onto existing map (not thread safe!)
+      std::size_t insert(const DetectorHistory& updates);
+
+      /// Insert new entry
+      void insert(CellID cell, const History& value);
+      /// Emplace new entry
+      void emplace(CellID cell, History&& value);
+
+      /// Access container size
+      std::size_t size()  const           { return this->data.size();        }
+      /// Check container if empty
+      bool        empty() const           { return this->data.empty();       }
+
+      /** Iteration support */
+      /// Begin iteration
+      iterator begin()                    { return this->data.begin();       }
+      /// End iteration
+      iterator end()                      { return this->data.end();         }
+      /// Begin iteration (CONST)
+      const_iterator begin() const        { return this->data.begin();       }
+      /// End iteration (CONST)
+      const_iterator end()   const        { return this->data.end();         }
+    };
+
+    /// Initializing constructor
+    inline DetectorHistory::DetectorHistory(const std::string& nam, Key::mask_type msk)
+      : SegmentEntry(nam, msk)
+    {
+    }
+
+    /// Emplace new entry
+    inline void DetectorHistory::emplace(CellID cell, History&& value)   {
+      this->data.emplace_back(cell, std::move(value));
+    }
+
+    /// Insert new entry
+    inline void DetectorHistory::insert(CellID cell, const History& value)   {
+      this->data.emplace_back(cell, value);
+    }
+
+
     ///  Data segment definition (locked map)
     /**
      *
@@ -580,7 +721,8 @@ namespace dd4hep {
      */
     class DataSegment   {
     public:
-      using container_map_t = std::map<Key::key_type, std::any>;
+      using key_t = Key::key_type;
+      using container_map_t = std::map<Key, std::any>;
       using iterator        = container_map_t::iterator;
       using const_iterator  = container_map_t::const_iterator;
 
@@ -598,10 +740,10 @@ namespace dd4hep {
     public:
       container_map_t data;
       std::mutex&     lock;
-
+      uint32_t        id  { 0 };
     public:
       /// Initializing constructor
-      DataSegment(std::mutex& lock);
+      DataSegment(std::mutex& lock, int id);
       /// Default constructor
       DataSegment() = delete;
       /// Disable move constructor
@@ -652,13 +794,13 @@ namespace dd4hep {
       /// End iteration
       iterator end()                      { return this->data.end();         }
       /// Find entry by key
-      iterator find(Key key)              { return this->data.find(key.key); }
+      iterator find(Key key)              { return this->data.find(key);     }
       /// Begin iteration (CONST)
       const_iterator begin() const        { return this->data.begin();       }
       /// End iteration (CONST)
       const_iterator end()   const        { return this->data.end();         }
       /// Find entry by key
-      const_iterator find(Key key) const  { return this->data.find(key.key); }
+      const_iterator find(Key key) const  { return this->data.find(key);     }
     };
 
     /// Access data as reference by key. If not existing, an exception is thrown
@@ -713,7 +855,7 @@ namespace dd4hep {
       segment_t m_deposits;
 
       /// Helper: Save access with segment creation if it does not exist
-      DataSegment& access_segment(segment_t& seg);
+      DataSegment& access_segment(segment_t& seg, uint32_t id);
 
     public:
       /// Current event number
diff --git a/DDDigi/include/DDDigi/DigiInputAction.h b/DDDigi/include/DDDigi/DigiInputAction.h
index ca3690b12550fbd401242e3c569ed1203f9c0fd4..87fc6496692b75dfaad23fd5b16cb50c53833311 100644
--- a/DDDigi/include/DDDigi/DigiInputAction.h
+++ b/DDDigi/include/DDDigi/DigiInputAction.h
@@ -16,9 +16,6 @@
 /// Framework include files
 #include <DDDigi/DigiEventAction.h>
 
-/// C/C++ include files
-#include <limits>
-
 /// Namespace for the AIDA detector description toolkit
 namespace dd4hep {
 
@@ -26,7 +23,6 @@ namespace dd4hep {
   namespace digi {
 
     // Forward declarations
-    class DigiAction;
     class DigiInputAction;
 
     /// Base class for input actions to the digitization
@@ -60,7 +56,6 @@ namespace dd4hep {
       /// Callback to read event input
       virtual void execute(DigiContext& context)  const override;
     };
-
   }    // End namespace digi
 }      // End namespace dd4hep
 #endif // DDDIGI_DIGIINPUTACTION_H
diff --git a/DDDigi/include/DDDigi/DigiOutputAction.h b/DDDigi/include/DDDigi/DigiOutputAction.h
new file mode 100644
index 0000000000000000000000000000000000000000..17314301fb723d082170999315fdfa5e5d058474
--- /dev/null
+++ b/DDDigi/include/DDDigi/DigiOutputAction.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_DIGIOUTPUTACTION_H
+#define DDDIGI_DIGIOUTPUTACTION_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 {
+
+    // Forward declarations
+    class DigiOutputAction;
+
+    /// Base class for output actions to the digitization
+    /**
+     *
+     *  \author  M.Frank
+     *  \version 1.0
+     *  \ingroup DD4HEP_DIGITIZATION
+     */
+    class DigiOutputAction : public DigiEventAction {
+    public:
+      enum { OUTPUT_START = -1  };
+      enum { NO_MASK     = 0x0 };
+
+    protected:
+      /// Array of data containers to be saved
+      std::vector<std::string> m_containers { };
+      /// Property: Output data specification
+      std::string              m_output { };
+      /// Property: Mask to flag output source items
+      int                      m_mask   { NO_MASK };
+
+    protected:
+      /// Define standard assignments and constructors
+      DDDIGI_DEFINE_ACTION_CONSTRUCTORS(DigiOutputAction);
+
+    public:
+      /// Standard constructor
+      DigiOutputAction(const DigiKernel& kernel, const std::string& nam);
+      /// Default destructor
+      virtual ~DigiOutputAction();
+
+      /// Callback to read event output
+      virtual void execute(DigiContext& context)  const override;
+    };
+
+  }    // End namespace digi
+}      // End namespace dd4hep
+#endif // DDDIGI_DIGIOUTPUTACTION_H
diff --git a/DDDigi/include/DDDigi/DigiParallelWorkers.h b/DDDigi/include/DDDigi/DigiParallelWorkers.h
index 33f9c8fcb629dbd9f60ebf67b6ac736fa2050ecf..a078abe4cdc3fa7d67bb89015e4a6c86d56c04a6 100644
--- a/DDDigi/include/DDDigi/DigiParallelWorkers.h
+++ b/DDDigi/include/DDDigi/DigiParallelWorkers.h
@@ -73,6 +73,7 @@ namespace dd4hep {
       std::size_t size()  const;
       bool empty()  const;
       bool insert(worker_t* entry)  const;
+      void clear();
     };
 
     template <typename T> inline
@@ -105,6 +106,13 @@ namespace dd4hep {
       bool DigiParallelWorkers<T>::empty() const   {
       return actors.empty();
     }
+
+    template <typename T> inline
+      void DigiParallelWorkers<T>::clear()    {
+      auto group = get_group(); // Lock worker array until no clients present
+      actors.clear();
+    }
+
     template <typename T> inline typename DigiParallelWorkers<T>::group_t
       DigiParallelWorkers<T>::get_group()  const  {
       return group_t(*this);
diff --git a/DDDigi/include/DDDigi/DigiROOTInput.h b/DDDigi/include/DDDigi/DigiROOTInput.h
index 46d9425ffd7bd670bf6806422a1c06fe4a945026..f52f7f7cdd4302d7b24dfd59e6fcb18b9ef42817 100644
--- a/DDDigi/include/DDDigi/DigiROOTInput.h
+++ b/DDDigi/include/DDDigi/DigiROOTInput.h
@@ -18,10 +18,6 @@
 
 // C/C++ include files
 #include <memory>
-#include <mutex>
-
-// Forward declarations
-class TClass;
 
 /// Namespace for the AIDA detector description toolkit
 namespace dd4hep {
diff --git a/DDDigi/include/DDDigi/DigiROOTOutput.h b/DDDigi/include/DDDigi/DigiROOTOutput.h
new file mode 100644
index 0000000000000000000000000000000000000000..2f6575a286da6badd5c41d31c4f6f23bd15789d4
--- /dev/null
+++ b/DDDigi/include/DDDigi/DigiROOTOutput.h
@@ -0,0 +1,79 @@
+//==========================================================================
+//  AIDA Detector description implementation 
+//--------------------------------------------------------------------------
+// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
+// All rights reserved.
+//
+// For the licensing terms see $DD4hepINSTALL/LICENSE.
+// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
+//
+// Author     : M.Frank
+//
+//==========================================================================
+#ifndef DDDIGI_DIGIROOTOUTPUT_H
+#define DDDIGI_DIGIROOTOUTPUT_H
+
+/// Framework include files
+#include <DDDigi/DigiOutputAction.h>
+
+/// C/C++ include files
+#include <memory>
+
+/// Forward declarations
+class TFile;
+class TTree;
+class TBranch;
+
+
+/// Namespace for the AIDA detector description toolkit
+namespace dd4hep {
+
+  /// Namespace for the Digitization part of the AIDA detector description toolkit
+  namespace digi {
+
+    // Forward declarations
+    class DigiROOTOutput;
+
+    /// Base class for output actions to the digitization
+    /**
+     *
+     *  \author  M.Frank
+     *  \version 1.0
+     *  \ingroup DD4HEP_DIGITIZATION
+     */
+    class DigiROOTOutput : public DigiOutputAction {
+
+    protected:
+      /// Helper classes
+      class internals_t;
+      /// Property: Name of the tree to connect to
+      std::string m_tree_name       { };
+      /// Property: Segment name to place output data default: outputs
+      std::string m_location        { };
+      /// Property: name of the event tree
+      std::string m_section         { };
+      /// Property: File size limit
+      std::size_t m_max_file_size   { std::numeric_limits<std::size_t>::max() };
+      /// Property: vector with disabled collections
+      std::vector<std::string> m_disabledCollections { };
+      /// Property: vector with disabled collections
+      bool  m_disableParticles      { false };
+
+      /// Connection parameters to the "current" output source
+      std::unique_ptr<internals_t> imp     { };
+
+    protected:
+      /// Define standard assignments and constructors
+      DDDIGI_DEFINE_ACTION_CONSTRUCTORS(DigiROOTOutput);
+
+    public:
+      /// Standard constructor
+      DigiROOTOutput(const DigiKernel& kernel, const std::string& nam);
+      /// Default destructor
+      virtual ~DigiROOTOutput();
+      /// Callback to read event output
+      virtual void execute(DigiContext& context)  const override;
+    };
+  }    // End namespace digi
+}      // End namespace dd4hep
+#endif // DDDIGI_DIGIROOTOUTPUT_H
diff --git a/DDDigi/plugins/Components.cpp b/DDDigi/plugins/Components.cpp
index abfe7880fc80658e1fc2a4a419a6817650d9fc98..b9ef72ec906249a0c1a86537b408798849161761 100644
--- a/DDDigi/plugins/Components.cpp
+++ b/DDDigi/plugins/Components.cpp
@@ -27,6 +27,12 @@ DECLARE_DIGIACTION_NS(dd4hep::digi,DigiInputAction)
 #include <DDDigi/DigiROOTInput.h>
 DECLARE_DIGIACTION_NS(dd4hep::digi,DigiROOTInput)
 
+#include <DDDigi/DigiOutputAction.h>
+DECLARE_DIGIACTION_NS(dd4hep::digi,DigiOutputAction)
+
+#include <DDDigi/DigiROOTOutput.h>
+DECLARE_DIGIACTION_NS(dd4hep::digi,DigiROOTOutput)
+
 #include <DDDigi/DigiSynchronize.h>
 DECLARE_DIGIACTION_NS(dd4hep::digi,DigiSynchronize)
 
@@ -54,6 +60,9 @@ DECLARE_DIGIACTION_NS(dd4hep::digi,DigiAttenuatorSequence)
 #include <DDDigi/DigiContainerCombine.h>
 DECLARE_DIGIACTION_NS(dd4hep::digi,DigiContainerCombine)
 
+#include <DDDigi/DigiContainerDrop.h>
+DECLARE_DIGIACTION_NS(dd4hep::digi,DigiContainerDrop)
+
 #include <DDDigi/DigiSegmentProcessor.h>
 DECLARE_DIGIACTION_NS(dd4hep::digi,DigiSegmentProcessor)
 DECLARE_DIGIACTION_NS(dd4hep::digi,DigiSegmentSequence)
diff --git a/DDDigi/plugins/DigiDepositSmearing.cpp b/DDDigi/plugins/DigiDepositSmearing.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..da28a26234e2de48b53edd7a0a39627ff6ae3a79
--- /dev/null
+++ b/DDDigi/plugins/DigiDepositSmearing.cpp
@@ -0,0 +1,87 @@
+//==========================================================================
+//  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 <DDDigi/DigiContainerProcessor.h>
+
+/// C/C++ include files
+#include <limits>
+
+/// Namespace for the AIDA detector description toolkit
+namespace dd4hep {
+  /// Namespace for the Digitization part of the AIDA detector description toolkit
+  namespace digi {
+
+    /// Actor to smear geographically energy deposits
+    /**
+     *
+     *  \author  M.Frank
+     *  \version 1.0
+     *  \ingroup DD4HEP_DIGITIZATION
+     */
+    class DigiDepositSmearing : public DigiContainerProcessor   {
+    protected:
+      /// Property: Energy cutoff. No hits will be merged with a deposit smaller
+      double m_cutoff { std::numeric_limits<double>::epsilon() };
+      /// Property: register empty containers
+      bool   m_register_empty_containers { true };
+
+    public:
+      /// Standard constructor
+      DigiDepositSmearing(const DigiKernel& krnl, const std::string& nam)
+	: DigiContainerProcessor(krnl, nam)
+      {
+	declareProperty("deposit_cutoff", m_cutoff);
+	declareProperty("m_register_empty_containers", m_register_empty_containers);
+      }
+
+      /// Create deposit mapping with updates on same cellIDs
+      template <typename T> void create_deposits(const T& cont, work_t& work)  const  {
+	Key key(cont.name, work.output.mask);
+	DepositMapping m(cont.name, work.output.mask);
+	std::size_t dropped = 0UL, updated = 0UL, added = 0UL;
+	for( const auto& dep : cont )    {
+	  const EnergyDeposit& depo = dep.second;
+	  if ( depo.deposit >= m_cutoff )   {
+	    CellID cell = dep.first;
+	    auto   iter = m.data.find(cell);
+	    if ( iter == m.data.end() )
+	      m.data.emplace(dep.first, depo), ++added;
+	    else
+	      iter->second.update_deposit_weighted(depo), ++updated;
+	    continue;
+	  }
+	  ++dropped;
+	}
+	if ( m_register_empty_containers )   {
+	  work.output.data.put(m.key, std::move(m));
+	}
+	info("+++ %-32s added %6ld updated %6ld dropped %6ld entries (now: %6ld) from mask: %04X to mask: %04X",
+	     cont.name.c_str(), added, updated, dropped, m.size(), cont.key.mask(), m.key.mask());
+      }
+
+      /// Main functional callback
+      virtual void execute(DigiContext&, work_t& work)  const override final  {
+	if ( const auto* v = work.get_input<DepositVector>() )
+	  create_deposits(*v, work);
+	else if ( const auto* m = work.get_input<DepositMapping>() )
+	  create_deposits(*m, work);
+	else
+	  except("Request to handle unknown data type: %s", work.input_type_name().c_str());
+      }
+    };
+  }    // End namespace digi
+}      // End namespace dd4hep
+
+#include <DDDigi/DigiFactories.h>
+DECLARE_DIGIACTION_NS(dd4hep::digi,DigiDepositSmearing)
diff --git a/DDDigi/plugins/DigiDepositWeightedPosition.cpp b/DDDigi/plugins/DigiDepositWeightedPosition.cpp
index 8a5ae36d48ee6f23c4fe65240a55e60f28109bfa..80ef0b495e8787be9789b99fd7d950c0142f3f94 100644
--- a/DDDigi/plugins/DigiDepositWeightedPosition.cpp
+++ b/DDDigi/plugins/DigiDepositWeightedPosition.cpp
@@ -22,9 +22,8 @@ namespace dd4hep {
   /// Namespace for the Digitization part of the AIDA detector description toolkit
   namespace digi {
 
-    /// Actor to select energy deposits according to the supplied segmentation
-    /** Actor to select energy deposits according to the supplied segmentation
-     *
+    /// Actor to merge energy deposits weighted with their energy deposit
+    /**
      *  The selected deposits are placed in the output container
      *  supplied by the arguments. Multiple CellIDs will be merged to one single 
      *  deposit, where the merge computes the resulting position and
diff --git a/DDDigi/plugins/DigiHitHistoryDrop.cpp b/DDDigi/plugins/DigiHitHistoryDrop.cpp
index b4da3d172a1ce476cd96a860d4494e0fcdfcf923..652129098a2027e16a894e715e2e93f485154d64 100644
--- a/DDDigi/plugins/DigiHitHistoryDrop.cpp
+++ b/DDDigi/plugins/DigiHitHistoryDrop.cpp
@@ -59,6 +59,18 @@ namespace dd4hep {
 	InstanceCount::increment(this);
       }
 
+      template <typename T>
+      std::pair<std::size_t, std::size_t> drop_history(T& cont)  const  {
+	std::size_t num_drop_hit = 0;
+	std::size_t num_drop_particle = 0;
+	for( auto& c : cont )    {
+	  auto ret = c.second.history.drop();
+	  num_drop_hit += ret.first;
+	  num_drop_particle += ret.second;
+	}
+	return std::make_pair(num_drop_hit,num_drop_particle);
+      }
+
       /// Main functional callback
       virtual void execute(DigiContext& context)  const  final  {
 	auto& inputs = context.event->get_segment(m_input);
@@ -69,20 +81,14 @@ namespace dd4hep {
 	  auto im = std::find(m_masks.begin(), m_masks.end(), key.mask());
 	  if ( im != m_masks.end() )   {
 	    if ( DepositMapping* m = std::any_cast<DepositMapping>(&i.second) )    {
-	      for( auto& c : *m )    {
-		num_drop_hit += c.second.hit_history.size();
-		c.second.hit_history.clear();
-		num_drop_particle += c.second.particle_history.size();
-		c.second.particle_history.clear();
-	      }
+	      auto ret = drop_history(*m);
+	      num_drop_hit += ret.first;
+	      num_drop_particle += ret.second;
 	    }
 	    if ( DepositVector* m = std::any_cast<DepositVector>(&i.second) )    {
-	      for( auto& c : *m )    {
-		num_drop_hit += c.second.hit_history.size();
-		c.second.hit_history.clear();
-		num_drop_particle += c.second.particle_history.size();
-		c.second.particle_history.clear();
-	      }
+	      auto ret = drop_history(*m);
+	      num_drop_hit += ret.first;
+	      num_drop_particle += ret.second;
 	    }
 	  }
 	}
diff --git a/DDDigi/plugins/DigiSegmentDepositExtractor.cpp b/DDDigi/plugins/DigiSegmentDepositExtractor.cpp
index bb6a5ebc2529fd32304e1625cd4b492493f06ff5..7ee93ee136647773d4148e5f562467c22e7a1d29 100644
--- a/DDDigi/plugins/DigiSegmentDepositExtractor.cpp
+++ b/DDDigi/plugins/DigiSegmentDepositExtractor.cpp
@@ -47,7 +47,7 @@ namespace dd4hep {
       }
       /// Main functional callback
       virtual void execute(DigiContext&, work_t& work)  const override final  {
-	if ( segment.matches(work.input.key.key) )   {
+	if ( segment.matches(work.input.key.value()) )   {
 	  if ( const auto* m = work.get_input<DepositMapping>() )
 	    copy_deposits(*m, work);
 	  else if ( const auto* v = work.get_input<DepositVector>() )
diff --git a/DDDigi/plugins/DigiSegmentDepositPrint.cpp b/DDDigi/plugins/DigiSegmentDepositPrint.cpp
index a8fa3b1a388275d83e3fd8fea5bdaad063d7e25a..a76fa9f06c81d482ee60dcda043e13469300d509 100644
--- a/DDDigi/plugins/DigiSegmentDepositPrint.cpp
+++ b/DDDigi/plugins/DigiSegmentDepositPrint.cpp
@@ -35,8 +35,8 @@ namespace dd4hep {
 
       void print_deposit(const char* format, CellID cell, const EnergyDeposit& depo)  const   {
 	info(format, segment.split_id(cell), cell,
-	     depo.hit_history.size(), 
-	     depo.particle_history.size(),
+	     depo.history.hits.size(), 
+	     depo.history.particles.size(),
 	     depo.deposit);
       }
       /// Main functional callback
@@ -54,7 +54,7 @@ namespace dd4hep {
 	else if ( const auto* v = work.get_input<DepositVector>() )
 	  std::for_each(v->begin(), v->end(), call);
 	else
-	  error("+++ Request to dump an invalid container %s", Key::key_name(work.input.key.item()).c_str());
+	  error("+++ Request to dump an invalid container %s", Key::key_name(work.input.key).c_str());
       }
     };
   }    // End namespace digi
diff --git a/DDDigi/plugins/DigiSimpleADCResponse.cpp b/DDDigi/plugins/DigiSimpleADCResponse.cpp
index 029f4ebc808c9644b8a0d24d3b77f9c9cc20ade9..b540f1d9a0c7479c713341e99f60840fc9b2b969 100644
--- a/DDDigi/plugins/DigiSimpleADCResponse.cpp
+++ b/DDDigi/plugins/DigiSimpleADCResponse.cpp
@@ -24,7 +24,8 @@ namespace dd4hep {
   namespace digi {
 
     class DigiSimpleADCResponse : public DigiSegmentProcessor  {
-      std::string m_name_postfix       { ".adc" };
+      std::string m_response_postfix   { ".adc" };
+      std::string m_history_postfix    { ".hist" };
       double      m_use_segmentation   { false  };
       double      m_signal_cutoff      { std::numeric_limits<double>::epsilon() };
       double      m_signal_saturation  { std::numeric_limits<double>::max() };
@@ -35,29 +36,34 @@ namespace dd4hep {
       DigiSimpleADCResponse(const DigiKernel& krnl, const std::string& nam)
 	: DigiSegmentProcessor(krnl, nam)
       {
-	declareProperty("cutoff",         m_signal_cutoff);
-	declareProperty("saturation",     m_signal_saturation);
-	declareProperty("adc_resolution", m_adc_resolution);
-	declareProperty("name_postfix",   m_name_postfix);
+	declareProperty("cutoff",           m_signal_cutoff);
+	declareProperty("saturation",       m_signal_saturation);
+	declareProperty("adc_resolution",   m_adc_resolution);
+	declareProperty("response_postfix", m_response_postfix);
+	declareProperty("history_postfix",  m_history_postfix);
       }
 
       /// Create container with ADC counts and register it to the output segment
       template <typename T, typename P>
       void create_adc_counts(const char* tag, const T& input, work_t& work, const P& predicate)  const  {
 	std::string postfix = m_use_segmentation ? "."+segment.identifier() : std::string();
-	std::string outname = input.name + postfix + m_name_postfix;
-	DetectorResponse response(outname, work.output.mask);
+	std::string response_name = input.name + postfix + m_response_postfix;
+	std::string history_name  = input.name + postfix + m_history_postfix;
+	DetectorResponse response(response_name, work.output.mask);
+	DetectorHistory  history (history_name, work.output.mask);
 	for( const auto& dep : input )   {
 	  if ( predicate(dep) )   {
 	    CellID      cell = dep.first;
 	    const auto& depo = dep.second;
 	    ADCValue::value_t adc_count = std::round((depo.deposit * m_adc_resolution) / m_signal_saturation);
 	    response.emplace(cell, {adc_count, ADCValue::address_t(cell)});
+	    history.insert(cell, depo.history);
 	  }
 	}
 	info("%s+++ %-32s %6ld ADC values. Input: %-32s %6ld deposits", tag,
-	     outname.c_str(), response.size(), input.name.c_str(), input.size());
+	     response_name.c_str(), response.size(), input.name.c_str(), input.size());
         work.output.data.put(response.key, std::move(response));
+        work.output.data.put(history.key,  std::move(history));
       }
       /// Create container with ADC counts and register it to the output segment
       template <typename P>
@@ -75,7 +81,7 @@ namespace dd4hep {
       virtual void execute(DigiContext& context, work_t& work)  const override final  {
 	if ( !m_use_segmentation )
 	  create_adc_counts(context, work, accept_all_t());
-	else if ( segment.matches(work.input.key.key) )
+	else if ( segment.matches(work.input.key.value()) )
 	  create_adc_counts(context, work, accept_segment_t(segment));
       }
     };
diff --git a/DDDigi/python/dddigi.py b/DDDigi/python/dddigi.py
index e36dffcdb2521f8528e8fa5f468b064b9e21703b..40e4d1bf73670bdacdcdf7d1e5b2510c40042944 100644
--- a/DDDigi/python/dddigi.py
+++ b/DDDigi/python/dddigi.py
@@ -159,11 +159,27 @@ def _setKernelProperty(self, name, value):
 # ---------------------------------------------------------------------------
 
 
+def TestAction(kernel, nam, sleep=0):
+  obj = Interface.createAction(kernel, str('DigiTestAction/' + nam))
+  if sleep != 0:
+    obj.sleep = sleep
+  return obj
+# ---------------------------------------------------------------------------
+
+
+def Action(kernel, nam, **options):
+  action = Interface.createAction(kernel, str(nam))
+  for option in options.items():
+    setattr(action, option[0], option[1])
+  return action
+# ---------------------------------------------------------------------------
+
+
 def _get_action(self):
   return Interface.toAction(self)
-  #if hasattr(self, 'I_am_a_ROOT_interface_handle'):
-  #  return Interface.toAction(self.get())
-  #return self
+  # if hasattr(self, 'I_am_a_ROOT_interface_handle'):
+  #   return Interface.toAction(self.get())
+  # return self
 # ---------------------------------------------------------------------------
 
 
@@ -214,13 +230,6 @@ Kernel.terminate = _kernel_terminate
 # ---------------------------------------------------------------------------
 
 
-def _get_container_processor(self):
-  if hasattr(self, 'I_am_a_ROOT_interface_handle'):
-    return Interface.toContainerProcessor(self.get())
-  return self
-# ---------------------------------------------------------------------------
-
-
 def _default_adopt(self, action):
   getattr(self, '__adopt')(action.get())
 # ---------------------------------------------------------------------------
@@ -228,22 +237,23 @@ def _default_adopt(self, action):
 
 def _adopt_event_action(self, action):
   " Helper to convert DigiActions objects to DigiEventAction "
-  getattr(self, '__adopt')(Interface.toEventAction(action.get()))
+  proc = Interface.toEventAction(_get_action(action))
+  attr = getattr(self, '__adopt')
+  attr(proc)
 # ---------------------------------------------------------------------------
 
 
-def _adopt_processor_action(self, action, container):
+def _adopt_container_processor(self, action, container):
   " Helper to convert DigiActions objects to DigiEventAction "
-  attr = getattr(self, 'adopt_processor')
-  proc = _get_container_processor(action)
+  attr = getattr(_get_action(self), 'adopt_processor')
+  proc = Interface.toContainerProcessor(_get_action(action))
   attr(proc, container)
-  # print('ContainerProcessor succesfully adopted')
 # ---------------------------------------------------------------------------
 
 
 def _adopt_sequence_action(self, name, **options):
   " Helper to adopt DigiAction objects for DigiSynchronize "
-  kernel = Interface.createKernel(Interface.toAction(self))
+  kernel = Interface.createKernel(_get_action(self))
   action = Action(kernel, name)
   for option in options.items():
     setattr(action, option[0], option[1])
@@ -253,16 +263,8 @@ def _adopt_sequence_action(self, name, **options):
 
 
 def _adopt_processor(self, action, containers):
-  getattr(self, '__adopt_processor')(action.get(), containers)
-# ---------------------------------------------------------------------------
-
-
-def _setup(obj, call='adopt', py_call=_default_adopt):
-  _import_class('digi', obj)
-  cls = getattr(current, obj)
-  setattr(cls, '__' + call, getattr(cls, call))
-  setattr(cls, call, py_call)
-  return cls
+  proc = Interface.toContainerProcessor(_get_action(action))
+  attr = getattr(_get_action(self), '__adopt_processor')(proc, containers)
 # ---------------------------------------------------------------------------
 
 
@@ -283,12 +285,12 @@ def _get(self, name):
 def _set(self, name, value):
   """This function is called when properties are passed to the c++ objects."""
   import dd4hep as dd4hep
-  a = Interface.toAction(self)
+  action = _get_action(self)
   name = dd4hep.unicode_2_string(name)
   value = dd4hep.unicode_2_string(value)
-  if Interface.setProperty(a, name, value):
+  if Interface.setProperty(action, name, value):
     return
-  msg = 'DigiAction::SetProperty [Unhandled]: Cannot set ' + a.name() + '.' + name + ' = ' + value
+  msg = 'DigiAction::SetProperty [Unhandled]: Cannot set ' + action.name() + '.' + name + ' = ' + value
   raise KeyError(msg)
 # ---------------------------------------------------------------------------
 
@@ -297,37 +299,25 @@ def _props(obj, **extensions):
   _import_class('digi', obj)
   cls = getattr(current, obj)
   for extension in extensions.items():
-    setattr(cls, extension[0], extension[1])
+    call = extension[0]
+    if hasattr(cls, call):
+      setattr(cls, '__' + call, getattr(cls, call))
+    setattr(cls, call, extension[1])
   cls.__getattr__ = _get
   cls.__setattr__ = _set
   return cls
 # ---------------------------------------------------------------------------
 
 
-def TestAction(kernel, nam, sleep=0):
-  obj = Interface.createAction(kernel, str('DigiTestAction/' + nam))
-  if sleep != 0:
-    obj.sleep = sleep
-  return obj
-# ---------------------------------------------------------------------------
-
-
-def Action(kernel, nam, **options):
-  action = Interface.createAction(kernel, str(nam))
-  for option in options.items():
-    setattr(action, option[0], option[1])
-  return action
-# ---------------------------------------------------------------------------
-
-
-_setup('DigiSynchronize', call='adopt', py_call=_adopt_event_action)
-_setup('DigiActionSequence', call='adopt', py_call=_adopt_event_action)
-
+#
+# Import unmodified classes from C++
 _import_class('digi', 'DigiKernel')
 _import_class('digi', 'DigiContext')
 _import_class('digi', 'DigiAction')
 _import_class('digi', 'DigiEventAction')
 _import_class('digi', 'DigiInputAction')
+#
+# Import classes with specialized python extensions
 _props('ActionHandle',
        adopt_property=_adopt_property,
        add_property=_add_property,
@@ -336,15 +326,13 @@ _props('ActionHandle',
        add_list_property=_add_list_property,
        add_vector_property=_add_vector_property,
        add_mapped_property=_add_mapped_property)
-_props('DigiSynchronize', adopt_action=_adopt_sequence_action)
-_props('DigiActionSequence', adopt_action=_adopt_sequence_action)
+_props('DigiSynchronize', adopt=_adopt_event_action, adopt_action=_adopt_sequence_action)
+_props('DigiActionSequence', adopt=_adopt_event_action, adopt_action=_adopt_sequence_action)
 _props('DigiParallelActionSequence', adopt_action=_adopt_sequence_action)
 _props('DigiSequentialActionSequence', adopt_action=_adopt_sequence_action)
-_props('DigiContainerSequenceAction', adopt_container_processor=_adopt_processor_action)
-
-_setup('DigiMultiContainerProcessor', call='adopt_processor', py_call=_adopt_processor)
-
-
+_props('DigiContainerSequenceAction', adopt_container_processor=_adopt_container_processor)
+_props('DigiMultiContainerProcessor', adopt_processor=_adopt_processor)
+#
 # Need to import digitize late, since it cross includes dddigi
 Digitize = None
 try:
diff --git a/DDDigi/src/DigiAttenuator.cpp b/DDDigi/src/DigiAttenuator.cpp
index 3eb43cde4887b27a65f7898672ce6ae6dbfc05ba..42f4746f38983b00a914d8e0d5dbdb44bbecbfe1 100644
--- a/DDDigi/src/DigiAttenuator.cpp
+++ b/DDDigi/src/DigiAttenuator.cpp
@@ -44,8 +44,12 @@ DigiAttenuator::~DigiAttenuator() {
 
 /// Attenuator callback for single container
 template <typename T> std::size_t DigiAttenuator::attenuate(T& cont) const {
-  for( auto& c : cont )
-    c.second.deposit *= m_factor;
+  for( auto& c : cont )   {
+    auto& depo = c.second;
+    depo.deposit *= m_factor;
+    for( auto& h : depo.history.hits ) h.weight *= m_factor;
+    for( auto& h : depo.history.particles ) h.weight *= m_factor;
+  }
   return cont.size();
 }
 
diff --git a/DDDigi/src/DigiContainerCombine.cpp b/DDDigi/src/DigiContainerCombine.cpp
index 2fa76e7eeb614528e74ff62d91e523e0a5a01df8..8f144b346522d6d95fa08e17ab5ef66d367cc64b 100644
--- a/DDDigi/src/DigiContainerCombine.cpp
+++ b/DDDigi/src/DigiContainerCombine.cpp
@@ -47,7 +47,7 @@ public:
     keys.reserve(inputs.size());
     work.reserve(inputs.size());
     for( auto& i : inputs )   {
-      Key  key = i.first;
+      Key  key(i.first);
       if ( combine->use_key(key) )   {
 	keys.emplace_back(key);
 	work.emplace_back(&i.second);
@@ -60,29 +60,57 @@ public:
     format[sizeof(format)-1] = 0;
   }
 
-  template<typename T> void merge_depos(DepositVector& output, T& input, int thr)  {
+  template<typename OUT, typename IN> void merge_depos(OUT& output, IN& input, int thr)  {
     std::size_t cnt = 0;
     if ( combine->m_erase_combined )
       cnt = output.merge(std::move(input));
     else
       cnt = output.insert(input);
-    combine->debug(this->format, thr, input.name.c_str(), input.key.values.mask, cnt, "deposits"); 
+    combine->debug(this->format, thr, input.name.c_str(), input.key.mask(), cnt, "deposits"); 
     this->cnt_depos += cnt;
     this->cnt_conts++;
   }
 
-  void merge(const std::string& nam, size_t start, int thr)  {
+  void merge_hist(const std::string& nam, size_t start, int thr)  {
+    std::size_t cnt;
     Key key = keys[start];
-    DepositVector out(nam, combine->m_deposit_mask);
-    for( std::size_t j = start; j < keys.size(); ++j )   {
+    DetectorHistory out(nam, combine->m_deposit_mask);
+    for( std::size_t j=start; j < keys.size(); ++j )   {
       if ( keys[j].item() == key.item() )   {
-	if ( DepositMapping* m = std::any_cast<DepositMapping>(work[j]) )
-	  merge_depos(out, *m, thr);
-	else if ( DepositVector* v = std::any_cast<DepositVector>(work[j]) )
-	  merge_depos(out, *v, thr);
-	else 
-	  continue;
-	this->work[j]->reset();
+	DetectorHistory* next = std::any_cast<DetectorHistory>(work[j]);
+	if ( combine->m_erase_combined )   {
+	  cnt = out.merge(std::move(*next));
+	  work[j]->reset();
+	}
+	else   {
+	  cnt = out.insert(*next);
+	}
+	combine->debug(format, thr, next->name.c_str(), keys[j].mask(), cnt, "histories"); 
+	cnt_parts += cnt;
+	cnt_conts++;
+      }
+    }
+    key.set_mask(combine->m_deposit_mask);
+    outputs.emplace(key, std::move(out));
+  }
+
+  void merge_response(const std::string& nam, size_t start, int thr)  {
+    std::size_t cnt;
+    Key key = keys[start];
+    DetectorResponse out(nam, combine->m_deposit_mask);
+    for( std::size_t j=start; j < keys.size(); ++j )   {
+      if ( keys[j].item() == key.item() )   {
+	DetectorResponse* next = std::any_cast<DetectorResponse>(work[j]);
+	if ( combine->m_erase_combined )   {
+	  cnt = out.merge(std::move(*next));
+	  work[j]->reset();
+	}
+	else   {
+	  cnt = out.insert(*next);
+	}
+	combine->debug(format, thr, next->name.c_str(), keys[j].mask(), cnt, "histories"); 
+	cnt_parts += cnt;
+	cnt_conts++;
       }
     }
     key.set_mask(combine->m_deposit_mask);
@@ -90,16 +118,42 @@ public:
   }
 
   void merge_parts(const std::string& nam, size_t start, int thr)  {
+    std::size_t cnt;
     Key key = keys[start];
     ParticleMapping out(nam, combine->m_deposit_mask);
     for( std::size_t j=start; j < keys.size(); ++j )   {
       if ( keys[j].item() == key.item() )   {
 	ParticleMapping* next = std::any_cast<ParticleMapping>(work[j]);
-	std::size_t cnt = out.merge(std::move(*next));
+	if ( combine->m_erase_combined )   {
+	  cnt = out.merge(std::move(*next));
+	  work[j]->reset();
+	}
+	else   {
+	  cnt = out.insert(*next);
+	}
 	combine->debug(format, thr, next->name.c_str(), keys[j].mask(), cnt, "particles"); 
 	cnt_parts += cnt;
 	cnt_conts++;
-	work[j]->reset();
+      }
+    }
+    key.set_mask(combine->m_deposit_mask);
+    outputs.emplace(key, std::move(out));
+  }
+
+  void merge(const std::string& nam, size_t start, int thr)  {
+    Key key = keys[start];
+    DepositVector out(nam, combine->m_deposit_mask);
+    for( std::size_t j = start; j < keys.size(); ++j )   {
+      if ( keys[j].item() == key.item() )   {
+	if ( DepositMapping* m = std::any_cast<DepositMapping>(work[j]) )
+	  merge_depos(out, *m, thr);
+	else if ( DepositVector* v = std::any_cast<DepositVector>(work[j]) )
+	  merge_depos(out, *v, thr);
+	else
+	  break;
+	if ( combine->m_erase_combined )
+	  this->work[j]->reset();
+	break;
       }
     }
     key.set_mask(combine->m_deposit_mask);
@@ -109,23 +163,29 @@ public:
   void merge_one(Key::itemkey_type itm, int thr)   {
     const std::string& opt = combine->m_output_name_flag;
     for( std::size_t i=0; i < keys.size(); ++i )   {
-      if ( keys[i].values.item != itm )
+      if ( keys[i].item() != itm )
 	continue;
       /// Merge deposit mapping
       if ( DepositMapping* depom = std::any_cast<DepositMapping>(work[i]) )   {
 	merge(depom->name+opt, i, thr);
-	break;
       }
       /// Merge deposit vector
       else if ( DepositVector* depov = std::any_cast<DepositVector>(work[i]) )   {
 	merge(depov->name+opt, i, thr);
-	break;
+      }
+      /// Merge detector response
+      else if ( DetectorResponse* resp = std::any_cast<DetectorResponse>(work[i]) )   {
+	merge_response(resp->name+opt, i, thr);
+      }
+      /// Merge response history
+      else if ( DetectorHistory* hist = std::any_cast<DetectorHistory>(work[i]) )   {
+	merge_hist(hist->name+opt, i, thr);
       }
       /// Merge particle container
       else if ( ParticleMapping* parts = std::any_cast<ParticleMapping>(work[i]) )   {
 	merge_parts(parts->name+opt, i, thr);
-	break;
       }
+      break;
     }
   }
 
@@ -173,14 +233,14 @@ DigiContainerCombine::~DigiContainerCombine() {
 void DigiContainerCombine::initialize()    {
   for ( const auto& cont : m_containers )   {
     Key key(cont, 0x0);
-    m_cont_keys.emplace(key.key);
+    m_cont_keys.emplace(key.item());
     if ( m_input_masks.empty() )   {
-      m_keys.emplace(key.key);
+      m_keys.emplace(key.value());
       continue;
     }
     for ( int m : m_input_masks )    {
-      key.values.mask = m;
-      m_keys.emplace(key.key);
+      key.set_mask(m);
+      m_keys.emplace(key.value());
     }
   }
   if ( !m_output_name_flag.empty() )
@@ -201,8 +261,10 @@ bool DigiContainerCombine::use_key(Key key)  const   {
   const auto& m = m_input_masks;
   bool use = m.empty() || m_keys.empty();
   if ( !use )  {
-    if ( !m_cont_keys.empty() )
-      return m_cont_keys.find(key.item()) != m_cont_keys.end();
+    if ( !m_cont_keys.empty() )  {
+      key.set_mask(0);
+      return m_cont_keys.find(key.value()) != m_cont_keys.end();
+    }
     return std::find(m.begin(), m.end(), key.mask()) != m.end();
   }
   return true;
diff --git a/DDDigi/src/DigiContainerDrop.cpp b/DDDigi/src/DigiContainerDrop.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..75a69639d05d2fc992d83a586b7123a7b0ca7419
--- /dev/null
+++ b/DDDigi/src/DigiContainerDrop.cpp
@@ -0,0 +1,158 @@
+//==========================================================================
+//  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/DigiContainerDrop.h>
+
+/// C/C++ include files
+#include <set>
+
+using namespace dd4hep::digi;
+
+class DigiContainerDrop::work_definition_t  {
+public:
+  const DigiContainerDrop* drop;
+  std::vector<Key>            keys;
+  std::vector<std::any*>      work;
+  std::set<Key::itemkey_type> items;
+
+  DigiEvent&                  event;
+  DataSegment&                inputs;
+
+  /// Initializing constructor
+  work_definition_t(const DigiContainerDrop* c, DigiEvent& ev, DataSegment& in)
+    : drop(c), event(ev), inputs(in)
+  {
+    keys.reserve(inputs.size());
+    work.reserve(inputs.size());
+    for( auto& i : inputs )   {
+      Key  key(i.first);
+      if ( drop->use_key(key) )   {
+	keys.emplace_back(key);
+	work.emplace_back(&i.second);
+	items.insert(key.item());
+      }
+    }
+  }
+
+  void drop_one(Key::itemkey_type itm)   {
+    for( std::size_t i=0; i < keys.size(); ++i )   {
+      if ( keys[i].item() != itm )
+	continue;
+      /// Drop deposit mapping
+      if (      std::any_cast<DepositMapping>(work[i]) )
+	work[i]->reset();
+      /// Drop deposit vector
+      else if ( std::any_cast<DepositVector>(work[i]) )
+	work[i]->reset();
+      /// Drop particle container
+      else if ( std::any_cast<ParticleMapping>(work[i]) )
+	work[i]->reset();
+      /// Drop deposit history
+      else if ( std::any_cast<DetectorHistory>(work[i]) )
+	work[i]->reset();
+      /// Drop detector response
+      else if ( std::any_cast<DetectorResponse>(work[i]) )
+	work[i]->reset();
+      break;
+    }
+  }
+
+  void drop_all()   {
+    for( auto itm : items )
+      drop_one(itm);
+  }
+};
+
+template <> void DigiParallelWorker<DigiContainerDrop,
+				    DigiContainerDrop::work_definition_t,
+				    std::size_t>::execute(void* data) const  {
+  calldata_t* args = reinterpret_cast<calldata_t*>(data);
+  std::size_t cnt = 0;
+  for( auto itm : args->items )  {
+    if ( cnt == this->options )   {
+      args->drop_one(itm);
+      return;
+    }
+    ++cnt;
+  }
+}
+
+/// Standard constructor
+DigiContainerDrop::DigiContainerDrop(const DigiKernel& krnl, const std::string& nam)
+  : DigiEventAction(krnl, nam)
+{
+  declareProperty("containers",       m_containers);
+  declareProperty("input_masks",      m_input_masks);
+  declareProperty("input_segment",    m_input  = "inputs");
+  m_kernel.register_initialize(Callback(this).make(&DigiContainerDrop::initialize));
+  InstanceCount::increment(this);
+}
+
+/// Default destructor
+DigiContainerDrop::~DigiContainerDrop() {
+  InstanceCount::decrement(this);
+}
+
+/// Initializing function: compute values which depend on properties
+void DigiContainerDrop::initialize()    {
+  for ( const auto& cont : m_containers )   {
+    Key key(cont, 0x0);
+    m_cont_keys.emplace(key.value());
+    if ( m_input_masks.empty() )   {
+      m_keys.emplace(key.value());
+      continue;
+    }
+    for ( int m : m_input_masks )    {
+      key.set_mask(m);
+      m_keys.emplace(key.value());
+    }
+  }
+}
+
+/// Decide if a continer is to dropd based on the properties
+bool DigiContainerDrop::use_key(Key key)  const   {
+  const auto& m = m_input_masks;
+  bool use = m.empty() || m_keys.empty();
+  if ( !use )  {
+    if ( !m_cont_keys.empty() )
+      return m_cont_keys.find(key.item()) != m_cont_keys.end();
+    return std::find(m.begin(), m.end(), key.mask()) != m.end();
+  }
+  return true;
+}
+
+/// Main functional callback
+void DigiContainerDrop::execute(DigiContext& context)  const    {
+  auto& event    = *context.event;
+  auto& inputs   = event.get_segment(m_input);
+  work_definition_t def(this, event, inputs);
+  if ( m_parallel )  {
+    size_t count = def.items.size();
+    if ( m_workers.size() < count )   {
+      auto group = m_workers.get_group(); // Lock worker group
+      for(size_t i=m_workers.size(); i <= count; ++i)
+	m_workers.insert(new Worker(nullptr, i));
+    }
+    m_kernel.submit(context, m_workers.get_group(), def.items.size(), &def);
+  }
+  else  {
+    def.drop_all();
+  }
+  inputs.erase(def.keys);
+}
+
diff --git a/DDDigi/src/DigiContainerProcessor.cpp b/DDDigi/src/DigiContainerProcessor.cpp
index 87adb9f3932d4a437e2873ebe83dcbfdacee8efd..758f75162a8246d43572294c78d691488810ac60 100644
--- a/DDDigi/src/DigiContainerProcessor.cpp
+++ b/DDDigi/src/DigiContainerProcessor.cpp
@@ -98,7 +98,7 @@ void DigiContainerProcessor::execute(DigiContext& context, work_t& work)  const
 /// Main functional callback if specific work is known
 void DigiContainerProcessor::execute(DigiContext& context, Key key, std::any& /* data */)  const    {
   info("%s+++ %p Using container: %016lX  --> %04X %08X %s",
-       context.event->id(), (void*)this, key.key, key.mask(), key.item(), Key::key_name(key).c_str());
+       context.event->id(), (void*)this, key.value(), key.mask(), key.item(), Key::key_name(key).c_str());
 }
 
 /// Standard constructor
@@ -156,9 +156,8 @@ DigiContainerSequenceAction::~DigiContainerSequenceAction() {
 /// Initialization callback
 void dd4hep::digi::DigiContainerSequenceAction::initialize()   {
   for( auto& ent : m_registered_processors )   {
-    Key key = ent.first;
     worker_t* w = new worker_t(ent.second, m_registered_workers.size());
-    m_registered_workers.emplace(key.item(), w);
+    m_registered_workers.emplace(ent.first, w);
     m_workers.insert(w);
   }
 }
@@ -168,7 +167,7 @@ void DigiContainerSequenceAction::adopt_processor(DigiContainerProcessor* action
 						  const std::string& container)
 {
   Key key(container, 0x0);
-  auto it = m_registered_processors.find(key.item());
+  auto it = m_registered_processors.find(key);
   if ( it != m_registered_processors.end() )   {
     if ( action != it->second )   {
       except("+++ The action %s was already registered to mask:%04X container:%s!",
@@ -181,7 +180,7 @@ void DigiContainerSequenceAction::adopt_processor(DigiContainerProcessor* action
     return;
   }
   action->addRef();
-  m_registered_processors.emplace(key.item(), action);
+  m_registered_processors.emplace(key, action);
   info("+++ Adding processor: %s for container: [%08X] %s",
        action->c_name(), key.item(), container.c_str());
 }
@@ -199,9 +198,8 @@ void DigiContainerSequenceAction::adopt_processor(DigiContainerProcessor* action
 /// Get hold of the registered processor for a given container
 DigiContainerSequenceAction::worker_t*
 DigiContainerSequenceAction::need_registered_worker(Key item_key, bool exc)   const  {
-  Key key;
-  key.set_item(item_key.item());
-  auto it = m_registered_workers.find(item_key.item());
+  item_key.set_mask(0);
+  auto it = m_registered_workers.find(item_key);
   if ( it != m_registered_workers.end() )  {
     return it->second;
   }
@@ -218,9 +216,9 @@ void DigiContainerSequenceAction::execute(DigiContext& context)  const   {
   auto& outputs = event.get_segment(m_output_segment);
   std::vector<ParallelWorker*> event_workers;
   output_t output { m_output_mask, outputs };
-  work_t   args   { context, {}, output, m_properties, *this };
+  work_t   args   { context, { }, output, m_properties, *this };
 
-  args.input_items.resize(m_workers.size(), {0, nullptr});
+  args.input_items.resize(m_workers.size(), { { }, nullptr });
   event_workers.reserve(inputs.size());
   for( auto& i : inputs )   {
     Key key(i.first);
@@ -254,6 +252,7 @@ DigiMultiContainerProcessor::DigiMultiContainerProcessor(const DigiKernel& krnl,
   this->declareProperty("input_segment",    m_input_segment);
   this->declareProperty("output_mask",      m_output_mask);
   this->declareProperty("output_segment",   m_output_segment);
+  m_kernel.register_initialize(Callback(this).make(&DigiMultiContainerProcessor::initialize));
   InstanceCount::increment(this);
 }
 
@@ -262,6 +261,58 @@ DigiMultiContainerProcessor::~DigiMultiContainerProcessor() {
   InstanceCount::decrement(this);
 }
 
+/// Initialize action object
+void DigiMultiContainerProcessor::initialize()   {
+  std::map<processor_t*,worker_t*> action_workers;
+  std::map<processor_t*,std::vector<Key> > keys;
+  std::map<processor_t*,std::vector<std::string> > action_containers;
+
+  m_worker_keys.clear();
+  m_worker_map.clear();
+  m_work_items.clear();
+  m_workers.clear();
+  for( auto& proc : m_processors )    {
+    Key key(proc.first, 0x0);
+    m_work_items.insert(key);
+    for ( auto* action : proc.second )   {
+      keys[action].push_back(key);
+      action_containers[action].push_back(proc.first);
+    }
+  }
+  /// We need to preserve the order the actions were submitted
+  /// and remove later added duplicates (for different containers)
+  for( auto* action : m_actions )   {
+    auto worker_keys = keys[action];
+    worker_t* w = nullptr;
+    auto iw = action_workers.find(action);
+    if ( iw != action_workers.end() )   {
+      w = iw->second;
+    }
+    else   {
+      w = new worker_t(action, m_workers.size());
+      m_worker_keys.emplace_back(worker_keys);
+      m_workers.insert(w);
+      action_workers[action] = w;
+    }
+    for( auto key : worker_keys )
+      m_worker_map[key.item()].push_back(w);
+  }
+  /// Add some printout about the configuration
+  for(auto* action : m_actions )   {
+    auto conts = action_containers[action];
+    std::stringstream str;
+    str << "[ ";
+    for( const auto& cont : conts )
+      str << cont << " ";
+    str << "]";
+    info("+++ Use processor: %-32s for processing: %s", action->c_name(), str.str().c_str());
+  }
+  /// All done: release reference count aquired in adopt_processor
+  for(auto* action : m_actions )
+    action->release();
+}
+
+/// Adopt new parallel worker
 void DigiMultiContainerProcessor::adopt_processor(DigiContainerProcessor* action, const std::vector<std::string>& containers)    {
   if ( !action )   {
     except("+++ Attempt to use invalid processor. Request FAILED.");
@@ -269,19 +320,13 @@ void DigiMultiContainerProcessor::adopt_processor(DigiContainerProcessor* action
   else if ( containers.empty() )   {
     except("+++ Processor %s is defined, but no workload was assigned. Request FAILED.");
   }
-  std::stringstream str;
-  std::vector<Key> keys;
-  str << "[ ";
   for(const auto& cont : containers)    {
-    Key key(cont, 0x0);
-    keys.push_back(key);
-    m_work_items.insert(key.item());
-    str << cont << " ";
+    m_processors[cont].push_back(action);
+  }
+  if ( std::find(m_actions.begin(), m_actions.end(), action) == m_actions.end() )   {
+    m_actions.emplace_back(action);
+    action->addRef();
   }
-  str << " ";
-  m_workers.insert(new worker_t(action, m_workers.size()));
-  m_worker_keys.emplace_back(std::move(keys));
-  info("+++ Use processor: %-32s for processing: %s", action->c_name(), str.str().c_str());
 }
 
 /// Main functional callback
@@ -293,10 +338,11 @@ void DigiMultiContainerProcessor::execute(DigiContext& context)  const  {
 
   work_items.reserve(inputs.size());
   for( auto& i : inputs )   {
-    Key in_key(i.first);
-    bool use = msk.empty() || std::find(msk.begin(), msk.end(), in_key.mask()) != msk.end();
+    Key  key(i.first);
+    key.set_mask(0);
+    bool use = msk.empty() || std::find(msk.begin(), msk.end(), key.mask()) != msk.end();
     if ( use )   {
-      use = m_work_items.empty() || m_work_items.find(in_key.item()) != m_work_items.end();
+      use = m_work_items.empty() || m_work_items.find(key) != m_work_items.end();
       if ( use )   {
 	work_items.emplace_back(std::make_pair(i.first, &i.second));
       }
@@ -319,17 +365,28 @@ template <> void DigiParallelWorker<DigiContainerProcessor,
   const auto& keys  = par.worker_keys(this->options);
   const auto& masks = par.input_masks();
   for( const auto& item : arg->items )  {
-    Key key = item.first;
+    Key key(item.first);
+    key.set_mask(0);
+    const char* tag = "";
     if ( masks.empty() || std::find(masks.begin(), masks.end(), key.mask()) != masks.end() )  {
+      tag = "mask accepted";
       if ( keys.empty() )  {
 	DigiContainerProcessor::work_t  work {arg->context, {key, *item.second }, arg->output, arg->properties };
 	action->execute(work.context, work);
+	continue;
       }
-      else if ( std::find(keys.begin(), keys.end(), Key(key.item())) != keys.end() )    {
+      else if ( std::find(keys.begin(), keys.end(), key) != keys.end() )    {
 	DigiContainerProcessor::work_t  work {arg->context, {key, *item.second }, arg->output, arg->properties };
 	action->execute(work.context, work);
+	continue;
       }
+      tag = "no keys matching";
     }
+    if ( tag )  {}
+#if 0
+    par.info("%s+++ Ignore container: %016lX  --> %04X %08X %s [%s]",
+	     arg->context.event->id(), key.value(), key.mask(), key.item(), Key::key_name(key).c_str(), tag);
+#endif
   }
 }
 
diff --git a/DDDigi/src/DigiData.cpp b/DDDigi/src/DigiData.cpp
index 7cdf283b01936d589239b7ff539181122a35ca2b..518d6cf5fb9bf06edb8de56b530ab01aca19c501 100644
--- a/DDDigi/src/DigiData.cpp
+++ b/DDDigi/src/DigiData.cpp
@@ -41,27 +41,48 @@ void Key::set(const std::string& name, int mask)    {
     except("DDDigi::Key", "+++ No key name was specified  --  this is illegal!");
   }
   this->key = 0;
-  this->values.mask = (Key::mask_type)(0xFFFF&mask);
-  this->values.item = detail::hash32(name);
+  this->set_mask(Key::mask_type(0xFFFF&mask));
+  this->set_item(detail::hash32(name));
   std::lock_guard<std::mutex> lock(_k.lock);
   _k.map[this->key] = name;
 }
 
+/// Set key submask
+Key& Key::set_submask(const char* opt_tag)   {
+  submask_type sm = detail::hash16(opt_tag);
+  this->values.submask = sm;
+  return *this;
+}
+
 /// Access key name (if registered properly)
 std::string 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);
+  std::map<unsigned long, std::string>::const_iterator it = _k.map.find(k.value());
   if ( it != _k.map.end() ) return it->second;
   Key kk;
-  kk.values.item = ~0x0;
+  kk.set_item(~0x0);
   for( const auto& e : _k.map )   {
-    if ( (e.first & kk.key) == k.values.item )
+    if ( (e.first & kk.value()) == k.values.item )
       return e.second;
   }
   return "UNKNOWN";
 }
 
+/// Update history
+void History::update(const History& upda)   {
+  hits.insert(hits.end(), upda.hits.begin(), upda.hits.end());
+  particles.insert(particles.end(), upda.particles.begin(), upda.particles.end());
+}
+
+/// Drop history information
+std::pair<std::size_t,std::size_t> History::drop()   {
+  std::pair<std::size_t,std::size_t> ret(hits.size(), particles.size());
+  hits.clear();
+  particles.clear();
+  return ret;
+}
+
 /// Update the deposit using deposit weighting
 void EnergyDeposit::update_deposit_weighted(const EnergyDeposit& upda)  {
   double    sum = deposit + upda.deposit;
@@ -70,8 +91,7 @@ void EnergyDeposit::update_deposit_weighted(const EnergyDeposit& upda)  {
   position = pos;
   momentum = mom;
   deposit  = sum;
-  hit_history.insert(hit_history.end(), upda.hit_history.begin(), upda.hit_history.end());
-  particle_history.insert(particle_history.end(), upda.particle_history.begin(), upda.particle_history.end());
+  history.update(upda.history);
 }
 
 /// Update the deposit using deposit weighting
@@ -82,8 +102,7 @@ void EnergyDeposit::update_deposit_weighted(EnergyDeposit&& upda)  {
   position = pos;
   momentum = mom;
   deposit  = sum;
-  hit_history.insert(hit_history.end(), upda.hit_history.begin(), upda.hit_history.end());
-  particle_history.insert(particle_history.end(), upda.particle_history.begin(), upda.particle_history.end());
+  history.update(upda.history);
 }
 
 /// Merge new deposit map onto existing map
@@ -174,13 +193,21 @@ std::size_t DepositMapping::insert(const DepositMapping& updates)    {
   return update_size;
 }
 
+/// Merge new deposit map onto existing map
+std::size_t ParticleMapping::insert(const ParticleMapping& updates)    {
+  std::size_t update_size = updates.size();
+  for( const ParticleMapping::value_type& c : updates )
+    this->insert(Key(c.first), c.second);
+  return update_size;
+}
+
 /// Merge new deposit map onto existing map
 std::size_t ParticleMapping::merge(ParticleMapping&& updates)    {
   std::size_t update_size = updates.size();
 #if defined(__GNUC__) && (__GNUC__ >= 10)
   for( ParticleMapping::value_type& c : updates )    {
     Particle part(std::move(c.second));
-    this->push(c.first, std::move(part));
+    this->push(Key(c.first), std::move(part));
   }
 #endif
   return update_size;
@@ -191,7 +218,7 @@ void ParticleMapping::push(Key particle_key, Particle&& particle_data)  {
   /// Lower compiler version have a bad implementation of std::any
   bool ret = false;
 #else
-  bool ret = data.emplace(particle_key.key, std::move(particle_data)).second;
+  bool ret = data.emplace(particle_key, std::move(particle_data)).second;
 #endif
   if ( !ret )   {
     except("ParticleMapping","Error in particle map. Duplicate ID: mask:%04X Number:%d History:%s",
@@ -199,17 +226,53 @@ void ParticleMapping::push(Key particle_key, Particle&& particle_data)  {
   }
 }
 
+void ParticleMapping::insert(Key particle_key, const Particle& particle_data)  {
+  bool ret = data.emplace(particle_key, particle_data).second;
+  if ( !ret )   {
+    except("ParticleMapping","Error in particle map. Duplicate ID: mask:%04X Number:%d History:%s",
+	   particle_key.mask(), particle_key.item(), yes_no(particle_data.history.has_value()));
+  }
+}
+
 /// Insert new entry
 void ParticleMapping::emplace(Key particle_key, Particle&& particle_data)  {
 #if defined(__GNUC__) && (__GNUC__ < 10)
   //return std::make_pair(false);
 #else
-  data.emplace(particle_key.key, std::move(particle_data)).second;
+  data.emplace(particle_key, std::move(particle_data)).second;
 #endif
 }
 
+/// Merge new deposit map onto existing map (not thread safe!)
+std::size_t DetectorResponse::merge(DetectorResponse&& updates)   {
+  std::size_t len = updates.size();
+  data.insert(data.end(), updates.data.begin(), updates.data.end());
+  return len;
+}
+
+/// Merge new deposit map onto existing map (not thread safe!)
+std::size_t DetectorResponse::insert(const DetectorResponse& updates)   {
+  std::size_t len = updates.size();
+  data.insert(data.end(), updates.data.begin(), updates.data.end());
+  return len;
+}
+
+/// Merge new deposit map onto existing map (not thread safe!)
+std::size_t DetectorHistory::merge(DetectorHistory&& updates)   {
+  std::size_t len = updates.size();
+  data.insert(data.end(), updates.data.begin(), updates.data.end());
+  return len;
+}
+
+/// Merge new deposit map onto existing map (not thread safe!)
+std::size_t DetectorHistory::insert(const DetectorHistory& updates)   {
+  std::size_t len = updates.size();
+  data.insert(data.end(), updates.data.begin(), updates.data.end());
+  return len;
+}
+
 /// Initializing constructor
-DataSegment::DataSegment(std::mutex& l) : lock(l)
+DataSegment::DataSegment(std::mutex& l, int i) : lock(l), id(i)
 {
 }
 
@@ -220,12 +283,12 @@ bool DataSegment::emplace(Key key, std::any&& item)    {
   /// Lower compiler version have a bad implementation of std::any
   bool ret = false;
 #else
-  bool ret = data.emplace(key.key, std::move(item)).second;
+  bool ret = data.emplace(key, std::move(item)).second;
 #endif
   if ( !ret )   {
     Key k(key);
     except("DataSegment","Error in DataSegment map. Duplicate ID: mask:%04X Number:%d Value:%s",
-	   k.values.mask, k.values.item, yes_no(item.has_value()));
+	   k.mask(), k.item(), yes_no(item.has_value()));
   }
   return ret;
 }
@@ -239,12 +302,13 @@ template <typename DATA> bool DataSegment::put(Key key, DATA&& value)   {
 template bool DataSegment::put(Key key, DepositVector&& data);
 template bool DataSegment::put(Key key, DepositMapping&& data);
 template bool DataSegment::put(Key key, ParticleMapping&& data);
+template bool DataSegment::put(Key key, DetectorHistory&& data);
 template bool DataSegment::put(Key key, DetectorResponse&& data);
 
 /// Remove data item from segment
 bool DataSegment::erase(Key key)    {
   std::lock_guard<std::mutex> l(lock);
-  auto iter = data.find(key.key);
+  auto iter = data.find(key);
   if ( iter != data.end() )   {
     data.erase(iter);
     return true;
@@ -257,7 +321,7 @@ std::size_t DataSegment::erase(const std::vector<Key>& keys)   {
   std::size_t count = 0;
   std::lock_guard<std::mutex> l(lock);
   for(auto key : keys)   {
-    auto iter = data.find(key.key);
+    auto iter = data.find(key);
     if ( iter != data.end() )   {
       data.erase(iter);
       ++count;
@@ -272,7 +336,7 @@ void DataSegment::print_keys()   const   {
   for( const auto& e : this->data )   {
     Key k(e.first);
     printout(INFO, "DataSegment", "Key No.%4: %16lX <> %16lX -> %04X %10ld",
-	     count, e.first, k.key, k.values.mask, k.values.item, 
+	     count, e.first, k.value(), k.mask(), k.item(),
 	     typeName(e.second.type()).c_str());
     ++count;
   }
@@ -281,17 +345,17 @@ void DataSegment::print_keys()   const   {
 /// Call on failed any-casts during data requests
 std::string DataSegment::invalid_cast(Key key, const std::type_info& type)  const   {
   return dd4hep::format(0, "Invalid segment data cast. Key:%ld type:%s",
-			key.key, typeName(type).c_str());
+			key.value(), typeName(type).c_str());
 }
 
 /// Call on failed data requests during data requests
 std::string DataSegment::invalid_request(Key key)  const   {
-  return dd4hep::format(0, "Invalid segment data requested. Key:%ld",key.key);
+  return dd4hep::format(0, "Invalid segment data requested. Key:%ld",key.value());
 }
 
 /// Access data item by key
 std::any* DataSegment::get_item(Key key, bool exc)   {
-  auto it = this->data.find(key.key);
+  auto it = this->data.find(key);
   if (it != this->data.end()) return &it->second;
   if ( exc ) throw std::runtime_error(invalid_request(key));
   return nullptr;
@@ -299,7 +363,7 @@ std::any* DataSegment::get_item(Key key, bool exc)   {
 
 /// Access data item by key  (CONST)
 const std::any* DataSegment::get_item(Key key, bool exc)  const   {
-  auto it = this->data.find(key.key);
+  auto it = this->data.find(key);
   if (it != this->data.end()) return &it->second;
   if ( exc ) throw std::runtime_error(invalid_request(key));
   return nullptr;
@@ -326,14 +390,14 @@ DigiEvent::~DigiEvent()
   InstanceCount::decrement(this);
 }
 
-DataSegment& DigiEvent::access_segment(std::unique_ptr<DataSegment>& segment)   {
+DataSegment& DigiEvent::access_segment(std::unique_ptr<DataSegment>& segment, uint32_t id)   {
   if ( segment )   {
     return *segment;
   }
   std::lock_guard<std::mutex> guard(m_lock);
   /// Check again after holding the lock:
   if ( !segment )   {
-    segment = std::make_unique<DataSegment>(this->m_lock);
+    segment = std::make_unique<DataSegment>(this->m_lock, id);
   }
   return *segment;
 }
@@ -342,19 +406,19 @@ DataSegment& DigiEvent::access_segment(std::unique_ptr<DataSegment>& segment)
 DataSegment& DigiEvent::get_segment(const std::string& name)   {
   switch(::toupper(name[0]))   {
   case 'I':
-    return access_segment(m_inputs);
+    return access_segment(m_inputs,1);
   case 'C':
-    return access_segment(m_counts);
+    return access_segment(m_counts,2);
   case 'D':
     switch(::toupper(name[1]))   {
     case 'E':
-      return access_segment(m_deposits);
+      return access_segment(m_deposits,3);
     default:
-      return access_segment(m_data);
+      return access_segment(m_data,0xFEED);
     }
     break;
   case 'O':
-    return access_segment(m_outputs);
+    return access_segment(m_outputs,4);
   default:
     break;
   }
diff --git a/DDDigi/src/DigiOutputAction.cpp b/DDDigi/src/DigiOutputAction.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ad23ac4b6df3abd809160c1dcf4366ebbb494c12
--- /dev/null
+++ b/DDDigi/src/DigiOutputAction.cpp
@@ -0,0 +1,44 @@
+//==========================================================================
+//  AIDA Detector description implementation 
+//--------------------------------------------------------------------------
+// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
+// All rights reserved.
+//
+// For the licensing terms see $DD4hepINSTALL/LICENSE.
+// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
+//
+// Author     : M.Frank
+//
+//==========================================================================
+
+// Framework include files
+#include <DD4hep/InstanceCount.h>
+#include <DDDigi/DigiOutputAction.h>
+
+// C/C++ include files
+#include <stdexcept>
+#include <unistd.h>
+
+using namespace std;
+using namespace dd4hep::digi;
+
+/// Standard constructor
+DigiOutputAction::DigiOutputAction(const DigiKernel& kernel, const string& nam)
+  : DigiEventAction(kernel, nam)
+{
+  declareProperty("containers", m_containers);
+  declareProperty("output",     m_output);
+  declareProperty("mask",       m_mask);
+  InstanceCount::increment(this);
+}
+
+/// Default destructor
+DigiOutputAction::~DigiOutputAction()   {
+  InstanceCount::decrement(this);
+}
+
+/// Pre-track action callback
+void DigiOutputAction::execute(DigiContext& /* context */)  const   {
+  info("+++ Virtual method execute() --- Should not be called");
+  ::sleep(1);
+}
diff --git a/DDDigi/src/DigiROOTInput.cpp b/DDDigi/src/DigiROOTInput.cpp
index e3f0cfd9a644e0026725ba38a8012889c48c3bee..8d353559422ea3ed73516656de0584625f58ff7c 100644
--- a/DDDigi/src/DigiROOTInput.cpp
+++ b/DDDigi/src/DigiROOTInput.cpp
@@ -131,7 +131,7 @@ void DigiROOTInput::open_new_file()   const  {
 	if ( this->m_containers.empty() )    {
 	  Key key(b->GetName(), this->m_mask);
 	  b->SetAutoDelete( kFALSE );
-	  imp->branches[key.key] = {b, cls, imp->input_converter(cls)};
+	  imp->branches[key.value()] = {b, cls, imp->input_converter(cls)};
 	  continue;
 	}
 	/// Otherwise only the entities asked for
@@ -139,7 +139,7 @@ void DigiROOTInput::open_new_file()   const  {
 	  if ( bname == b->GetName() )   {
 	    Key key(b->GetName(), this->m_mask);
 	    b->SetAutoDelete( kFALSE );
-	    imp->branches[key.key] = {b, cls, imp->input_converter(cls)};
+	    imp->branches[key.value()] = {b, cls, imp->input_converter(cls)};
 	    break;
 	  }
 	}
diff --git a/DDDigi/src/DigiROOTOutput.cpp b/DDDigi/src/DigiROOTOutput.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3929794e72888167caacd64ea2e8ee2f34f68297
--- /dev/null
+++ b/DDDigi/src/DigiROOTOutput.cpp
@@ -0,0 +1,237 @@
+//==========================================================================
+//  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/DigiROOTOutput.h>
+
+/// ROOT include files
+#include <TFile.h>
+#include <TTree.h>
+#include <TBranch.h>
+
+/// C/C++ include files
+#include <stdexcept>
+#include <unistd.h>
+
+using namespace std;
+using namespace dd4hep::digi;
+
+class DigiROOTOutput::internals_t  {
+public:
+  typedef std::map<std::string, TBranch*> Branches;
+  typedef std::map<std::string, TTree*> Sections;
+  /// Reference to the ROOT file to open
+  TFile* m_file   { nullptr };
+  /// Reference to the event data tree
+  TTree* m_tree   { nullptr };
+  /// Known file sections
+  Sections m_sections;
+  /// Branches in the event tree
+  Branches m_branches;
+  DigiROOTOutput* output { nullptr };
+
+public:
+  internals_t(DigiROOTOutput* o) 
+    : output(o) 
+  {
+  }
+  ~internals_t()    {
+    if (m_file) {
+      TDirectory::TContext ctxt(m_file);
+      m_tree->Write();
+      m_file->Close();
+      m_tree = 0;
+      detail::deletePtr (m_file);
+    }
+  }
+  /// Create/access tree by name for non collection user data
+  TTree* section(const std::string& nam)   {
+    auto i = m_sections.find(nam);
+    if ( i == m_sections.end() ) {
+      TDirectory::TContext ctxt(m_file);
+      TTree* t = new TTree(nam.c_str(), ("Digitization " + nam + " information").c_str());
+      m_sections.emplace(nam, t);
+      return t;
+    }
+    return i->second;
+  }
+  /// Commit data at end of filling procedure
+  void commit()   {
+    if ( m_file ) {
+      TObjArray* a = m_tree->GetListOfBranches();
+      Long64_t evt = m_tree->GetEntries() + 1;
+      Int_t nb = a->GetEntriesFast();
+      /// Fill NULL pointers to all branches, which have less entries than the Event branch
+      for (Int_t i = 0; i < nb; ++i) {
+	TBranch* br_ptr = (TBranch*) a->UncheckedAt(i);
+	Long64_t br_evt = br_ptr->GetEntries();
+	if (br_evt < evt) {
+	  Long64_t num = evt - br_evt;
+	  br_ptr->SetAddress(0);
+	  while (num > 0) {
+	    br_ptr->Fill();
+	    --num;
+	  }
+	}
+      }
+      m_tree->SetEntries(evt);
+    }
+  }
+  /// Fill single EVENT branch entry (Geant4 collection data)
+  int fill(const string& nam, const std::type_info& type, void* ptr) {
+    if (m_file) {
+      TBranch* b = 0;
+      auto i = m_branches.find(nam);
+      if (i == m_branches.end()) {
+	TClass* cl = TBuffer::GetClass(type);
+	if (cl) {
+	  b = m_tree->Branch(nam.c_str(), cl->GetName(), (void*) 0);
+	  b->SetAutoDelete(false);
+	  m_branches.emplace(nam, b);
+	}
+	else {
+	  throw runtime_error("No ROOT TClass object availible for object type:" + typeName(type));
+	}
+      }
+      else {
+	b = (*i).second;
+      }
+      Long64_t evt = b->GetEntries(), nevt = b->GetTree()->GetEntries(), num = nevt - evt;
+      if (nevt > evt) {
+	b->SetAddress(0);
+	while (num > 0) {
+	  b->Fill();
+	  --num;
+	}
+      }
+      b->SetAddress(&ptr);
+      int nbytes = b->Fill();
+      if (nbytes < 0) {
+	throw runtime_error("Failed to write ROOT collection:" + nam + "!");
+      }
+      return nbytes;
+    }
+    return 0;
+  }
+  /// Callback to store the Geant4 event
+  void saveEvent(DigiContext& /* ctxt */) {
+    if ( !output->m_disableParticles )  {
+#if 0
+      Geant4ParticleMap* parts = context()->event().extension<Geant4ParticleMap>();
+      if ( parts )   {
+	typedef Geant4HitWrapper::HitManipulator Manip;
+	typedef Geant4ParticleMap::ParticleMap ParticleMap;
+	Manip* manipulator = Geant4HitWrapper::manipulator<Geant4Particle>();
+	const ParticleMap& pm = parts->particles();
+	vector<void*> particles;
+	particles.reserve(pm.size());
+	for ( const auto& i : pm )   {
+	  particles.emplace_back((ParticleMap::mapped_type*)i.second);
+	}
+	fill("MCParticles",manipulator->vec_type,&particles);
+      }
+#endif
+    }
+  }
+};
+
+/// Standard constructor
+DigiROOTOutput::DigiROOTOutput(const DigiKernel& kernel, const std::string& nam)
+  : DigiOutputAction(kernel, nam)
+{
+  imp = std::make_unique<internals_t>(this);
+  declareProperty("section",              m_section = "EVENT");
+  declareProperty("max_file_size",        m_max_file_size);
+  declareProperty("disabled_collections", m_disabledCollections);
+  declareProperty("disable_particles",    m_disableParticles);
+  InstanceCount::increment(this);
+}
+
+/// Default destructor
+DigiROOTOutput::~DigiROOTOutput() {
+  imp.reset();
+  InstanceCount::decrement(this);
+}
+
+/// Pre-track action callback
+void DigiROOTOutput::execute(DigiContext& context)  const   {
+  imp->saveEvent(context);
+#if 0
+  for (int i = 0; i < nCol; ++i) {
+    G4VHitsCollection* hc = hce->GetHC(i);
+    saveCollection(ctxt, hc);
+  }
+#endif
+}
+
+#if 0
+/// Callback to store the Geant4 run information
+void DigiROOTOutput::beginRun(const G4Run* run) {
+  if (!m_file && !m_output.empty()) {
+    TDirectory::TContext ctxt(TDirectory::CurrentDirectory());
+    m_file = TFile::Open(m_output.c_str(), "RECREATE", "DD4hep digitization data");
+    if (m_file->IsZombie()) {
+      detail::deletePtr (m_file);
+      except("+++ Failed to open ROOT output file:'" + m_output + "'");
+    }
+    m_tree = section("EVENT");
+  }
+  Geant4OutputAction::beginRun(run);
+}
+
+
+
+/// Callback to store each Geant4 hit collection
+void DigiROOTOutput::saveCollection(DigiContext& /* ctxt */, G4VHitsCollection* collection) {
+  Geant4HitCollection* coll = dynamic_cast<Geant4HitCollection*>(collection);
+  string hc_nam = collection->GetName();
+  for(const auto& n : m_disabledCollections)  {
+    if ( n == hc_nam )   {
+      return;
+    }
+  }
+  if (coll) {
+    vector<void*> hits;
+    coll->getHitsUnchecked(hits);
+    size_t nhits = coll->GetSize();
+    if ( m_handleMCTruth && m_truth && nhits > 0 )   {
+      hits.reserve(nhits);
+      try  {
+        for(size_t i=0; i<nhits; ++i)   {
+          Geant4HitData* h = coll->hit(i);
+          Geant4Tracker::Hit* trk_hit = dynamic_cast<Geant4Tracker::Hit*>(h);
+          if ( 0 != trk_hit )   {
+            Geant4HitData::Contribution& t = trk_hit->truth;
+            int trackID = t.trackID;
+            t.trackID = m_truth->particleID(trackID);
+          }
+          Geant4Calorimeter::Hit* cal_hit = dynamic_cast<Geant4Calorimeter::Hit*>(h);
+          if ( 0 != cal_hit )   {
+            Geant4HitData::Contributions& c = cal_hit->truth;
+            for(Geant4HitData::Contributions::iterator j=c.begin(); j!=c.end(); ++j)  {
+              Geant4HitData::Contribution& t = *j;
+              int trackID = t.trackID;
+              t.trackID = m_truth->particleID(trackID);
+            }
+          }
+        }
+      }
+      catch(...)   {
+        printout(ERROR,name(),"+++ Exception while saving collection %s.",hc_nam.c_str());
+      }
+    }
+    fill(hc_nam, coll->vector_type(), &hits);
+  }
+}
+#endif
diff --git a/DDDigi/src/DigiSegmentSplitter.cpp b/DDDigi/src/DigiSegmentSplitter.cpp
index b4236d508e26e70f38b9e40e7057fee53572047e..8b22c28c7db107a843b2cead53b125e34c36aa81 100644
--- a/DDDigi/src/DigiSegmentSplitter.cpp
+++ b/DDDigi/src/DigiSegmentSplitter.cpp
@@ -120,7 +120,8 @@ void DigiSegmentSplitter::adopt_processor(DigiContainerProcessor* action)   {
 /// Main functional callback
 void DigiSegmentSplitter::execute(DigiContext& context, work_t& work)  const    {
   Key key = work.input_key();
-  Key unmasked_key(key.item());
+  Key unmasked_key;
+  unmasked_key.set_item(key.item());
   if ( std::find(m_keys.begin(), m_keys.end(), unmasked_key) != m_keys.end() )   {
     if ( work.has_input() )   {
       info("+++ Got hit collection %04X %08X. Prepare processors for %sparallel execution.",
diff --git a/DDDigi/src/DigiStoreDump.cpp b/DDDigi/src/DigiStoreDump.cpp
index 09c66b52c89ac2cf793dffeb6e957dcdf3d69c21..7f17ad0caa314dff265a233221b74decc5344b1c 100644
--- a/DDDigi/src/DigiStoreDump.cpp
+++ b/DDDigi/src/DigiStoreDump.cpp
@@ -59,28 +59,33 @@ void dd4hep::digi::DigiStoreDump::dump(const std::string& tag,
     typ = str_replace(str_replace(typ,"std::",""),"dd4hep::","");
     typ = str_replace(str_replace(typ,"sim::",""),"digi::","");
     if ( const auto* mapping = std::any_cast<DepositMapping>(&data) )   {
-      str = this->format("%s|----  %4X %08X %-32s: %6ld deposits   [%s]", 
-			 event.id(), key.values.mask, key.values.item,
+      str = this->format("%s|----  %04X %08X %-32s: %6ld deposits   [%s]", 
+			 event.id(), key.mask(), key.item(),
 			 nam.c_str(), mapping->size(), typ.c_str());
     }
     else if ( const auto* vector = std::any_cast<DepositVector>(&data) )   {
-      str = this->format("%s|----  %4X %08X %-32s: %6ld deposits   [%s]", 
-			 event.id(), key.values.mask, key.values.item,
+      str = this->format("%s|----  %04X %08X %-32s: %6ld deposits   [%s]", 
+			 event.id(), key.mask(), key.item(),
 			 nam.c_str(), vector->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,
+      str = this->format("%s|----  %04X %08X %-32s: %6ld particles  [%s]", 
+			 event.id(), key.mask(), key.item(),
 			 nam.c_str(), parts->size(), typ.c_str());
     }
     else if ( const auto* adcs = std::any_cast<DetectorResponse>(&data) )   {
-      str = this->format("%s|----  %4X %08X %-32s: %6ld ADC values [%s]", 
-			 event.id(), key.values.mask, key.values.item,
+      str = this->format("%s|----  %04X %08X %-32s: %6ld ADC values [%s]", 
+			 event.id(), key.mask(), key.item(),
 			 nam.c_str(), adcs->size(), typ.c_str());
     }
+    else if ( const auto* hist = std::any_cast<DetectorHistory>(&data) )   {
+      str = this->format("%s|----  %04X %08X %-32s: %6ld histories  [%s]", 
+			 event.id(), key.mask(), key.item(),
+			 nam.c_str(), hist->size(), typ.c_str());
+    }
     else   {
-      str = this->format("%s|----  %4X %08X %-32s: %s", 
-			 event.id(), key.values.mask, key.values.item, 
+      str = this->format("%s|----  %04X %08X %-32s: %s", 
+			 event.id(), key.mask(), key.item(), 
 			 nam.c_str(), typ.c_str());
     }
     records.push_back(str);
diff --git a/examples/DDDigi/scripts/DigiTest.py b/examples/DDDigi/scripts/DigiTest.py
index f0cfb73a3c7333d633d26973c56c983995319308..31a1836bcf5178a370d6ef9392c026881cec1796 100644
--- a/examples/DDDigi/scripts/DigiTest.py
+++ b/examples/DDDigi/scripts/DigiTest.py
@@ -112,6 +112,7 @@ class Test(dddigi.Digitize):
       self.used_inputs = []
     next = self.inputs[len(self.used_inputs)]
     self.used_inputs.append(next)
+    self.info('Prepariing next input file: ' + str(next))
     return next
 
   def run_checked(self, num_events=5, num_threads=5, parallel=3):
diff --git a/examples/DDDigi/scripts/TestHitProcessing.py b/examples/DDDigi/scripts/TestHitProcessing.py
index b21d9faf4523710265aa749fd4f8b87293399da5..e8e3d9192af3897597788bea93330936a8850c29 100644
--- a/examples/DDDigi/scripts/TestHitProcessing.py
+++ b/examples/DDDigi/scripts/TestHitProcessing.py
@@ -18,50 +18,37 @@ def run():
   input = digi.input_action('DigiParallelActionSequence/READER')
   # ========================================================================================================
   digi.info('Created SIGNAL input')
-  signal = input.adopt_action('DigiROOTInput/SignalReader', mask=0x0, input=[digi.next_input()])
-  digi.check_creation([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/Read-1', mask=0x1, input=[digi.next_input()])
-  digi.check_creation([overlay, evtreader])
+  overlay.adopt_action('DigiROOTInput/Read-1', mask=0x1, input=[digi.next_input()])
   digi.info('Created input.overlay-1')
   # ========================================================================================================
   overlay = input.adopt_action('DigiSequentialActionSequence/Overlay-2')
-  evtreader = overlay.adopt_action('DigiROOTInput/Read-2', mask=0x2, input=[digi.next_input()])
-  digi.check_creation([overlay, evtreader])
+  overlay.adopt_action('DigiROOTInput/Read-2', mask=0x2, input=[digi.next_input()])
   digi.info('Created input.overlay-2')
   # ========================================================================================================
   event = digi.event_action('DigiSequentialActionSequence/EventAction')
   combine = event.adopt_action('DigiContainerCombine/Combine',
                                parallel=True,
-                               input_masks=[0x0, 0x1, 0x2, 0x3],
-                               output_mask=0xFEED,
-                               output_segment='deposits',
-                               erase_combined=False)
+                               input_masks=[0x0, 0x1, 0x2],
+                               output_mask=0xAAA0,
+                               output_segment='inputs')
   combine.erase_combined = True
-  proc = event.adopt_action('DigiContainerSequenceAction/HitP1',
-                            parallel=True,
-                            input_mask=0xFEED,
-                            input_segment='deposits')
-  count = digi.create_action('DigiCellMultiplicityCounter/CellCounter')
-  proc.adopt_container_processor(count, digi.containers())
   proc = event.adopt_action('DigiContainerSequenceAction/HitP2',
                             parallel=True,
-                            input_mask=0xFEED,
-                            input_segment='deposits',
-                            output_mask=0x0,
-                            output_segment='output')
+                            input_mask=0xAAA0,
+                            input_segment='inputs',
+                            output_mask=0xAAA1,
+                            output_segment='inputs')
   count = digi.create_action('DigiDepositWeightedPosition/CellCreator')
   proc.adopt_container_processor(count, digi.containers())
-  dump = event.adopt_action('DigiStoreDump/StoreDump')
-
-  digi.check_creation([combine, dump, proc])
-  digi.info('Created event.dump')
-
+  event.adopt_action('DigiStoreDump/StoreDump')
   # ========================================================================================================
-  digi.run_checked(num_events=5, num_threads=5, parallel=3)
+  digi.info('Starting digitization core')
+  digi.run_checked(num_events=3, num_threads=25, parallel=5)
 
 
 if __name__ == '__main__':
diff --git a/examples/DDDigi/scripts/TestMultiContainerParallel.py b/examples/DDDigi/scripts/TestMultiContainerParallel.py
index 8934b1fb39a4e7089ee043f293a76f1fd7a78b43..72fff4e167862e2b79091dccf0cb697068f73783 100644
--- a/examples/DDDigi/scripts/TestMultiContainerParallel.py
+++ b/examples/DDDigi/scripts/TestMultiContainerParallel.py
@@ -24,7 +24,7 @@ def run():
   # ========================================================================
   event = digi.event_action('DigiSequentialActionSequence/EventAction')
   proc = event.adopt_action('DigiMultiContainerProcessor/ContainerProc',
-                            input_masks=[0x0, 0x1, 0x2, 0x3, 0xFEED])
+                            parallel=True, input_masks=[0x0, 0x1, 0x2, 0x3, 0xFEED])
   conts = digi.containers(2)
   for i in range(len(conts)):
     merge = dddigi.Action(digi.kernel(), 'DigiContainerProcessor/SegmentPrint_%03d' % (i,))
diff --git a/examples/DDDigi/scripts/TestSimpleADCResponse.py b/examples/DDDigi/scripts/TestSimpleADCResponse.py
index 6bb327b960bdef0443df205ea5ad730905582f8a..fb1529cc5817a86da00d612b7f43d11db3dac400 100644
--- a/examples/DDDigi/scripts/TestSimpleADCResponse.py
+++ b/examples/DDDigi/scripts/TestSimpleADCResponse.py
@@ -16,16 +16,19 @@ def run():
   digi = DigiTest.Test(geometry=None)
 
   # ========================================================================================================
-  input = digi.input_action('DigiParallelActionSequence/READER')
+  input = digi.input_action('DigiSequentialActionSequence/READER')
   input.adopt_action('DigiROOTInput/SignalReader', mask=0x0, input=[digi.next_input()])
   # ========================================================================================================
   event = digi.event_action('DigiSequentialActionSequence/EventAction')
+  event.adopt_action('DigiStoreDump/DumpInput')
   proc = event.adopt_action('DigiContainerCombine/Combine',
                             parallel=True,
-                            input_masks=[0x0, 0x1, 0x2, 0x3],
+                            input_masks=[0x0],
+                            input_segment='inputs',
                             output_mask=0xFEED,
                             output_segment='deposits',
-                            erase_combined=True)
+                            erase_combined=False)
+  event.adopt_action('DigiStoreDump/DumpCombine')
   proc = event.adopt_action('DigiContainerSequenceAction/ADCsequence',
                             parallel=True,
                             input_mask=0xFEED,
@@ -34,12 +37,15 @@ def run():
                             output_segment='output')
   count = digi.create_action('DigiSimpleADCResponse/ADCCreate')
   proc.adopt_container_processor(count, digi.containers())
-
-  event.adopt_action('DigiStoreDump/StoreDump')
+  event.adopt_action('DigiContainerDrop/DropCombine',
+                     parallel=True,
+                     input_masks=[0xFEED],
+                     input_segment='deposits')
+  event.adopt_action('DigiStoreDump/DumpOutput')
   digi.info('Created event.dump')
 
   # ========================================================================================================
-  digi.run_checked(num_events=5, num_threads=5, parallel=3)
+  digi.run_checked(num_events=5, num_threads=1, parallel=3)
 
 
 if __name__ == '__main__':
diff --git a/examples/DDDigi/scripts/TestSpillover.py b/examples/DDDigi/scripts/TestSpillover.py
index 6745adb40ce62ee76148881cd480b1580fa9cf45..e62e21c4bddda182b4addc7071dde87d0e7940f9 100644
--- a/examples/DDDigi/scripts/TestSpillover.py
+++ b/examples/DDDigi/scripts/TestSpillover.py
@@ -19,8 +19,7 @@ def run():
 
   input = digi.input_action('DigiParallelActionSequence/READER')
   # ========================================================================================================
-  signal = input.adopt_action('DigiROOTInput/SignalReader', mask=0x0, input=[digi.next_input()])
-  digi.check_creation([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.....')
diff --git a/examples/DDG4/CMakeLists.txt b/examples/DDG4/CMakeLists.txt
index f2c00182bd2655a8d3aa2a251f69438c2b2b1994..4634ff08eeef2f2d75de239bd38f85be3b9b2280 100644
--- a/examples/DDG4/CMakeLists.txt
+++ b/examples/DDG4/CMakeLists.txt
@@ -87,4 +87,12 @@ if (DD4HEP_USE_GEANT4)
     REGEX_PASS "Created specialize logical volume \\[G4LogicalCrystalVolume\\]: ChannelingDevice_vol"
     REGEX_FAIL " ERROR ;EXCEPTION;Exception"
   )
+  #
+  # Test G4 stacking action
+  dd4hep_add_test_reg( DDG4_TestStackingAction
+    COMMAND    "${CMAKE_INSTALL_PREFIX}/bin/run_test_DDG4.sh"
+    EXEC_ARGS  ${Python_EXECUTABLE} ${DDG4examples_INSTALL}/scripts/TestStacking.py -batch -events 3
+    REGEX_PASS " \\[2\\] Calling classifyNewTrack. StackManager"
+    REGEX_FAIL " ERROR ;EXCEPTION;Exception"
+  )
 endif()