diff --git a/DDCore/include/DD4hep/ComponentProperties.h b/DDCore/include/DD4hep/ComponentProperties.h
index bb354cb40bc619525af0cdbd79374d6e65967c45..cce28c8b713ad0fd6df759a6cb14d4b9b16c6f73 100644
--- a/DDCore/include/DD4hep/ComponentProperties.h
+++ b/DDCore/include/DD4hep/ComponentProperties.h
@@ -268,7 +268,7 @@ namespace dd4hep {
     template <typename FUNCTOR> void for_each(const FUNCTOR& func)   {
       std::for_each(m_properties.begin(), m_properties.end(), func);
     }
-    /// Export properties of another instance
+    /// Import properties of another instance
     void adopt(const PropertyManager& copy);
     /// Dump string values
     void dump() const;
diff --git a/DDCore/include/Parsers/Printout.h b/DDCore/include/Parsers/Printout.h
index 98b3fbd43e0dfa788376bdf5f473de524a19bb99..6a96d5a98f21131f11ee2a89fcf098877fb75c72 100644
--- a/DDCore/include/Parsers/Printout.h
+++ b/DDCore/include/Parsers/Printout.h
@@ -44,7 +44,19 @@ namespace dd4hep {
     WARNING  = 4,
     ERROR    = 5,
     FATAL    = 6,
-    ALWAYS   = 7
+    ALWAYS   = 7,
+
+    /// Forced printout levels if the output level is handled
+    /// e.g. by a Geant4Action or DigiAction. These always pass
+    /// The default DD4hep print level restrictions.
+    FORCE_LEVEL    = 0x10,
+    FORCE_VERBOSE  = FORCE_LEVEL + 1,
+    FORCE_DEBUG    = FORCE_LEVEL + 2,
+    FORCE_INFO     = FORCE_LEVEL + 3,
+    FORCE_WARNING  = FORCE_LEVEL + 4,
+    FORCE_ERROR    = FORCE_LEVEL + 5,
+    FORCE_FATAL    = FORCE_LEVEL + 6,
+    FORCE_ALWAYS   = FORCE_LEVEL + 7
   };
 
 #ifndef __CINT__
diff --git a/DDCore/python/dd4hep_base.py b/DDCore/python/dd4hep_base.py
index b0921a864722b3aa0dc12a73372755d97878cd3b..713f057e36bb71a4cc98d651d8c1dbe8ef292ed8 100644
--- a/DDCore/python/dd4hep_base.py
+++ b/DDCore/python/dd4hep_base.py
@@ -124,6 +124,14 @@ def unicode_2_string(value):
 
 
 OutputLevel = _Levels()
+VERBOSE = OutputLevel.VERBOSE
+DEBUG = OutputLevel.DEBUG
+INFO = OutputLevel.INFO
+WARNING = OutputLevel.WARNING
+ERROR = OutputLevel.ERROR
+FATAL = OutputLevel.FATAL
+
+
 # ------------------------Generic STL stuff can be accessed using std:  -----
 #
 # -- e.g. Create an instance of std::vector<dd4hep::sim::Geant4Vertex*>:
@@ -149,7 +157,8 @@ import_namespace_item('core', 'NamedObject')
 import_namespace_item('core', 'run_interpreter')
 #
 import_namespace_item('detail', 'interp')
-import_namespace_item('detail', 'eval')
+# No: This inhibits the usage of native python eval!
+# import_namespace_item('detail', 'eval')
 
 # ---------------------------------------------------------------------------
 # def run_interpreter(name):   detail.interp.run(name)
diff --git a/DDCore/src/ComponentProperties.cpp b/DDCore/src/ComponentProperties.cpp
index 92b5d2f82b7fc99d64bed40b7abca9561cdb019f..867c314d030323104f278528763c5736df78de48 100644
--- a/DDCore/src/ComponentProperties.cpp
+++ b/DDCore/src/ComponentProperties.cpp
@@ -135,7 +135,7 @@ size_t PropertyManager::size()  const   {
   return m_properties.size();
 }
 
-/// Export properties of another instance
+/// Import properties of another instance
 void PropertyManager::adopt(const PropertyManager& copy)   {
   m_properties = copy.m_properties;
 }
diff --git a/DDCore/src/Printout.cpp b/DDCore/src/Printout.cpp
index d0a6bfd15799d22127fd09dfd014d63af3dcb79f..79b49f467ba7d0f15c9ee3d8d4b57e0d130fbe17 100644
--- a/DDCore/src/Printout.cpp
+++ b/DDCore/src/Printout.cpp
@@ -242,7 +242,7 @@ int dd4hep::printout(PrintLevel severity, const string& src, const string& fmt,
  */
 int dd4hep::printout(PrintLevel severity, const char* src, const char* fmt, va_list& args) {
   if (severity >= print_lvl) {
-    print_func_2(print_arg, severity,src,fmt,args);
+    print_func_2(print_arg, PrintLevel(severity&(~FORCE_LEVEL)), src, fmt, args);
   }
   return 1;
 }
diff --git a/DDDigi/ddg4/DigiDDG4Input.cpp b/DDDigi/ddg4/DigiDDG4Input.cpp
index 9c9c5101fe92ada613847a3905352d23f8251824..5aeb34738ba53947ab553672e55d059b92cc6969 100644
--- a/DDDigi/ddg4/DigiDDG4Input.cpp
+++ b/DDDigi/ddg4/DigiDDG4Input.cpp
@@ -37,8 +37,11 @@ namespace dd4hep {
     class DigiDDG4ROOT : public DigiROOTInput    {
     public:
       static constexpr double epsilon = std::numeric_limits<double>::epsilon();
+
       /// Property to generate extra history records
-      bool m_seperate_history  { false };
+      bool m_seperate_history  { true };
+      bool m_keep_raw          { false };
+
       mutable TClass* m_trackerHitClass { nullptr };
       mutable TClass* m_caloHitClass    { nullptr };
       mutable TClass* m_particlesClass  { nullptr };
@@ -77,11 +80,15 @@ namespace dd4hep {
 	: DigiROOTInput(krnl, nam)
       {
 	declareProperty("seperate_history", m_seperate_history);
+	declareProperty("keep_raw", m_keep_raw);
       }
 
       template <typename T>
-      void conv_hits(DataSegment& segment, const std::string& tag, int mask, const char* name, void* ptr)   const {
+      void conv_hits(DigiContext& context, DataSegment& segment,
+		     const std::string& tag, int mask, const char* name, void* ptr)   const
+      {
 	using wrap_t = std::shared_ptr<sim::Geant4HitData>;
+        bool sep_history = m_seperate_history;
 	std::size_t len = 0;
 	std::string nam = name;
 	std::vector<wrap_t> geant4_hits;
@@ -93,6 +100,8 @@ namespace dd4hep {
 	    auto* p = (*data.items)[i];
 	    if ( p->energyDeposit > epsilon )   {
 	      Key history_key;
+	      CellID cell = p->cellID;
+	      wrap_t raw(p);
 	      EnergyDeposit dep { };
 	      Position pos = p->position;
 	      pos *= 1./dd4hep::mm;
@@ -102,34 +111,41 @@ namespace dd4hep {
 	      dep.position = pos;
 
 	      history_key.set_mask(Key::mask_type(mask));
-	      history_key.set_item(geant4_hits.size());
+	      history_key.set_item(out.size());
 	      history_key.set_segment(segment.id);
 
-	      dep.history.hits.emplace_back(history_key, dep.deposit);
-	      add_particle_history(p, history_key, dep.history);
-
-	      out.emplace(p->cellID, std::move(dep));
-	      if ( m_seperate_history )   {
-		hist.insert(p->cellID, dep.history);
+	      if ( sep_history )   {
+		History entry { };
+		entry.hits.emplace_back(history_key, dep.deposit);
+		add_particle_history(p, history_key, entry);
+		hist.emplace(cell, std::move(entry));
+	      }
+	      out.emplace(cell, std::move(dep));
+	      if ( m_keep_raw )   {
+		geant4_hits.emplace_back(std::move(raw));
 	      }
-	      geant4_hits.emplace_back(wrap_t(p));
 	    }
 	  }
 	  len = data.items->size();
 	  data.items->clear();
 	}
-	debug("++ Converted %ld %s to %ld cell deposits", len, tag.c_str(), out.size());
+	info("%s++ %-24s Converted %6ld DDG4 %-14s hits to %6ld cell deposits",
+	     context.event->id(), name, len, tag.c_str(), out.size());
 	Key depo_key(out.name, mask);
 	segment.emplace(depo_key, std::make_any<DepositVector>(std::move(out)));
-	Key src_key(nam+".ddg4", mask);
-	segment.emplace(src_key, std::make_any<std::vector<wrap_t>>(std::move(geant4_hits)));
-	if ( m_seperate_history )   {
+	if ( m_keep_raw )   {
+	  Key src_key(nam+".ddg4", mask);
+	  segment.emplace(src_key, std::make_any<std::vector<wrap_t>>(std::move(geant4_hits)));
+	}
+	if ( sep_history )   {
 	  Key hist_key(hist.name, mask);
 	  segment.emplace(hist_key, std::make_any<DetectorHistory>(std::move(hist)));
 	}
       }
 
-      void conv_particles(DataSegment& segment, int mask, const char* name, void* ptr)   const {
+      void conv_particles(DigiContext& context, DataSegment& segment,
+			  int mask, const char* name, void* ptr)   const
+      {
 	using wrap_t  = std::shared_ptr<sim::Geant4Particle>;
 	ParticleMapping out(name, mask);
 	std::map<Key, wrap_t> source;
@@ -156,15 +172,17 @@ namespace dd4hep {
 	  }
 	  items->clear();
 	}
-	debug("++ Converted %ld DDG4 particles", out.size());
+	debug("%s++ Converted %ld DDG4 particles", context.event->id(), out.size());
 	std::string nam = name;
 	segment.emplace(part_key, std::make_any<ParticleMapping>(std::move(out)));
-	Key src_key(nam+".ddg4", mask);
-	segment.emplace(src_key, std::make_any<std::map<Key, wrap_t> >(std::move(source)));
+	if ( m_keep_raw )   {
+	  Key src_key(nam+".ddg4", mask);
+	  segment.emplace(src_key, std::make_any<std::map<Key, wrap_t> >(std::move(source)));
+	}
       }
 
       /// Callback to handle single branch
-      virtual void operator()(DigiContext& /* context */, work_t& work)  const  override  {
+      virtual void operator()(DigiContext& context, work_t& work)  const  override  {
 	TBranch& br = work.branch;
 	TClass&  cl = work.cl;
 	TClass*  c  = get_class_pointers(&cl, br.GetClassName());
@@ -173,11 +191,11 @@ namespace dd4hep {
 	int mask = work.input_key.mask();
 	auto& seg = work.input_segment;
 	if ( c == m_caloHitClass )
-	  conv_hits<sim::Geant4Calorimeter::Hit>(seg, "DDG4 calorimeter hits", mask, nam, *addr);
+	  conv_hits<sim::Geant4Calorimeter::Hit>(context, seg, "calorimeter", mask, nam, *addr);
 	else if ( c == m_trackerHitClass )
-	  conv_hits<sim::Geant4Tracker::Hit>(seg, "DDG4 tracker hits", mask, nam, *addr);
+	  conv_hits<sim::Geant4Tracker::Hit>(context, seg, "tracker", mask, nam, *addr);
 	else if ( c == m_particlesClass )
-	  conv_particles(seg, mask, nam, *addr);
+	  conv_particles(context, seg, mask, nam, *addr);
 	else
 	  except("Unknown data type encountered in branch: %s", nam);
       }
diff --git a/DDDigi/include/DDDigi/DigiAction.h b/DDDigi/include/DDDigi/DigiAction.h
index d6c8ec41d0016269dd32b174ceeb9fdc1283f073..583f8c772c284d9f3dbc261afff843a8388029ad 100644
--- a/DDDigi/include/DDDigi/DigiAction.h
+++ b/DDDigi/include/DDDigi/DigiAction.h
@@ -102,7 +102,7 @@ namespace dd4hep {
 
     protected:
 #else
-      const kernel_t&  m_kernel;
+      const kernel_t&    m_kernel;
 #endif
       /// Action name
       std::string        m_name;
@@ -156,6 +156,7 @@ namespace dd4hep {
       /// Set the output level; returns previous value
       PrintLevel setOutputLevel(PrintLevel new_level);
       
+      /** Property access                            */
       /// Declare property
       template <typename T> DigiAction& declareProperty(const std::string& nam, T& val);
       /// Declare property
@@ -170,6 +171,8 @@ namespace dd4hep {
       Property& property(const std::string& name);
       /// Access single property (CONST)
       const Property& property(const std::string& name)  const;
+      /// Print the property values
+      virtual std::size_t printProperties() const;
 
       /// Adopt named property of another action for data processing
       virtual void adopt_property(DigiAction* action, const std::string& foreign_name, const std::string& local_name);
@@ -177,10 +180,13 @@ namespace dd4hep {
       /// Adopt named tool to delegate actions
       virtual void adopt_tool(DigiAction* action, const std::string& typ);
 
+      /** Support for output messages       */
       /// Support for messages with variable output level using output level
       void print(const char* fmt, ...) const;
       /// Support for building formatted messages
       std::string format(const char* fmt, ...) const;
+      /// Support of messages always printed.
+      void always(const char* fmt, ...) const;
       /// Support of debug messages.
       void debug(const char* fmt, ...) const;
       /// Support of info messages.
diff --git a/DDDigi/include/DDDigi/DigiAttenuator.h b/DDDigi/include/DDDigi/DigiAttenuator.h
index a5d85b88689e16b1ef083d3201581d008a43abc4..f492d48b49e0184c7e602164e6e46c4428b1aef4 100644
--- a/DDDigi/include/DDDigi/DigiAttenuator.h
+++ b/DDDigi/include/DDDigi/DigiAttenuator.h
@@ -87,6 +87,10 @@ namespace dd4hep {
       std::map<std::string, double>  m_container_attenuation  { };
       /// Property: T0 with respect to central crossing
       double                         m_t0     { 0e0 };
+      /// Property: Flag to act on hit input data
+      bool                           m_attenuate_data  { true };
+      /// Property: Flag to act on history objects as well
+      bool                           m_attenuate_history  { true };
 
     protected:
       /// Define standard assignments and constructors
diff --git a/DDDigi/include/DDDigi/DigiContainerDrop.h b/DDDigi/include/DDDigi/DigiContainerDrop.h
index 6083701174a12d89f95d1f4b1111cc684b53806a..9be69945344f48a5ea1ecaed0f8e3956cefb6092 100644
--- a/DDDigi/include/DDDigi/DigiContainerDrop.h
+++ b/DDDigi/include/DDDigi/DigiContainerDrop.h
@@ -35,9 +35,9 @@ namespace dd4hep {
     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>;
+      using self_t    = DigiContainerDrop;
+      using worker_t  = DigiParallelWorker<self_t,work_definition_t>;
+      using workers_t = DigiParallelWorkers<worker_t>;
 
     protected:
       /// Property: Container names to be loaded
@@ -52,7 +52,7 @@ namespace dd4hep {
       std::set<Key::itemkey_type> m_cont_keys  { };
 
       /// Worker objects to be submitted to TBB each performing part of the job
-      Workers m_workers;
+      workers_t m_workers;
 
     protected:
       /// Define standard assignments and constructors
diff --git a/DDDigi/include/DDDigi/DigiContainerProcessor.h b/DDDigi/include/DDDigi/DigiContainerProcessor.h
index 9be4485e7f907546178cffaeecbd3039479f87bb..5c83cfcf381f7e80c0ef0f2da341bec9a216a4d2 100644
--- a/DDDigi/include/DDDigi/DigiContainerProcessor.h
+++ b/DDDigi/include/DDDigi/DigiContainerProcessor.h
@@ -17,6 +17,7 @@
 #include <DD4hep/Callback.h>
 #include <DDDigi/DigiData.h>
 #include <DDDigi/DigiEventAction.h>
+#include <DDDigi/DigiDepositMonitor.h>
 #include <DDDigi/DigiParallelWorker.h>
 
 /// C/C++ include files
@@ -29,6 +30,7 @@ namespace dd4hep {
   namespace digi {
 
     /// Forward declarations
+    class DigiDepositMonitor;
     class DigiSegmentContext;
     class DigiContainerSequence;
     class DigiContainerProcessor;
@@ -52,10 +54,12 @@ namespace dd4hep {
 
       /// Input definition
       struct input_t  {
+	/// Input segment reference
+	segment_t*      segment;
 	/// Input data key
 	Key             key;
 	/// Input deposits
-	std::any&       data;
+	std::any*       data;
       };
 
       /// Output handle definition
@@ -66,11 +70,12 @@ namespace dd4hep {
 
       /// Hit processing predicate
       struct predicate_t  {
-	using deposit_t = std::pair<const CellID, EnergyDeposit>;
+	using deposit_t  = std::pair<const CellID, EnergyDeposit>;
 	using callback_t = std::function<bool(const deposit_t&)>;
 	callback_t            callback      { };
 	uint32_t              id            { 0 };
 	const segmentation_t* segmentation  { nullptr };
+
 	predicate_t() = default;
 	predicate_t(std::function<bool(const deposit_t&)> func, uint32_t i, const segmentation_t* s)
 	: callback(func), id(i), segmentation(s) {}
@@ -80,22 +85,27 @@ namespace dd4hep {
 	predicate_t& operator = (const predicate_t& copy) = default;
 	/// Check if a deposit should be processed
 	bool operator()(const deposit_t& deposit)   const;
-	static bool always_true(const deposit_t&)   { return true; }
+	static bool always_true(const deposit_t&)        { return true; }
+	static bool not_killed (const deposit_t& depo)   { return 0 == (depo.second.flag&EnergyDeposit::KILLED); }
       };
 
-      /// Work definition
-      struct work_t  {
+      struct env_t   {
 	/// Event processing context
 	context_t&        context;
-	/// Input data
-	input_t           input;
-	/// Output data
-	output_t&         output;
 	/// Optional properties
 	const property_t& properties;
+	/// Output data
+	output_t&         output;
+      };
+
+      /// Work definition
+      struct work_t  {
+	env_t             environ;
+	/// Input data
+	input_t           input;
 
 	/// Basic check if input data are present
-	bool has_input()  const    {  return this->input.data.has_value();  }
+	bool has_input()  const    {  return this->input.data->has_value();  }
 	/// Access key of input data
 	Key  input_key()  const    {  return this->input.key;               }
 	/// Access the input data type
@@ -106,20 +116,29 @@ namespace dd4hep {
 	template <typename DATA> DATA* get_input(bool exc=false);
 	/// Access input data by type
 	template <typename DATA> const DATA* get_input(bool exc=false)  const;
+	/// Access the deposit history of a deposit container
+	const DepositsHistory* get_history(const std::string& container, bool exc=false)  const;
       };
 
+      /// Monitoring object
+      DigiDepositMonitor* m_monitor { nullptr };
+
     protected:
       /// Define standard assignments and constructors
       DDDIGI_DEFINE_ACTION_CONSTRUCTORS(DigiContainerProcessor);
 
     public:
-      /// Access to default callback
+      /// Access to default deposit predicate accepting all
       static const predicate_t& accept_all();
+      /// Access to default deposit predicate accepting all
+      static const predicate_t& accept_not_killed();
 
       /// Standard constructor
       DigiContainerProcessor(const kernel_t& kernel, const std::string& name);
       /// Default destructor
       virtual ~DigiContainerProcessor();
+      /// Adopt monitoring action
+      void adopt_monitor(DigiDepositMonitor* monitor);
       /// Main functional callback adapter
       virtual void execute(context_t& context, work_t& work, const predicate_t& predicate)  const;
     };
@@ -168,9 +187,9 @@ namespace dd4hep {
       /// Structure imports
       using self_t      = DigiContainerSequence;
       using processor_t = DigiContainerProcessor;
-      using worker_t    = DigiParallelWorker<processor_t,work_t>;
+      using worker_t    = DigiParallelWorker<processor_t,work_t,std::size_t,self_t&>;
       using workers_t   = DigiParallelWorkers<worker_t>;
-      friend class DigiParallelWorker<processor_t,work_t>;
+      friend class DigiParallelWorker<processor_t,work_t,std::size_t,self_t&>;
 
     protected:
       /**  Member variables                           */
@@ -178,6 +197,9 @@ namespace dd4hep {
       bool               m_parallel { false };
       /// Array of sub-workers
       workers_t          m_workers;
+      /// Default Deposit predicate
+      predicate_t        m_worker_predicate = processor_t::accept_all();
+
       /// Lock for output merging
       mutable std::mutex m_output_lock;
 
@@ -193,12 +215,28 @@ namespace dd4hep {
     public:
       /// Standard constructor
       DigiContainerSequence(const kernel_t& kernel, const std::string& name);
+      /// Set the default predicate
+      void set_predicate(const predicate_t& predicate);
       /// Adopt new parallel worker
       virtual void adopt_processor(DigiContainerProcessor* action);
       /// Main functional callback adapter
       virtual void execute(context_t& context, work_t& work, const predicate_t& predicate)  const;
     };
 
+
+    struct DigiMultiProcessorParent   {
+    public:
+      using action_t     = DigiAction;
+      using processor_t  = DigiContainerProcessor;
+      using env_t        = processor_t::env_t;
+      using segment_t    = processor_t::segment_t;
+      using predicate_t  = processor_t::predicate_t;
+      using output_t     = processor_t::output_t;
+      using property_t   = processor_t::property_t;
+      using work_item_t  = processor_t::input_t;
+      using work_items_t = std::vector<processor_t::input_t>;
+    };
+
     /// Worker base class to analyse containers from the input segment in parallel
     /**
      *  Depending on the adopted processors, the full input record is scanned and
@@ -208,55 +246,45 @@ namespace dd4hep {
      *  \version 1.0
      *  \ingroup DD4HEP_DIGITIZATION
      */
-    class DigiContainerSequenceAction : public DigiEventAction  {
+    class DigiContainerSequenceAction : public DigiEventAction, public DigiMultiProcessorParent  {
 
     protected:
       /// Structure imports
-      using action_t    = DigiAction;
       using self_t      = DigiContainerSequenceAction;
-      using processor_t = DigiContainerProcessor;
-      using output_t    = processor_t::output_t;
-      using property_t  = processor_t::property_t;
-
-      /// Single worker work item definition
-      struct work_item_t  {
-	Key key;
-	std::any* data;
-      };
-      /// Work definition structure
-      /// Argument structure for client calls
+      /// Work definition structure: Argument structure for client calls
       struct work_t  {
-	context_t&             context;
-	std::vector<work_item_t> input_items;
-	output_t&                output;
-	const property_t&        properties;
-	const self_t&            parent;
+	env_t&              environ;
+	work_items_t&       input_items;
+	const self_t&       parent;
       };
 
-      using worker_t         = DigiParallelWorker<processor_t, work_t>;
+      using worker_t         = DigiParallelWorker<processor_t, work_t, std::size_t, self_t&>;
       using workers_t        = DigiParallelWorkers<worker_t>;
+      using predicate_t      = processor_t::predicate_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
-      workers_t          m_workers;
-      /// Registered action map
-      reg_processors_t   m_registered_processors;
-      /// Registered worker map
-      reg_workers_t      m_registered_workers;
+      friend class DigiParallelWorker<processor_t, work_t, std::size_t, self_t&>;
 
       /// Property: Input data segment name
-      std::string        m_input_segment  { "inputs" };
+      std::string              m_input_segment         { "inputs" };
       /// Property: Input mask to be handled
-      int                m_input_mask     { 0x0 };
+      int                      m_input_mask            { 0x0 };
       /// Property: Input data segment name
-      std::string        m_output_segment { "outputs" };
+      std::string              m_output_segment        { "outputs" };
       /// Property: event mask for output data
-      int                m_output_mask    { 0x0 };
+      int                      m_output_mask           { 0x0 };
+
+      /// Array of sub-workers
+      workers_t                m_workers               { };
+      /// Registered action map
+      reg_processors_t         m_registered_processors { };
+      /// Registered worker map
+      reg_workers_t            m_registered_workers    { };
+      /// Default Deposit predicate
+      predicate_t              m_worker_predicate      { processor_t::accept_all() };
 
       /// Lock for output merging
-      mutable std::mutex m_output_lock;
+      mutable std::mutex       m_output_lock           { };
       
     protected:
       /// Define standard assignments and constructors
@@ -273,6 +301,8 @@ namespace dd4hep {
     public:
       /// Standard constructor
       DigiContainerSequenceAction(const kernel_t& kernel, const std::string& name);
+      /// Set the default predicate
+      void set_predicate(const predicate_t& predicate);
       /// Adopt new parallel worker acting on one single container
       void adopt_processor(DigiContainerProcessor* action, const std::string& container);
       /// Adopt new parallel worker acting on multiple containers
@@ -288,36 +318,30 @@ namespace dd4hep {
      *  \version 1.0
      *  \ingroup DD4HEP_DIGITIZATION
      */
-    class DigiMultiContainerProcessor : virtual public DigiEventAction   {
+    class DigiMultiContainerProcessor : public DigiEventAction, public DigiMultiProcessorParent   {
     protected:
       using self_t        = DigiMultiContainerProcessor;
-      using processor_t   = DigiContainerProcessor;
       using worker_keys_t = std::vector<std::vector<Key> >;
-      using work_items_t  = std::vector<std::pair<Key, std::any*> >;
-      using output_t      = processor_t::output_t;
-      using property_t    = processor_t::property_t;
 
       /// Argument structure required to support multiple client calls
       struct work_t  {
-	context_t&        context;
-	work_items_t&     items;
-	output_t&         output;
-	const property_t& properties;
-	const self_t&     parent;
+	env_t&              environ;
+	work_items_t&       items;
+	const self_t&       parent;
       };
-      using worker_t      = DigiParallelWorker<processor_t, work_t>;
+      using worker_t      = DigiParallelWorker<processor_t, work_t, std::size_t, self_t&>;
       using workers_t     = DigiParallelWorkers<worker_t>;
-      friend class DigiParallelWorker<processor_t, work_t>;
+      friend class DigiParallelWorker<processor_t, work_t, std::size_t, self_t&>;
 
     protected:
       /// Property: Input data segment name
-      std::string        m_input_segment { "inputs" };
+      std::string        m_input_segment  { "inputs" };
       /// Property: event masks to be handled
-      std::vector<int>   m_input_masks  { };
+      std::vector<int>   m_input_masks    { };
       /// Property: Input data segment name
       std::string        m_output_segment { "outputs" };
       /// Property: event mask for output data
-      int                m_output_mask  { 0x0 };
+      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;
@@ -329,11 +353,13 @@ namespace dd4hep {
       worker_keys_t             m_worker_keys;
       /// Ordered list of actions registered
       std::vector<processor_t*> m_actions;
+      /// Default Deposit predicate
+      predicate_t               m_worker_predicate = processor_t::accept_all();
       /// Lock for output merging
       mutable std::mutex        m_output_lock;
 
       /// Array of sub-workers
-      workers_t          m_workers;
+      workers_t                 m_workers;
 
     protected:
        /// Define standard assignments and constructors
@@ -352,6 +378,8 @@ namespace dd4hep {
       const std::vector<int>& input_masks()  const   {
 	return this->m_input_masks;
       }
+      /// Set the default predicate
+      void set_predicate(const predicate_t& predicate);
       /// Adopt new parallel worker
       void adopt_processor(DigiContainerProcessor* action, const std::vector<std::string>& containers);
       /// Main functional callback
diff --git a/DDDigi/include/DDDigi/DigiData.h b/DDDigi/include/DDDigi/DigiData.h
index 4937b1753ed351c9c395eba6e084a93b19280a04..016f17d65a84477b87978fad0d32275a7944ed09 100644
--- a/DDDigi/include/DDDigi/DigiData.h
+++ b/DDDigi/include/DDDigi/DigiData.h
@@ -472,7 +472,8 @@ namespace dd4hep {
 	POSITION_SMEARED   = 1 << 2,
 	TIME_SMEARED       = 1 << 3,
 	ZERO_SUPPRESSED    = 1 << 4,
-        RECALIBRATED       = 1 << 5
+	DEPOSIT_NOISE      = 1 << 5,
+        RECALIBRATED       = 1 << 6
       };
 
       /// Hit position
@@ -490,9 +491,6 @@ namespace dd4hep {
       /// Source mask of this deposit
       Key::mask_type mask        { 0 };
 
-      /// Sources contributing to this deposit
-      History        history;
-
     public:
       /// Default constructor
       EnergyDeposit() = default;
@@ -807,6 +805,7 @@ namespace dd4hep {
     inline void DetectorHistory::insert(CellID cell, const History& value)   {
       this->data.emplace_back(cell, value);
     }
+    typedef DetectorHistory DepositsHistory;
 
 
     ///  Data segment definition (locked map)
diff --git a/DDDigi/include/DDDigi/DigiDepositMonitor.h b/DDDigi/include/DDDigi/DigiDepositMonitor.h
new file mode 100644
index 0000000000000000000000000000000000000000..1a4a15d818f79478de23bf154b2b87912724e00a
--- /dev/null
+++ b/DDDigi/include/DDDigi/DigiDepositMonitor.h
@@ -0,0 +1,231 @@
+//==========================================================================
+//  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_DIGIDEPOSITMONITOR_H
+#define DDDIGI_DIGIDEPOSITMONITOR_H
+
+/// Framework include files
+#include <DDDigi/DigiData.h>
+#include <DDDigi/DigiAction.h>
+#include <DDDigi/DigiMonitorOptions.h>
+
+/// Forward declarations
+class TH1;
+class TH2;
+
+/// Namespace for the AIDA detector description toolkit
+namespace dd4hep {
+
+  /// Namespace for the Digitization part of the AIDA detector description toolkit
+  namespace digi {
+
+    template <typename HISTO> class Histogram  {
+      friend class DigiKernel;
+      friend class DigiDepositMonitor;
+    protected:
+      HISTO* hist  { nullptr };
+    public:
+      Histogram(HISTO* h) : hist(h) {}
+    };
+
+    /// Wrapper for 1 dimensional monitoring histograms
+    /**
+     *
+     *  \author  M.Frank
+     *  \version 1.0
+     *  \ingroup DD4HEP_DIGITIZATION
+     */
+    class Histo1D : public Histogram<TH1>  {
+    public:
+      /// Add 1D histogram entry with weight
+      void fill(double x, double weight=1.0);
+    };
+
+    /// Wrapper for 2 dimensional monitoring histograms
+    /**
+     *
+     *  \author  M.Frank
+     *  \version 1.0
+     *  \ingroup DD4HEP_DIGITIZATION
+     */
+    class Histo2D : public Histogram<TH2>   {
+    public:
+      /// Add 2D histogram entry with weight
+      void fill(double x, double y, double weight=1.0);
+    };
+
+    /// Monitor base class to histogram deposit property changes
+    /**
+     *
+     *  \author  M.Frank
+     *  \version 1.0
+     *  \ingroup DD4HEP_DIGITIZATION
+     */
+    class DigiDepositMonitor : public DigiAction   {
+
+    protected:
+      using deposit_t = std::pair<CellID, EnergyDeposit>;
+
+      std::function<void(std::size_t, std::size_t )> count_shift_monitor
+	{ [](std::size_t, std::size_t) {} };
+      std::function<void(const deposit_t& , double )> time_shift_monitor
+	{ [](const deposit_t&, double) {} };
+      std::function<void(const deposit_t& , double )> energy_shift_monitor
+	{ [](const deposit_t&, double) {} };
+      std::function<void(const deposit_t& , const Position&, const Position& )> position_shift_monitor
+	{ [](const deposit_t&, const Position&, const Position&) {} };
+
+      template <typename T> void declare_monitor_time(T* object, void (T::*pmf)(const deposit_t& , double))   {
+	time_shift_monitor = std::bind(pmf, object, std::placeholders::_1, std::placeholders::_2);
+      }
+      template <typename T> void declare_monitor_energy(T* object, void (T::*pmf)(const deposit_t& , double))   {
+	energy_shift_monitor = std::bind(pmf, object, std::placeholders::_1, std::placeholders::_2);
+      }
+      template <typename T> void declare_monitor_count(T* object, void (T::*pmf)(std::size_t, std::size_t))   {
+	count_shift_monitor = std::bind(pmf, object, std::placeholders::_1, std::placeholders::_2);
+      }
+      template <typename T> void declare_monitor_position(T* object, void (T::*pmf)(const deposit_t& , const Position&, const Position&))   {
+	position_shift_monitor = std::bind(pmf, object, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
+      }
+
+    protected:
+      /// Define standard assignments and constructors
+      DDDIGI_DEFINE_ACTION_CONSTRUCTORS(DigiDepositMonitor);
+
+      /// Default destructor
+      virtual ~DigiDepositMonitor();
+
+      /// Initializing function: overload for sub-classes to e.g. book histograms
+      virtual void initialize();
+
+      /// Book 1D histogram and register it to the kernel for output handling
+      Histo1D book1D(const std::string& name, const std::string& title,
+		     std::size_t nbin_x, double min_x, double max_x);
+
+      /// Book 1D histogram and register it to the kernel for output handling
+      Histo2D book2D(const std::string& name, const std::string& title,
+		     std::size_t nbin_x, double min_x, double max_x,
+		     std::size_t nbin_y, double min_y, double max_y);
+
+    public:
+      /// Standard constructor
+      DigiDepositMonitor(const kernel_t& kernel, const std::string& name);
+
+      inline void time_shift(const deposit_t& deposit, double change)    {
+	time_shift_monitor(deposit, change);
+      }
+      inline void energy_shift(const deposit_t& deposit, double change)    {
+	energy_shift_monitor(deposit, change);
+      }
+      inline void position_shift(const deposit_t& deposit, const Position& position, const Position& change)   {
+	position_shift_monitor(deposit, position, change);
+      }
+      inline void count_shift(std::size_t start_value, std::size_t change)   {
+	count_shift_monitor(start_value, change);
+      }
+    };
+
+    /// Monitor base class to histogram the changes of the proper time of energy deposits
+    /**
+     *
+     *  \author  M.Frank
+     *  \version 1.0
+     *  \ingroup DD4HEP_DIGITIZATION
+     */
+    class DigiDepositTimeMonitor : public DigiDepositMonitor   {
+
+    protected:
+      /// Property with the 1D histogram parameters to fill the histogram with deposits
+      H1DParams histo1D_deposits { "", "", -1, 0e0, 0e0 };
+      /// Property with the 1D histogram parameters to fill the histogram with deposit deltas
+      H1DParams histo1D_delta    { "", "", -1, 0e0, 0e0 };
+
+      /// Pointer to deposit histogram
+      Histo1D  m_deposits   { nullptr };
+      /// Pointer to delta histogram
+      Histo1D  m_deltas     { nullptr };
+
+      /// Initializing function: overload for sub-classes to e.g. book histograms
+      virtual void initialize();
+
+      /// Fill the monitoring histograms
+      void monitor_time_shift(const deposit_t& deposit, double change);
+
+    public:
+      /// Standard constructor
+      DigiDepositTimeMonitor(const kernel_t& kernel, const std::string& name);
+    };
+
+    /// Monitor base class to histogram energy deposit changes
+    /**
+     *
+     *  \author  M.Frank
+     *  \version 1.0
+     *  \ingroup DD4HEP_DIGITIZATION
+     */
+    class DigiDepositEnergyMonitor : public DigiDepositMonitor   {
+    protected:
+      /// Property with the 1D histogram parameters to fill the histogram with deposits
+      H1DParams histo1D_deposits { "", "", -1, 0e0, 0e0 };
+      /// Property with the 1D histogram parameters to fill the histogram with deposit deltas
+      H1DParams histo1D_delta    { "", "", -1, 0e0, 0e0 };
+
+      /// Pointer to deposit histogram
+      Histo1D m_deposits   { nullptr };
+      /// Pointer to delta histogram
+      Histo1D m_deltas     { nullptr };
+
+      /// Initializing function: overload for sub-classes to e.g. book histograms
+      virtual void initialize();
+
+      /// Fill the monitoring histograms
+      void monitor_energy_shift(const deposit_t& deposit, double change);
+
+    public:
+      /// Standard constructor
+      DigiDepositEnergyMonitor(const kernel_t& kernel, const std::string& name);
+    };
+
+    /// Monitor base class to histogram the changes of the position of energy deposits
+    /**
+     *
+     *  \author  M.Frank
+     *  \version 1.0
+     *  \ingroup DD4HEP_DIGITIZATION
+     */
+    class DigiDepositPositionMonitor : public DigiDepositMonitor   {
+
+    protected:
+      /// Property with the 1D histogram parameters to fill the histogram with deposits
+      H1DParams histo1D_deposits { "", "", -1, 0e0, 0e0 };
+      /// Property with the 1D histogram parameters to fill the histogram with deposit deltas
+      H1DParams histo1D_delta    { "", "", -1, 0e0, 0e0 };
+
+      /// Pointer to deposit histogram
+      Histo1D m_deposits   { nullptr };
+      /// Pointer to delta histogram
+      Histo1D m_deltas     { nullptr };
+
+      /// Initializing function: overload for sub-classes to e.g. book histograms
+      virtual void initialize();
+
+      /// Fill the monitoring histograms
+      void monitor_position_shift(const deposit_t& deposit, const Position& position, const Position& change);
+
+    public:
+      /// Standard constructor
+      DigiDepositPositionMonitor(const kernel_t& kernel, const std::string& name);
+    };
+
+  }    // End namespace digi
+}      // End namespace dd4hep
+#endif // DDDIGI_DIGIDEPOSITMONITOR_H
diff --git a/DDDigi/include/DDDigi/DigiHandle.h b/DDDigi/include/DDDigi/DigiHandle.h
index b2fedc28350560b5f7ba0232ae6d4e14d24ab1ad..3be1457d87fb503c8f7477db389381438e4cd9e3 100644
--- a/DDDigi/include/DDDigi/DigiHandle.h
+++ b/DDDigi/include/DDDigi/DigiHandle.h
@@ -57,6 +57,8 @@ namespace dd4hep {
       DigiKernel* get() const        { return value; }
       /// Access to the underlying object
       DigiKernel* operator->() const { return value; }
+      /// Property accessor
+      Property& operator[](const std::string& property_name) const;
       /// Access to worker thread
       KernelHandle worker();
       /// Destroy referenced object (program termination)
diff --git a/DDDigi/include/DDDigi/DigiKernel.h b/DDDigi/include/DDDigi/DigiKernel.h
index 85b374db36d6c713603aab255ec56796319ff96c..1250477789219b7209ae7296339c437dc8fe86b2 100644
--- a/DDDigi/include/DDDigi/DigiKernel.h
+++ b/DDDigi/include/DDDigi/DigiKernel.h
@@ -13,14 +13,17 @@
 #ifndef DDDIGI_DIGIKERNEL_H
 #define DDDIGI_DIGIKERNEL_H
 
-// Framework include files
-#include <DDDigi/DigiEventAction.h>
+/// Framework include files
+#include <DDDigi/DigiActionSequence.h>
 #include <DDDigi/DigiParallelWorker.h>
 
-// C/C++ include files
+/// C/C++ include files
 #include <mutex>
 #include <memory>
 
+/// Forward declarations
+class TH1;
+
 /// Namespace for the AIDA detector description toolkit
 namespace dd4hep {
 
@@ -39,7 +42,7 @@ namespace dd4hep {
      *  \version 1.0
      *  \ingroup DD4HEP_DIGITIZATION
      */
-    class DigiKernel  {
+    class DigiKernel : public DigiAction   {
     public:
       typedef std::map<std::string,int>                 ClientOutputLevels;
       typedef std::pair<void*, const std::type_info*>   UserFramework;
@@ -100,24 +103,10 @@ namespace dd4hep {
       std::mutex& global_output_lock()   const;
       
       /** Property access                            */
-      /// Access to the properties of the object
-      PropertyManager& properties();
       /// Print the property values
-      void printProperties() const;
-      /// Declare property
-      template <typename T> DigiKernel& declareProperty(const std::string& nam, T& val);
-      /// Declare property
-      template <typename T> DigiKernel& declareProperty(const char* nam, T& val);
-      /// Check property for existence
-      bool hasProperty(const std::string& name) const;
-      /// Access single property
-      Property& property(const std::string& name);
-
-      /** Output level settings                       */
-      /// Access the output level
-      PrintLevel outputLevel() const;
-      /// Set the global output level of the kernel object; returns previous value
-      PrintLevel setOutputLevel(PrintLevel new_level);
+      virtual std::size_t printProperties() const  override;
+
+      /** Client output level settings               */
       /// Fill cache with the global output level of a named object. Must be set before instantiation
       void setOutputLevel(const std::string object, PrintLevel new_level);
       /// Retrieve the global output level of a named object.
@@ -141,6 +130,9 @@ namespace dd4hep {
       /// Register end event callback. Signature:   (function)(DigiContext*)
       void register_end_event(const std::function<void(DigiContext&)>& callback)   const;
 
+      /// Registration of monitoring objects eventually saved by the handler
+      void register_monitor(DigiAction* action, TNamed* histo)  const;
+
       /// Construct detector geometry using description plugin
       virtual void loadGeometry(const std::string& compact_file);
       /// Load XML file 
@@ -172,18 +164,6 @@ namespace dd4hep {
       virtual void wait(DigiContext& context)   const;
 
     };
-
-    /// Declare property
-    template <typename T> inline DigiKernel& DigiKernel::declareProperty(const std::string& nam, T& val) {
-      properties().add(nam, val);
-      return *this;
-    }
-
-    /// Declare property
-    template <typename T> inline DigiKernel& DigiKernel::declareProperty(const char* nam, T& val) {
-      properties().add(nam, val);
-      return *this;
-    }
   }    // End namespace digi
 }      // End namespace dd4hep
 #endif // DDDIGI_DIGIKERNEL_H
diff --git a/DDDigi/include/DDDigi/DigiMonitorHandler.h b/DDDigi/include/DDDigi/DigiMonitorHandler.h
new file mode 100644
index 0000000000000000000000000000000000000000..9e12a285610015203cf90760488fa5d2b162d53e
--- /dev/null
+++ b/DDDigi/include/DDDigi/DigiMonitorHandler.h
@@ -0,0 +1,59 @@
+//==========================================================================
+//  AIDA Detector description implementation 
+//--------------------------------------------------------------------------
+// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
+// All rights reserved.
+//
+// For the licensing terms see $DD4hepINSTALL/LICENSE.
+// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
+//
+// Author     : M.Frank
+//
+//==========================================================================
+#ifndef DDDIGI_DIGIMONITORHANDLER_H
+#define DDDIGI_DIGIMONITORHANDLER_H
+
+/// Framework include files
+#include <DDDigi/DigiAction.h>
+
+/// C/C++ include files
+class TNamed;
+
+/// 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 DigiMonitorHandler;
+
+    /// Class to execute non-reentrant subhandler in wrapped mode
+    /**
+     *
+     *  \author  M.Frank
+     *  \version 1.0
+     *  \ingroup DD4HEP_DIGITIZATION
+     */
+    class DigiMonitorHandler : public DigiAction {
+    protected:
+      /// Property: output file name if monitor saving is desired (delegated to kernel)
+      std::string m_output_file;
+
+      /// Map of monitoring items
+      std::map<DigiAction*, std::set<TNamed*> > m_monitors;
+
+    public:
+      /// Standard constructor
+      DigiMonitorHandler(const kernel_t& kernel, const std::string& nam);
+      /// Standard destructor
+      virtual ~DigiMonitorHandler();
+      /// Adopt monitor and keep reference for saving
+      void adopt(DigiAction* source, TNamed* object);
+      /// Save monitors
+      void save();
+    };
+
+  }    // End namespace digi
+}      // End namespace dd4hep
+#endif // DDDIGI_DIGIMONITORHANDLER_H
diff --git a/DDDigi/include/DDDigi/DigiMonitorOptions.h b/DDDigi/include/DDDigi/DigiMonitorOptions.h
new file mode 100644
index 0000000000000000000000000000000000000000..d3ecf519db956f0d38240ccf053674a46b93aaa5
--- /dev/null
+++ b/DDDigi/include/DDDigi/DigiMonitorOptions.h
@@ -0,0 +1,59 @@
+//==========================================================================
+//  AIDA Detector description implementation 
+//--------------------------------------------------------------------------
+// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
+// All rights reserved.
+//
+// For the licensing terms see $DD4hepINSTALL/LICENSE.
+// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
+//
+// Author     : M.Frank
+//
+//==========================================================================
+#ifndef DDDIGI_DIGIMONITOROPTIONS_H
+#define DDDIGI_DIGIMONITOROPTIONS_H
+
+/// Framework include files
+#include <DDDigi/DigiAction.h>
+#include <DDDigi/DigiData.h>
+
+/// Namespace for the AIDA detector description toolkit
+namespace dd4hep {
+
+  /// Namespace for the Digitization part of the AIDA detector description toolkit
+  namespace digi {
+
+    /// Property to parse 1D histogram options
+    /**
+     *
+     *  \author  M.Frank
+     *  \version 1.0
+     *  \ingroup DD4HEP_DIGITIZATION
+     */
+    class H1DParams   {
+    public:
+      std::string name;
+      std::string title;
+      int nbin_x;
+      double min_x, max_x;
+    };
+
+    /// Property to parse 2D histogram options
+    /**
+     *
+     *  \author  M.Frank
+     *  \version 1.0
+     *  \ingroup DD4HEP_DIGITIZATION
+     */
+    class H2DParams   {
+    public:
+      std::string name;
+      std::string title;
+      int    nbin_x;
+      double min_x, max_x;
+      int    nbin_y;
+      double min_y, max_y;
+    };
+  }    // End namespace digi
+}      // End namespace dd4hep
+#endif // DDDIGI_DIGIMONITOROPTIONS_H
diff --git a/DDDigi/include/DDDigi/DigiParallelWorker.h b/DDDigi/include/DDDigi/DigiParallelWorker.h
index ae1316f1ab1562c1e404d176bd1b508c4af9b2f3..4d6eab39707b2a53006baf040b497d48041d846d 100644
--- a/DDDigi/include/DDDigi/DigiParallelWorker.h
+++ b/DDDigi/include/DDDigi/DigiParallelWorker.h
@@ -22,6 +22,9 @@ namespace dd4hep {
   /// Namespace for the Digitization part of the AIDA detector description toolkit
   namespace digi {
 
+    /// Forward declarations
+    class WorkerPredicate;
+
     /// Wrapper class to submit bulk actions
     /**
      *
@@ -48,19 +51,21 @@ namespace dd4hep {
      *  \version 1.0
      *  \ingroup DD4HEP_DIGITIZATION
      */
-    template <typename ACTION_TYPE, typename CALLDATA, typename OPTIONS=std::size_t>
+    template <typename ACTION_TYPE, typename CALLDATA, typename OPTIONS=std::size_t, typename PREDICATE=std::size_t>
       class DigiParallelWorker : public ParallelWorker   {
     public:
     using action_t = ACTION_TYPE;
     using options_t = OPTIONS;
     using calldata_t = CALLDATA;
-    
-    action_t* action   { nullptr };
-    options_t options  { nullptr };
+    using predicate_t = PREDICATE;
+
+    action_t*        action    { nullptr };
+    options_t        options   { nullptr };
+    predicate_t      predicate { nullptr };
 
     public:
     /// Initializing constructor
-    DigiParallelWorker(ACTION_TYPE* p, const OPTIONS& opts);
+    DigiParallelWorker(action_t* a, const options_t& opts, const predicate_t& p={});
     /// Default constructor
     DigiParallelWorker() = delete;
     /// Move constructor
@@ -80,16 +85,16 @@ namespace dd4hep {
     };
 
     /// Initializing constructor
-    template <typename ACTION_TYPE, typename CALLDATA, typename OPTIONS>
-      DigiParallelWorker<ACTION_TYPE, CALLDATA, OPTIONS>::DigiParallelWorker(ACTION_TYPE* proc, const OPTIONS& opts)
-      : ParallelWorker(), action(proc), options(opts)
+    template <typename ACTION_TYPE, typename CALLDATA, typename OPTIONS, typename PREDICATE>
+      DigiParallelWorker<ACTION_TYPE, CALLDATA, OPTIONS, PREDICATE>::DigiParallelWorker(action_t* a, const options_t& o, const predicate_t& p)
+      : ParallelWorker(), action(a), options(o), predicate(p)
     {
       if ( action ) action->addRef();
     }
 
     /// Default destructor
-    template <typename ACTION_TYPE, typename CALLDATA, typename OPTIONS>
-      DigiParallelWorker<ACTION_TYPE, CALLDATA, OPTIONS>::~DigiParallelWorker()   {
+    template <typename ACTION_TYPE, typename CALLDATA, typename OPTIONS, typename PREDICATE>
+      DigiParallelWorker<ACTION_TYPE, CALLDATA, OPTIONS, PREDICATE>::~DigiParallelWorker()   {
       if ( action )   {
 	action->release();
 	action = nullptr;
diff --git a/DDDigi/include/DDDigi/DigiParallelWorkers.h b/DDDigi/include/DDDigi/DigiParallelWorkers.h
index a078abe4cdc3fa7d67bb89015e4a6c86d56c04a6..72c8c4d0421aadb2f6b75f36b639b8b54ddad320 100644
--- a/DDDigi/include/DDDigi/DigiParallelWorkers.h
+++ b/DDDigi/include/DDDigi/DigiParallelWorkers.h
@@ -29,7 +29,6 @@ namespace dd4hep {
 
     /// Forward declarations
     class ParallelWorker;
-    template <typename T, typename A, typename O> class DigiParallelWorker;
     template <typename T> class DigiParallelWorkers;
     template <typename T> class DigiParallelWorkerGroup;
 
diff --git a/DDDigi/include/DDDigi/DigiSegmentSplitter.h b/DDDigi/include/DDDigi/DigiSegmentSplitter.h
index 0c59ba13e5fa8ba95eef4d8129e0c868fa7e8fb8..a433e060351db480a2c5922a69c756ba861d4b93 100644
--- a/DDDigi/include/DDDigi/DigiSegmentSplitter.h
+++ b/DDDigi/include/DDDigi/DigiSegmentSplitter.h
@@ -111,7 +111,7 @@ namespace dd4hep {
       using segment_t   = DigiSegmentProcessContext;
       using processor_t = DigiContainerProcessor;
 
-      using worker_t    = DigiParallelWorker<processor_t,work_t, segment_t>;
+      using worker_t    = DigiParallelWorker<processor_t, work_t, segment_t>;
       using workers_t   = DigiParallelWorkers<worker_t>;
       friend class DigiParallelWorker<processor_t, work_t, segment_t>;
 
@@ -138,6 +138,7 @@ namespace dd4hep {
       splits_t           m_splits;
       /// Array of sub-workers
       workers_t          m_workers;
+
       /// Lock for output merging
       mutable std::mutex m_output_lock;
       /// Segmentation too instance
diff --git a/DDDigi/include/DDDigi/DigiSynchronize.h b/DDDigi/include/DDDigi/DigiSynchronize.h
index 6a16e2b4547c748ba1c557705790bfd78c64cae2..e4c5cbee780231f58892b826647c6fb0e5388bd0 100644
--- a/DDDigi/include/DDDigi/DigiSynchronize.h
+++ b/DDDigi/include/DDDigi/DigiSynchronize.h
@@ -34,10 +34,14 @@ namespace dd4hep {
      */
     class DigiSynchronize : public DigiEventAction {
     protected:
-      using Worker  = DigiParallelWorker<DigiEventAction,context_t,int>;
-      using Workers = DigiParallelWorkers<Worker>;
+      using work_t    = context_t;
+      using self_t    = DigiSynchronize;
+      using worker_t  = DigiParallelWorker<DigiEventAction, work_t, std::size_t, self_t&>;
+      using workers_t = DigiParallelWorkers<worker_t>;
+      friend class DigiParallelWorker<DigiEventAction, work_t, std::size_t, self_t&>;
+
       /// The list of action objects to be called
-      Workers m_actors;
+      workers_t m_actors;
 
     protected:
       /// Define standard assignments and constructors
diff --git a/DDDigi/plugins/Components.cpp b/DDDigi/plugins/Components.cpp
index c375684435a55aaf68fddf16422a047919bf9219..c976ba968796a886bbcded903e4045214a3e9094 100644
--- a/DDDigi/plugins/Components.cpp
+++ b/DDDigi/plugins/Components.cpp
@@ -69,6 +69,11 @@ DECLARE_DIGIACTION_NS(dd4hep::digi,DigiContainerSequence)
 DECLARE_DIGIACTION_NS(dd4hep::digi,DigiContainerProcessor)
 DECLARE_DIGIACTION_NS(dd4hep::digi,DigiContainerSequenceAction)
 
+#include <DDDigi/DigiDepositMonitor.h>
+DECLARE_DIGIACTION_NS(dd4hep::digi,DigiDepositTimeMonitor)
+DECLARE_DIGIACTION_NS(dd4hep::digi,DigiDepositEnergyMonitor)
+DECLARE_DIGIACTION_NS(dd4hep::digi,DigiDepositPositionMonitor)
+
 /// Basic entry point 
 static long dummy(dd4hep::Detector&, int, char**) {
   return 0;
diff --git a/DDDigi/plugins/DigiDepositDropKilled.cpp b/DDDigi/plugins/DigiDepositDropKilled.cpp
index 60ba5b2e61af6e36641b1dc7c03f1c0041233255..e9c115ce7241c946bbc52f9eedc4711a8875a615 100644
--- a/DDDigi/plugins/DigiDepositDropKilled.cpp
+++ b/DDDigi/plugins/DigiDepositDropKilled.cpp
@@ -13,11 +13,6 @@
 
 // Framework include files
 #include <DDDigi/DigiContainerProcessor.h>
-#include <DD4hep/InstanceCount.h>
-#include <DD4hep/DD4hepUnits.h>
-
-/// C/C++ include files
-#include <limits>
 
 /// Namespace for the AIDA detector description toolkit
 namespace dd4hep {
@@ -25,49 +20,34 @@ namespace dd4hep {
   /// Namespace for the Digitization part of the AIDA detector description toolkit
   namespace digi {
 
-    /// Actor to drop energy deposits of a container having the "KILLED" flag
+    /// Actor to drop energy deposits of a container having deposits with the "KILLED" flag set
     /**
-     *
      *
      *  \author  M.Frank
      *  \version 1.0
      *  \ingroup DD4HEP_DIGITIZATION
      */
     class DigiDepositDropKilled : public DigiContainerProcessor   {
-    protected:
-      /// Property: Flag to update existing container in-place or create a new container
-      bool   m_update_in_place            { true  };
-
     public:
       /// Standard constructor
-      DigiDepositDropKilled(const DigiKernel& krnl, const std::string& nam)
-	: DigiContainerProcessor(krnl, nam)
-      {
-	declareProperty("update_in_place",            m_update_in_place = true);
-	InstanceCount::increment(this);
-      }
+      using DigiContainerProcessor::DigiContainerProcessor;
 
-      /// Default destructor
-      virtual ~DigiDepositDropKilled() {
-	InstanceCount::decrement(this);
-      }
-      template <typename T> std::size_t length(const T* m)  const {  return m->size(); }
       /// Main functional callback
       virtual void execute(DigiContext& context, work_t& work, const predicate_t&)  const override final  {
 	std::size_t killed = 0, total = 0, i = 0;
 	if ( auto* v = work.get_input<DepositVector>() )   {
-	  total = length(v);
+	  total = v->size();
 	  for( auto iter = v->begin(); iter != v->end(); ++iter, ++i )   {
 	    if ( v->at(i).flag&EnergyDeposit::KILLED )   {
 	      v->remove(iter);
 	      iter = v->begin() + (--i);
 	    }
 	  }
-	  killed = total - length(v);
+	  killed = total - v->size();
 	}
 	else if ( auto* m = work.get_input<DepositMapping>() )   {
 	  CellID last_cell = ~0x0LL;
-	  total = length(m);
+	  total = m->size();
 	  for( auto iter = m->begin(); iter != m->end(); ++iter )   {
 	    if ( iter->second.flag&EnergyDeposit::KILLED )   {
 	      m->remove(iter);
@@ -76,11 +56,12 @@ namespace dd4hep {
 	    }
 	    last_cell = iter->first;
 	  }
-	  killed = total - length(v);
+	  killed = total - m->size();
 	}
 	else   {
 	  except("Request to handle unknown data type: %s", work.input_type_name().c_str());
 	}
+	if ( m_monitor ) m_monitor->count_shift(total, killed);
 	info("%s+++ Killed %6ld out of %6ld deposit entries from container: %s",context.event->id(), killed, total);
       }
     };
diff --git a/DDDigi/plugins/DigiDepositEnergyCut.cpp b/DDDigi/plugins/DigiDepositEnergyCut.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c695f9015457bd51893cc1dce94ec9c98ab655c4
--- /dev/null
+++ b/DDDigi/plugins/DigiDepositEnergyCut.cpp
@@ -0,0 +1,73 @@
+//==========================================================================
+//  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 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
+     *  momentum according to the contribution of the hits.
+     *
+     *  \author  M.Frank
+     *  \version 1.0
+     *  \ingroup DD4HEP_DIGITIZATION
+     */
+    class DigiDepositEnergyCut : public DigiDepositsProcessor   {
+    protected:
+      /// Property: Energy cutoff. No hits will be merged with a deposit smaller
+      double m_cutoff { -std::numeric_limits<double>::epsilon() };
+
+    public:
+      /// Create deposit mapping with updates on same cellIDs
+      template <typename T> void
+      cut_energy(context_t& context, T& cont, work_t& /* work */, const predicate_t& predicate)  const  {
+	std::size_t dropped = 0UL;
+	for( auto& dep : cont )    {
+	  if ( predicate(dep) )   {
+	    EnergyDeposit& depo = dep.second;
+	    if ( depo.deposit < m_cutoff )   {
+	      depo.flag |= EnergyDeposit::KILLED;
+	      ++dropped;
+	    }
+	  }
+	}
+	if ( m_monitor ) m_monitor->count_shift(cont.size(), dropped);
+	info("%s+++ %-32s dropped %6ld out of %6ld entries from mask: %04X",
+	     context.event->id(), cont.name.c_str(), dropped, cont.size(), cont.key.mask());
+      }
+
+      /// Standard constructor
+      DigiDepositEnergyCut(const DigiKernel& krnl, const std::string& nam)
+	: DigiDepositsProcessor(krnl, nam)
+      {
+	declareProperty("deposit_cutoff", m_cutoff);
+	DEPOSIT_PROCESSOR_BIND_HANDLERS(DigiDepositEnergyCut::cut_energy)
+      }
+    };
+  }    // End namespace digi
+}      // End namespace dd4hep
+
+#include <DDDigi/DigiFactories.h>
+DECLARE_DIGIACTION_NS(dd4hep::digi,DigiDepositEnergyCut)
diff --git a/DDDigi/plugins/DigiDepositMapCreator.cpp b/DDDigi/plugins/DigiDepositMapCreator.cpp
index 86765d0e18e4d0edbce90f55f1e3340b5ec3f9dc..19fcf5180ef4f582df3cf190a8b7afc6b9e42eff 100644
--- a/DDDigi/plugins/DigiDepositMapCreator.cpp
+++ b/DDDigi/plugins/DigiDepositMapCreator.cpp
@@ -37,8 +37,8 @@ namespace dd4hep {
 
       template <typename T> void
       create_deposits(const char* tag, const T& cont, work_t& work, const predicate_t& predicate)  const  {
-	Key key(cont.name, work.output.mask);
-	DepositMapping m(cont.name, work.output.mask);
+	Key key(cont.name, work.environ.output.mask);
+	DepositMapping m(cont.name, work.environ.output.mask);
 	std::size_t start = m.size();
 	for( const auto& dep : cont )   {
 	  if ( predicate(dep) )    {
@@ -46,7 +46,7 @@ namespace dd4hep {
 	  }
 	}
 	std::size_t end   = m.size();
-	work.output.data.put(m.key, std::move(m));
+	work.environ.output.data.put(m.key, std::move(m));
 	info("%s+++ %-32s added %6ld entries (now: %6ld) from mask: %04X to mask: %04X",
 	     tag, cont.name.c_str(), end-start, end, cont.key.mask(), m.key.mask());
       }
diff --git a/DDDigi/plugins/DigiDepositNoiseOnSignal.cpp b/DDDigi/plugins/DigiDepositNoiseOnSignal.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..62d63043505d3c258f9419dc035c13dd25aa474e
--- /dev/null
+++ b/DDDigi/plugins/DigiDepositNoiseOnSignal.cpp
@@ -0,0 +1,74 @@
+//==========================================================================
+//  AIDA Detector description implementation 
+//--------------------------------------------------------------------------
+// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
+// All rights reserved.
+//
+// For the licensing terms see $DD4hepINSTALL/LICENSE.
+// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
+//
+// Author     : M.Frank
+//
+//==========================================================================
+
+// Framework include files
+#include <DDDigi/DigiContainerProcessor.h>
+#include <DD4hep/DD4hepUnits.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 timing information of energy deposits
+    /**
+     *
+     *  \author  M.Frank
+     *  \version 1.0
+     *  \ingroup DD4HEP_DIGITIZATION
+     */
+    class DigiDepositNoiseOnSignal : public DigiDepositsProcessor  {
+    protected:
+      /// Property: Mean of the added noise on signal in absolute values 
+      double m_mean                { 0e0 };
+      /// Property: Sigma of the noise in absolute values
+      double m_sigma               { 0e0 };
+
+    public:
+      /// Create deposit mapping with updates on same cellIDs
+      template <typename T> void
+      create_noise(DigiContext& context, T& cont, work_t& /* work */, const predicate_t& predicate)  const  {
+	auto& random = context.randomGenerator();
+	std::size_t updated = 0UL;
+	for( auto& dep : cont )  {
+	  if ( predicate(dep) )  {
+	    int flag = EnergyDeposit::DEPOSIT_NOISE;
+	    double delta_E = random.gaussian(m_mean, m_sigma);
+	    if ( m_monitor ) m_monitor->energy_shift(dep, delta_E);
+	    dep.second.deposit += delta_E;
+	    dep.second.flag |= flag;
+	    ++updated;
+	  }
+	}
+	info("%s+++ %-32s Noise on signal: %6ld entries, updated %6ld entries. mask: %04X",
+	     context.event->id(), cont.name.c_str(), cont.size(), updated, cont.key.mask());
+      }
+
+      /// Standard constructor
+      DigiDepositNoiseOnSignal(const DigiKernel& krnl, const std::string& nam)
+	: DigiDepositsProcessor(krnl, nam)
+      {
+	declareProperty("mean",  m_mean);
+	declareProperty("sigma", m_sigma);
+	DEPOSIT_PROCESSOR_BIND_HANDLERS(DigiDepositNoiseOnSignal::create_noise)
+      }
+    };
+  }    // End namespace digi
+}      // End namespace dd4hep
+
+#include <DDDigi/DigiFactories.h>
+DECLARE_DIGIACTION_NS(dd4hep::digi,DigiDepositNoiseOnSignal)
diff --git a/DDDigi/plugins/DigiDepositRecalibEnergy.cpp b/DDDigi/plugins/DigiDepositRecalibEnergy.cpp
index 490a23b1fbdcad1a08e4ac7b6bc24529f833c50d..8d61d232301444e017b2e76cdabf0866ae410dbf 100644
--- a/DDDigi/plugins/DigiDepositRecalibEnergy.cpp
+++ b/DDDigi/plugins/DigiDepositRecalibEnergy.cpp
@@ -32,42 +32,27 @@ namespace dd4hep {
      *  \version 1.0
      *  \ingroup DD4HEP_DIGITIZATION
      */
-    class DigiDepositRecalibEnergy : public DigiContainerProcessor   {
+    class DigiDepositRecalibEnergy : public DigiDepositsProcessor   {
     protected:
       /// Property: Polynomial parameters to recalibrate the energy
       std::vector<double> m_polynomial        {  };
       /// Property: Energy base point to compute delta(energy)
       double              m_e0                { 0e0 };
-      /// Property: Flag to update existing container in-place or create a new container
-      bool                m_update_in_place   { true };
 
     public:
       /// Standard constructor
       DigiDepositRecalibEnergy(const DigiKernel& krnl, const std::string& nam)
-	: DigiContainerProcessor(krnl, nam)
+	: DigiDepositsProcessor(krnl, nam)
       {
 	declareProperty("e0", m_e0);
 	declareProperty("parameters" , m_polynomial);
-	InstanceCount::increment(this);
-      }
-
-      /// Default destructor
-      virtual ~DigiDepositRecalibEnergy() {
-	InstanceCount::decrement(this);
+	DEPOSIT_PROCESSOR_BIND_HANDLERS(DigiDepositRecalibEnergy::recalibrate_deposit_energy)
       }
 
       /// Create deposit mapping with updates on same cellIDs
-      template <typename T> void recalibrate_deposit_energy(DigiContext& context,
-							    T& cont,
-							    work_t& work,
-							    const predicate_t& predicate)  const  {
-	T output_cont(cont.name, work.output.mask);
+      template <typename T> void 
+      recalibrate_deposit_energy(DigiContext& context, T& cont, work_t& /* work */, const predicate_t& predicate)  const  {
 	std::size_t updated = 0UL;
-	std::size_t created = 0UL;
-	std::size_t killed  = 0UL;
-
-	info("%s+++ Recalibrarting deposit container: %s %6ld entries",
-	     context.event->id(), cont.name.c_str(), cont.size());
 	for( auto& dep : cont )    {
 	  if ( predicate(dep) )   {
 	    double deposit = dep.second.deposit;
@@ -77,39 +62,14 @@ namespace dd4hep {
 	      deposit += param * fac;
 	      fac     *= delta_E;
 	    }
-	    if ( m_update_in_place )   {
-	      EnergyDeposit& d = dep.second;
-	      d.deposit = deposit;
-	      d.flag |= EnergyDeposit::RECALIBRATED;
-	      ++updated;
-	    }
-	    else if ( !(dep.second.flag&EnergyDeposit::KILLED) )  {
-	      EnergyDeposit d(dep.second);
-	      d.deposit = deposit;
-	      d.flag |= EnergyDeposit::RECALIBRATED;
-	      output_cont.emplace(dep.first, std::move(d));
-	      ++created;
-	    }
-	    else  {
-	      ++killed;
-	    }
+	    if ( m_monitor ) m_monitor->energy_shift(dep, delta_E);
+	    dep.second.deposit = deposit;
+	    dep.second.flag |= EnergyDeposit::RECALIBRATED;
+	    ++updated;
 	  }
 	}
-	if ( !m_update_in_place )   {
-	  work.output.data.put(output_cont.key, std::move(output_cont));
-	}
-	info("%s+++ %-32s Smearing: created %6ld updated %6ld killed %6ld entries from mask: %04X",
-	     context.event->id(), cont.name.c_str(), created, updated, killed, cont.key.mask());
-      }
-
-      /// Main functional callback
-      virtual void execute(DigiContext& context, work_t& work, const predicate_t& predicate)  const override final  {
-	if ( auto* v = work.get_input<DepositVector>() )
-	  recalibrate_deposit_energy(context, *v, work, predicate);
-	else if ( auto* m = work.get_input<DepositMapping>() )
-	  recalibrate_deposit_energy(context, *m, work, predicate);
-	else
-	  except("Request to handle unknown data type: %s", work.input_type_name().c_str());
+	info("%s+++ %-32s Recalibrating: updated %6ld out of %6ld entries from mask: %04X",
+	     context.event->id(), cont.name.c_str(), updated, cont.size(), cont.key.mask());
       }
     };
   }    // End namespace digi
diff --git a/DDDigi/plugins/DigiDepositSmearEnergy.cpp b/DDDigi/plugins/DigiDepositSmearEnergy.cpp
index 3aaa47538d5c18ebb90e77ae61e436930ca0a40a..d7d97aa6a96f9511dd0f771e18564a61bc3652cf 100644
--- a/DDDigi/plugins/DigiDepositSmearEnergy.cpp
+++ b/DDDigi/plugins/DigiDepositSmearEnergy.cpp
@@ -13,7 +13,6 @@
 
 // Framework include files
 #include <DDDigi/DigiContainerProcessor.h>
-#include <DD4hep/InstanceCount.h>
 #include <DD4hep/DD4hepUnits.h>
 
 /// C/C++ include files
@@ -61,10 +60,8 @@ namespace dd4hep {
      *  \version 1.0
      *  \ingroup DD4HEP_DIGITIZATION
      */
-    class DigiDepositSmearEnergy : public DigiContainerProcessor   {
+    class DigiDepositSmearEnergy : public DigiDepositsProcessor   {
     protected:
-      /// Property: Energy cutoff. No hits will be merged with a deposit smaller
-      double m_deposit_cutoff { std::numeric_limits<double>::epsilon() };
       /// Property: Intrinsic energy resolution constant (gaussian ~ std::sqrt(energy))
       double m_intrinsic_fluctuation      { 0e0 };
       /// Property: Systematic energy resolution constant (gaussian ~deposit energy)
@@ -75,115 +72,67 @@ namespace dd4hep {
       double m_pair_ionization_energy     { 0e0 };
       /// Property: Flag to use ionization fluctuation smearing (poisson ~ # e-ion-pairs)
       bool   m_ionization_fluctuation     { false };
-      /// Property: Flag to update existing container in-place or create a new container
-      bool   m_update_in_place            { true  };
 
     public:
       /// Standard constructor
       DigiDepositSmearEnergy(const DigiKernel& krnl, const std::string& nam)
-	: DigiContainerProcessor(krnl, nam)
+	: DigiDepositsProcessor(krnl, nam)
       {
-	declareProperty("deposit_cutoff",             m_deposit_cutoff);
 	declareProperty("intrinsic_fluctuation",      m_intrinsic_fluctuation = 0e0);
 	declareProperty("instrumentation_resolution", m_instrumentation_resolution = 0e0);
 	declareProperty("systematic_resolution",      m_systematic_resolution  = 0e0);	
 	declareProperty("pair_ionisation_energy",     m_pair_ionization_energy = 3.6*dd4hep::eV);
 	declareProperty("ionization_fluctuation",     m_ionization_fluctuation = false);
-	declareProperty("update_in_place",            m_update_in_place = true);
-	InstanceCount::increment(this);
-      }
-
-      /// Default destructor
-      virtual ~DigiDepositSmearEnergy() {
-	InstanceCount::decrement(this);
+	DEPOSIT_PROCESSOR_BIND_HANDLERS(DigiDepositSmearEnergy::smear)
       }
 
       /// Create deposit mapping with updates on same cellIDs
       template <typename T> void
-      smear(DigiContext& context, T& cont, work_t& work, const predicate_t& predicate)  const  {
+      smear(DigiContext& context, T& cont, work_t& /* work */, const predicate_t& predicate)  const  {
 	auto& random = context.randomGenerator();
-	T output_cont(cont.name, work.output.mask);
-	std::size_t killed = 0UL;
 	std::size_t updated = 0UL;
-	std::size_t created = 0UL;
 
-	if ( dd4hep::isActivePrintLevel(outputLevel()) )   {
-	  print("%s+++ Smearing container: %s %6ld entries",
-		context.event->id(), cont.name.c_str(), cont.size());
-	}
 	for( auto& dep : cont )    {
 	  if ( predicate(dep) )   {
 	    CellID cell = dep.first;
-	    const EnergyDeposit& depo = dep.second;
+	    EnergyDeposit& depo = dep.second;
 	    double deposit = depo.deposit;
-	    if ( deposit >= m_deposit_cutoff )   {
-	      double delta_E = 0e0;
-	      double energy  = deposit / dd4hep::GeV; // E in units of GeV
-	      double sigma_E_systematic   = m_systematic_resolution * energy;
-	      double sigma_E_intrin_fluct = m_intrinsic_fluctuation * std::sqrt(energy);
-	      double sigma_E_instrument   = m_instrumentation_resolution / dd4hep::GeV;
-	      double delta_ion = 0e0, num_pairs = 0e0;
-	      constexpr static double eps = std::numeric_limits<double>::epsilon();
-	      if ( sigma_E_systematic > eps )   {
-		delta_E += sigma_E_systematic * random.gaussian(0e0, 1e0);
-	      }
-	      if ( sigma_E_intrin_fluct > eps )   {
-		delta_E += sigma_E_intrin_fluct * random.gaussian(0e0, 1e0);
-	      }
-	      if ( sigma_E_instrument > eps )   {
-		delta_E += sigma_E_instrument * random.gaussian(0e0, 1e0);
-	      }
-	      if ( m_ionization_fluctuation )   {
-		num_pairs = energy / (m_pair_ionization_energy/dd4hep::GeV);
-		delta_ion = energy * (random.poisson(num_pairs)/num_pairs);
-		delta_E += delta_ion;
-	      }
-	      if ( dd4hep::isActivePrintLevel(outputLevel()) )   {
-		print("+++ %016lX [GeV] E:%9.2e [%9.2e %9.2e] intrin_fluct:%9.2e systematic:%9.2e instrument:%9.2e ioni:%9.2e/%.0f %s",
-		      cell, energy, deposit/dd4hep::GeV, delta_E,
-		      sigma_E_intrin_fluct, sigma_E_systematic, sigma_E_instrument, delta_ion, num_pairs,
-		      deposit < m_deposit_cutoff ? "KILLED" : "");
-	      }
-	      /// delta_E is in GeV
-	      if ( deposit > m_deposit_cutoff )  {
-		if ( m_update_in_place )   {
-		  EnergyDeposit& d = dep.second;
-		  d.deposit = deposit + (delta_E * dd4hep::GeV);
-		  d.flag |= EnergyDeposit::ENERGY_SMEARED;
-		  ++updated;
-		}
-		else   {
-		  EnergyDeposit d(depo);
-		  d.deposit = deposit + (delta_E * dd4hep::GeV);
-		  d.flag |= EnergyDeposit::ENERGY_SMEARED;	
-		  output_cont.emplace(cell, EnergyDeposit(depo));
-		  ++created;
-		}
-		continue;
-	      }
+	    double delta_E = 0e0;
+	    double energy  = deposit / dd4hep::GeV; // E in units of GeV
+	    double sigma_E_systematic   = m_systematic_resolution * energy;
+	    double sigma_E_intrin_fluct = m_intrinsic_fluctuation * std::sqrt(energy);
+	    double sigma_E_instrument   = m_instrumentation_resolution / dd4hep::GeV;
+	    double delta_ion = 0e0, num_pairs = 0e0;
+	    constexpr static double eps = std::numeric_limits<double>::epsilon();
+	    if ( sigma_E_systematic > eps )   {
+	      delta_E += sigma_E_systematic * random.gaussian(0e0, 1e0);
+	    }
+	    if ( sigma_E_intrin_fluct > eps )   {
+	      delta_E += sigma_E_intrin_fluct * random.gaussian(0e0, 1e0);
+	    }
+	    if ( sigma_E_instrument > eps )   {
+	      delta_E += sigma_E_instrument * random.gaussian(0e0, 1e0);
 	    }
-	    else if ( !m_update_in_place )   {
-	      EnergyDeposit& d = dep.second;
-	      d.flag |= EnergyDeposit::KILLED;
-	      ++killed;
+	    if ( m_ionization_fluctuation )   {
+	      num_pairs = energy / (m_pair_ionization_energy/dd4hep::GeV);
+	      delta_ion = energy * (random.poisson(num_pairs)/num_pairs);
+	      delta_E += delta_ion;
 	    }
+	    if ( dd4hep::isActivePrintLevel(outputLevel()) )   {
+	      print("%s+++ %016lX [GeV] E:%9.2e [%9.2e %9.2e] intrin_fluct:%9.2e systematic:%9.2e instrument:%9.2e ioni:%9.2e/%.0f",
+		    context.event->id(), cell, energy, deposit/dd4hep::GeV, delta_E,
+		    sigma_E_intrin_fluct, sigma_E_systematic, sigma_E_instrument, delta_ion, num_pairs);
+	    }
+	    /// delta_E is in GeV
+	    delta_E *= dd4hep::GeV;
+	    if ( m_monitor ) m_monitor->energy_shift(dep, delta_E);
+	    depo.deposit = deposit + (delta_E);
+	    depo.flag |= EnergyDeposit::ENERGY_SMEARED;
+	    ++updated;
 	  }
 	}
-	if ( !m_update_in_place )   {
-	  work.output.data.put(output_cont.key, std::move(output_cont));
-	}
-	info("%s+++ %-32s Smearing: created %6ld updated %6ld killed %6ld entries from mask: %04X",
-	     context.event->id(), cont.name.c_str(), created, updated, killed, cont.key.mask());
-      }
-
-      /// Main functional callback
-      virtual void execute(DigiContext& context, work_t& work, const predicate_t& predicate)  const override final  {
-	if ( auto* v = work.get_input<DepositVector>() )
-	  smear(context, *v, work, predicate);
-	else if ( auto* m = work.get_input<DepositMapping>() )
-	  smear(context, *m, work, predicate);
-	else
-	  except("Request to handle unknown data type: %s", work.input_type_name().c_str());
+	info("%s+++ %-32s Smear energy: updated %6ld out of %6ld entries from mask: %04X",
+	     context.event->id(), cont.name.c_str(), updated, cont.size(), cont.key.mask());
       }
     };
   }    // End namespace digi
diff --git a/DDDigi/plugins/DigiDepositSmearPositionResolution.cpp b/DDDigi/plugins/DigiDepositSmearPositionResolution.cpp
index 5c82012e054bddaa3e0219d6268cc44a8087421a..3946c530463e5c0ce07c4e152987966b9828e195 100644
--- a/DDDigi/plugins/DigiDepositSmearPositionResolution.cpp
+++ b/DDDigi/plugins/DigiDepositSmearPositionResolution.cpp
@@ -15,7 +15,6 @@
 #include <DDDigi/DigiContainerProcessor.h>
 #include <DDDigi/DigiKernel.h>
 
-#include <DD4hep/InstanceCount.h>
 #include <DD4hep/DD4hepUnits.h>
 #include <DD4hep/Detector.h>
 #include <DD4hep/VolumeManager.h>
@@ -36,104 +35,60 @@ namespace dd4hep {
      *  \version 1.0
      *  \ingroup DD4HEP_DIGITIZATION
      */
-    class DigiDepositSmearPositionResolution : public DigiContainerProcessor   {
+    class DigiDepositSmearPositionResolution : public DigiDepositsProcessor   {
     protected:
-      /// Property: Energy cutoff. No hits will be merged with a deposit smaller
-      double m_deposit_cutoff   { detail::numeric_epsilon };
       /// Property: Resolution in loacl sensor's U coordinates along (1, 0, 0)
       double m_resolution_u     { 0e0 * dd4hep::mm };
       /// Property: Resolution in loacl sensor's V coordinates along (0, 1, 0)
       double m_resolution_v     { 0e0 * dd4hep::mm };
-      /// Property: Flag to update existing container in-place or create a new container
-      bool   m_update_in_place  { true  };
+
+      /// Optional local position monitor
+      DigiDepositMonitor* m_local_monitor { nullptr };
 
     public:
       /// Standard constructor
       DigiDepositSmearPositionResolution(const DigiKernel& krnl, const std::string& nam)
-	: DigiContainerProcessor(krnl, nam)
+	: DigiDepositsProcessor(krnl, nam)
       {
-	declareProperty("deposit_cutoff",             m_deposit_cutoff);
-	declareProperty("update_in_place",            m_update_in_place = true);
 	declareProperty("resolution_u",               m_resolution_u);
 	declareProperty("resolution_v",               m_resolution_v);
-	InstanceCount::increment(this);
-      }
-
-      /// Default destructor
-      virtual ~DigiDepositSmearPositionResolution() {
-	InstanceCount::decrement(this);
+	DEPOSIT_PROCESSOR_BIND_HANDLERS(DigiDepositSmearPositionResolution::smear)
       }
 
       /// Create deposit mapping with updates on same cellIDs
       template <typename T> void
-      smear(DigiContext& context, T& cont, work_t& work, const predicate_t& predicate)  const  {
-	T output_cont(cont.name, work.output.mask);
+      smear(DigiContext& context, T& cont, work_t& /* work */, const predicate_t& predicate)  const  {
+	VolumeManager volMgr = m_kernel.detectorDescription().volumeManager();
 	auto& random = context.randomGenerator();
-	std::size_t killed = 0UL;
 	std::size_t updated = 0UL;
-	std::size_t created = 0UL;
 
-	if ( dd4hep::isActivePrintLevel(outputLevel()) )   {
-	  print("%s+++ Smearing container: %s %6ld entries",
-		context.event->id(), cont.name.c_str(), cont.size());
-	}
-	VolumeManager volMgr = m_kernel.detectorDescription().volumeManager();
 	for( auto& dep : cont )    {
 	  if ( predicate(dep) )   {
 	    CellID cell = dep.first;
-	    const EnergyDeposit& depo = dep.second;
-	    double deposit = depo.deposit;
-	    if ( deposit >= m_deposit_cutoff )   {
-	      auto*     ctxt = volMgr.lookupContext(cell);
-	      Position  local_pos = ctxt->worldToLocal(depo.position);
-	      double    delta_u   = m_resolution_u * random.gaussian();
-	      double    delta_v   = m_resolution_v * random.gaussian();
-	      Position  delta_pos(delta_u, delta_v, 0e0);
-	      Position  oldpos = depo.position;
-	      Position  newpos = ctxt->localToWorld(local_pos + delta_pos);
+	    EnergyDeposit& depo = dep.second;
+	    auto*     ctxt = volMgr.lookupContext(cell);
+	    Position  local_pos = ctxt->worldToLocal(depo.position);
+	    double    delta_u   = m_resolution_u * random.gaussian();
+	    double    delta_v   = m_resolution_v * random.gaussian();
+	    Position  delta_pos(delta_u, delta_v, 0e0);
+	    Position  oldpos = depo.position;
+	    Position  newpos = ctxt->localToWorld(local_pos + delta_pos);
+
+	    if ( m_local_monitor ) m_local_monitor->position_shift(dep, local_pos, delta_pos);
+	    delta_pos = newpos - oldpos;
+	    if ( m_monitor ) m_monitor->position_shift(dep, oldpos, delta_pos);
 
-	      delta_pos = newpos - oldpos;
-	      info("+++ %016lX Smeared position [%9.2e %9.2e %9.2e] by [%9.2e %9.2e %9.2e] to [%9.2e %9.2e %9.2e] [mm]",
-		   oldpos.X(), oldpos.Y(), oldpos.Z(), delta_pos.X(), delta_pos.Y(), delta_pos.Z(),
-		   newpos.X(), newpos.Y(), newpos.Z());
+	    info("+++ %016lX Smeared position [%9.2e %9.2e %9.2e] by [%9.2e %9.2e %9.2e] to [%9.2e %9.2e %9.2e] [mm]",
+		 oldpos.X(), oldpos.Y(), oldpos.Z(), delta_pos.X(), delta_pos.Y(), delta_pos.Z(),
+		 newpos.X(), newpos.Y(), newpos.Z());
 
-	      /// Update / create deposit with smeared position
-	      if ( m_update_in_place )   {
-		EnergyDeposit& d = dep.second;
-		d.position = newpos;
-		d.flag |= EnergyDeposit::POSITION_SMEARED;
-		++updated;
-	      }
-	      else   {
-		EnergyDeposit d(depo);
-		d.position = newpos;
-		d.flag |= EnergyDeposit::POSITION_SMEARED;
-		output_cont.emplace(cell, std::move(d));
-		++created;
-	      }
-	    }
-	    else if ( !m_update_in_place )   {
-	      EnergyDeposit& d = dep.second;
-	      d.flag |= EnergyDeposit::KILLED;
-	      ++killed;
-	    }
+	    depo.position = newpos;
+	    depo.flag |= EnergyDeposit::POSITION_SMEARED;
+	    ++updated;
 	  }
 	}
-	if ( !m_update_in_place )   {
-	  work.output.data.put(output_cont.key, std::move(output_cont));
-	}
-	info("%s+++ %-32s Smearing: created %6ld updated %6ld killed %6ld entries from mask: %04X",
-	     context.event->id(), cont.name.c_str(), created, updated, killed, cont.key.mask());
-      }
-
-      /// Main functional callback
-      virtual void execute(DigiContext& context, work_t& work, const predicate_t& predicate)  const override final  {
-	if ( auto* v = work.get_input<DepositVector>() )
-	  smear(context, *v, work, predicate);
-	else if ( auto* m = work.get_input<DepositMapping>() )
-	  smear(context, *m, work, predicate);
-	else
-	  except("Request to handle unknown data type: %s", work.input_type_name().c_str());
+	info("%s+++ %-32s Smear position(resolution): updated %6ld out of %6ld entries from mask: %04X",
+	     context.event->id(), cont.name.c_str(), updated, cont.size(), cont.key.mask());
       }
     };
   }    // End namespace digi
diff --git a/DDDigi/plugins/DigiDepositSmearPositionTrack.cpp b/DDDigi/plugins/DigiDepositSmearPositionTrack.cpp
index 25aad28fedea174844a58d4a01afdf9ac897c684..0cd9ff32415ab5b0a6e4b650982c634b48b11858 100644
--- a/DDDigi/plugins/DigiDepositSmearPositionTrack.cpp
+++ b/DDDigi/plugins/DigiDepositSmearPositionTrack.cpp
@@ -15,7 +15,6 @@
 #include <DDDigi/DigiContainerProcessor.h>
 #include <DDDigi/DigiKernel.h>
 
-#include <DD4hep/InstanceCount.h>
 #include <DD4hep/DD4hepUnits.h>
 #include <DD4hep/Detector.h>
 #include <DD4hep/VolumeManager.h>
@@ -36,116 +35,77 @@ namespace dd4hep {
      *  \version 1.0
      *  \ingroup DD4HEP_DIGITIZATION
      */
-    class DigiDepositSmearPositionTrack : public DigiContainerProcessor   {
+    class DigiDepositSmearPositionTrack : public DigiDepositsProcessor   {
     protected:
-      /// Property: Energy cutoff. No hits will be merged with a deposit smaller
-      double m_deposit_cutoff   { detail::numeric_epsilon };
       /// Property: Resolution in loacl sensor's U coordinates along (1, 0, 0)
       double m_resolution_u     { 0e0 * dd4hep::mm };
       /// Property: Resolution in loacl sensor's V coordinates along (0, 1, 0)
       double m_resolution_v     { 0e0 * dd4hep::mm };
-      /// Property: Flag to update existing container in-place or create a new container
-      bool   m_update_in_place  { true  };
+
+      /// Optional local position monitor
+      DigiDepositMonitor* m_local_monitor { nullptr };
 
     public:
       /// Standard constructor
       DigiDepositSmearPositionTrack(const DigiKernel& krnl, const std::string& nam)
-	: DigiContainerProcessor(krnl, nam)
+	: DigiDepositsProcessor(krnl, nam)
       {
-	declareProperty("deposit_cutoff",             m_deposit_cutoff);
-	declareProperty("update_in_place",            m_update_in_place = true);
 	declareProperty("resolution_u",               m_resolution_u);
 	declareProperty("resolution_v",               m_resolution_v);
-	InstanceCount::increment(this);
-      }
-
-      /// Default destructor
-      virtual ~DigiDepositSmearPositionTrack() {
-	InstanceCount::decrement(this);
+	DEPOSIT_PROCESSOR_BIND_HANDLERS(DigiDepositSmearPositionTrack::smear)
       }
 
       /// Create deposit mapping with updates on same cellIDs
       template <typename T> void
       smear(DigiContext& context, T& cont, work_t& work, const predicate_t& predicate)  const  {
 	constexpr double eps = detail::numeric_epsilon;
-	T output_cont(cont.name, work.output.mask);
 	auto& random = context.randomGenerator();
 	const auto& ev = *(context.event);
-	std::size_t killed = 0UL;
 	std::size_t updated = 0UL;
-	std::size_t created = 0UL;
+	auto* h = work.get_history(cont.name);
 
-	if ( dd4hep::isActivePrintLevel(outputLevel()) )   {
-	  print("%s+++ Smearing container: %s %6ld entries",
-		context.event->id(), cont.name.c_str(), cont.size());
-	}
 	VolumeManager volMgr = m_kernel.detectorDescription().volumeManager();
 	for( auto& dep : cont )    {
 	  if ( predicate(dep) )   {
 	    CellID cell = dep.first;
-	    const EnergyDeposit& depo = dep.second;
-	    double deposit = depo.deposit;
-	    if ( deposit >= m_deposit_cutoff )   {
-	      auto*     ctxt = volMgr.lookupContext(cell);
-	      Direction part_momentum = depo.history.average_particle_momentum(ev);
-	      Position  local_pos = ctxt->worldToLocal(depo.position);
-	      Position  local_dir = ctxt->worldToLocal(part_momentum).unit();
-	      double    cos_u   = local_dir.Dot(Position(1,0,0));
-	      double    sin_u   = std::sqrt(1e0 - cos_u*cos_u);
-	      double    tan_u   = sin_u/(std::abs(cos_u)>eps ? cos_u : eps);
-	      double    delta_u = tan_u * m_resolution_u * random.gaussian();
+	    EnergyDeposit& depo = dep.second;
+	    auto*     ctxt = volMgr.lookupContext(cell);
+#ifdef DDDIGI_INPLACE_HISTORY
+	    Direction part_momentum = depo.history.average_particle_momentum(ev);
+#else
+	    Direction part_momentum = depo.momentum;
+#endif
+	    Position  local_pos = ctxt->worldToLocal(depo.position);
+	    Position  local_dir = ctxt->worldToLocal(part_momentum).unit();
+	    double    cos_u   = local_dir.Dot(Position(1,0,0));
+	    double    sin_u   = std::sqrt(1e0 - cos_u*cos_u);
+	    double    tan_u   = sin_u/(std::abs(cos_u)>eps ? cos_u : eps);
+	    double    delta_u = tan_u * m_resolution_u * random.gaussian();
 
-	      double    cos_v   = local_dir.Dot(Position(0,1,0));
-	      double    sin_v   = std::sqrt(1e0 - cos_v*cos_v);
-	      double    tan_v   = sin_v/(std::abs(cos_v)>eps ? cos_v : eps);
-	      double    delta_v = tan_v * m_resolution_v * random.gaussian();
+	    double    cos_v   = local_dir.Dot(Position(0,1,0));
+	    double    sin_v   = std::sqrt(1e0 - cos_v*cos_v);
+	    double    tan_v   = sin_v/(std::abs(cos_v)>eps ? cos_v : eps);
+	    double    delta_v = tan_v * m_resolution_v * random.gaussian();
 
-	      Position  delta_pos(delta_u, delta_v, 0e0);
-	      Position  oldpos = depo.position;
-	      Position  newpos = ctxt->localToWorld(local_pos + delta_pos);
+	    Position  delta_pos(delta_u, delta_v, 0e0);
+	    Position  oldpos = depo.position;
+	    Position  newpos = ctxt->localToWorld(local_pos + delta_pos);
 
-	      delta_pos = newpos - oldpos;
-	      info("+++ %016lX Smeared position [%9.2e %9.2e %9.2e] by [%9.2e %9.2e %9.2e] to [%9.2e %9.2e %9.2e] [mm]",
-		   oldpos.X(), oldpos.Y(), oldpos.Z(), delta_pos.X(), delta_pos.Y(), delta_pos.Z(),
-		   newpos.X(), newpos.Y(), newpos.Z());
+	    if ( m_local_monitor ) m_local_monitor->position_shift(dep, local_pos, delta_pos);
+	    delta_pos = newpos - oldpos;
+	    if ( m_monitor ) m_monitor->position_shift(dep, oldpos, delta_pos);
 
-	      /// Update / create deposit with smeared position
-	      if ( m_update_in_place )   {
-		EnergyDeposit& d = dep.second;
-		d.position = newpos;
-		d.flag |= EnergyDeposit::POSITION_SMEARED;
-		++updated;
-	      }
-	      else   {
-		EnergyDeposit d(depo);
-		d.position = newpos;
-		d.flag |= EnergyDeposit::POSITION_SMEARED;
-		output_cont.emplace(cell, std::move(d));
-		++created;
-	      }
-	    }
-	    else if ( !m_update_in_place )   {
-	      EnergyDeposit& d = dep.second;
-	      d.flag |= EnergyDeposit::KILLED;
-	      ++killed;
-	    }
+	    info("%s+++ %016lX Smeared position [%9.2e %9.2e %9.2e] by [%9.2e %9.2e %9.2e] to [%9.2e %9.2e %9.2e] [mm]",
+		 ev.id(), oldpos.X(), oldpos.Y(), oldpos.Z(), delta_pos.X(), delta_pos.Y(), delta_pos.Z(),
+		 newpos.X(), newpos.Y(), newpos.Z());
+
+	    depo.position = newpos;
+	    depo.flag |= EnergyDeposit::POSITION_SMEARED;
+	    ++updated;
 	  }
 	}
-	if ( !m_update_in_place )   {
-	  work.output.data.put(output_cont.key, std::move(output_cont));
-	}
-	info("%s+++ %-32s Smearing: created %6ld updated %6ld killed %6ld entries from mask: %04X",
-	     context.event->id(), cont.name.c_str(), created, updated, killed, cont.key.mask());
-      }
-
-      /// Main functional callback
-      virtual void execute(DigiContext& context, work_t& work, const predicate_t& predicate)  const override final  {
-	if ( auto* v = work.get_input<DepositVector>() )
-	  smear(context, *v, work, predicate);
-	else if ( auto* m = work.get_input<DepositMapping>() )
-	  smear(context, *m, work, predicate);
-	else
-	  except("Request to handle unknown data type: %s", work.input_type_name().c_str());
+	info("%s+++ %-32s Smear position(track): updated %6ld out of %6ld entries from mask: %04X",
+	     context.event->id(), cont.name.c_str(), updated, cont.size(), cont.key.mask());
       }
     };
   }    // End namespace digi
diff --git a/DDDigi/plugins/DigiDepositSmearTime.cpp b/DDDigi/plugins/DigiDepositSmearTime.cpp
index e3e208de30a412dcfa3ee0c56efac508fbc8af14..ff782129608cb34aaeaf1478c4efb9d777ef505e 100644
--- a/DDDigi/plugins/DigiDepositSmearTime.cpp
+++ b/DDDigi/plugins/DigiDepositSmearTime.cpp
@@ -55,11 +55,13 @@ namespace dd4hep {
 	      flag |= EnergyDeposit::KILLED;
 	      ++killed;
 	    }
+	    if ( m_monitor ) m_monitor->time_shift(dep, delta_T);
 	    dep.second.time += delta_T;
 	    dep.second.flag |= flag;
 	    ++updated;
 	  }
 	}
+	if ( m_monitor ) m_monitor->count_shift(cont.size(), -killed);
 	info("%s+++ %-32s Smeared time resolution: %6ld entries, updated %6ld killed %6ld entries from mask: %04X",
 	     context.event->id(), cont.name.c_str(), cont.size(), updated, killed, cont.key.mask());
       }
diff --git a/DDDigi/plugins/DigiDepositWeightedPosition.cpp b/DDDigi/plugins/DigiDepositWeightedPosition.cpp
index 36e1f1ed04da3fd7110532b8cf93dac6f6843ff0..6fdd9bc6fc1ed0d9464ad510d32fa0eb9e935de2 100644
--- a/DDDigi/plugins/DigiDepositWeightedPosition.cpp
+++ b/DDDigi/plugins/DigiDepositWeightedPosition.cpp
@@ -13,7 +13,6 @@
 
 // Framework include files
 #include <DDDigi/DigiContainerProcessor.h>
-#include <DD4hep/InstanceCount.h>
 
 /// C/C++ include files
 #include <limits>
@@ -44,8 +43,8 @@ namespace dd4hep {
       /// Create deposit mapping with updates on same cellIDs
       template <typename T> void
       create_deposits(context_t& context, const T& cont, work_t& work, const predicate_t& predicate)  const  {
-	Key key(cont.name, work.output.mask);
-	DepositMapping m(cont.name, work.output.mask);
+	Key key(cont.name, work.environ.output.mask);
+	DepositMapping m(cont.name, work.environ.output.mask);
 	std::size_t dropped = 0UL, updated = 0UL, added = 0UL;
 	for( const auto& dep : cont )    {
 	  if ( predicate(dep) )   {
@@ -64,22 +63,16 @@ namespace dd4hep {
 	}
 	info("%s+++ %-32s added %6ld updated %6ld dropped %6ld entries (now: %6ld) from mask: %04X to mask: %04X",
 	     context.event->id(), cont.name.c_str(), added, updated, dropped, m.size(), cont.key.mask(), m.key.mask());
-	work.output.data.put(m.key, std::move(m));
+	work.environ.output.data.put(m.key, std::move(m));
       }
 
       /// Standard constructor
       DigiDepositWeightedPosition(const DigiKernel& krnl, const std::string& nam)
 	: DigiDepositsProcessor(krnl, nam)
       {
-	InstanceCount::increment(this);
 	declareProperty("deposit_cutoff", m_cutoff);
 	DEPOSIT_PROCESSOR_BIND_HANDLERS(DigiDepositWeightedPosition::create_deposits)
       }
-
-      /// Default destructor
-      virtual ~DigiDepositWeightedPosition() {
-	InstanceCount::decrement(this);
-      }
     };
   }    // End namespace digi
 }      // End namespace dd4hep
diff --git a/DDDigi/plugins/DigiHitHistoryDrop.cpp b/DDDigi/plugins/DigiHitHistoryDrop.cpp
index 5b3c663dc064e47c7f1b786c4e39b568e1e1ea9d..e30bcd61ec185dbf554425d1893f1b867d212902 100644
--- a/DDDigi/plugins/DigiHitHistoryDrop.cpp
+++ b/DDDigi/plugins/DigiHitHistoryDrop.cpp
@@ -59,12 +59,11 @@ namespace dd4hep {
 	InstanceCount::increment(this);
       }
 
-      template <typename T>
-      std::pair<std::size_t, std::size_t> drop_history(T& cont)  const  {
+      std::pair<std::size_t, std::size_t> drop_history(DetectorHistory& cont)  const  {
 	std::size_t num_drop_hit = 0;
 	std::size_t num_drop_particle = 0;
 	for( auto& dep : cont )    {
-	  auto ret = dep.second.history.drop();
+	  auto ret = dep.second.drop();
 	  num_drop_hit += ret.first;
 	  num_drop_particle += ret.second;
 	}
@@ -80,15 +79,10 @@ namespace dd4hep {
 	  Key key(i.first);
 	  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) )    {
-	      auto ret = drop_history(*m);
-	      num_drop_hit += ret.first;
-	      num_drop_particle += ret.second;
-	    }
-	    if( DepositVector* m = std::any_cast<DepositVector>(&i.second) )    {
-	      auto ret = drop_history(*m);
-	      num_drop_hit += ret.first;
-	      num_drop_particle += ret.second;
+	    if( DetectorHistory* h = std::any_cast<DetectorHistory>(&i.second) )    {
+	      auto [nhit, npart] = drop_history(*h);
+	      num_drop_hit += nhit;
+	      num_drop_particle += npart;	      
 	    }
 	  }
 	}
diff --git a/DDDigi/plugins/DigiResegment.cpp b/DDDigi/plugins/DigiResegment.cpp
index 70faf83aa7711dee7cc1362cdfe4f76d9ddfef17..6a4d3df9b1e2fdd4df1ee9a2931fdec6a1f2acbb 100644
--- a/DDDigi/plugins/DigiResegment.cpp
+++ b/DDDigi/plugins/DigiResegment.cpp
@@ -105,8 +105,8 @@ namespace dd4hep {
 
       template <typename T> void
       resegment_deposits(const T& cont, work_t& work, const predicate_t& predicate)  const  {
-	Key key(cont.name, work.output.mask);
-	DepositVector m(cont.name, work.output.mask);
+	Key key(cont.name, work.environ.output.mask);
+	DepositVector m(cont.name, key.mask());
 	std::size_t start = m.size();
 	for( const auto& dep : cont )   {
 	  if( predicate(dep) )   {
@@ -138,7 +138,7 @@ namespace dd4hep {
 	  }
 	}
 	std::size_t end   = m.size();
-	work.output.data.put(m.key, std::move(m));
+	work.environ.output.data.put(m.key, std::move(m));
 	info("+++ %-32s added %6ld entries (now: %6ld) from mask: %04X to mask: %04X",
 	     cont.name.c_str(), end-start, end, cont.key.mask(), m.key.mask());
       }
diff --git a/DDDigi/plugins/DigiSegmentDepositExtractor.cpp b/DDDigi/plugins/DigiSegmentDepositExtractor.cpp
index 5039e39eb3a4e0137b3c9ed61bf68d7a99742685..baa9ab1c7ec40feff8e4dfcbea6cda01eb22f8a8 100644
--- a/DDDigi/plugins/DigiSegmentDepositExtractor.cpp
+++ b/DDDigi/plugins/DigiSegmentDepositExtractor.cpp
@@ -38,7 +38,7 @@ namespace dd4hep {
 	: DigiContainerProcessor(kernel, nam) {}
 
       template <typename T> void copy_deposits(const T& cont, work_t& work, const predicate_t& predicate)  const  {
-	DepositVector deposits(cont.name, work.output.mask);
+	DepositVector deposits(cont.name, work.environ.output.mask);
 	for( const auto& dep : cont )   {
 	  if( predicate(dep) )   {
 	    CellID        cell = dep.first;
@@ -46,7 +46,7 @@ namespace dd4hep {
 	    deposits.data.emplace_back(cell, std::move(depo));
 	  }
 	}
-        work.output.data.put(deposits.key, std::move(deposits));
+        work.environ.output.data.put(deposits.key, std::move(deposits));
       }
       /// Main functional callback
       virtual void execute(DigiContext&, work_t& work, const predicate_t& predicate)  const override final  {
diff --git a/DDDigi/plugins/DigiSegmentDepositPrint.cpp b/DDDigi/plugins/DigiSegmentDepositPrint.cpp
index 5a17bf7da66f0fd98f4aa4b48835e07d10327ba1..d4e72a230898c99f364d4e98913b1e21e9290dce 100644
--- a/DDDigi/plugins/DigiSegmentDepositPrint.cpp
+++ b/DDDigi/plugins/DigiSegmentDepositPrint.cpp
@@ -41,8 +41,10 @@ namespace dd4hep {
 	for( const auto& dep : cont )   {
 	  if( predicate(dep) )   {
 	    info(fmt, predicate.segmentation->split_id(dep.first), dep.first,
+#ifdef DDDIGI_INPLACE_HISTORY
 		 dep.second.history.hits.size(), 
 		 dep.second.history.particles.size(),
+#endif
 		 dep.second.deposit);
 	  }
 	}
@@ -53,7 +55,10 @@ namespace dd4hep {
 	char format[256];
 	::snprintf(format, sizeof(format), 
 		   "%s[%s] %s-id: %%d [processor:%d] Cell: %%016lX mask: %016lX  "
-		   "hist:%%4ld hits %%4ld parts. entries deposit: %%f", 
+#ifdef DDDIGI_INPLACE_HISTORY
+		   "hist:%%4ld hits %%4ld parts. "
+#endif
+		   "entries deposit: %%f", 
 		   context.event->id(),
 		   predicate.segmentation->idspec.name(), predicate.segmentation->cname(),
 		   predicate.id, predicate.segmentation->split_mask);
diff --git a/DDDigi/plugins/DigiSimpleADCResponse.cpp b/DDDigi/plugins/DigiSimpleADCResponse.cpp
index 564756338dcc91ca2cc6b7814893f658513e48d1..a6adf2c53d8d9c180586fc6ac82cc5aadade6d2b 100644
--- a/DDDigi/plugins/DigiSimpleADCResponse.cpp
+++ b/DDDigi/plugins/DigiSimpleADCResponse.cpp
@@ -25,11 +25,10 @@ namespace dd4hep {
   /// Namespace for the Digitization part of the AIDA detector description toolkit
   namespace digi {
 
-    class DigiSimpleADCResponse : public DigiContainerProcessor  {
+    class DigiSimpleADCResponse : public DigiDepositsProcessor  {
       using segmentation_t = DigiSegmentProcessContext;
       std::string    m_response_postfix   { ".adc" };
       std::string    m_history_postfix    { ".hist" };
-      double         m_signal_cutoff      { std::numeric_limits<double>::epsilon() };
       double         m_signal_saturation  { std::numeric_limits<double>::max() };
       double         m_adc_offset         { 0e0  };
       std::size_t    m_adc_resolution     { 1024 };
@@ -37,23 +36,22 @@ namespace dd4hep {
       public:
       /// Standard constructor
       DigiSimpleADCResponse(const DigiKernel& krnl, const std::string& nam)
-	: DigiContainerProcessor(krnl, nam)
+	: DigiDepositsProcessor(krnl, nam)
       {
-	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);
+	DEPOSIT_PROCESSOR_BIND_HANDLERS(DigiSimpleADCResponse::emulate_adc)
       }
 
       /// Create container with ADC counts and register it to the output segment
-      template <typename T, typename P>
-      void emulate_adc(const char* tag, const T& input, work_t& work, const P& predicate)  const  {
+      template <typename T>
+      void emulate_adc(DigiContext& context, const T& input, work_t& work, const predicate_t& predicate)  const  {
+	const char* tag = context.event->id();
 	std::string postfix = predicate.segmentation ? "."+predicate.segmentation->identifier(predicate.id) : std::string();
-	std::string history_name  = input.name + postfix + m_history_postfix;
 	std::string response_name = input.name + postfix + m_response_postfix;
-	DetectorHistory  history (history_name, work.output.mask);
-	DetectorResponse response(response_name, work.output.mask);
+	DetectorResponse response(response_name, work.environ.output.mask);
 	for( const auto& dep : input )   {
 	  if ( predicate(dep) )   {
 	    CellID      cell = dep.first;
@@ -62,31 +60,21 @@ namespace dd4hep {
 	    ADCValue::value_t adc_count = std::round(((offset_ene) * m_adc_resolution) / m_signal_saturation);
 	    adc_count = std::min(adc_count, ADCValue::value_t(m_adc_resolution));
 	    response.emplace(cell, {adc_count, ADCValue::address_t(cell)});
-	    history.insert(cell, depo.history);
 	  }
 	}
+#ifdef DDDIGI_INPLACE_HISTORY
+	std::string history_name  = input.name + postfix + m_history_postfix;
+	DetectorHistory  history (history_name,  work.output.mask);
+	for( const auto& dep : input )   {
+	  if ( predicate(dep) )   {
+	    history.insert(dep.first, dep.second.history);
+	  }
+	}
+        work.output.data.put(history.key,  std::move(history));
+#endif
 	info("%s+++ %-32s %6ld ADC values. Input: %-32s %6ld deposits", tag,
 	     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>
-      void emulate_adc(DigiContext& context, work_t& work, const P& predicate)  const  {
-	const char* tag = context.event->id();
-	if ( const auto* m = work.get_input<DepositMapping>() )
-	  emulate_adc(tag, *m, work, predicate);
-	else if ( const auto* v = work.get_input<DepositVector>() )
-	  emulate_adc(tag, *v, work, predicate);
-	else
-	  except("%s+++ Request to handle unknown data type: %s",
-		 tag, work.input_type_name().c_str());
-      }
-
-      /// Main functional callback
-      virtual void execute(DigiContext& context, work_t& work, const predicate_t& predicate)  const final  {
-	emulate_adc(context, work, predicate);
+        work.environ.output.data.put(response.key, std::move(response));
       }
     };
   }    // End namespace digi
diff --git a/DDDigi/python/DDDigiDict.C b/DDDigi/python/DDDigiDict.C
index 56b77864a307bd4254354c302d8f20bd174caae6..87270724102bf321a24ae2860d08b8c60014a50d 100644
--- a/DDDigi/python/DDDigiDict.C
+++ b/DDDigi/python/DDDigiDict.C
@@ -84,8 +84,8 @@ namespace dd4hep {
 
     struct PropertyResult  {
     public:
-      std::string data  {};
-      int status  { 0 };
+      std::string data   {   };
+      int status         { 0 };
       PropertyResult() = default;
       PropertyResult(const std::string& d, int s);
       PropertyResult(const PropertyResult& c) = default;
@@ -118,29 +118,15 @@ namespace dd4hep {
         DigiHandle<DigiAction> action(*kernel.get(),name_type);
         return ActionHandle(action.get());
       }
+      static DigiAction* toAction(DigiKernel* f)    { return f;        }
       static DigiAction* toAction(DigiAction* f)    { return f;        }
+      static DigiAction* toAction(KernelHandle f)   { return f.value;  }
       static DigiAction* toAction(ActionHandle f)   { return f.action; }
 
       static DigiEventAction*        toEventAction(DigiAction* a) { return cst<DigiEventAction>(a); }
+      static DigiDepositMonitor*     toDepositMonitor(DigiAction* a) { return cst<DigiDepositMonitor>(a); }
       static DigiContainerProcessor* toContainerProcessor(DigiAction* a) { return cst<DigiContainerProcessor>(a); }
 
-      /// Access kernel property
-      static PropertyResult getPropertyKernel(DigiKernel* kernel, const std::string& name)  {
-        if ( kernel->hasProperty(name) )  {
-          return PropertyResult(kernel->property(name).str(),1);
-        }
-        return PropertyResult("",0);
-      }
-
-      /// Set kernel property
-      static int setPropertyKernel(DigiKernel* kernel, const std::string& name, const std::string& value)  {
-        if ( kernel->hasProperty(name) )  {
-          kernel->property(name).str(value);
-          return 1;
-        }
-        return 0;
-      }
-
       /// Access DigiAction property
       static PropertyResult getProperty(DigiAction* action, const std::string& name)  {
         if ( action->hasProperty(name) )  {
@@ -193,6 +179,7 @@ namespace dd4hep {
 #include <DDDigi/DigiSegmentSplitter.h>
 #include <DDDigi/DigiActionSequence.h>
 #include <DDDigi/DigiSignalProcessor.h>
+#include <DDDigi/DigiDepositMonitor.h>
 
 // CINT configuration
 #if defined(__CINT__) || defined(__MAKECINT__) || defined(__CLING__) || defined(__ROOTCLING__)
@@ -226,6 +213,8 @@ using namespace std;
 
 #pragma link C++ class dd4hep::digi::DigiSegmentSplitter;
 
+#pragma link C++ class dd4hep::digi::DigiDepositMonitor;
+
 /// Digi data item wrappers
 #pragma link C++ class dd4hep::digi::Particle+;
 #pragma link C++ class dd4hep::digi::EnergyDeposit+;
diff --git a/DDDigi/python/dddigi.py b/DDDigi/python/dddigi.py
index 2f53ab5ad35577face9a1db7846a38fd429cbc8c..bd20465893d4a8426c860618f43bc7bc3af0f9c8 100644
--- a/DDDigi/python/dddigi.py
+++ b/DDDigi/python/dddigi.py
@@ -14,7 +14,6 @@ from dd4hep_base import *  # noqa: F401, F403
 
 logger = None
 
-
 def loadDDDigi():
   global logger
   import ROOT
@@ -137,28 +136,6 @@ def importConstants(description, namespace=None, debug=False):
     logger.info('+++ Imported %d global values to namespace:%s' % (num, ns.__name__),)
 
 
-# ---------------------------------------------------------------------------
-def _getKernelProperty(self, name):
-  ret = Interface.getPropertyKernel(self.get(), name)
-  if ret.status > 0:
-    return ret.data
-  elif hasattr(self.get(), name):
-    return getattr(self.get(), name)
-  elif hasattr(self, name):
-    return getattr(self, name)
-  msg = 'DigiKernel::GetProperty [Unhandled]: Cannot access Kernel.' + name
-  raise KeyError(msg)
-
-
-# ---------------------------------------------------------------------------
-def _setKernelProperty(self, name, value):
-  if Interface.setPropertyKernel(self.get(), str(name), str(value)):
-    return
-  msg = 'DigiKernel::SetProperty [Unhandled]: Cannot set Kernel.' + name + ' = ' + str(value)
-  raise KeyError(msg)
-# ---------------------------------------------------------------------------
-
-
 def TestAction(kernel, nam, sleep=0):
   obj = Interface.createAction(kernel, str('DigiTestAction/' + nam))
   if sleep != 0:
@@ -176,57 +153,51 @@ def Action(kernel, nam, **options):
 
 
 def _get_action(self):
+  " Convert handles to action references to access underlying properties provided a dictionary exists. "
   return Interface.toAction(self)
-  # if hasattr(self, 'I_am_a_ROOT_interface_handle'):
-  #   return Interface.toAction(self.get())
-  # return self
-# ---------------------------------------------------------------------------
 
 
-def _adopt_property(self, action, foreign_name, local_name):
+# ---------------------------------------------------------------------------
+def _adopt_property(self, action, foreign_name, local_name=None):
   proc = _get_action(action)
+  if not local_name:
+    local_name = foreign_name
   _get_action(self).adopt_property(proc, str(foreign_name), str(local_name))
 
 
 # ---------------------------------------------------------------------------
-def _add_property(self, name, value):
+def _add_new_property(self, name, value):
   Interface.addProperty(_get_action(self), str(name), value)
 
 
 # ---------------------------------------------------------------------------
-def _add_position_property(self, name, value):
+def _add_new_position_property(self, name, value):
   Interface.addPositionProperty(_get_action(self), str(name), str(value))
 
 
 # ---------------------------------------------------------------------------
-def _add_set_property(self, name, value):
+def _add_new_set_property(self, name, value):
   Interface.addSetProperty(_get_action(self), str(name), value)
 
 
 # ---------------------------------------------------------------------------
-def _add_list_property(self, name, value):
+def _add_new_list_property(self, name, value):
   Interface.addListProperty(_get_action(self), str(name), value)
 
 
 # ---------------------------------------------------------------------------
-def _add_vector_property(self, name, value):
+def _add_new_vector_property(self, name, value):
   Interface.addVectorProperty(_get_action(self), str(name), value)
 
 
 # ---------------------------------------------------------------------------
-def _add_mapped_property(self, name, value):
+def _add_new_mapped_property(self, name, value):
   Interface.addMappedProperty(_get_action(self), str(name), value)
+# ---------------------------------------------------------------------------
 
 
-# ---------------------------------------------------------------------------
 def _kernel_terminate(self):
   return self.get().terminate()
-
-
-# ---------------------------------------------------------------------------
-Kernel.__getattr__ = _getKernelProperty
-Kernel.__setattr__ = _setKernelProperty
-Kernel.terminate = _kernel_terminate
 # ---------------------------------------------------------------------------
 
 
@@ -281,11 +252,17 @@ def _get(self, name):
   a = Interface.toAction(self)
   ret = Interface.getProperty(a, name)
   if ret.status > 0:
-    return ret.data
-  elif hasattr(self.action, name):
-    return getattr(self.action, name)
-  elif a.__class__ != self.__class__ and hasattr(a, name):
+    # print('Property: %s = %s [%s]' % (name, str(ret.data), str(ret.data.__class__),))
+    v = ret.data
+    try:
+      v = eval(v)
+    except:
+      pass
+    return v
+  elif hasattr(a, name):
     return getattr(a, name)
+  # elif a.__class__ != self.__class__ and hasattr(a, name):
+  #   return getattr(a, name)
   msg = 'DigiAction::GetProperty [Unhandled]: Cannot access property ' + a.name() + '.' + name
   raise KeyError(msg)
 # ---------------------------------------------------------------------------
@@ -294,12 +271,15 @@ 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
-  action = _get_action(self)
-  name = dd4hep.unicode_2_string(name)
-  value = dd4hep.unicode_2_string(value)
-  if Interface.setProperty(action, name, value):
+  act = _get_action(self)
+  nam = dd4hep.unicode_2_string(name)
+  if isinstance(value,str):
+    val = dd4hep.unicode_2_string(value)
+  else:
+    val = str(value)
+  if Interface.setProperty(act, nam, val):
     return
-  msg = 'DigiAction::SetProperty [Unhandled]: Cannot set ' + action.name() + '.' + name + ' = ' + value
+  msg = 'DigiAction::SetProperty [Unhandled]: Cannot set ' + act.name() + '.' + name + ' = ' + value
   raise KeyError(msg)
 # ---------------------------------------------------------------------------
 
@@ -314,7 +294,7 @@ def _props(obj, **extensions):
       # print('Overloading: ' + str(cls) + ' ' + call + ' to __' + call)
       setattr(cls, '__' + call, getattr(cls, call))
     else:
-      print('FAILED: Overloading: ' + str(cls) + ' ' + call + ' to __' + call + ' ' + str(hasattr(cls, call)))
+      debug('FAILED','Overloading: ' + str(cls) + ' ' + call + ' to __' + call + ' ' + str(hasattr(cls, call)))
     setattr(cls, call, extension[1])
   cls.__getattr__ = _get
   cls.__setattr__ = _set
@@ -324,21 +304,25 @@ def _props(obj, **extensions):
 
 #
 # Import unmodified classes from C++
-_import_class('digi', 'DigiKernel')
 _import_class('digi', 'DigiContext')
-_import_class('digi', 'DigiAction')
+
+
+# ---------------------------------------------------------------------------
+Kernel = _props('KernelHandle')
+_props('DigiKernel')
+_props('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,
-       add_position_property=_add_position_property,
-       add_set_property=_add_set_property,
-       add_list_property=_add_list_property,
-       add_vector_property=_add_vector_property,
-       add_mapped_property=_add_mapped_property)
+       add_property=_add_new_property,
+       add_position_property=_add_new_position_property,
+       add_set_property=_add_new_set_property,
+       add_list_property=_add_new_list_property,
+       add_vector_property=_add_new_vector_property,
+       add_mapped_property=_add_new_mapped_property)
 _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)
@@ -346,11 +330,17 @@ _props('DigiSequentialActionSequence', adopt_action=_adopt_sequence_action)
 _props('DigiContainerSequenceAction', adopt_container_processor=_adopt_container_processor)
 _props('DigiMultiContainerProcessor', adopt_processor=_adopt_processor)
 _props('DigiSegmentSplitter', adopt_segment_processor=_adopt_segment_processor)
+# ---------------------------------------------------------------------------
+
+
+# ---------------------------------------------------------------------------
 #
 # Need to import digitize late, since it cross includes dddigi
+# ---------------------------------------------------------------------------
 Digitize = None
 try:
   import digitize
   Digitize = digitize.Digitize
 except Exception as X:
-  logger.error('Failed to import digitize: ' + str(X))
+  logger.error('Failed to import digitize application: ' + str(X))
+# ---------------------------------------------------------------------------
diff --git a/DDDigi/src/DigiAction.cpp b/DDDigi/src/DigiAction.cpp
index f68f560caf4a22dff707370448382b8895e1e06c..b76216bab256d27dfdf99b1c2341cb5de356f7cd 100644
--- a/DDDigi/src/DigiAction.cpp
+++ b/DDDigi/src/DigiAction.cpp
@@ -40,9 +40,8 @@ DigiAction::DigiAction(const DigiKernel& krnl, const std::string& nam)
   : m_kernel(krnl), m_name(nam), m_outputLevel(INFO)
 {
   InstanceCount::increment(this);
-  declareProperty("Name", m_name);
   declareProperty("name", m_name);
-  declareProperty("OutputLevel", m_outputLevel);
+  declareProperty("OutputLevel", m_outputLevel=printLevel());
 }
 
 /// Default destructor
@@ -62,13 +61,23 @@ long DigiAction::addRef() {
 long DigiAction::release() {
   long count = --m_refCount;
   if (m_refCount <= 0) {
-    info("Deleting object %s of type %s Pointer:%p",
-	 m_name.c_str(),typeName(typeid(*this)).c_str(),(void*)this);
+    debug("Deleting object %s of type %s Pointer:%p",
+	  m_name.c_str(),typeName(typeid(*this)).c_str(),(void*)this);
     delete this;
   }
   return count;
 }
 
+/// Set DigiAction property
+std::size_t DigiAction::printProperties()   const {
+  const auto& props = properties().properties();
+  for( const auto& p : props )   {
+    std::string pn = name()+"."+p.first;
+    always("+++ %-32s = %-42s  [%s]", pn.c_str(), p.second.str().c_str(), p.second.type().c_str());
+  }
+  return props.size();
+}
+
 /// Adopt named property of another action for data processing
 void DigiAction::adopt_property(DigiAction* action, const std::string& foreign_name, const std::string& local_name)   {
   if ( action )    {
@@ -108,6 +117,15 @@ const dd4hep::Property& DigiAction::property(const std::string& nam)   const  {
   return properties()[nam];
 }
 
+/// Support of debug messages.
+std::string DigiAction::format(const char* fmt, ...) const {
+  va_list args;
+  va_start(args, fmt);
+  std::string str = dd4hep::format(nullptr, fmt, args);
+  va_end(args);
+  return str;
+}
+
 /// Support for messages with variable output level using output level
 void DigiAction::print(const char* fmt, ...) const   {
   int level = std::max(int(outputLevel()),(int)VERBOSE);
@@ -120,60 +138,66 @@ void DigiAction::print(const char* fmt, ...) const   {
 }
 
 /// Support of debug messages.
-std::string DigiAction::format(const char* fmt, ...) const {
+void DigiAction::always(const char* fmt, ...) const {
   va_list args;
   va_start(args, fmt);
-  std::string str = dd4hep::format(nullptr, fmt, args);
+  dd4hep::printout(dd4hep::FORCE_ALWAYS, m_name, fmt, args);
   va_end(args);
-  return str;
 }
 
 /// Support of debug messages.
 void DigiAction::debug(const char* fmt, ...) const {
-  if ( std::max(int(outputLevel()),(int)VERBOSE) >= DEBUG )  {
+  int level = std::max(int(outputLevel()),(int)VERBOSE);
+  if ( level <= DEBUG )  {
     va_list args;
     va_start(args, fmt);
-    dd4hep::printout(dd4hep::DEBUG, m_name, fmt, args);
+    dd4hep::printout(dd4hep::FORCE_DEBUG, m_name, fmt, args);
     va_end(args);
   }
 }
 
 /// Support of info messages.
 void DigiAction::info(const char* fmt, ...) const {
-  if ( std::max(int(outputLevel()),(int)VERBOSE) >= INFO )  {
+  int level = std::max(int(outputLevel()),(int)VERBOSE);
+  if ( level <= INFO )  {
     va_list args;
     va_start(args, fmt);
-    dd4hep::printout(dd4hep::INFO, m_name, fmt, args);
+    dd4hep::printout(dd4hep::FORCE_INFO, m_name, fmt, args);
     va_end(args);
   }
 }
 
 /// Support of warning messages.
 void DigiAction::warning(const char* fmt, ...) const {
-  if ( std::max(int(outputLevel()),(int)VERBOSE) >= WARNING )  {
+  int level = std::max(int(outputLevel()),(int)VERBOSE);
+  if ( level <= WARNING )  {
     va_list args;
     va_start(args, fmt);
-    dd4hep::printout(dd4hep::WARNING, m_name, fmt, args);
+    dd4hep::printout(dd4hep::FORCE_WARNING, m_name, fmt, args);
     va_end(args);
   }
 }
 
 /// Action to support error messages.
 void DigiAction::error(const char* fmt, ...) const {
-  if ( std::max(int(outputLevel()),(int)VERBOSE) >= ERROR )  {
+  int level = std::max(int(outputLevel()),(int)VERBOSE);
+  if ( level <= ERROR )  {
     va_list args;
     va_start(args, fmt);
-    dd4hep::printout(dd4hep::ERROR, m_name, fmt, args);
+    dd4hep::printout(dd4hep::FORCE_ERROR, m_name, fmt, args);
     va_end(args);
   }
 }
 
 /// Action to support error messages.
 bool DigiAction::return_error(bool return_value, const char* fmt, ...) const {
-  va_list args;
-  va_start(args, fmt);
-  dd4hep::printout(dd4hep::ERROR, m_name, fmt, args);
-  va_end(args);
+  int level = std::max(int(outputLevel()),(int)VERBOSE);
+  if ( level <= ERROR )  {
+    va_list args;
+    va_start(args, fmt);
+    dd4hep::printout(dd4hep::FORCE_ERROR, m_name, fmt, args);
+    va_end(args);
+  }
   return return_value;
 }
 
@@ -181,7 +205,7 @@ bool DigiAction::return_error(bool return_value, const char* fmt, ...) const {
 void DigiAction::fatal(const char* fmt, ...) const {
   va_list args;
   va_start(args, fmt);
-  dd4hep::printout(dd4hep::FATAL, m_name, fmt, args);
+  dd4hep::printout(dd4hep::FORCE_FATAL, m_name, fmt, args);
   va_end(args);
 }
 
@@ -190,7 +214,7 @@ void DigiAction::except(const char* fmt, ...) const {
   va_list args;
   va_start(args, fmt);
   std::string err = dd4hep::format(m_name, fmt, args);
-  dd4hep::printout(dd4hep::FATAL, m_name, err.c_str());
+  dd4hep::printout(dd4hep::FORCE_FATAL, m_name, err.c_str());
   va_end(args);
   throw std::runtime_error(err);
 }
@@ -202,7 +226,8 @@ namespace dd4hep {
   namespace digi {
     template <typename VAL>
     int add_action_property(DigiAction* action, const std::string& name, VAL value)   {
-      action->addProperty(name, value);
+      VAL* new_val = new VAL(value);
+      action->addProperty(name, *(new_val));
       printout(INFO, "addProperty", "+++ Added property %s of type %s",
 	       name.c_str(), typeName(typeid(VAL)).c_str());
       return 1;
diff --git a/DDDigi/src/DigiAttenuator.cpp b/DDDigi/src/DigiAttenuator.cpp
index df9c9a12e3d984b9f105b75d2fa3c6d27e31dc90..cd9c7421a29dff41a1b4b92519866f7332d382b4 100644
--- a/DDDigi/src/DigiAttenuator.cpp
+++ b/DDDigi/src/DigiAttenuator.cpp
@@ -47,15 +47,23 @@ template <typename T> std::size_t
 DigiAttenuator::attenuate(T& cont, const predicate_t& predicate) const {
   for( auto& dep : cont )   {
     if ( predicate(dep) )   {
-      auto& depo = dep.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;
+      dep.second.deposit *= m_factor;
     }
   }
   return cont.size();
 }
 
+/// Attenuator callback for single container
+template <> std::size_t
+DigiAttenuator::attenuate<DetectorHistory>(DetectorHistory& cont, const predicate_t& /* predicate */) const {
+  for( auto& history : cont )   {
+    auto& entry = history.second;
+    for( auto& h : entry.hits ) h.weight *= m_factor;
+    for( auto& h : entry.particles ) h.weight *= m_factor;
+  }
+  return cont.size();
+}
+
 /// Main functional callback adapter
 void DigiAttenuator::execute(DigiContext& context, work_t& work, const predicate_t& predicate)  const   {
   std::size_t count = 0;
@@ -63,6 +71,8 @@ void DigiAttenuator::execute(DigiContext& context, work_t& work, const predicate
     count = this->attenuate(*m, predicate);
   else if ( auto* v = work.get_input<DepositVector>() )
     count = this->attenuate(*v, predicate);
+  else if ( auto* h = work.get_input<DetectorHistory>() )
+    count = this->attenuate(*h, predicate);
   Key key { work.input.key };
   std::string nam = Key::key_name(key)+":";
   info("%s+++ %-32s mask:%04X item: %08X Attenuated %6ld hits by %8.5f",
@@ -73,10 +83,12 @@ void DigiAttenuator::execute(DigiContext& context, work_t& work, const predicate
 DigiAttenuatorSequence::DigiAttenuatorSequence(const DigiKernel& krnl, const std::string& nam)
   : DigiContainerSequenceAction(krnl, nam)
 {
-  declareProperty("processor_type", m_processor_type = "DigiAttenuator");
-  declareProperty("containers",     m_container_attenuation);
-  declareProperty("signal_decay",   m_signal_decay = "exponential");
-  declareProperty("t0",             m_t0);
+  declareProperty("attenuate_history", m_attenuate_history);
+  declareProperty("attenuate_data",    m_attenuate_data);
+  declareProperty("processor_type",    m_processor_type = "DigiAttenuator");
+  declareProperty("containers",        m_container_attenuation);
+  declareProperty("signal_decay",      m_signal_decay = "exponential");
+  declareProperty("t0",                m_t0);
   InstanceCount::increment(this);
 }
 
@@ -93,7 +105,6 @@ void DigiAttenuatorSequence::initialize()   {
     return;
   }
   for ( const auto& c : m_container_attenuation )   {
-    std::string nam = name() + "." + c.first;
     double factor = 0e0;
     switch( ::toupper(m_signal_decay[0]) )   {
     case 'E':
@@ -104,13 +115,30 @@ void DigiAttenuatorSequence::initialize()   {
 	     m_signal_decay.c_str());
       break;
     }
-    auto* att = createAction<DigiAttenuator>(m_processor_type, m_kernel, nam);
-    if ( !att )   {
-      except("+++ Failed to create signal attenuator: %s of type: %s",
-	     nam.c_str(), m_processor_type.c_str());
+    // First bunch of processors: Attenuate the signal
+    if ( m_attenuate_data )    {
+      std::string nam = name() + ".D." + c.first;
+      auto* att = createAction<DigiAttenuator>(m_processor_type, m_kernel, nam);
+      if ( !att )   {
+	except("+++ Failed to create signal attenuator: %s of type: %s",
+	       nam.c_str(), m_processor_type.c_str());
+      }
+      att->property("factor").set(factor);
+      att->property("OutputLevel").set(int(outputLevel()));
+      adopt_processor(att, c.first);
+    }
+    // Second bunch of processors: Attenuate the history weights accordingly
+    if ( m_attenuate_history )    {
+      std::string nam = name() + ".H." + c.first;
+      auto* att = createAction<DigiAttenuator>(m_processor_type, m_kernel, nam);
+      if ( !att )   {
+	except("+++ Failed to create signal attenuator: %s of type: %s",
+	       nam.c_str(), m_processor_type.c_str());
+      }
+      att->property("factor").set(factor);
+      adopt_processor(att, c.first+".hist");
+      att->property("OutputLevel").set(int(outputLevel()));
     }
-    att->property("factor").set(factor);
-    adopt_processor(att, c.first);
   }
   this->DigiContainerSequenceAction::initialize();
 }
diff --git a/DDDigi/src/DigiContainerCombine.cpp b/DDDigi/src/DigiContainerCombine.cpp
index 22939f5a5cdef5e8d43a75aae9fa1a382c0c2127..a68e6f53915829aa79362093b7349af8a4580229 100644
--- a/DDDigi/src/DigiContainerCombine.cpp
+++ b/DDDigi/src/DigiContainerCombine.cpp
@@ -71,7 +71,7 @@ public:
       }
     }
     ::snprintf(format, sizeof(format),
-	       "%s+++%%2d++ %%-32s Mask: $%04X Input: $%%04X Merged %%6ld %%s",
+	       "%s Thread:%%2d+++ %%-32s Out-Mask: $%04X In-Mask: $%%04X Merged %%6ld %%s",
 	       event.id(), combine->m_deposit_mask);
     format[sizeof(format)-1] = 0;
   }
@@ -90,7 +90,7 @@ public:
       cnt = output.merge(std::move(input));
     else
       cnt = output.insert(input);
-    combine->debug(this->format, thr, nam.c_str(), mask, cnt, "deposits"); 
+    combine->info(this->format, thr, nam.c_str(), mask, cnt, "deposits"); 
     this->cnt_depos += cnt;
     this->cnt_conts++;
   }
@@ -105,7 +105,7 @@ public:
 	DetectorHistory* next = std::any_cast<DetectorHistory>(work[j]);
 	std::string next_name = next->name;
 	cnt = (combine->m_erase_combined) ? out.merge(std::move(*next)) : out.insert(*next);
-	combine->debug(format, thr, next_name.c_str(), keys[j].mask(), cnt, "histories"); 
+	combine->info(format, thr, next_name.c_str(), keys[j].mask(), cnt, "histories"); 
 	used_keys_insert(keys[j]);
 	cnt_hist += cnt;
 	cnt_conts++;
@@ -124,7 +124,7 @@ public:
 	DetectorResponse* next = std::any_cast<DetectorResponse>(work[j]);
 	std::string next_name = next->name;
 	cnt = (combine->m_erase_combined) ? out.merge(std::move(*next)) : out.insert(*next);
-	combine->debug(format, thr, next_name.c_str(), keys[j].mask(), cnt, "histories"); 
+	combine->info(format, thr, next_name.c_str(), keys[j].mask(), cnt, "responses"); 
 	used_keys_insert(keys[j]);
 	cnt_response += cnt;
 	cnt_conts++;
@@ -143,7 +143,7 @@ public:
 	ParticleMapping* next = std::any_cast<ParticleMapping>(work[j]);
 	std::string next_name = next->name;
 	cnt = (combine->m_erase_combined) ? out.merge(std::move(*next)) : out.insert(*next);
-	combine->debug(format, thr, next_name.c_str(), keys[j].mask(), cnt, "particles"); 
+	combine->info(format, thr, next_name.c_str(), keys[j].mask(), cnt, "particles"); 
 	used_keys_insert(keys[j]);
 	cnt_parts += cnt;
 	cnt_conts++;
diff --git a/DDDigi/src/DigiContainerDrop.cpp b/DDDigi/src/DigiContainerDrop.cpp
index efdcd5f3a6d56a72dde8e1378ff1daf8410ddd75..d88b8e6271fda46b0c9900257f5ba12b4094a86b 100644
--- a/DDDigi/src/DigiContainerDrop.cpp
+++ b/DDDigi/src/DigiContainerDrop.cpp
@@ -151,7 +151,7 @@ void DigiContainerDrop::execute(DigiContext& context)  const    {
     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_workers.insert(new worker_t(nullptr, i));
     }
     m_kernel.submit(context, m_workers.get_group(), def.items.size(), &def);
   }
diff --git a/DDDigi/src/DigiContainerProcessor.cpp b/DDDigi/src/DigiContainerProcessor.cpp
index 0fe42335f6bbb21e6aba1a75a943e55f5c94deca..7c87f6ef5dc58368988f844ec8226692abce3fa2 100644
--- a/DDDigi/src/DigiContainerProcessor.cpp
+++ b/DDDigi/src/DigiContainerProcessor.cpp
@@ -31,8 +31,8 @@ namespace dd4hep {
   namespace digi {
 
     template <typename T> T* DigiContainerProcessor::work_t::get_input(bool exc)   {
-      if ( input.data.has_value() )  {
-	T* object = std::any_cast<T>(&input.data);
+      if ( input.data->has_value() )  {
+	T* object = std::any_cast<T>(input.data);
 	if ( object )   {
 	  return object;
 	}
@@ -46,8 +46,8 @@ namespace dd4hep {
     }
 
     template <typename T> const T* DigiContainerProcessor::work_t::get_input(bool exc)  const  {
-      if ( input.data.has_value() )  {
-	const T* object = std::any_cast<T>(&input.data);
+      if ( input.data->has_value() )  {
+	const T* object = std::any_cast<T>(input.data);
 	if ( object )   {
 	  return object;
 	}
@@ -62,21 +62,36 @@ namespace dd4hep {
   }    // End namespace digi
 }      // End namespace dd4hep
 
-template       DepositVector*   DigiContainerProcessor::work_t::get_input(bool exc);
-template const DepositVector*   DigiContainerProcessor::work_t::get_input(bool exc)  const;
-template       DepositMapping*  DigiContainerProcessor::work_t::get_input(bool exc);
-template const DepositMapping*  DigiContainerProcessor::work_t::get_input(bool exc)  const;
-template       ParticleMapping* DigiContainerProcessor::work_t::get_input(bool exc);
-template const ParticleMapping* DigiContainerProcessor::work_t::get_input(bool exc)  const;
+template       DepositVector*    DigiContainerProcessor::work_t::get_input(bool exc);
+template const DepositVector*    DigiContainerProcessor::work_t::get_input(bool exc)  const;
+template       DepositMapping*   DigiContainerProcessor::work_t::get_input(bool exc);
+template const DepositMapping*   DigiContainerProcessor::work_t::get_input(bool exc)  const;
+template       ParticleMapping*  DigiContainerProcessor::work_t::get_input(bool exc);
+template const ParticleMapping*  DigiContainerProcessor::work_t::get_input(bool exc)  const;
+template       DetectorHistory*  DigiContainerProcessor::work_t::get_input(bool exc);
+template const DetectorHistory*  DigiContainerProcessor::work_t::get_input(bool exc)  const;
+template       DetectorResponse* DigiContainerProcessor::work_t::get_input(bool exc);
+template const DetectorResponse* DigiContainerProcessor::work_t::get_input(bool exc)  const;
+
+/// Access the deposit history of a deposit container
+const DepositsHistory* 
+DigiContainerProcessor::work_t::get_history(const std::string& container, bool exc)  const  {
+  std::string hist_name = container+".hist";
+  if ( exc )   {
+    dd4hep::except("DigiContainerProcessor", "+++ Cannot access history %s.", hist_name.c_str());
+  }
+  return nullptr;
+}
+
 
 /// input data type
 const std::type_info& DigiContainerProcessor::work_t::input_type()  const   {
-  return input.data.type();
+  return input.data->type();
 }
 
 /// String form of the input data type
 std::string DigiContainerProcessor::work_t::input_type_name()  const   {
-  return typeName(input.data.type());
+  return typeName(input.data->type());
 }
 
 /// Access to default callback 
@@ -85,6 +100,12 @@ const DigiContainerProcessor::predicate_t& DigiContainerProcessor::accept_all()
   return s_pred;
 }
 
+/// Access to default callback 
+const DigiContainerProcessor::predicate_t& DigiContainerProcessor::accept_not_killed()  {
+  static predicate_t s_pred { std::bind(predicate_t::not_killed, std::placeholders::_1), 0, nullptr };
+  return s_pred;
+}
+
 /// Standard constructor
 DigiContainerProcessor::DigiContainerProcessor(const kernel_t& kernel, const std::string& name)   
   : DigiAction(kernel, name)
@@ -97,8 +118,15 @@ DigiContainerProcessor::~DigiContainerProcessor() {
   InstanceCount::decrement(this);
 }
 
+/// Adopt monitoring action
+void DigiContainerProcessor::adopt_monitor(DigiDepositMonitor* monitor)    {
+  if ( monitor ) monitor->addRef();
+  if ( m_monitor ) m_monitor->release();
+  m_monitor = monitor;
+}
+
 /// Main functional callback if specific work is known
-void DigiContainerProcessor::execute(context_t&       /* context   */,
+void DigiContainerProcessor::execute(context_t&         /* context   */,
 				     work_t&            /* work      */,
 				     const predicate_t& /* predicate */)  const   {
 }
@@ -132,7 +160,7 @@ void DigiContainerSequence::adopt_processor(DigiContainerProcessor* action)   {
     except("+++ FAILED: attempt to add invalid processor!");
     return;
   }
-  m_workers.insert(new worker_t(action, m_workers.size()));
+  m_workers.insert(new worker_t(action, m_workers.size(), *this));
 }
 
 /// Main functional callback if specific work is known
@@ -144,9 +172,10 @@ void DigiContainerSequence::execute(context_t& context, work_t& work, const pred
 /// Worker adaptor for caller DigiContainerSequence
 template <> void DigiParallelWorker<DigiContainerProcessor,
 				    DigiContainerSequence::work_t,
-				    std::size_t>::execute(void* data) const  {
+				    std::size_t,
+				    DigiContainerSequence&>::execute(void* data) const  {
   calldata_t* arg  = reinterpret_cast<calldata_t*>(data);
-  action->execute(arg->context, *arg, action->accept_all());
+  action->execute(arg->environ.context, *arg, predicate.m_worker_predicate);
 }
 
 /// Standard constructor
@@ -169,13 +198,18 @@ DigiContainerSequenceAction::~DigiContainerSequenceAction() {
 /// Initialization callback
 void dd4hep::digi::DigiContainerSequenceAction::initialize()   {
   for( auto& ent : m_registered_processors )   {
-    worker_t* w = new worker_t(ent.second, m_registered_workers.size());
+    worker_t* w = new worker_t(ent.second, m_registered_workers.size(), *this);
     m_registered_workers.emplace(ent.first, w);
     m_workers.insert(w);
     ent.second->release();
   }
 }
 
+/// Set the default predicate
+void DigiContainerSequenceAction::set_predicate(const predicate_t& predicate)   {
+  m_worker_predicate = predicate;
+}
+
 /// Adopt new parallel worker
 void DigiContainerSequenceAction::adopt_processor(DigiContainerProcessor* action,
 						  const std::string& container)
@@ -230,16 +264,19 @@ void DigiContainerSequenceAction::execute(context_t& context)  const   {
   auto& input  = event.get_segment(m_input_segment);
   auto& output = event.get_segment(m_output_segment);
   output_t out { m_output_mask, output };
-  work_t   arg { context, { }, out, m_properties, *this };
+  env_t    env { context, m_properties, out };
+  work_items_t items;
+  work_t   arg { env, items, *this };
+  work_item_t itm { nullptr, { }, nullptr };
 
-  arg.input_items.resize(m_workers.size(), { { }, nullptr });
+  arg.input_items.resize(m_workers.size(), itm);
   event_workers.reserve(input.size());
   for( auto& i : input )   {
     Key key(i.first);
     if ( key.mask() == m_input_mask )   {
       if ( worker_t* w = need_registered_worker(key, false) )  {
 	event_workers.emplace_back(w);
-	arg.input_items[w->options] = { key, &i.second };
+	arg.input_items[w->options] = { &input, key, &i.second };
       }
     }
   }
@@ -251,11 +288,12 @@ void DigiContainerSequenceAction::execute(context_t& context)  const   {
 /// Worker adaptor for caller DigiContainerSequenceAction
 template <> void DigiParallelWorker<DigiContainerProcessor,
 				    DigiContainerSequenceAction::work_t,
-				    std::size_t>::execute(void* data) const  {
-  calldata_t* args = reinterpret_cast<calldata_t*>(data);
-  auto&       item = args->input_items[this->options];
-  DigiContainerProcessor::work_t work { args->context, { item.key, *item.data }, args->output, args->properties };
-  action->execute(args->context, work, action->accept_all());
+				    std::size_t,
+				    DigiContainerSequenceAction&>::execute(void* data) const  {
+  auto* args = reinterpret_cast<calldata_t*>(data);
+  auto& item = args->input_items[this->options];
+  DigiContainerProcessor::work_t work { args->environ, item };
+  action->execute(args->environ.context, work, predicate.m_worker_predicate);
 }
 
 /// Standard constructor
@@ -303,7 +341,7 @@ void DigiMultiContainerProcessor::initialize()   {
       w = iw->second;
     }
     else   {
-      w = new worker_t(action, m_workers.size());
+      w = new worker_t(action, m_workers.size(), *this);
       m_worker_keys.emplace_back(worker_keys);
       m_workers.insert(w);
       action_workers[action] = w;
@@ -326,6 +364,11 @@ void DigiMultiContainerProcessor::initialize()   {
     action->release();
 }
 
+/// Set the default predicate
+void DigiMultiContainerProcessor::set_predicate(const predicate_t& predicate)   {
+  m_worker_predicate = predicate;
+}
+
 /// Adopt new parallel worker
 void DigiMultiContainerProcessor::adopt_processor(DigiContainerProcessor* action, const std::vector<std::string>& containers)    {
   if ( !action )   {
@@ -345,12 +388,12 @@ void DigiMultiContainerProcessor::adopt_processor(DigiContainerProcessor* action
 
 /// Main functional callback
 void DigiMultiContainerProcessor::execute(context_t& context)  const  {
-  work_items_t work_items;
+  work_items_t items;
   auto& mask  = m_input_masks;
   auto& event = *context.event;
   auto& input = event.get_segment(m_input_segment);
 
-  work_items.reserve(input.size());
+  items.reserve(input.size());
   for( auto& i : input )   {
     Key key(i.first);
     key.set_mask(0);
@@ -358,14 +401,15 @@ void DigiMultiContainerProcessor::execute(context_t& context)  const  {
     if ( use )   {
       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));
+	items.push_back({ &input, i.first, &i.second});
       }
     }
   }
-  if ( !work_items.empty() )   {
+  if ( !items.empty() )   {
     auto& output = event.get_segment(m_output_segment);
     output_t out { m_output_mask, output };
-    work_t   arg { context, work_items, out, properties(), *this };
+    env_t    env { context, properties(), out };
+    work_t   arg { env, items, *this };
     m_kernel.submit(context, m_workers.get_group(), m_workers.size(), &arg, m_parallel);
   }
 }
@@ -373,25 +417,26 @@ void DigiMultiContainerProcessor::execute(context_t& context)  const  {
 /// Worker adaptor for caller DigiMultiContainerProcessor
 template <> void DigiParallelWorker<DigiContainerProcessor,
 				    DigiMultiContainerProcessor::work_t,
-				    std::size_t>::execute(void* data) const  {
+				    std::size_t,
+				    DigiMultiContainerProcessor&>::execute(void* data) const  {
   calldata_t* arg   = reinterpret_cast<calldata_t*>(data);
   const auto& par   = arg->parent;
   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.key);
     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, action->accept_all());
+	DigiContainerProcessor::work_t  work { arg->environ, item };
+	action->execute(work.environ.context, work, predicate.m_worker_predicate);
 	continue;
       }
       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, action->accept_all());
+	DigiContainerProcessor::work_t work { arg->environ, item };
+	action->execute(work.environ.context, work, predicate.m_worker_predicate);
 	continue;
       }
       tag = "no keys matching";
diff --git a/DDDigi/src/DigiData.cpp b/DDDigi/src/DigiData.cpp
index 9f40c8773052702cc4d847c02103fded09895d9a..bbe18cd3ebcadb2eaeb5d69939edb80c6d404367 100644
--- a/DDDigi/src/DigiData.cpp
+++ b/DDDigi/src/DigiData.cpp
@@ -155,7 +155,6 @@ void EnergyDeposit::update_deposit_weighted(const EnergyDeposit& upda)  {
   position = pos;
   momentum = mom;
   deposit  = sum;
-  history.update(upda.history);
 }
 
 /// Update the deposit using deposit weighting
@@ -166,7 +165,6 @@ void EnergyDeposit::update_deposit_weighted(EnergyDeposit&& upda)  {
   position = pos;
   momentum = mom;
   deposit  = sum;
-  history.update(upda.history);
 }
 
 /// Merge new deposit map onto existing map
diff --git a/DDDigi/src/DigiDepositMonitor.cpp b/DDDigi/src/DigiDepositMonitor.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..40acfdf34497178a3eb6478ca646a865722ba839
--- /dev/null
+++ b/DDDigi/src/DigiDepositMonitor.cpp
@@ -0,0 +1,138 @@
+//==========================================================================
+//  AIDA Detector description implementation 
+//--------------------------------------------------------------------------
+// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
+// All rights reserved.
+//
+// For the licensing terms see $DD4hepINSTALL/LICENSE.
+// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
+//
+// Author     : M.Frank
+//
+//==========================================================================
+
+/// Framework include files
+#include <DD4hep/InstanceCount.h>
+#include <DDDigi/DigiKernel.h>
+#include <DDDigi/DigiDepositMonitor.h>
+
+/// ROOT include filess
+#include <TH1F.h>
+#include <TH2F.h>
+
+/// C/C++ include files
+
+using namespace dd4hep::digi;
+
+/// Add 1D histogram entry with weight
+void Histo1D::fill(double x, double weight)    {
+  hist->Fill(x, weight);
+}
+
+/// Add 2D histogram entry with weight
+void Histo2D::fill(double x, double y, double weight)    {
+  hist->Fill(x, y, weight);
+}
+
+/// Standard constructor
+DigiDepositMonitor::DigiDepositMonitor(const DigiKernel& krnl, const std::string& nam)
+  : DigiAction(krnl, nam)
+{
+  m_kernel.register_initialize(std::bind(&DigiDepositMonitor::initialize,this));
+  InstanceCount::increment(this);
+}
+
+/// Default destructor
+DigiDepositMonitor::~DigiDepositMonitor() {
+  InstanceCount::decrement(this);
+}
+
+/// Initializing function: compute values which depend on properties
+void DigiDepositMonitor::initialize()    {
+}
+
+/// Book 1D histogram and register it to the kernel for output handling
+Histo1D DigiDepositMonitor::book1D(const std::string& name, const std::string& title,
+				   std::size_t nbin_x, double min_x, double max_x)   {
+  auto* h = new TH1F(name.c_str(), title.c_str(), nbin_x, min_x, max_x);
+  m_kernel.register_monitor(this, h);
+  return { h };
+}
+
+/// Book 1D histogram and register it to the kernel for output handling
+Histo2D DigiDepositMonitor::book2D(const std::string& name, const std::string& title,
+				   std::size_t nbin_x, double min_x, double max_x,
+				   std::size_t nbin_y, double min_y, double max_y)   {
+  auto* h = new TH2F(name.c_str(), title.c_str(), nbin_x, min_x, max_x, nbin_y, min_y, max_y);
+  m_kernel.register_monitor(this, h);
+  return { h };
+}
+
+/// Standard constructor
+DigiDepositEnergyMonitor::DigiDepositEnergyMonitor(const kernel_t& kernel, const std::string& name)
+  : DigiDepositMonitor(kernel, name)
+{
+  declareProperty("histo1D_deposits", histo1D_deposits);
+  declareProperty("histo1D_delta",    histo1D_delta);
+}
+
+/// Initializing function: overload for sub-classes to e.g. book histograms
+void DigiDepositEnergyMonitor::initialize()    {
+  declare_monitor_energy(this, &DigiDepositEnergyMonitor::monitor_energy_shift);
+  m_deltas = book1D(histo1D_delta.name.c_str(), histo1D_delta.title.c_str(), 
+		    histo1D_delta.nbin_x, histo1D_delta.min_x, histo1D_delta.max_x);
+  m_deposits = book1D(histo1D_deposits.name.c_str(), histo1D_deposits.title.c_str(), 
+		      histo1D_deposits.nbin_x, histo1D_deposits.min_x, histo1D_deposits.max_x);
+}
+
+/// Fill the monitoring histograms
+void DigiDepositEnergyMonitor::monitor_energy_shift(const deposit_t& deposit, double change)   {
+  m_deposits.fill(deposit.second.deposit, 1e0);
+  m_deltas.fill(change, 1e0);
+}
+
+/// Standard constructor
+DigiDepositTimeMonitor::DigiDepositTimeMonitor(const kernel_t& kernel, const std::string& name)
+  : DigiDepositMonitor(kernel, name)
+{
+  declareProperty("histo1D_deposits", histo1D_deposits);
+  declareProperty("histo1D_delta",    histo1D_delta);
+}
+
+/// Initializing function: overload for sub-classes to e.g. book histograms
+void DigiDepositTimeMonitor::initialize()    {
+  declare_monitor_time(this, &DigiDepositTimeMonitor::monitor_time_shift);
+  m_deltas = book1D(histo1D_delta.name.c_str(), histo1D_delta.title.c_str(), 
+		    histo1D_delta.nbin_x, histo1D_delta.min_x, histo1D_delta.max_x);
+  m_deposits = book1D(histo1D_deposits.name.c_str(), histo1D_deposits.title.c_str(), 
+		      histo1D_deposits.nbin_x, histo1D_deposits.min_x, histo1D_deposits.max_x);
+}
+
+/// Fill the monitoring histograms
+void DigiDepositTimeMonitor::monitor_time_shift(const deposit_t& deposit, double change)   {
+  m_deposits.fill(deposit.second.time, 1e0);
+  m_deltas.fill(change, 1e0);
+}
+
+/// Standard constructor
+DigiDepositPositionMonitor::DigiDepositPositionMonitor(const kernel_t& kernel, const std::string& name)
+  : DigiDepositMonitor(kernel, name)
+{
+  declareProperty("histo1D_deposits", histo1D_deposits);
+  declareProperty("histo1D_delta",    histo1D_delta);
+}
+
+/// Initializing function: overload for sub-classes to e.g. book histograms
+void DigiDepositPositionMonitor::initialize()    {
+  declare_monitor_position(this, &DigiDepositPositionMonitor::monitor_position_shift);
+  m_deltas = book1D(histo1D_delta.name.c_str(), histo1D_delta.title.c_str(), 
+		    histo1D_delta.nbin_x, histo1D_delta.min_x, histo1D_delta.max_x);
+  m_deposits = book1D(histo1D_deposits.name.c_str(), histo1D_deposits.title.c_str(), 
+		      histo1D_deposits.nbin_x, histo1D_deposits.min_x, histo1D_deposits.max_x);
+}
+
+/// Fill the monitoring histograms
+void DigiDepositPositionMonitor::monitor_position_shift(const deposit_t&, const Position& position, const Position& change)   {
+  m_deposits.fill(std::sqrt(position.Mag2()), 1e0);
+  m_deltas.fill(std::sqrt(change.Mag2()), 1e0);
+}
diff --git a/DDDigi/src/DigiHandle.cpp b/DDDigi/src/DigiHandle.cpp
index 1099d011d975f2741a0e9e615d60c79b26370ec5..f115968eea1aae5405d81f6e25f2572891e48252 100644
--- a/DDDigi/src/DigiHandle.cpp
+++ b/DDDigi/src/DigiHandle.cpp
@@ -184,6 +184,12 @@ namespace dd4hep {
 
     KernelHandle::KernelHandle(DigiKernel* k) : value(k)  {
     }
+
+    Property& KernelHandle::operator[](const string& property_name) const {
+      PropertyManager& pm = checked_value(value)->properties();
+      return pm[property_name];
+    }
+
   }
 }
 
diff --git a/DDDigi/src/DigiKernel.cpp b/DDDigi/src/DigiKernel.cpp
index cbf1a625624b580b97628b741334629c986f7bad..ff508c2d095226e25f1833b65e6f420e5c467e67 100644
--- a/DDDigi/src/DigiKernel.cpp
+++ b/DDDigi/src/DigiKernel.cpp
@@ -22,6 +22,7 @@
 #include <DDDigi/DigiKernel.h>
 #include <DDDigi/DigiContext.h>
 #include <DDDigi/DigiActionSequence.h>
+#include <DDDigi/DigiMonitorHandler.h>
 
 #ifdef DD4HEP_USE_TBB
 #include <tbb/task_group.h>
@@ -53,8 +54,6 @@ namespace  {
  */
 class DigiKernel::Internals   {
 public:
-  /// Property pool
-  PropertyManager       properties;
   /// Property: Client output levels
   ClientOutputLevels    clientLevels;
   /// Atomic counter: Number of events still to be processed in this run
@@ -76,15 +75,16 @@ public:
   /// Lock for global output logging
   std::mutex            global_output_lock  { };
 
-  using callbacks_t = std::vector<std::function<void()> >;
+  using callbacks_t    = std::vector<std::function<void()> >;
   using ev_callbacks_t = std::vector<std::function<void(DigiContext&)> >;
+
   /// Configure callbacks
   callbacks_t           configurators       { };
   /// Initialize callbacks
   callbacks_t           initializers        { };
-  //// Termination callback
+  /// Termination callback
   callbacks_t           terminators         { };
-      /// Register start event callback
+  /// Register start event callback
   ev_callbacks_t        start_event         { };
   /// Register end event callback
   ev_callbacks_t        end_event           { };
@@ -95,9 +95,12 @@ public:
   DigiActionSequence*   event_action         { nullptr };
   /// The main data output action sequence
   DigiActionSequence*   output_action        { nullptr };
+  /// The histogram handler entity
+  DigiMonitorHandler*   monitor_handler    { nullptr };
 
   /// Random generator
   TRandom* root_random;
+  /// Shared random number generator
   std::shared_ptr<DigiRandomGenerator> random  { };
   /// TBB initializer (If TBB is used)
   std::unique_ptr<tbb::global_control> tbb_init { };
@@ -111,7 +114,11 @@ public:
   int                   num_threads;
   /// Property: Allow to stop execution from interactive prompt
   bool                  stop = false;
+
+public:
+  /// Default constructor
   Internals() = default;
+  /// Default destructor
   ~Internals() = default;
 };
 
@@ -171,7 +178,7 @@ public:
 
 /// Standard constructor
 DigiKernel::DigiKernel(Detector& description_ref)
-  : m_detDesc(&description_ref)
+  : DigiAction(*this, "DigiKernel"), m_detDesc(&description_ref)
 {
   internals = new Internals();
   internals->num_threads = tbb::global_control::max_allowed_parallelism;
@@ -179,8 +186,11 @@ DigiKernel::DigiKernel(Detector& description_ref)
   declareProperty("numThreads",       internals->num_threads);
   declareProperty("numEvents",        internals->numEvents = 10);
   declareProperty("stop",             internals->stop = false);
-  declareProperty("OutputLevel",      internals->outputLevel = DEBUG);
   declareProperty("OutputLevels",     internals->clientLevels);
+  auto* h = new DigiMonitorHandler(*this, "MonitorData");
+  properties().add("MonitorOutput", h->property("MonitorOutput"));
+  internals->monitor_handler = h;
+
   internals->input_action  = new DigiActionSequence(*this, "InputAction");
   internals->event_action  = new DigiActionSequence(*this, "EventAction");
   internals->output_action = new DigiActionSequence(*this, "OutputAction");
@@ -189,7 +199,7 @@ DigiKernel::DigiKernel(Detector& description_ref)
   internals->output_action->setExecuteParallel(false);
   internals->root_random = new TRandom();
   internals->random = std::make_shared<DigiRandomGenerator>();
-  internals->random->engine = [this] {  return this->internals->root_random->Uniform(1.0);  };
+  internals->random->engine = [this] {  return internals->root_random->Uniform(1.0);  };
   InstanceCount::increment(this);
 }
 
@@ -197,9 +207,12 @@ DigiKernel::DigiKernel(Detector& description_ref)
 DigiKernel::~DigiKernel() {
   std::lock_guard<std::mutex> lock(kernel_mutex);
   internals->tbb_init.reset();
+  detail::releasePtr(internals->monitor_handler);
   detail::releasePtr(internals->output_action);
   detail::releasePtr(internals->event_action);
   detail::releasePtr(internals->input_action);
+  detail::deletePtr(internals->root_random);
+  internals->random.reset();
   detail::deletePtr(internals);
   InstanceCount::decrement(this);
 }
@@ -231,32 +244,14 @@ std::mutex& DigiKernel::global_io_lock()   const  {
   return internals->global_io_lock;
 }
 
-/// Access to the properties of the object
-PropertyManager& DigiKernel::properties()   {
-  return internals->properties;
-}
-
 /// Print the property values
-void DigiKernel::printProperties()  const  {
-  printout(ALWAYS, "DigiKernel", "OutputLevel:  %d", internals->outputLevel);
+std::size_t DigiKernel::printProperties()  const  {
+  std::size_t count = this->DigiAction::printProperties();
   for( const auto& cl : internals->clientLevels )  {
-    printout(ALWAYS, "DigiKernel", "OutputLevel[%s]:  %d", cl.first.c_str(), cl.second);
+    always("OutputLevel[%s]:  %d", cl.first.c_str(), cl.second);
+    ++count;
   }
-}
-
-/// Check property for existence
-bool DigiKernel::hasProperty(const std::string& name) const    {
-  return internals->properties.exists(name);
-}
-
-/// Access single property
-dd4hep::Property& DigiKernel::property(const std::string& name)   {
-  return internals->properties[name];
-}
-
-/// Access the output level
-PrintLevel DigiKernel::outputLevel() const  {
-  return (PrintLevel)internals->outputLevel;
+  return count;
 }
 
 /// Fill cache with the global output level of a named object. Must be set before instantiation
@@ -271,31 +266,24 @@ dd4hep::PrintLevel DigiKernel::getOutputLevel(const std::string object) const
   return dd4hep::PrintLevel(dd4hep::printLevel()-1);
 }
 
-/// Set the output level; returns previous value
-dd4hep::PrintLevel DigiKernel::setOutputLevel(PrintLevel new_level)  {
-  int old = internals->outputLevel;
-  internals->outputLevel = new_level;
-  return (PrintLevel)old;
-}
-
 /// Access current number of events still to process
 std::size_t DigiKernel::events_todo()  const   {
-  std::lock_guard<std::mutex> lock(this->internals->counter_lock);
-  std::size_t evts = this->internals->events_todo;
+  std::lock_guard<std::mutex> lock(internals->counter_lock);
+  std::size_t evts = internals->events_todo;
   return evts;
 }
 
 /// Access current number of events already processed
 std::size_t DigiKernel::events_done()  const   {
-  std::lock_guard<std::mutex> lock(this->internals->counter_lock);
-  std::size_t evts = this->internals->numEvents - this->internals->events_todo;
+  std::lock_guard<std::mutex> lock(internals->counter_lock);
+  std::size_t evts = internals->numEvents - internals->events_todo;
   return evts;
 }
 
 /// Access current number of events processing (events in flight)
 std::size_t DigiKernel::events_processing()  const   {
-  std::lock_guard<std::mutex> lock(this->internals->counter_lock);
-  std::size_t evts = this->internals->events_submitted - this->internals->events_finished;
+  std::lock_guard<std::mutex> lock(internals->counter_lock);
+  std::size_t evts = internals->events_submitted - internals->events_finished;
   return evts;
 }
 
@@ -323,6 +311,21 @@ int DigiKernel::initialize()   {
   return 1;
 }
 
+/// Access to the main input action sequence from the kernel object
+DigiActionSequence& DigiKernel::inputAction() const    {
+  return *internals->input_action;
+}
+
+/// Access to the main event action sequence from the kernel object
+DigiActionSequence& DigiKernel::eventAction() const    {
+  return *internals->event_action;
+}
+
+/// Access to the main output action sequence from the kernel object
+DigiActionSequence& DigiKernel::outputAction() const    {
+  return *internals->output_action;
+}
+
 /// Register configure callback
 void DigiKernel::register_configure(const std::function<void()>& callback)   const  {
   std::lock_guard<std::mutex> lock(initializer_lock());
@@ -330,7 +333,7 @@ void DigiKernel::register_configure(const std::function<void()>& callback)   con
 }
 
 /// Register initialize callback
-void DigiKernel::register_initialize(const std::function<void()>& callback)   const  {
+void DigiKernel::register_initialize(const std::function<void()>& callback)  const  {
   std::lock_guard<std::mutex> lock(initializer_lock());
   internals->initializers.push_back(callback);
 }
@@ -351,19 +354,17 @@ void DigiKernel::register_end_event(const std::function<void(DigiContext&)>& cal
   internals->end_event.push_back(callback);
 }
 
-/// Access to the main input action sequence from the kernel object
-DigiActionSequence& DigiKernel::inputAction() const    {
-  return *internals->input_action;
-}
-
-/// Access to the main event action sequence from the kernel object
-DigiActionSequence& DigiKernel::eventAction() const    {
-  return *internals->event_action;
-}
-
-/// Access to the main output action sequence from the kernel object
-DigiActionSequence& DigiKernel::outputAction() const    {
-  return *internals->output_action;
+/// Registration of monitoring objects eventually saved by the handler
+void DigiKernel::register_monitor(DigiAction* action, TNamed* object)  const    {
+  if ( action && object )  {
+    std::lock_guard<std::mutex> lock(internals->counter_lock);
+    internals->monitor_handler->adopt(action, object);
+    return;
+  }
+  except("DigiKernel","+++ Invalid monitor request from action %s with object %s: %s",
+	 action ? action->name().c_str() : "[Invalid]",
+	 object ? object->GetName() : "[Invalid]",
+	 object ? object->GetTitle() : "");
 }
 
 /// Submit a bunch of actions to be executed in parallel
@@ -373,21 +374,21 @@ void DigiKernel::submit (DigiContext& context, ParallelCall*const algorithms[],
   bool para = parallel && (internals->tbb_init && internals->num_threads > 0);
   if ( para )   {
     tbb::task_group que;
-    printout(INFO,"DigiKernel","%s+++ Executing chunk of %ld execution entries in parallel", tag, count);
+    info("%s+++ Executing chunk of %3ld execution entries in parallel", tag, count);
     for( std::size_t i=0; i<count; ++i)
       que.run( Wrapper<ParallelCall,void*>(algorithms[i], data) );
     que.wait();
     return;
   }
 #endif
-  printout(INFO,"DigiKernel","%s+++ Executing chunk of %ld execution entries sequentially", tag, count);
+  info("%s+++ Executing chunk of %3ld execution entries sequentially", tag, count);
   for( std::size_t i=0; i<count; ++i)
     algorithms[i]->execute(data);
 }
 
 /// Submit a bunch of actions to be executed in parallel
 void DigiKernel::submit (DigiContext& context, const std::vector<ParallelCall*>& algorithms, void* data, bool parallel)  const  {
-  this->submit(context, &algorithms[0], algorithms.size(), data, parallel);
+  submit(context, &algorithms[0], algorithms.size(), data, parallel);
 }
 
 void DigiKernel::wait(DigiContext& context)   const  {
@@ -423,8 +424,8 @@ void DigiKernel::notify(std::unique_ptr<DigiContext>&& context)   {
 void DigiKernel::notify(std::unique_ptr<DigiContext>&& context, const std::exception& e)   {
   const char* tag = context->event->id();
   internals->stop = true;
-  printout(ERROR,"DigiKernel","%s+++ Exception during event processing [Shall stop the event loop]", tag);
-  printout(ERROR,"DigiKernel","%s -> %s", tag, e.what());
+  error("%s+++ Exception during event processing [Shall stop the event loop]", tag);
+  error("%s -> %s", tag, e.what());
   notify(std::move(context));
 }
 
@@ -435,15 +436,15 @@ int DigiKernel::run()   {
   internals->events_finished = 0;
   internals->events_submitted = 0;
   internals->events_todo = internals->numEvents;
-  printout(INFO,"DigiKernel","+++ Total number of events:    %d",internals->numEvents);
+  info("+++ Total number of events:    %d",internals->numEvents);
 #ifdef DD4HEP_USE_TBB
   if ( !internals->tbb_init && internals->num_threads > 0 )   {
     using ctrl_t = tbb::global_control;
     if ( 0 == internals->num_threads )  {
       internals->num_threads = ctrl_t::max_allowed_parallelism;
     }
-    printout(INFO, "DigiKernel", "+++ Number of TBB threads to:  %d",internals->num_threads);
-    printout(INFO, "DigiKernel", "+++ Number of parallel events: %d",internals->maxEventsParallel);
+    info("+++ Number of TBB threads to:  %d",internals->num_threads);
+    info("+++ Number of parallel events: %d",internals->maxEventsParallel);
     internals->tbb_init = std::make_unique<ctrl_t>(ctrl_t::max_allowed_parallelism,internals->num_threads+1);
     if ( internals->maxEventsParallel >= 0 )   {
       int todo_evt = internals->events_todo;
@@ -453,7 +454,7 @@ int DigiKernel::run()   {
         main_group.run(Processor(*this));
       main_group.wait();
     }
-    printout(DEBUG, "DigiKernel", "+++ All event processing threads Synchronized --- Done!");
+    debug("+++ All event processing threads Synchronized --- Done!");
   }
   else
 #endif
@@ -466,16 +467,18 @@ int DigiKernel::run()   {
     }
   std::chrono::duration<double> duration = std::chrono::system_clock::now() - start;
   double sec = std::chrono::duration_cast<std::chrono::seconds>(duration).count();
-  printout(DEBUG, "DigiKernel", "+++ %d Events out of %d processed. "
-           "Total: %7.1f seconds %7.3f seconds/event",
-           internals->numEvents-int(internals->events_todo), internals->numEvents,
-           sec, sec/double(std::max(1,internals->numEvents)));
+  debug("+++ %d Events out of %d processed. "
+	"Total: %7.1f seconds %7.3f seconds/event",
+	internals->numEvents-int(internals->events_todo), internals->numEvents,
+	sec, sec/double(std::max(1,internals->numEvents)));
   return 1;
 }
 
 /// Terminate the digitization: call all registered terminators and release the allocated resources
 int DigiKernel::terminate() {
-  printout(INFO, "DigiKernel", "++ Terminate Digi and delete associated actions.");
+  info("++ Saving monitoring quantities.");
+  internals->monitor_handler->save();
+  info("++ Terminate Digi and delete associated actions.");
   for(auto& call : internals->terminators) call();
   m_detDesc->destroyInstance();
   m_detDesc = 0;
diff --git a/DDDigi/src/DigiMonitorHandler.cpp b/DDDigi/src/DigiMonitorHandler.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..31abb1180ab2cc446eed54a7169c6df51df41a43
--- /dev/null
+++ b/DDDigi/src/DigiMonitorHandler.cpp
@@ -0,0 +1,82 @@
+//==========================================================================
+//  AIDA Detector description implementation 
+//--------------------------------------------------------------------------
+// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
+// All rights reserved.
+//
+// For the licensing terms see $DD4hepINSTALL/LICENSE.
+// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
+//
+// Author     : M.Frank
+//
+//==========================================================================
+
+/// Framework include files
+#include <DD4hep/Printout.h>
+#include <DDDigi/DigiMonitorHandler.h>
+
+/// ROOT include files
+#include <TFile.h>
+
+/// C/C++ include files
+
+using namespace std;
+using namespace dd4hep::digi;
+
+/// Standard constructor
+DigiMonitorHandler::DigiMonitorHandler(const DigiKernel& kernel, const string& nam)
+  : DigiAction(kernel, nam)
+{
+  declareProperty("MonitorOutput", m_output_file);
+}
+
+/// Default destructor
+DigiMonitorHandler::~DigiMonitorHandler()    {
+  for( auto& m : m_monitors )   {
+    m.first->release();
+    for( auto* itm : m.second )   {
+      detail::deletePtr(itm);
+    }
+    m.second.clear();
+  }
+  m_monitors.clear();
+}
+
+/// Adopt monitor and keep reference for saving
+void DigiMonitorHandler::adopt(DigiAction* source, TNamed* object)    {
+  source->addRef();
+  m_monitors[source].insert(object);
+}
+
+/// Save monitors
+void DigiMonitorHandler::save()    {
+  if ( !m_output_file.empty() )    {
+    TFile* output = TFile::Open(m_output_file.c_str(),
+				"DD4hep Digitization monitoring information",
+				"RECREATE");
+    TDirectory::TContext top_context(output);
+    if ( output && !output->IsZombie() )    {
+      for( const auto& m : m_monitors )   {
+	const auto* act   = m.first;
+	const auto& items = m.second;
+	const auto& nam   = act->name();
+	std::string title = "Monitor items of digitization action "+nam;
+	TDirectory* direc = output->mkdir(nam.c_str(), title.c_str(), kTRUE);
+	TDirectory::TContext action_context(direc);
+	for( const auto* itm : items )   {
+	  Int_t nbytes = direc->WriteTObject(itm);
+	  if ( nbytes <= 0 )  {
+	    error("+++ Failed to write object: %s -> %s", nam.c_str(), itm->GetName());
+	  }
+	}
+	direc->Write();
+      }
+      output->Write();
+      output->Close();
+      delete output;
+      return;
+    }
+    except("+++ Failed to open monitoring output file: %s", m_output_file.c_str());
+  }
+}
+
diff --git a/DDDigi/src/DigiMonitorParser.cpp b/DDDigi/src/DigiMonitorParser.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0103ee38c56d9c291bd50ca6326fbd3e2200a26f
--- /dev/null
+++ b/DDDigi/src/DigiMonitorParser.cpp
@@ -0,0 +1,209 @@
+//==========================================================================
+//  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 <Parsers/spirit/ParsersFactory.h>
+#include <DDDigi/DigiMonitorOptions.h>
+
+// ============================================================================
+namespace dd4hep   {
+  // ==========================================================================
+  namespace Parsers  {
+
+    // ========================================================================
+    // 1D histogram parameters
+    // ========================================================================
+    std::ostream& toStream(const dd4hep::digi::H1DParams& o, std::ostream& s)   {
+      return s << "( "
+	       << '"' << o.name  << '"' << " , "
+	       << '"' << o.title << '"' << " , "
+	       << o.nbin_x << " , "
+	       << o.min_x  << " , "
+	       << o.max_x
+	       << " )" ;
+    }
+
+    // ========================================================================
+    template< typename Iterator, typename Skipper>
+    class H1DParamsGrammar : public qi::grammar<Iterator, dd4hep::digi::H1DParams(), Skipper>
+    {
+    public:
+      // ======================================================================
+      typedef dd4hep::digi::H1DParams ResultT;
+      // ======================================================================
+    public:
+      struct tag_name{};
+      struct tag_title{};
+      struct tag_nbin_x{};
+      struct tag_min_x{};
+      struct tag_max_x{};
+      struct Operations {
+        // Some magic:
+        template <typename A, typename B = boost::fusion::unused_type,
+		  typename C = boost::fusion::unused_type,
+		  typename D = boost::fusion::unused_type>
+        struct result { typedef void type; };
+        // Actions:
+        // --------------------------------------------------------------------
+        void operator()(dd4hep::digi::H1DParams& val, const int bin, tag_nbin_x) const {
+	  val.nbin_x = bin;
+        }
+
+        void operator()(dd4hep::digi::H1DParams& val, const float x, tag_min_x) const {
+	  val.min_x = x;
+        }
+
+        void operator()(dd4hep::digi::H1DParams& val, const float x, tag_max_x) const {
+	  val.max_x = x;
+        }
+
+        void operator()(dd4hep::digi::H1DParams& val, const std::string& name, tag_name) const {
+	  val.name = name;
+        }
+
+        void operator()(dd4hep::digi::H1DParams& val, const std::string& title, tag_title) const {
+	  val.title = title;
+        }
+
+      };
+    public:
+      H1DParamsGrammar() : H1DParamsGrammar::base_type(para)      {
+	para = qi::lit('(')
+	  >> name[op(qi::_val, qi::_1, tag_name())]
+	  >> ','
+	  >> title[op(qi::_val, qi::_1, tag_title())]
+	  >> ','
+	  >> qi::int_[op(qi::_val, qi::_1, tag_nbin_x())]
+	  >> ','
+	  >> qi::double_[op(qi::_val, qi::_1, tag_min_x())]
+	  >> ','
+	  >> qi::double_[op(qi::_val, qi::_1, tag_max_x())]
+	  >> ')';
+      }
+      qi::rule<Iterator, dd4hep::digi::H1DParams(), Skipper> para;
+      StringGrammar<Iterator, Skipper> name;
+      StringGrammar<Iterator, Skipper> title;
+      ph::function<Operations> op;
+      // ======================================================================
+    };
+    REGISTER_GRAMMAR(dd4hep::digi::H1DParams, H1DParamsGrammar);
+    // ========================================================================
+    int parse(dd4hep::digi::H1DParams& result, const std::string& input)   {
+      return parse_(result, input);
+    }
+
+    // ========================================================================
+    // 2D histogram parameters
+    // ========================================================================
+    std::ostream& toStream(const dd4hep::digi::H2DParams& o, std::ostream& s)   {
+      return s << "[ "
+	       << '"' << o.name << "\" , "
+	       << '"' << o.title << "\" , "
+	       << o.nbin_x << " , "
+	       << o.min_x  << " , "
+	       << o.max_x  << " , "
+	       << o.nbin_y << " , "
+	       << o.min_y  << " , "
+	       << o.max_y
+	       << " ]" ;
+    }
+    // ========================================================================
+    template< typename Iterator, typename Skipper>
+    class H2DParamsGrammar : public qi::grammar<Iterator, dd4hep::digi::H2DParams(), Skipper>
+    {
+    public:
+      // ======================================================================
+      typedef dd4hep::digi::H2DParams ResultT;
+      // ======================================================================
+    public:
+      struct tag_name{};
+      struct tag_title{};
+      struct tag_nbin_x{};
+      struct tag_min_x{};
+      struct tag_max_x{};
+      struct tag_nbin_y{};
+      struct tag_min_y{};
+      struct tag_max_y{};
+      struct Operations {
+        // Some magic:
+        template <typename A, typename B = boost::fusion::unused_type,
+		  typename C = boost::fusion::unused_type,
+		  typename D = boost::fusion::unused_type>
+        struct result { typedef void type; };
+        // Actions:
+        // --------------------------------------------------------------------
+        void operator()(dd4hep::digi::H2DParams& val, const int bin, tag_nbin_x) const {
+	  val.nbin_x = bin;
+        }
+        void operator()(dd4hep::digi::H2DParams& val, const float x, tag_min_x) const {
+	  val.min_x = x;
+        }
+        void operator()(dd4hep::digi::H2DParams& val, const float x, tag_max_x) const {
+	  val.max_x = x;
+        }
+        void operator()(dd4hep::digi::H2DParams& val, const int bin, tag_nbin_y) const {
+	  val.nbin_y = bin;
+        }
+        void operator()(dd4hep::digi::H2DParams& val, const float y, tag_min_y) const {
+	  val.min_y = y;
+        }
+        void operator()(dd4hep::digi::H2DParams& val, const float y, tag_max_y) const {
+	  val.max_y = y;
+        }
+        void operator()(dd4hep::digi::H2DParams& val, const std::string& name, tag_name) const {
+	  val.name = name;
+        }
+        void operator()(dd4hep::digi::H2DParams& val, const std::string& title, tag_title) const {
+	  val.title = title;
+        }
+
+      };
+    public:
+      H2DParamsGrammar() : H2DParamsGrammar::base_type(para)      {
+	para = qi::lit('[')
+	  >> name[op(qi::_val, qi::_1, tag_name())]
+	  >> ','
+	  >> title[op(qi::_val, qi::_1, tag_title())]
+	  >> ','
+	  >> qi::int_[op(qi::_val, qi::_1, tag_nbin_x())]
+	  >> ','
+	  >> qi::float_[op(qi::_val, qi::_1, tag_min_x())]
+	  >> ','
+	  >> qi::float_[op(qi::_val, qi::_1, tag_max_x())]
+	  >> ','
+	  >> qi::int_[op(qi::_val, qi::_1, tag_nbin_y())]
+	  >> ','
+	  >> qi::float_[op(qi::_val, qi::_1, tag_min_y())]
+	  >> ','
+	  >> qi::float_[op(qi::_val, qi::_1, tag_max_y())]
+	  >> ']' ;
+        }
+        qi::rule<Iterator, dd4hep::digi::H2DParams(), Skipper> para;
+        StringGrammar<Iterator, Skipper> name;
+        StringGrammar<Iterator, Skipper> title;
+        ph::function<Operations> op;
+      // ======================================================================
+    };
+    REGISTER_GRAMMAR(dd4hep::digi::H2DParams, H2DParamsGrammar);
+    // ========================================================================
+    int parse(dd4hep::digi::H2DParams& result, const std::string& input)   {
+      return parse_(result, input);
+    }
+    // ========================================================================
+  } //                                         end of namespace dd4hep::Parsers
+  // ==========================================================================
+} //                                                    end of namespace dd4hep
+// ============================================================================
+#include "DD4hep/GrammarParsed.h"
+static auto s_registry = dd4hep::GrammarRegistry::pre_note<dd4hep::digi::H1DParams>()
+  .pre_note<dd4hep::digi::H2DParams>();
diff --git a/DDDigi/src/DigiSegmentSplitter.cpp b/DDDigi/src/DigiSegmentSplitter.cpp
index 0b25a61e3fc4b533c6638c0bbe3717e92c14b918..c3486b780bb0c31a7ace6608c1458400b09bafa1 100644
--- a/DDDigi/src/DigiSegmentSplitter.cpp
+++ b/DDDigi/src/DigiSegmentSplitter.cpp
@@ -50,7 +50,7 @@ template <> void DigiParallelWorker<DigiContainerProcessor,
 				    DigiContainerProcessor::work_t,
 				    DigiSegmentProcessContext>::execute(void* ptr) const  {
   calldata_t* args  = reinterpret_cast<calldata_t*>(ptr);
-  action->execute(args->context, *args, this->options.predicate);
+  action->execute(args->environ.context, *args, this->options.predicate);
 }
 
 /// Standard constructor
diff --git a/DDDigi/src/DigiStoreDump.cpp b/DDDigi/src/DigiStoreDump.cpp
index c0e1d07efa5c26e7767771f331934b445d0db1a8..84ab134c1e9ee0b8e604302295aeab20b0e2ddf8 100644
--- a/DDDigi/src/DigiStoreDump.cpp
+++ b/DDDigi/src/DigiStoreDump.cpp
@@ -70,7 +70,6 @@ template <> std::string DigiStoreDump::data_header(Key key, const std::string& t
   return data_header(key, tag, data.type());
 }
 
-
 template <> std::vector<std::string>
 DigiStoreDump::dump_history(DigiContext& context, 
 			    Key key,
@@ -101,6 +100,7 @@ DigiStoreDump::dump_history(DigiContext& context,
   return records;
 }
 
+#ifdef DDDIGI_INPLACE_HISTORY
 template <> std::vector<std::string> 
 DigiStoreDump::dump_history(DigiContext& context,
 			    Key container_key,
@@ -151,13 +151,65 @@ DigiStoreDump::dump_history(DigiContext& context,
   }
   return records;
 }
+#endif
+
+template <> std::vector<std::string> 
+DigiStoreDump::dump_history(DigiContext& context,
+			    Key container_key,
+			    const std::pair<const CellID, History>& data,
+			    std::size_t seq_no)  const
+{
+  std::string line;
+  std::stringstream str;
+  auto& ev = *(context.event);
+  const auto& history = data.second;
+  const CellID cell = data.first;
+  std::vector<std::string> records;
+
+  str << Key::key_name(container_key) << "[" << seq_no << "]:";
+  line = format("+----- %-30s Container: Segment:%04X Mask:%04X Item:%08X Cell:%016X Hist: Hits:%ld Parts:%ld",
+		str.str().c_str(), container_key.segment(), container_key.mask(), container_key.item(),
+		cell, history.hits.size(), history.particles.size());
+  records.emplace_back(line);
+  for( std::size_t i=0; i<history.hits.size(); ++i )   {
+    const auto& entry = history.hits[i];
+    const EnergyDeposit&  dep = entry.get_deposit(ev, container_key.item());
+    const Position& pos = dep.position;
+    const Position& mom = dep.momentum;
+    Key k = entry.source;
+    str.str("");
+    str << "|        Hit-history[" << i << "]:";
+    line = format("%-30s Segment:%04X Mask:%04X Cell:%08X  %.8g",
+		  str.str().c_str(), k.segment(), k.mask(), k.item(), entry.weight);
+    records.emplace_back(line);
+    line = format("|              pos: %7.3f %7.3f %7.3f   p: %7.3f %7.3f %7.3f deposit: %7.3f",
+		  pos.X(), pos.Y(), pos.Z(), mom.X(), mom.Y(), mom.Z(), dep.deposit);
+    records.emplace_back(line);
+  }
+  for( std::size_t i=0; i<history.particles.size(); ++i )   {
+    const auto&      ent = history.particles[i];
+    const Particle&  par = ent.get_particle(ev);
+    const Direction& mom = par.momentum;
+    const Position&  vtx = par.start_position;
+    Key key = ent.source;
+    str.str("");
+    str << "|        Part-history[" << i << "]:";
+    line = format("%-30s Segment:%04X Mask:%04X Key: %08X  %.8g",
+		  str.str().c_str(), key.segment(), key.mask(), key.item(), ent.weight);
+    records.emplace_back(line);
+    line = format("|              PDG:%6d Charge:%-2d Mass:%7.3f v:%7.3f %7.3f %7.3f   p:%7.3f %7.3f %7.3f",
+		  par.pdgID, int(par.charge), par.mass, vtx.X(), vtx.Y(), vtx.Z(), mom.X(), mom.Y(), mom.Z());
+    records.emplace_back(line);
+  }
+  return records;
+}
 
 template <typename T> std::vector<std::string>
 DigiStoreDump::dump_history(DigiContext& context, Key container_key, const T& container)  const {
   std::size_t count = 0;
   std::vector<std::string> records;
   for( const auto& item : container )  {
-    auto rec = ump_history(context, container_key, item, count++);
+    auto rec = dump_history(context, container_key, item, count++);
     records.insert(records.end(), rec.begin(), rec.end());
   }
   return records;
@@ -169,10 +221,12 @@ DigiStoreDump::dump_deposit_history(DigiContext& context, Key container_key, con
   std::vector<std::string> records;
   auto line = format("|----  %s", data_header(container_key, "deposits", container).c_str());
   records.emplace_back(line);
+#ifdef DDDIGI_INPLACE_HISTORY
   for( const auto& item : container )   {
     auto rec = dump_history(context, container_key, item, count++);
     records.insert(records.end(), rec.begin(), rec.end());
   }
+#endif
   return records;
 }
 
@@ -182,10 +236,12 @@ DigiStoreDump::dump_deposit_history(DigiContext& context, Key container_key, con
   std::vector<std::string> records;
   auto line = format("|----  %s", data_header(container_key, "deposits", container).c_str());
   records.emplace_back(line);
+#ifdef DDDIGI_INPLACE_HISTORY
   for( const auto& item : container )   {
     auto rec = dump_history(context, container_key, item, count++);
     records.insert(records.end(), rec.begin(), rec.end());
   }
+#endif
   return records;
 }
 
diff --git a/DDDigi/src/DigiSynchronize.cpp b/DDDigi/src/DigiSynchronize.cpp
index e29262286ab0b3e11f7bbdbfcdad84ba7dff12d6..4729c818e0c139c9c7c7ab6451f67d549a3250fe 100644
--- a/DDDigi/src/DigiSynchronize.cpp
+++ b/DDDigi/src/DigiSynchronize.cpp
@@ -25,7 +25,7 @@ using namespace dd4hep::digi;
 
 
 template <> void 
-DigiParallelWorker<DigiEventAction, DigiContext, int>::execute(void* data) const  {
+DigiParallelWorker<DigiEventAction, DigiSynchronize::work_t, std::size_t, DigiSynchronize&>::execute(void* data) const  {
   calldata_t* args = reinterpret_cast<calldata_t*>(data);
   action->execute(*args);
 }
@@ -58,7 +58,7 @@ void DigiSynchronize::execute(DigiContext& context)  const   {
 /// Add an actor responding to all callbacks. Sequence takes ownership.
 void DigiSynchronize::adopt(DigiEventAction* action) {
   if (action)    {
-    m_actors.insert(new Worker(action, 0));
+    m_actors.insert(new worker_t(action, m_actors.size(), *this));
     return;
   }
   except("DigiSynchronize","++ Attempt to add invalid actor!");
diff --git a/DDG4/include/DDG4/Geant4Kernel.h b/DDG4/include/DDG4/Geant4Kernel.h
index 2736fd970c34c5413f113e79fa88e30634ab0389..7032959b33b45a4b889cdf3634ac3a73fd13b0a3 100644
--- a/DDG4/include/DDG4/Geant4Kernel.h
+++ b/DDG4/include/DDG4/Geant4Kernel.h
@@ -19,6 +19,7 @@
 // C/C++ include files
 #include <map>
 #include <typeinfo>
+#include <functional>
 
 class DD4hep_End_Of_File : public std::exception {
 public:
@@ -56,6 +57,7 @@ namespace dd4hep {
       typedef std::map<std::string, Geant4Action*>      GlobalActions;
       typedef std::map<std::string,int>                 ClientOutputLevels;
       typedef std::pair<void*, const std::type_info*>   UserFramework;
+      using UserCallbacks = std::vector<std::function<void()> >;
 
     protected:
       /// Reference to the run manager
@@ -100,6 +102,15 @@ namespace dd4hep {
       //bool        m_multiThreaded;
       /// Master property: Number of execution threads in multi threaded mode.
       int         m_numThreads;
+
+      /// Registered action callbacks on configure
+      UserCallbacks m_actionConfigure;
+      /// Registered action callbacks on initialize
+      UserCallbacks m_actionInitialize;
+      /// Registered action callbacks on terminate
+      UserCallbacks m_actionTerminate;
+
+
       /// Flag: Master instance (id<0) or worker (id >= 0)
       unsigned long      m_id, m_ident;
       /// Access to geometry world
@@ -223,6 +234,13 @@ namespace dd4hep {
       /// Retrieve the global output level of a named object.
       PrintLevel getOutputLevel(const std::string object) const;
 
+      /// Register configure callback. Signature:   (function)()
+      void register_configure(const std::function<void()>& callback);
+      /// Register initialize callback. Signature:  (function)()
+      void register_initialize(const std::function<void()>& callback);
+      /// Register terminate callback. Signature:   (function)()
+      void register_terminate(const std::function<void()>& callback);
+
       /// Register action by name to be retrieved when setting up and connecting action objects
       /** Note: registered actions MUST be unique.
        *  However, not all actions need to registered....
diff --git a/DDG4/include/DDG4/Geant4UIManager.h b/DDG4/include/DDG4/Geant4UIManager.h
index 50d2bda572574f15a7536fb599c3c594847a4f22..b696a7cdea88660739b6067ce8091b6da964200f 100644
--- a/DDG4/include/DDG4/Geant4UIManager.h
+++ b/DDG4/include/DDG4/Geant4UIManager.h
@@ -58,8 +58,14 @@ namespace dd4hep {
       std::string m_uiSetup;
       /// Property: Name of the visualization macro file
       std::string m_visSetup;
-      /// Property: Array of macro files to be chained
-      std::vector<std::string> m_commands;
+      /// Property: Array of macro files to be chained and executed when the Geant4Kernel gets configured
+      std::vector<std::string> m_configureCommands;
+      /// Property: Array of macro files to be chained and executed when the Geant4Kernel gets initialized
+      std::vector<std::string> m_initializeCommands;
+      /// Property: Array of macro files to be chained and executed when the Geant4Kernel gets terminated
+      std::vector<std::string> m_terminateCommands;
+      /// Property: Array of macro files to be chained and executed BEFORE running
+      std::vector<std::string> m_preRunCommands;
       /// Property: Array of macro files to be chained and executed AFTER running
       std::vector<std::string> m_postRunCommands;
       /// Property: Array of commands to be chained
@@ -74,11 +80,20 @@ namespace dd4hep {
       G4VisManager* m_vis;
       /// Reference to Geant4 UI manager
       G4UIExecutive*  m_ui;
+
     public:
       /// Initializing constructor
       Geant4UIManager(Geant4Context* context, const std::string& name);
       /// Default destructor
       virtual ~Geant4UIManager();
+
+      /// Configure the object. Callback registered to the Geant4Kernel.
+      void configure();
+      /// Initialize the object. Callback registered to the Geant4Kernel.
+      void initialize();
+      /// Callback on terminate. Callback registered to the Geant4Kernel.
+      void terminate();
+
       /// Install command control messenger to write GDML file from command prompt.
       void installCommandMessenger();
       /// Start visualization
@@ -93,7 +108,9 @@ namespace dd4hep {
       void forceExit();
       /// Regularly exiting this process without calling atexit handlers
       void regularExit();
-	/// Run UI
+      /// Apply single command
+      void applyCommand(const std::string& command);
+      /// Run UI
       virtual void operator()(void* param);
     };
 
diff --git a/DDG4/python/DDG4.py b/DDG4/python/DDG4.py
index 7d000ba214537578fd594a870143a325777b0568..bfc40a5096af297f259868e319ad42a280029236 100644
--- a/DDG4/python/DDG4.py
+++ b/DDG4/python/DDG4.py
@@ -131,14 +131,27 @@ def _registerGlobalFilter(self, filter):
   self.get().registerGlobalFilter(Interface.toAction(filter))
 
 
+def _evalProperty(data):
+  """
+    Function necessary to extract real strings from the property value.
+    Strings may be emraced by quotes: '<value>'
+  """
+  try:
+    if isinstance(data,str):
+      return eval(data)
+  except:
+    pass
+  return data
+
+
 def _getKernelProperty(self, name):
   ret = Interface.getPropertyKernel(self.get(), name)
   if ret.status > 0:
-    return ret.data
+    return _evalProperty(ret.data)
   elif hasattr(self.get(), name):
-    return getattr(self.get(), name)
+    return _evalProperty(getattr(self.get(), name))
   elif hasattr(self, name):
-    return getattr(self, name)
+    return _evalProperty(getattr(self, name))
   msg = 'Geant4Kernel::GetProperty [Unhandled]: Cannot access Kernel.' + name
   raise KeyError(msg)
 
@@ -447,6 +460,15 @@ class Geant4:
     """
     return self.setupUI(typ='csh', vis=vis, ui=ui, macro=macro)
 
+  def ui(self):
+    """
+    Access UI manager action from the kernel object
+
+    \author  M.Frank
+    """
+    ui_name = getattr(self.master(),'UI')
+    return self.master().globalAction(ui_name)
+
   def addUserInitialization(self, worker, worker_args=None, master=None, master_args=None):
     """
     Configure Geant4 user initialization for optionasl multi-threading mode
diff --git a/DDG4/python/DDG4Dict.C b/DDG4/python/DDG4Dict.C
index ec18b78c4f97f4d454afde772fa247c9b2b6d7ae..cd9925d657fd878a4b81fd05bc499b031562ba34 100644
--- a/DDG4/python/DDG4Dict.C
+++ b/DDG4/python/DDG4Dict.C
@@ -17,13 +17,13 @@
 //====================================================================
 
 // Framework include files
-#include "DDG4/DDG4Dict.h"
-#include "DDG4/Geant4Config.h"
-#include "DDG4/Geant4Primary.h"
-#include "DDG4/Geant4Random.h"
-#include "DDG4/Geant4DataDump.h"
-#include "DDG4/Geant4InputAction.h"
-#include "DDG4/Geant4GeneratorWrapper.h"
+#include <DDG4/DDG4Dict.h>
+#include <DDG4/Geant4Config.h>
+#include <DDG4/Geant4Primary.h>
+#include <DDG4/Geant4Random.h>
+#include <DDG4/Geant4DataDump.h>
+#include <DDG4/Geant4InputAction.h>
+#include <DDG4/Geant4GeneratorWrapper.h>
 
 /// Namespace for the AIDA detector description toolkit
 namespace dd4hep {
@@ -205,7 +205,8 @@ namespace dd4hep {
 
 typedef dd4hep::sim::Geant4ActionCreation Geant4ActionCreation;
 
-#include "DD4hep/detail/DetectorInterna.h"
+#include <DD4hep/detail/DetectorInterna.h>
+#include <DDG4/Geant4UIManager.h>
 
 // CINT configuration
 #if defined(__CINT__) || defined(__MAKECINT__) || defined(__CLING__) || defined(__ROOTCLING__)
@@ -325,6 +326,7 @@ typedef dd4hep::sim::Geant4ActionCreation Geant4ActionCreation;
 #pragma link C++ class dd4hep::sim::Geant4DataDump;
 #pragma link C++ class dd4hep::sim::Geant4Random;
 #pragma link C++ class dd4hep::sim::Geant4ParticleHandler;
+#pragma link C++ class dd4hep::sim::Geant4UIManager;
 #pragma link C++ class dd4hep::sim::Geant4UserParticleHandler;
 
 
@@ -335,7 +337,7 @@ typedef dd4hep::sim::Geant4ActionCreation Geant4ActionCreation;
 #endif
 
 // CLHEP stuff
-#include "CLHEP/Random/Random.h"
+#include <CLHEP/Random/Random.h>
 #if defined(__CINT__) || defined(__MAKECINT__) || defined(__CLING__) || defined(__ROOTCLING__)
 
 #pragma link C++ namespace CLHEP;
diff --git a/DDG4/src/Geant4Exec.cpp b/DDG4/src/Geant4Exec.cpp
index 949d6aa0860fd1869a49da4dd8584fdea3821275..1a7ac3b34f33cfce61a7710ddb9ccf5a49714293 100644
--- a/DDG4/src/Geant4Exec.cpp
+++ b/DDG4/src/Geant4Exec.cpp
@@ -419,9 +419,9 @@ namespace dd4hep {
 
     /// Construct electro magnetic field entity from the dd4hep field
     G4VPhysicalVolume* Geant4UserDetectorConstruction::Construct()    {
-      // The G4TransportationManager is thread-local. 
-      // Thus, regardless of whether the field class object is global or local 
-      // to a certain volume, a field object must be assigned to G4FieldManager.
+      /// The G4TransportationManager is thread-local. 
+      /// Thus, regardless of whether the field class object is global or local 
+      /// to a certain volume, a field object must be assigned to G4FieldManager.
       G4AutoLock protection_lock(&action_mutex);
       updateContext(m_sequence->context());
       m_sequence->constructGeo(&m_ctxt);
@@ -447,33 +447,33 @@ namespace dd4hep {
         m_sequence->build();
         m_sequence->updateContext(old);
       }
-      // Set user generator action sequence. Not optional, since event context is defined inside
+      /// Set user generator action sequence. Not optional, since event context is defined inside
       Geant4UserGeneratorAction* gen_action = new Geant4UserGeneratorAction(ctx,krnl.generatorAction(false));
       SetUserAction(gen_action);
 
-      // Set the run action sequence. Not optional, since run context is defined/destroyed inside
+      /// Set the run action sequence. Not optional, since run context is defined/destroyed inside
       Geant4UserRunAction* run_action = new Geant4UserRunAction(ctx,krnl.runAction(false));
       SetUserAction(run_action);
 
-      // Set the event action sequence. Not optional, since event context is destroyed inside
+      /// Set the event action sequence. Not optional, since event context is destroyed inside
       Geant4UserEventAction* evt_action = new Geant4UserEventAction(ctx,krnl.eventAction(false));
       run_action->eventAction = evt_action;
       evt_action->runAction = run_action;
       SetUserAction(evt_action);
 
-      // Set the tracking action sequence
+      /// Set the tracking action sequence
       Geant4TrackingActionSequence* trk_action = krnl.trackingAction(false);
       if ( trk_action ) {
         Geant4UserTrackingAction* action = new Geant4UserTrackingAction(ctx, trk_action);
         SetUserAction(action);
       }
-      // Set the stepping action sequence
+      /// Set the stepping action sequence
       Geant4SteppingActionSequence* stp_action = krnl.steppingAction(false);
       if ( stp_action ) {
         Geant4UserSteppingAction* action = new Geant4UserSteppingAction(ctx, stp_action);
         SetUserAction(action);
       }
-      // Set the stacking action sequence
+      /// Set the stacking action sequence
       Geant4StackingActionSequence* stk_action = krnl.stackingAction(false);
       if ( stk_action ) {
         Geant4UserStackingAction* action = new Geant4UserStackingAction(ctx, stk_action);
@@ -530,14 +530,14 @@ Geant4DetectorConstructionSequence* Geant4Compatibility::buildDefaultDetectorCon
   Geant4DetectorConstructionSequence* seq = kernel.detectorConstruction(true);
   printout(WARNING, "Geant4Exec", "+++ Building default Geant4DetectorConstruction for single threaded compatibility.");
 
-  // Attach first the geometry converter from dd4hep to Geant4
+  /// Attach first the geometry converter from dd4hep to Geant4
   cr = PluginService::Create<Geant4Action*>("Geant4DetectorGeometryConstruction",ctx,string("ConstructGeometry"));
   det_cr = dynamic_cast<Geant4DetectorConstruction*>(cr);
   if ( det_cr ) 
     seq->adopt(det_cr);
   else
     throw runtime_error("Panic! Failed to build Geant4DetectorGeometryConstruction.");
-  // Attach the sensitive detector manipulator:
+  /// Attach the sensitive detector manipulator:
   cr = PluginService::Create<Geant4Action*>("Geant4DetectorSensitivesConstruction",ctx,string("ConstructSensitives"));
   det_cr = dynamic_cast<Geant4DetectorConstruction*>(cr);
   if ( det_cr )
@@ -561,17 +561,17 @@ int Geant4Exec::configure(Geant4Kernel& kernel) {
   Geant4Random::setMainInstance(rndm);
   kernel.executePhase("configure",0);
 
-  // Construct the default run manager
+  /// Construct the default run manager
   G4RunManager& runManager = kernel.runManager();
 
-  // Check if the geometry was loaded
+  /// Check if the geometry was loaded
   if (description.sensitiveDetectors().size() <= 1) {
     printout(WARNING, "Geant4Exec", "+++ Only %d subdetectors present. "
              "You sure you loaded the geometry properly?",
              int(description.sensitiveDetectors().size()));
   }
 
-  // Get the detector constructed
+  /// Get the detector constructed
   Geant4DetectorConstructionSequence* user_det = kernel.detectorConstruction(false);
   if ( 0 == user_det && kernel.isMultiThreaded() )   {
     throw runtime_error("Panic! No valid detector construction sequencer present. [Mandatory MT]");
@@ -582,7 +582,7 @@ int Geant4Exec::configure(Geant4Kernel& kernel) {
   Geant4UserDetectorConstruction* det_seq = new Geant4UserDetectorConstruction(ctx,user_det);
   runManager.SetUserInitialization(det_seq);
 
-  // Get the physics list constructed
+  /// Get the physics list constructed
   Geant4PhysicsListActionSequence* phys_seq = kernel.physicsList(false);
   if ( 0 == phys_seq )   {
     string phys_model = "QGSP_BERT";
@@ -603,13 +603,13 @@ int Geant4Exec::configure(Geant4Kernel& kernel) {
   phys_seq->enable(physics);
   runManager.SetUserInitialization(physics);
 
-  // Construct the remaining user initialization in multi-threaded mode
+  /// Construct the remaining user initialization in multi-threaded mode
   Geant4UserInitializationSequence* user_init = kernel.userInitialization(false);
   if ( 0 == user_init && kernel.isMultiThreaded() )   {
     throw runtime_error("Panic! No valid user initialization sequencer present. [Mandatory MT]");
   }
   else if ( 0 == user_init && !kernel.isMultiThreaded() )  {
-    // Use default actions registered to the default kernel. Will do the right thing...
+    /// Use default actions registered to the default kernel. Will do the right thing...
     user_init = kernel.userInitialization(true);
   }
   Geant4UserActionInitialization* init = new Geant4UserActionInitialization(ctx,user_init);
@@ -619,11 +619,11 @@ int Geant4Exec::configure(Geant4Kernel& kernel) {
 
 /// Initialize the simulation
 int Geant4Exec::initialize(Geant4Kernel& kernel) {
-  // Construct the default run manager
+  /// Construct the default run manager
   G4RunManager& runManager = kernel.runManager();
-  //
-  // Initialize G4 engine
-  //
+  ///
+  /// Initialize G4 engine
+  ///
   kernel.executePhase("initialize",0);
   runManager.Initialize();
   return 1;
@@ -640,7 +640,7 @@ int Geant4Exec::run(Geant4Kernel& kernel) {
     if ( ui )  {
       Geant4Call* c = dynamic_cast<Geant4Call*>(ui);
       if ( c )  {
-        (*c)(0);
+        (*c)(nullptr);
         kernel.executePhase("stop",0);
         return 1;
       }
diff --git a/DDG4/src/Geant4Kernel.cpp b/DDG4/src/Geant4Kernel.cpp
index f3bcc53909ad04413eca9640d57478f38313db02..bc42fb39fb4dca32ca0ff783022f038901963a61 100644
--- a/DDG4/src/Geant4Kernel.cpp
+++ b/DDG4/src/Geant4Kernel.cpp
@@ -307,14 +307,44 @@ void Geant4Kernel::loadXML(const char* fname) {
   m_detDesc->apply("DD4hep_XMLLoader", 1, (char**) args);
 }
 
+/// Register configure callback
+void Geant4Kernel::register_configure(const std::function<void()>& callback)  {
+  m_actionConfigure.push_back(callback);
+}
+
+/// Register initialize callback
+void Geant4Kernel::register_initialize(const std::function<void()>& callback)  {
+  m_actionInitialize.push_back(callback);
+}
+
+/// Register terminate callback
+void Geant4Kernel::register_terminate(const std::function<void()>& callback)  {
+  m_actionTerminate.push_back(callback);
+}
+
+/// Configure Geant4 kernel object
 int Geant4Kernel::configure() {
-  return Geant4Exec::configure(*this);
+  int status = Geant4Exec::configure(*this);
+  if ( status )   {
+    for(auto& call : m_actionConfigure) call();
+    return status;
+  }
+  except("Geant4Kernel","++ FAILED to configure DDG4 executive");
+  return status;
 }
 
+/// Initialize Geant4 kernel object
 int Geant4Kernel::initialize() {
-  return Geant4Exec::initialize(*this);
+  int status = Geant4Exec::initialize(*this);
+  if ( status )   {
+    for(auto& call : m_actionInitialize) call();
+    return status;
+  }
+  except("Geant4Kernel","++ FAILED to initialize DDG4 executive");
+  return status;
 }
 
+/// Run Geant4
 int Geant4Kernel::run() {
   try  {
     auto result = Geant4Exec::run(*this);
@@ -340,7 +370,10 @@ int Geant4Kernel::terminate() {
   const Geant4Kernel* ptr = s_main_instance.get();
   printout(INFO,"Geant4Kernel","++ Terminate Geant4 and delete associated actions.");
   if ( ptr == this )  {
+    auto calls = std::move(m_actionTerminate);
+    for(auto& call : calls) call();
     Geant4Exec::terminate(*this);
+    m_actionTerminate = std::move(calls);
   }
   destroyPhases();
   detail::releaseObjects(m_globalFilters);
diff --git a/DDG4/src/Geant4UIManager.cpp b/DDG4/src/Geant4UIManager.cpp
index 307c561c8e1974c13e4a8c1ae53e26faaaadf96d..c02e8dd71afe9e2e9e8d227d602f5df03644dd3c 100644
--- a/DDG4/src/Geant4UIManager.cpp
+++ b/DDG4/src/Geant4UIManager.cpp
@@ -11,23 +11,24 @@
 //
 //==========================================================================
 
-// Framework include files
-#include "DDG4/Geant4UIManager.h"
-#include "DDG4/Geant4Kernel.h"
-#include "DDG4/Geant4UIMessenger.h"
-#include "DD4hep/Primitives.h"
-#include "DD4hep/Printout.h"
-
-// Geant4 include files
-#include "G4Version.hh"
-#include "G4VisExecutive.hh"
-#include "G4UImanager.hh"
-#include "G4UIsession.hh"
-#include "G4VisExecutive.hh"
-#include "G4UIExecutive.hh"
-#include "G4RunManager.hh"
-
+/// Framework include files
+#include <DDG4/Geant4UIManager.h>
+#include <DDG4/Geant4Kernel.h>
+#include <DDG4/Geant4UIMessenger.h>
+#include <DD4hep/Primitives.h>
+
+/// Geant4 include files
+#include <G4Version.hh>
+#include <G4VisExecutive.hh>
+#include <G4UImanager.hh>
+#include <G4UIsession.hh>
+#include <G4VisExecutive.hh>
+#include <G4UIExecutive.hh>
+#include <G4RunManager.hh>
+
+/// C/C++ include files
 #include <cstdlib>
+#include <functional>
 
 using namespace dd4hep::sim;
 using namespace std;
@@ -39,18 +40,25 @@ namespace   {
 }
 
 /// Initializing constructor
-Geant4UIManager::Geant4UIManager(Geant4Context* ctxt, const std::string& nam)
+Geant4UIManager::Geant4UIManager(Geant4Context* ctxt, const string& nam)
   : Geant4Action(ctxt,nam), m_vis(0), m_ui(0)
 {
-  declareProperty("SetupUI",        m_uiSetup="");
-  declareProperty("SetupVIS",       m_visSetup="");
-  declareProperty("SessionType",    m_sessionType="tcsh");
-  declareProperty("Macros",         m_macros);
-  declareProperty("Commands",       m_commands);
-  declareProperty("PostRunCommands",m_postRunCommands);
-  declareProperty("HaveVIS",        m_haveVis=false);
-  declareProperty("HaveUI",         m_haveUI=true);
-  declareProperty("Prompt",         m_prompt);
+  declareProperty("SetupUI",            m_uiSetup="");
+  declareProperty("SetupVIS",           m_visSetup="");
+  declareProperty("SessionType",        m_sessionType="tcsh");
+  declareProperty("Macros",             m_macros);
+  declareProperty("ConfigureCommands",  m_configureCommands);
+  declareProperty("InitializeCommands", m_initializeCommands);
+  declareProperty("TerminateCommands",  m_terminateCommands);
+  declareProperty("Commands",           m_preRunCommands);
+  declareProperty("PreRunCommands",     m_preRunCommands);
+  declareProperty("PostRunCommands",    m_postRunCommands);
+  declareProperty("HaveVIS",            m_haveVis=false);
+  declareProperty("HaveUI",             m_haveUI=true);
+  declareProperty("Prompt",             m_prompt);
+  context()->kernel().register_configure(bind(&Geant4UIManager::configure,this));
+  context()->kernel().register_initialize(bind(&Geant4UIManager::initialize,this));
+  context()->kernel().register_terminate(bind(&Geant4UIManager::terminate,this));
   enableUI();
 }
 
@@ -58,6 +66,55 @@ Geant4UIManager::Geant4UIManager(Geant4Context* ctxt, const std::string& nam)
 Geant4UIManager::~Geant4UIManager()   {
 }
 
+/// Configure the object
+void Geant4UIManager::configure()   {
+  /// Get the pointer to the User Interface manager
+  G4UImanager* mgr = G4UImanager::GetUIpointer();
+  /// Start UI instance
+  if ( m_haveUI ) {
+    m_ui = startUI();
+  }
+  /// Execute the chained command statements
+  for(const auto& c : m_configureCommands)  {
+    info("++ Executing configure command:%s",c.c_str());
+    mgr->ApplyCommand(c.c_str());
+  }
+}
+
+/// Initialize the object
+void Geant4UIManager::initialize()   {
+  /// Get the pointer to the User Interface manager
+  G4UImanager* mgr = G4UImanager::GetUIpointer();
+  /// Execute the chained command statements
+  for(const auto& c : m_initializeCommands)  {
+    info("++ Executing initialization command:%s",c.c_str());
+    mgr->ApplyCommand(c.c_str());
+  }
+}
+
+/// Callback on terminate
+void Geant4UIManager::terminate() {
+  /// Get the pointer to the User Interface manager
+  G4UImanager* mgr = G4UImanager::GetUIpointer();
+  /// Execute the chained command statements
+  for(const auto& c : m_terminateCommands)  {
+    info("++ Executing finalization command:%s",c.c_str());
+    mgr->ApplyCommand(c.c_str());
+  }
+}
+
+/// Apply single command
+void Geant4UIManager::applyCommand(const string& command)   {
+  /// Get the pointer to the User Interface manager
+  G4UImanager* mgr = G4UImanager::GetUIpointer();
+  if ( mgr )    {
+    info("++ Executing G4 command: %s",command.c_str());
+    mgr->ApplyCommand(command.c_str());
+    return;
+  }
+  except("No UI reference present. Too early to interact with Geant4!");
+}
+
 /// Install command control messenger to write GDML file from command prompt.
 void Geant4UIManager::installCommandMessenger()   {
   m_control->addCall("exit", "Force exiting this process",
@@ -73,15 +130,15 @@ void Geant4UIManager::forceExit()   {
 
 /// Regularly exiting this process without calling atexit handlers
 void Geant4UIManager::regularExit()   {
-  printout(INFO,"Geant4UIManager","++ End of processing requested.");
-  this->context()->kernel().terminate();
-  this->forceExit();
+  info("++ End of processing requested.");
+  context()->kernel().terminate();
+  forceExit();
 }
 
 /// Start visualization
 G4VisManager* Geant4UIManager::startVis()  {
-  // Initialize visualization
-  printout(INFO,"Geant4UIManager","+++ Starting G4VisExecutive ....");
+  /// Initialize visualization
+  info("+++ Starting G4VisExecutive ....");
   G4VisManager* vis = new G4VisExecutive();
   vis->Initialize();
   return vis;
@@ -91,9 +148,7 @@ G4VisManager* Geant4UIManager::startVis()  {
 G4UIExecutive* Geant4UIManager::startUI()   {
   G4UIExecutive* ui = 0;
   const char* args[] = {"DDG4","",""};
-  printout(INFO,"Geant4UIManager","+++ Starting G4UIExecutive '%s' of type %s....",
-           args[0], m_sessionType.c_str());
-
+  info("+++ Starting G4UIExecutive '%s' of type %s....", args[0], m_sessionType.c_str());
 #if (G4VERSION_NUMBER >= 960)
   ui = new G4UIExecutive(1,(char**)args,m_sessionType.c_str());
 #else
@@ -113,70 +168,71 @@ void Geant4UIManager::operator()(void* )   {
 
 /// Start manager & session
 void Geant4UIManager::start() {
-  // Get the pointer to the User Interface manager
+  /// Get the pointer to the User Interface manager
   G4UImanager* mgr = G4UImanager::GetUIpointer();
   bool executed_statements = false;
 
-  // Start visualization
+  /// Start visualization
   if ( m_haveVis || !m_visSetup.empty() ) {
     m_vis = startVis();
-    m_haveVis = true;   // If graphics setup, vis is always true
-    m_haveUI = true;    // No graphics without UI!
-  }
-  // Start UI instance
-  if ( m_haveUI ) {
-    m_ui = startUI();
+    m_haveVis = true;   /// If graphics setup, vis is always true
+    m_haveUI = true;    /// No graphics without UI!
   }
-  // Configure visualization instance
+  /// Configure visualization instance
   if ( !m_visSetup.empty() ) {
-    printout(INFO,"Geant4UIManager","++ Executing visualization setup:%s",m_visSetup.c_str());
+    info("++ Executing visualization setup:%s",m_visSetup.c_str());
     mgr->ApplyCommand(make_cmd(m_visSetup).c_str());
   }
-  // Configure UI instance
+  /// Configure UI instance
   if ( !m_uiSetup.empty() )   {
-    printout(INFO,"Geant4UIManager","++ Executing UI setup:%s",m_uiSetup.c_str());
+    info("++ Executing UI setup:%s",m_uiSetup.c_str());
     mgr->ApplyCommand(make_cmd(m_uiSetup).c_str());
     executed_statements = true;
   }
-  // Execute the chained macro files
+  /// Execute the chained macro files
   for(const auto& m : m_macros)  {
-    printout(INFO,"Geant4UIManager","++ Executing Macro file:%s",m.c_str());
+    info("++ Executing Macro file:%s",m.c_str());
     mgr->ApplyCommand(make_cmd(m.c_str()));
     executed_statements = true;
   }
-  // Execute the chained command statements
-  for(const auto& c : m_commands)  {
-    printout(INFO,"Geant4UIManager","++ Executing Command statement:%s",c.c_str());
+  /// Execute the chained pre-run command statements
+  for(const auto& c : m_preRunCommands)  {
+    info("++ Executing pre-run statement:%s",c.c_str());
     mgr->ApplyCommand(c.c_str());
     executed_statements = true;
   }
-  // Start UI session if present
+  /// Start UI session if present
   if ( m_haveUI && m_ui )   {
     m_ui->SessionStart();
-    // Execute the chained command statements
+    /// Execute the chained post-run command statements
     for(const auto& c : m_postRunCommands)  {
-      printout(INFO,"Geant4UIManager","++ Executing Command statement:%s",c.c_str());
+      info("++ Executing post-run statement:%s",c.c_str());
       mgr->ApplyCommand(c.c_str());
       executed_statements = true;
     }
     return;
   }
   else if ( m_haveUI )   {
-    printout(WARNING,"Geant4UIManager","++ No UI manager found. Exit.");
+    warning("++ No UI manager found. Exit.");
     return;
   }
   else if ( executed_statements )  {
+    /// Execute the chained post-run command statements
+    for(const auto& c : m_postRunCommands)  {
+      info("++ Executing post-run statement:%s",c.c_str());
+      mgr->ApplyCommand(c.c_str());
+    }
     return;
   }
 
-  // No UI. Pure batch mode: Simply execute requested number of events
+  /// No UI. Pure batch mode: Simply execute requested number of events
   long numEvent = context()->kernel().property("NumEvents").value<long>();
-  if(numEvent < 0) numEvent = std::numeric_limits<int>::max();
-  printout(INFO,"Geant4UIManager","++ Start run with %d events.",numEvent);
+  if(numEvent < 0) numEvent = numeric_limits<int>::max();
+  info("++ Start run with %d events.",numEvent);
   try {
     context()->kernel().runManager().BeamOn(numEvent);
   } catch (DD4hep_End_Of_File& e) {
-    printout(INFO,"Geant4UIManager","++ End of file reached, ending run...");
+    info("++ End of file reached, ending run...");
     context()->kernel().runManager().RunTermination();
   }
 }
diff --git a/examples/DDDigi/scripts/DigiTest.py b/examples/DDDigi/scripts/DigiTest.py
index 9b0c5b298bb20ec70488375c434a204adb768244..d356a212c1ca308dad81ce5b23f94431a8cf899b 100644
--- a/examples/DDDigi/scripts/DigiTest.py
+++ b/examples/DDDigi/scripts/DigiTest.py
@@ -13,6 +13,7 @@ import os
 import dddigi
 import logging
 from dd4hep import units
+from dddigi import DEBUG, INFO, WARNING, ERROR
 
 logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.INFO)
 logger = logging.getLogger(__name__)
@@ -126,7 +127,7 @@ class Test(dddigi.Digitize):
 
 
 # ==========================================================================================================
-def test_setup_1(digi):
+def test_setup_1(digi, print_level=WARNING, parallel=True):
   """
       Create default setup for tests. Simply too bad to repeat the same lines over and over again.
 
@@ -136,28 +137,29 @@ def test_setup_1(digi):
   # ========================================================================================================
   digi.info('Created SIGNAL input')
   input = digi.input_action('DigiParallelActionSequence/READER')
-  input.adopt_action('DigiDDG4ROOT/SignalReader', mask=0xCBAA, input=[digi.next_input()])
+  input.adopt_action('DigiDDG4ROOT/SignalReader', mask=0xCBAA, input=[digi.next_input()], OutputLevel=print_level, keep_raw=False)
   # ========================================================================================================
   digi.info('Creating collision overlay....')
   # ========================================================================================================
   overlay = input.adopt_action('DigiSequentialActionSequence/Overlay-1')
-  overlay.adopt_action('DigiDDG4ROOT/Read-1', mask=0xCBEE, input=[digi.next_input()])
+  overlay.adopt_action('DigiDDG4ROOT/Read-1', mask=0xCBEE, input=[digi.next_input()], OutputLevel=print_level, keep_raw=False)
   digi.info('Created input.overlay-1')
   # ========================================================================================================
   event = digi.event_action('DigiSequentialActionSequence/EventAction')
   combine = event.adopt_action('DigiContainerCombine/Combine',
-                               parallel=False,
+                               OutputLevel=print_level,
+                               parallel=parallel,
                                input_masks=[0xCBAA, 0xCBEE],
                                output_mask=0xAAA0,
                                output_segment='deposits')
-  combine.erase_combined = False
-  proc = event.adopt_action('DigiContainerSequenceAction/HitP2',
-                            parallel=False,
+  combine.erase_combined = True
+  proc = event.adopt_action('DigiContainerSequenceAction/HitP1',
+                            parallel=parallel,
                             input_mask=0xAAA0,
                             input_segment='deposits',
                             output_mask=0xEEE5,
                             output_segment='deposits')
-  combine = digi.create_action('DigiDepositWeightedPosition/DepoCombine')
+  combine = digi.create_action('DigiDepositWeightedPosition/WeightedPosition', OutputLevel=print_level)
   proc.adopt_container_processor(combine, digi.containers())
   conts = [c for c in digi.containers()]
   event.adopt_action('DigiContainerDrop/Drop',
diff --git a/examples/DDDigi/scripts/TestAttenuate.py b/examples/DDDigi/scripts/TestAttenuate.py
new file mode 100644
index 0000000000000000000000000000000000000000..5f857e446a7685c4fcbb4b562c85996d1174c9ba
--- /dev/null
+++ b/examples/DDDigi/scripts/TestAttenuate.py
@@ -0,0 +1,49 @@
+# ==========================================================================
+#  AIDA Detector description implementation
+# --------------------------------------------------------------------------
+# Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
+# All rights reserved.
+#
+# For the licensing terms see $DD4hepINSTALL/LICENSE.
+# For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
+#
+# ==========================================================================
+from __future__ import absolute_import
+from g4units import ns
+
+
+def run():
+  import DigiTest
+  digi = DigiTest.Test(geometry=None)
+  attenuation = digi.attenuation
+
+  input = digi.input_action('DigiParallelActionSequence/READER')
+  # ========================================================================================================
+  spillover = input.adopt_action('DigiSequentialActionSequence/Spillover-25')
+  evtreader = spillover.adopt_action('DigiDDG4ROOT/Reader-25ns', mask=0x1, input=[digi.next_input()], keep_raw=False)
+  attenuate = spillover.adopt_action('DigiAttenuatorSequence/Att-25ns',
+                                     t0=-25 * ns,
+                                     signal_decay='exponential',
+                                     processor_type='DigiAttenuator',
+                                     input_mask=evtreader.mask,
+                                     input_segment='inputs',
+                                     containers=attenuation)
+  hist_drop = spillover.adopt_action('DigiHitHistoryDrop/Drop-25ns', masks=[evtreader.mask])
+  digi.check_creation([spillover, evtreader, attenuate, hist_drop])
+  digi.info('Created input.spillover-25')
+  # ========================================================================================================
+  event = digi.event_action('DigiSequentialActionSequence/EventAction')
+  combine = event.adopt_action('DigiContainerCombine/Combine',
+                               input_masks=[0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6],
+                               input_segment='inputs',
+                               output_mask=0xFEED,
+                               output_segment='deposits')
+  evtdump = event.adopt_action('DigiStoreDump/StoreDump')
+  digi.check_creation([evtdump])
+  digi.info('Created event.dump')
+  # ========================================================================================================
+  digi.run_checked(num_events=5, num_threads=5, parallel=3)
+
+
+if __name__ == '__main__':
+  run()
diff --git a/examples/DDDigi/scripts/TestDepositSmearEnergy.py b/examples/DDDigi/scripts/TestDepositSmearEnergy.py
index cb375d6f623028628acef0d920c6954cbbc788fa..52622580d16e22243490b482ee9200c9a052f8a5 100644
--- a/examples/DDDigi/scripts/TestDepositSmearEnergy.py
+++ b/examples/DDDigi/scripts/TestDepositSmearEnergy.py
@@ -24,8 +24,7 @@ def run():
                             input_segment='deposits',
                             output_mask=0xFFF0,
                             output_segment='outputs')
-  smear = digi.create_action('DigiDepositSmearing/Smear')
-  smear.deposit_cutoff = 1e-55
+  smear = digi.create_action('DigiDepositSmearEnergy/Smear')
   #  sigma(E)[GeV]/E[GeV] = 0.02        (systematic) + 0.005 / sqrt(E[GeV]) (intrinsic) + 1keV/E[GeV] (instrumentation)
   #  sigma(E)[GeV]        = 0.02*E[GeV] (systematic) + 0.005 * sqrt(E[GeV]) (intrinsic) + 1keV (instrumentation)
   smear.intrinsic_fluctuation = 0.005 / math.sqrt(units.GeV)
@@ -33,7 +32,6 @@ def run():
   smear.instrumentation_resolution = 1 * units.keV
   smear.pair_ionisation_energy = 10 * units.eV
   smear.ionization_fluctuation = True
-  smear.update_in_place = False
   # proc.adopt_container_processor(smear, conts)
   proc.adopt_container_processor(smear, ['EcalBarrelHits', 'EcalEndcapHits', 'HcalBarrelHits'])
 
diff --git a/examples/DDDigi/scripts/TestDepositSmearTime.py b/examples/DDDigi/scripts/TestDepositSmearTime.py
index 48b68cc5c8347acb1b98d461406839755dc05b0e..81b98bd7b46a13864647ff95c4948b7463b1e30e 100644
--- a/examples/DDDigi/scripts/TestDepositSmearTime.py
+++ b/examples/DDDigi/scripts/TestDepositSmearTime.py
@@ -15,6 +15,7 @@ def run():
   import DigiTest
   from dd4hep import units
   digi = DigiTest.Test(geometry=None)
+  digi.kernel().OutputLevel = DigiTest.INFO
   digi.load_geo(volume_manager=True)
 
   event = DigiTest.test_setup_1(digi)
@@ -26,8 +27,7 @@ def run():
   smear = digi.create_action('DigiDepositSmearTime/Smear',
                              resolution_time=1e-6 * units.second)
   proc.adopt_container_processor(smear, ['SiVertexEndcapHits', 'SiVertexBarrelHits'])
-
-  event.adopt_action('DigiStoreDump/HeaderDump')
+  event.adopt_action('DigiStoreDump/HeaderDump', OutputLevel=DigiTest.INFO)
   # ========================================================================================================
   digi.info('Starting digitization core')
   digi.run_checked(num_events=3, num_threads=10, parallel=5)
diff --git a/examples/DDDigi/scripts/TestDepositWeighted.py b/examples/DDDigi/scripts/TestDepositWeighted.py
index 067eab2140dffcc6dca9799f9ea000899a988971..75e31f1f8ac39883cf61da845b4915fd43c4b8e0 100644
--- a/examples/DDDigi/scripts/TestDepositWeighted.py
+++ b/examples/DDDigi/scripts/TestDepositWeighted.py
@@ -15,21 +15,22 @@ def run():
   import DigiTest
   digi = DigiTest.Test(geometry=None)
 
+  rdr_output = DigiTest.DEBUG
   input = digi.input_action('DigiParallelActionSequence/READER')
   # ========================================================================================================
   digi.info('Created SIGNAL input')
-  signal = input.adopt_action('DigiDDG4ROOT/SignalReader', mask=0x0, input=[digi.next_input()])
+  signal = input.adopt_action('DigiDDG4ROOT/SignalReader', mask=0x0, input=[digi.next_input()], OutputLevel=rdr_output)
   digi.check_creation([signal])
   # ========================================================================================================
   digi.info('Creating collision overlays....')
   # ========================================================================================================
   overlay = input.adopt_action('DigiSequentialActionSequence/Overlay-1')
-  evtreader = overlay.adopt_action('DigiDDG4ROOT/Read-1', mask=0x1, input=[digi.next_input()])
+  evtreader = overlay.adopt_action('DigiDDG4ROOT/Read-1', mask=0x1, input=[digi.next_input()], OutputLevel=rdr_output)
   digi.check_creation([overlay, evtreader])
   digi.info('Created input.overlay-1')
   # ========================================================================================================
   overlay = input.adopt_action('DigiSequentialActionSequence/Overlay-2')
-  evtreader = overlay.adopt_action('DigiDDG4ROOT/Read-2', mask=0x2, input=[digi.next_input()])
+  evtreader = overlay.adopt_action('DigiDDG4ROOT/Read-2', mask=0x2, input=[digi.next_input()], OutputLevel=rdr_output)
   digi.check_creation([overlay, evtreader])
   digi.info('Created input.overlay-2')
   # ========================================================================================================
diff --git a/examples/DDDigi/scripts/TestPositionSmearTrack.py b/examples/DDDigi/scripts/TestPositionSmearTrack.py
index 4b5a0b3d33f57acb615cd33b3fb9a81d12e8d1d7..17c5b01857b8c5417ba156e7f73bb1c90039f26f 100644
--- a/examples/DDDigi/scripts/TestPositionSmearTrack.py
+++ b/examples/DDDigi/scripts/TestPositionSmearTrack.py
@@ -17,14 +17,13 @@ def run():
   digi = DigiTest.Test(geometry=None)
   digi.load_geo(volume_manager=True)
 
-  event = DigiTest.test_setup_1(digi)
+  event = DigiTest.test_setup_1(digi, print_level=DigiTest.INFO, parallel=False)
   # ========================================================================================================
   proc = event.adopt_action('DigiContainerSequenceAction/Smearing',
                             parallel=False,
                             input_mask=0xEEE5,
                             input_segment='deposits')
   smear = digi.create_action('DigiDepositSmearPositionTrack/Smear',
-                             deposit_cutoff=1e-55 * units.MeV,
                              resolution_u=1e-2 * units.mm,
                              resolution_v=1e-2 * units.mm)
   proc.adopt_container_processor(smear, ['SiVertexEndcapHits', 'SiVertexBarrelHits',
diff --git a/examples/DDDigi/scripts/TestProperties.py b/examples/DDDigi/scripts/TestProperties.py
index b0d2cce05f4d29c8fa7d81bc820c7d765af82469..caf1a67cc2eb0f8799df0eca646258ceb1b6ff95 100644
--- a/examples/DDDigi/scripts/TestProperties.py
+++ b/examples/DDDigi/scripts/TestProperties.py
@@ -20,74 +20,122 @@ def yes_no(val):
 def run():
   import DigiTest
   digi = DigiTest.Test(geometry=None)
+  info = digi.info
+  num_tests = 0
+  histo = digi.create_action('DigiDepositEnergyMonitor/TestHisto')
+  histo.histo1D_deposits = ("Energy", u"Some main deposit Title", 101, -0.5, 100.5)
+  num_tests = num_tests + 1
+  histo.histo1D_delta    = ("Delta",  u"Some delta Title", 50, -5, 5)
+  num_tests = num_tests + 1
+  histo.printProperties()
+  info('property: histo1D_deposits =       %s [%s]' %
+       (str(histo.histo1D_deposits), str(histo.histo1D_deposits.__class__),))
+  num_tests = num_tests + 1
+
   input = digi.input_action('DigiParallelActionSequence/Test')
 
   input.add_property('property_int', 1)
-  print('property: has_property =    %s' % (yes_no(input.hasProperty('property_int')),))
-  print('property: property_int =    %s' % (str(input.property_int),))
+  info('property: has_property =           %s  [%s]' %
+       (yes_no(input.hasProperty('property_int')), str(input.property_int.__class__),))
+  info('property: property_int =           %s' % (str(input.property_int),))
   input.property_int = 123456
-  print('property: property_int =    %s' % (str(input.property_int),))
+  info('property: property_int =           %s' % (str(input.property_int),))
+  if input.hasProperty('property_int'):
+    num_tests = num_tests + 1
 
   input.add_vector_property('property_vector_int', [1, 2, 3])
-  print('property: has_property =           %s' % (yes_no(input.hasProperty('property_vector_int')),))
-  print('property: property_vector_int =    %s' % (str(input.property_vector_int),))
+  info('property: has_property =           %s [%s]' %
+       (yes_no(input.hasProperty('property_vector_int')), str(input.property_vector_int.__class__), ))
+  info('property: property_vector_int =    %s' % (str(input.property_vector_int),))
   input.property_vector_int = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
-  print('property: property_vector_int =    %s' % (str(input.property_vector_int),))
+  info('property: property_vector_int =    %s' % (str(input.property_vector_int),))
+  if input.hasProperty('property_vector_int'):
+    num_tests = num_tests + 1
 
   input.add_list_property('property_list_int', [1, 2, 3])
-  print('property: has_property =           %s' % (yes_no(input.hasProperty('property_list_int')),))
-  print('property: property_list_int =      %s' % (str(input.property_list_int),))
+  info('property: has_property =           %s [%s]' %
+       (yes_no(input.hasProperty('property_list_int')), str(input.property_list_int.__class__),))
+  info('property: property_list_int =      %s' % (str(input.property_list_int),))
   input.property_list_int = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
-  print('property: property_list_int =      %s' % (str(input.property_list_int),))
+  info('property: property_list_int =      %s' % (str(input.property_list_int),))
+  if input.hasProperty('property_list_int'):
+    num_tests = num_tests + 1
 
   input.add_set_property('property_set_int', [1, 2, 3])
-  print('property: has_property =           %s' % (yes_no(input.hasProperty('property_set_int')),))
-  print('property: property_set_int =       %s' % (str(input.property_set_int),))
+  info('property: has_property =           %s [%s]' %
+       (yes_no(input.hasProperty('property_set_int')), str(input.property_set_int.__class__),))
+  info('property: property_set_int =       %s' % (str(input.property_set_int),))
   input.property_set_int = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
-  print('property: property_set_int =       %s' % (str(input.property_set_int),))
+  info('property: property_set_int =       %s' % (str(input.property_set_int),))
+  if input.hasProperty('property_set_int'):
+    num_tests = num_tests + 1
 
   input.add_property('property_double', 1.0)
-  print('property: has_property =           %s' % (yes_no(input.hasProperty('property_double')),))
-  print('property: property_double =        %s' % (str(input.property_double),))
+  info('property: has_property =           %s [%s]' %
+       (yes_no(input.hasProperty('property_double')), str(input.property_double.__class__),))
+  info('property: property_double =        %s' % (str(input.property_double),))
   input.property_double = 123456.7
-  print('property: property_double =        %s' % (str(input.property_double),))
+  info('property: property_double =        %s' % (str(input.property_double),))
+  if input.hasProperty('property_double'):
+    num_tests = num_tests + 1
 
   input.add_vector_property('property_vector_double', [1.1, 2, 3])
-  print('property: has_property =           %s' % (yes_no(input.hasProperty('property_vector_double')),))
-  print('property: property_vector_double = %s' % (str(input.property_vector_double),))
+  info('property: has_property =           %s [%s]' %
+       (yes_no(input.hasProperty('property_vector_double')), str(input.property_vector_double.__class__),))
+  info('property: property_vector_double = %s' % (str(input.property_vector_double),))
   input.property_vector_double = [1.5, 2, 3, 4, 5, 6, 7, 8, 9, 0]
-  print('property: property_vector_double = %s' % (str(input.property_vector_double),))
+  info('property: property_vector_double = %s' % (str(input.property_vector_double),))
+  if input.hasProperty('property_vector_double'):
+    num_tests = num_tests + 1
 
   input.add_list_property('property_list_double', [1.1, 2, 3])
-  print('property: has_property =           %s' % (yes_no(input.hasProperty('property_list_double')),))
-  print('property: property_list_double =   %s' % (str(input.property_list_double),))
+  info('property: has_property =           %s [%s]' %
+       (yes_no(input.hasProperty('property_list_double')), str(input.property_list_double.__class__), ))
+  info('property: property_list_double =   %s' % (str(input.property_list_double),))
   input.property_list_double = [1.5, 2, 3, 4, 5, 6, 7, 8, 9, 0]
-  print('property: property_list_double =   %s' % (str(input.property_list_double),))
+  info('property: property_list_double =   %s' % (str(input.property_list_double),))
+  if input.hasProperty('property_list_double'):
+    num_tests = num_tests + 1
 
   input.add_set_property('property_set_double', [1.1, 2, 3])
-  print('property: has_property =           %s' % (yes_no(input.hasProperty('property_set_double')),))
-  print('property: property_set_double =    %s' % (str(input.property_set_double),))
+  info('property: has_property =           %s [%s]' %
+       (yes_no(input.hasProperty('property_set_double')), str(input.property_set_double.__class__),))
+  info('property: property_set_double =    %s' % (str(input.property_set_double),))
   input.property_set_double = [1.5, 2, 3, 4, 5, 6, 7, 8, 9, 0]
-  print('property: property_set_double =    %s' % (str(input.property_set_double),))
+  info('property: property_set_double =    %s' % (str(input.property_set_double),))
+  if input.hasProperty('property_set_double'):
+    num_tests = num_tests + 1
 
   input.add_property('property_string', "string_1")
-  print('property: has_property =           %s' % (yes_no(input.hasProperty('property_string')),))
-  print('property: property_string =        %s' % (input.property_string,))
+  info('property: has_property =           %s [%s]' % 
+       (yes_no(input.hasProperty('property_string')), str(input.property_string.__class__),))
+  info('property: property_string =        %s' % (input.property_string,))
   input.property_string = "string_1123456"
-  print('property: property_string =        %s' % (input.property_string,))
+  info('property: property_string =        %s' % (input.property_string,))
+  if input.hasProperty('property_string'):
+    num_tests = num_tests + 1
 
   input.add_vector_property('property_vector_string', ["string1", "string2", "string3"])
-  print('property: has_property =           %s' % (yes_no(input.hasProperty('property_vector_string')),))
-  print('property: property_vector_string = %s' % (input.property_vector_string,))
+  info('property: has_property =           %s [%s]' %
+       (yes_no(input.hasProperty('property_vector_string')), str(input.property_vector_string.__class__),))
+  info('property: property_vector_string = %s' % (input.property_vector_string,))
   input.property_vector_string = ["string1", "string2", "string3", "string4", "string5", "string6"]
-  print('property: property_vector_string = %s' % (input.property_vector_string,))
+  info('property: property_vector_string = %s' % (input.property_vector_string,))
+  if input.hasProperty('property_vector_string'):
+    num_tests = num_tests + 1
 
   input.add_position_property('property_position', (1., 2., 3.))
-  print('property: has_property =           %s' % (yes_no(input.hasProperty('property_position')),))
-  print('property: property_position =      %s' % (input.property_position,))
+  info('property: has_property =           %s [%s]' %
+       (yes_no(input.hasProperty('property_position')), str(input.property_position.__class__),))
+  info('property: property_position =      %s' % (input.property_position,))
   input.property_position = (111.1, 222.2, 333.3)
-  print('property: property_position =      %s' % (input.property_position,))
+  info('property: property_position =      %s' % (input.property_position,))
+  if input.hasProperty('property_position'):
+    num_tests = num_tests + 1
 
+  info('We checked %d properties interactions.' % (num_tests,))
+  if num_tests == 14:
+    info('Property test PASSED')
 
 if __name__ == '__main__':
   run()
diff --git a/examples/DDDigi/scripts/TestSpillover.py b/examples/DDDigi/scripts/TestSpillover.py
index dd3a9a4b3c1c0845ecb95bd07229e731484cf2bf..4379c5177c1490918a0660c80f2b6f78901820d5 100644
--- a/examples/DDDigi/scripts/TestSpillover.py
+++ b/examples/DDDigi/scripts/TestSpillover.py
@@ -16,16 +16,16 @@ def run():
   import DigiTest
   digi = DigiTest.Test(geometry=None)
   attenuation = digi.attenuation
-
+  rdr_output = DigiTest.DEBUG
   input = digi.input_action('DigiParallelActionSequence/READER')
   # ========================================================================================================
-  input.adopt_action('DigiDDG4ROOT/SignalReader', mask=0x0, input=[digi.next_input()])
+  input.adopt_action('DigiDDG4ROOT/SignalReader', mask=0x0, input=[digi.next_input()], OutputLevel=rdr_output)
   digi.info('Created input.signal')
   # ========================================================================================================
   digi.info('Creating spillover sequence for EARLIER bunch crossings.....')
   # ========================================================================================================
   spillover = input.adopt_action('DigiSequentialActionSequence/Spillover-25')
-  evtreader = spillover.adopt_action('DigiDDG4ROOT/Reader-25ns', mask=0x1, input=[digi.next_input()])
+  evtreader = spillover.adopt_action('DigiDDG4ROOT/Reader-25ns', mask=0x1, input=[digi.next_input()], OutputLevel=rdr_output)
   attenuate = spillover.adopt_action('DigiAttenuatorSequence/Att-25ns',
                                      t0=-25 * ns,
                                      signal_decay='exponential',
@@ -38,17 +38,17 @@ def run():
   digi.info('Created input.spillover-25')
   # ========================================================================================================
   spillover = input.adopt_action('DigiSequentialActionSequence/Spillover-50')
-  evtreader = spillover.adopt_action('DigiDDG4ROOT/Reader-50ns', mask=0x2, input=[digi.next_input()])
+  evtreader = spillover.adopt_action('DigiDDG4ROOT/Reader-50ns', mask=0x2, input=[digi.next_input()], OutputLevel=rdr_output)
   attenuate = spillover.adopt_action('DigiAttenuatorSequence/Att-50ns',
-                                     t0=-50 * ns, input_mask=evtreader.mask, containers=attenuation)
+                                     t0=-50 * ns, input_mask=evtreader.mask, containers=attenuation, OutputLevel=rdr_output)
   hist_drop = spillover.adopt_action('DigiHitHistoryDrop/Drop-50ns', masks=[evtreader.mask])
   digi.check_creation([spillover, evtreader, attenuate, hist_drop])
   digi.info('Created input.spillover-50')
   # ========================================================================================================
   spillover = input.adopt_action('DigiSequentialActionSequence/Spillover-75')
-  evtreader = spillover.adopt_action('DigiDDG4ROOT/Reader-75ns', mask=0x3, input=[digi.next_input()])
+  evtreader = spillover.adopt_action('DigiDDG4ROOT/Reader-75ns', mask=0x3, input=[digi.next_input()], OutputLevel=rdr_output)
   attenuate = spillover.adopt_action('DigiAttenuatorSequence/Att-75ns',
-                                     t0=-75 * ns, input_mask=evtreader.mask, containers=attenuation)
+                                     t0=-75 * ns, input_mask=evtreader.mask, containers=attenuation, OutputLevel=rdr_output)
   hist_drop = spillover.adopt_action('DigiHitHistoryDrop/Drop-75ns', masks=[evtreader.mask])
   digi.check_creation([spillover, evtreader, attenuate, hist_drop])
   digi.info('Created input.spillover-75')
@@ -56,25 +56,25 @@ def run():
   digi.info('Creating spillover sequence for LATER bunch crossings.....')
   # ========================================================================================================
   spillover = input.adopt_action('DigiSequentialActionSequence/Spillover+25')
-  evtreader = spillover.adopt_action('DigiDDG4ROOT/Reader+25ns', mask=0x4, input=[digi.next_input()])
+  evtreader = spillover.adopt_action('DigiDDG4ROOT/Reader+25ns', mask=0x4, input=[digi.next_input()], OutputLevel=rdr_output)
   attenuate = spillover.adopt_action('DigiAttenuatorSequence/Att+25ns',
-                                     t0=25 * ns, input_mask=evtreader.mask, containers=attenuation)
+                                     t0=25 * ns, input_mask=evtreader.mask, containers=attenuation, OutputLevel=rdr_output)
   hist_drop = spillover.adopt_action('DigiHitHistoryDrop/Drop+25ns', masks=[evtreader.mask])
   digi.check_creation([spillover, evtreader, attenuate, hist_drop])
   digi.info('Created input.spillover+25')
   # ========================================================================================================
   spillover = input.adopt_action('DigiSequentialActionSequence/Spillover+50')
-  evtreader = spillover.adopt_action('DigiDDG4ROOT/Reader+50ns', mask=0x5, input=[digi.next_input()])
+  evtreader = spillover.adopt_action('DigiDDG4ROOT/Reader+50ns', mask=0x5, input=[digi.next_input()], OutputLevel=rdr_output)
   attenuate = spillover.adopt_action('DigiAttenuatorSequence/Att+50ns',
-                                     t0=50 * ns, input_mask=evtreader.mask, containers=attenuation)
+                                     t0=50 * ns, input_mask=evtreader.mask, containers=attenuation, OutputLevel=rdr_output)
   hist_drop = spillover.adopt_action('DigiHitHistoryDrop/Drop_50ns', masks=[evtreader.mask])
   digi.check_creation([spillover, evtreader, attenuate, hist_drop])
   digi.info('Created input.spillover+50')
   # ========================================================================================================
   spillover = input.adopt_action('DigiSequentialActionSequence/Spillover+75')
-  evtreader = spillover.adopt_action('DigiDDG4ROOT/Reader+75ns', mask=0x6, input=[digi.next_input()])
+  evtreader = spillover.adopt_action('DigiDDG4ROOT/Reader+75ns', mask=0x6, input=[digi.next_input()], OutputLevel=rdr_output)
   attenuate = spillover.adopt_action('DigiAttenuatorSequence/Att+75ns',
-                                     t0=75 * ns, input_mask=evtreader.mask, containers=attenuation)
+                                     t0=75 * ns, input_mask=evtreader.mask, containers=attenuation, OutputLevel=rdr_output)
   hist_drop = spillover.adopt_action('DigiHitHistoryDrop/Drop+75ns', masks=[evtreader.mask])
   digi.check_creation([spillover, evtreader, attenuate, hist_drop])
   digi.info('Created input.spillover+75')
diff --git a/examples/DDG4/CMakeLists.txt b/examples/DDG4/CMakeLists.txt
index 4634ff08eeef2f2d75de239bd38f85be3b9b2280..8ca826955779edcc01d7bd5b16835b030202295b 100644
--- a/examples/DDG4/CMakeLists.txt
+++ b/examples/DDG4/CMakeLists.txt
@@ -95,4 +95,12 @@ if (DD4HEP_USE_GEANT4)
     REGEX_PASS " \\[2\\] Calling classifyNewTrack. StackManager"
     REGEX_FAIL " ERROR ;EXCEPTION;Exception"
   )
+  #
+  # Test G4 command UI
+  dd4hep_add_test_reg( DDG4_UIManager
+    COMMAND    "${CMAKE_INSTALL_PREFIX}/bin/run_test_DDG4.sh"
+    EXEC_ARGS  ${Python_EXECUTABLE} ${DDG4examples_INSTALL}/scripts/TestUserCommands.py
+    REGEX_PASS " Parameter value at call 13 is 'terminate-command-2'"
+    REGEX_FAIL " ERROR ;EXCEPTION;Exception"
+  )
 endif()
diff --git a/examples/DDG4/scripts/TestUserCommands.py b/examples/DDG4/scripts/TestUserCommands.py
new file mode 100644
index 0000000000000000000000000000000000000000..04a9dafa48b67b91c9677065ffc85e4f793f238e
--- /dev/null
+++ b/examples/DDG4/scripts/TestUserCommands.py
@@ -0,0 +1,117 @@
+# ==========================================================================
+#  AIDA Detector description implementation
+# --------------------------------------------------------------------------
+# Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
+# All rights reserved.
+#
+# For the licensing terms see $DD4hepINSTALL/LICENSE.
+# For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
+#
+# ==========================================================================
+#
+from __future__ import absolute_import, unicode_literals
+import logging
+#
+logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.INFO)
+logger = logging.getLogger(__name__)
+#
+#
+"""
+
+   dd4hep simulation example setup using the python configuration
+
+   @author  M.Frank
+   @version 1.0
+
+"""
+
+
+def run():
+  import os
+  import DDG4
+  from DDG4 import OutputLevel as Output
+  from g4units import keV
+
+  args = DDG4.CommandLine()
+  if args.help:
+    import sys
+    logger.info("""
+         python <dir>/TestUserCommands.py -option [-option]
+              -vis                            Enable visualization
+              -macro                          Pass G4 macro file to UI executive
+    """)
+    sys.exit(0)
+
+
+  kernel = DDG4.Kernel()
+  kernel.loadGeometry(str("file:" + os.environ['DD4hepExamplesINSTALL'] + "/examples/ClientTests/compact/BoxTrafos.xml"))
+  geant4 = DDG4.Geant4(kernel)
+  # Configure UI
+  if args.macro:
+    ui = geant4.setupCshUI(macro=args.macro, vis=args.vis)
+  else:
+    ui = geant4.setupCshUI(vis=args.vis)
+
+  ui.HaveUI = False
+
+  ui.ConfigureCommands = [
+    '/ddg4/Print/param configure-command-1',
+    '/ddg4/Print/print_param',
+    '/ddg4/Print/param configure-command-2',
+    '/ddg4/Print/print_param'
+  ]
+  ui.InitializeCommands = [
+    '/ddg4/Print/param initialize-command-1',
+    '/ddg4/Print/print_param',
+    '/ddg4/Print/param initialize-command-2',
+    '/ddg4/Print/print_param'
+  ]
+  ui.PreRunCommands = [
+    '/ddg4/Print/param pre-run-command-1',
+    '/ddg4/Print/print_param',
+    '/ddg4/Print/param pre-run-command-2',
+    '/ddg4/Print/print_param'
+  ]
+  ui.TerminateCommands = [
+    '/ddg4/Print/param terminate-command-1',
+    '/ddg4/Print/print_param',
+    '/ddg4/Print/param terminate-command-2',
+    '/ddg4/Print/print_param',
+    '/ddg4/UI/terminate']
+  # Post-run commands are only executed in interactive mode!
+  ui.PostRunCommands = [
+    '/ddg4/Print/param post-run-command-1',
+    '/ddg4/Print/print_param',
+    '/ddg4/Print/param post-run-command-2',
+    '/ddg4/Print/print_param'
+  ]
+
+  prt = DDG4.Action(kernel, 'TestPrintAction/Print')
+  prt.enableUI()
+  kernel.registerGlobalAction(prt)
+
+  ui.applyCommand('/ddg4/Print/param interactive-1')
+  ui.applyCommand('/ddg4/Print/print_param')
+
+  # Now build the physics list:
+  phys = geant4.setupPhysics('QGSP_BERT')
+  logger.info('# Execute some G4 action using the UI handle from DDG4....')
+  geant4.ui().applyCommand('/ddg4/Print/param interactive-2')
+  geant4.ui().applyCommand('/ddg4/Print/print_param')
+
+  # Start the engine...
+  logger.info("# No we should see the configuration commands:")
+  kernel.configure()
+  logger.info("# No we should see the initialization commands:")
+  kernel.initialize()
+  kernel.NumEvents = 0
+  logger.info("# No we should see the pre-run commands:")
+  kernel.run()
+  logger.info("# No we should see the termination commands:")
+  ui.applyCommand('/ddg4/Print/param interactive-3')
+  ui.applyCommand('/ddg4/Print/print_param')
+  kernel.terminate()
+
+
+if __name__ == "__main__":
+  run()
diff --git a/examples/DDG4/src/TestPrintAction.cpp b/examples/DDG4/src/TestPrintAction.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7a7ca844a5592bb97fbbdf41a62628b59b6ff921
--- /dev/null
+++ b/examples/DDG4/src/TestPrintAction.cpp
@@ -0,0 +1,58 @@
+//==========================================================================
+//  AIDA Detector description implementation 
+//--------------------------------------------------------------------------
+// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
+// All rights reserved.
+//
+// For the licensing terms see $DD4hepINSTALL/LICENSE.
+// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
+//
+// Author     : M.Frank
+//
+//==========================================================================
+
+// Framework include files
+#include "DDG4/Geant4Action.h"
+#include "DDG4/Geant4UIMessenger.h"
+
+/// Namespace for the AIDA detector description toolkit
+namespace dd4hep {
+
+  /// Namespace for the Geant4 based simulation part of the AIDA detector description toolkit
+  namespace sim {
+    
+    /// Class to print message for debugging
+    /** Class to print message for debugging
+     *
+     *  \author  M.Frank
+     *  \version 1.0
+     *  \ingroup DD4HEP_SIMULATION
+     */
+    class TestPrintAction : public Geant4Action {
+      int num_calls { 0 };
+      std::string param  { "Uninitalized" };
+    public:
+      /// Standard constructor
+      TestPrintAction(Geant4Context* context, const std::string& nam)
+	: Geant4Action(context, nam) 
+      {
+	declareProperty("param", param);
+      }
+      /// Default destructor
+      virtual ~TestPrintAction()   {
+      }
+      /// Messenger callback
+      void print_par()   {
+	always("Parameter value at call %d is '%s'", ++num_calls, param.c_str());
+      }
+      /// Install command control messenger to write GDML file from command prompt.
+      virtual void installCommandMessenger()  override {
+	m_control->addCall("print_param", "Printing some increasing parameter",
+			   Callback(this).make(&TestPrintAction::print_par),0);
+      }
+    };
+  }    // End namespace sim
+}      // End namespace dd4hep
+
+#include "DDG4/Factories.h"
+DECLARE_GEANT4ACTION_NS(dd4hep::sim,TestPrintAction)