From 47085c0cefdabfc94d7c2b6f167e2064356b198e Mon Sep 17 00:00:00 2001
From: Markus Frank <Markus.Frank@cern.ch>
Date: Mon, 17 Oct 2022 18:43:56 +0200
Subject: [PATCH] Improve parallelization. No event dependent variables in
 actors

---
 DDDigi/CMakeLists.txt                         |   4 +-
 DDDigi/include/DDDigi/DigiData.h              |  40 +++--
 DDDigi/include/DDDigi/DigiKernel.h            |  41 ++---
 .../DDDigi/DigiMultiContainerProcessor.h      |  70 ++------
 DDDigi/include/DDDigi/DigiParallelWorker.h    |  81 ++++++++++
 DDDigi/include/DDDigi/DigiSegmentAction.h     |  24 +--
 ...tationSplitter.h => DigiSegmentSplitter.h} |  63 +++++---
 DDDigi/include/DDDigi/DigiSynchronize.h       |  16 +-
 DDDigi/plugins/Components.cpp                 |   4 +-
 DDDigi/plugins/DigiSegmentDepositPrint.cpp    |  10 +-
 DDDigi/python/dddigi.py                       |   1 +
 DDDigi/src/DigiData.cpp                       |  18 +++
 DDDigi/src/DigiHandle.cpp                     |   2 +-
 DDDigi/src/DigiKernel.cpp                     |  30 ++--
 DDDigi/src/DigiMultiContainerProcessor.cpp    |  52 +++---
 DDDigi/src/DigiSegmentAction.cpp              |  37 +++++
 DDDigi/src/DigiSegmentSplitter.cpp            | 138 ++++++++++++++++
 DDDigi/src/DigiSegmentationSplitter.cpp       | 149 ------------------
 DDDigi/src/DigiSynchronize.cpp                |  26 ++-
 examples/DDDigi/scripts/DigiTest.py           |  16 +-
 .../scripts/TestMultiContainerParallel.py     |  19 +--
 .../DDDigi/scripts/TestSegmentationSplit.py   |  10 +-
 22 files changed, 473 insertions(+), 378 deletions(-)
 create mode 100644 DDDigi/include/DDDigi/DigiParallelWorker.h
 rename DDDigi/include/DDDigi/{DigiSegmentationSplitter.h => DigiSegmentSplitter.h} (57%)
 create mode 100644 DDDigi/src/DigiSegmentAction.cpp
 create mode 100644 DDDigi/src/DigiSegmentSplitter.cpp
 delete mode 100644 DDDigi/src/DigiSegmentationSplitter.cpp

diff --git a/DDDigi/CMakeLists.txt b/DDDigi/CMakeLists.txt
index 8026b13af..e7a4e3803 100644
--- a/DDDigi/CMakeLists.txt
+++ b/DDDigi/CMakeLists.txt
@@ -51,13 +51,13 @@ if (DD4HEP_USE_GEANT4)
   dd4hep_add_dictionary(G__DDDigi_DDG4_IO
     SOURCES ../DDCore/include/ROOT/Warnings.h ddg4/IO.cpp
     LINKDEF ../DDCore/include/ROOT/LinkDef.h
-    USES    DD4hep::DDG4 
+    USES    DD4hep::DDG4 DD4hep::DDCore
     )
 
   dd4hep_add_plugin(DDDigi_DDG4_IO
     SOURCES        ddg4/*.cpp
     GENERATED      G__DDDigi_DDG4_IO.cxx
-    USES           DD4hep::DDDigi
+    USES           DD4hep::DDDigi DD4hep::DDG4 DD4hep::DDCore
     )
 else()
   dd4hep_print( "|++> Geant4 not used. DDDigi will not be able to read DDG4 output.")
diff --git a/DDDigi/include/DDDigi/DigiData.h b/DDDigi/include/DDDigi/DigiData.h
index 72d63000f..55d30ca12 100644
--- a/DDDigi/include/DDDigi/DigiData.h
+++ b/DDDigi/include/DDDigi/DigiData.h
@@ -84,37 +84,47 @@ namespace dd4hep {
       /// Operator greator
       bool operator > (const Key&)   const;
 
+      /// Generate key using hash algorithm
+      void set(const std::string& name, int mask);
+
       /// Conversion to uint64
       key_type toLong()  const  {
 	return key;
       }
-      /// Project the mask part of the key
-      itemkey_type item()  {
-	return this->values.item;
-      }
+
       /// Project the item part of the key
       mask_type mask()  {
 	return this->values.mask;
       }
-      /// Generate key using hash algorithm
-      void set(const std::string& name, int mask);
-      
-      /// Project the mask part of the key
-      static itemkey_type item(key_type k)  {
-	return Key(k).values.item;
+      /// Set key mask
+      void set_mask(Key k)  {
+	this->values.mask = k.values.mask;
+      }
+      /// Set key mask
+      void set_mask(mask_type m)  {
+	this->values.mask = m;
       }
       /// Project the item part of the key
       static mask_type mask(key_type k)  {
 	return Key(k).values.mask;
       }
-      /// Project the mask part of the key
-      static itemkey_type item(Key k)  {
-	return k.values.item;
-      }
       /// Project the item part of the key
       static mask_type mask(Key k)  {
 	return k.values.mask;
       }
+
+      /// Project the mask part of the key
+      itemkey_type item()  {
+	return this->values.item;
+      }
+      /// Project the mask part of the key
+      static itemkey_type item(key_type k)  {
+	return Key(k).values.item;
+      }
+      /// Project the mask part of the key
+      static itemkey_type item(Key k)  {
+	return k.values.item;
+      }
       /// Access key name (if registered properly)
       static std::string key_name(const Key& key);
     };
@@ -350,6 +360,8 @@ namespace dd4hep {
       DepositMapping& operator=(const DepositMapping& copy) = default;      
       /// Merge new deposit map onto existing map (not thread safe!)
       std::size_t merge(DepositMapping&& updates);
+      /// Merge new deposit map onto existing map (not thread safe!)
+      std::size_t merge(DepositVector&& updates);
     };
 
     /// Initializing constructor
diff --git a/DDDigi/include/DDDigi/DigiKernel.h b/DDDigi/include/DDDigi/DigiKernel.h
index 0bd549d99..6cc5b9129 100644
--- a/DDDigi/include/DDDigi/DigiKernel.h
+++ b/DDDigi/include/DDDigi/DigiKernel.h
@@ -27,6 +27,7 @@ namespace dd4hep {
   namespace digi {
 
     /// Forward declarations
+    class DigiAction;
     class DigiActionSequence;
     
     /// Class, which allows all DigiAction derivatives to access the DDG4 kernel structures.
@@ -42,24 +43,22 @@ namespace dd4hep {
       typedef std::map<std::string,int>                 ClientOutputLevels;
       typedef std::pair<void*, const std::type_info*>   UserFramework;
 
-      class CallWrapper     {
+      class ParallelCall     {
       public:
-	CallWrapper* worker { nullptr };
-      public:
-	CallWrapper(CallWrapper* worker);
-        CallWrapper() = default;
-	CallWrapper(CallWrapper&& copy) = default;
-	CallWrapper(const CallWrapper& copy) = default;
-	CallWrapper& operator=(CallWrapper&& copy) = delete;
-	CallWrapper& operator=(const CallWrapper& copy) = delete;
-	virtual ~CallWrapper() = default;
-	virtual void operator()() const;
+        ParallelCall(ParallelCall* p, void* a);
+        ParallelCall() = default;
+	ParallelCall(ParallelCall&& copy) = default;
+	ParallelCall(const ParallelCall& copy) = default;
+	ParallelCall& operator=(ParallelCall&& copy) = default;
+	ParallelCall& operator=(const ParallelCall& copy) = default;
+	virtual ~ParallelCall() = default;
+	virtual void execute(void* args) const = 0;
       };
 
     private:
       class Internals;
       class Processor;
-      class Wrapper;
+      template <typename ACTION, typename ARGUMENT> class Wrapper;
 
       /// Internal only data structures;
       Internals*            internals   { nullptr };
@@ -164,29 +163,19 @@ namespace dd4hep {
       DigiActionSequence& outputAction() const;
 
       /// Submit a bunch of actions to be executed in parallel
-      virtual void submit (const std::vector<CallWrapper*>& algorithms)  const;
+      virtual void submit (const std::vector<ParallelCall*>& algorithms, void* data)  const;
       /// Submit a bunch of actions to be executed serially
-      virtual void execute(const std::vector<CallWrapper*>& algorithms)  const;
-
+      virtual void execute(const std::vector<ParallelCall*>& algorithms, void* data)  const;
+#if 0
       /// Submit a bunch of actions to be executed in parallel
       virtual void submit (const DigiAction::Actors<DigiEventAction>& algorithms, DigiContext& context)  const;
       /// Submit a bunch of actions to be executed serially
       virtual void execute(const DigiAction::Actors<DigiEventAction>& algorithms, DigiContext& context)  const;
+#endif
       /// If running multithreaded: wait until the thread-group finished execution
       virtual void wait(DigiContext& context)   const;
 
     };
-  
-    inline DigiKernel::CallWrapper::CallWrapper(CallWrapper* w)
-      : worker(w)
-    {
-    }
-
-    inline void DigiKernel::CallWrapper::operator()() const   {
-      if ( this->worker )   {
-	(*this->worker)();
-      }
-    }
 
     /// Declare property
     template <typename T> inline DigiKernel& DigiKernel::declareProperty(const std::string& nam, T& val) {
diff --git a/DDDigi/include/DDDigi/DigiMultiContainerProcessor.h b/DDDigi/include/DDDigi/DigiMultiContainerProcessor.h
index 1b0c7c0ed..4784853e5 100644
--- a/DDDigi/include/DDDigi/DigiMultiContainerProcessor.h
+++ b/DDDigi/include/DDDigi/DigiMultiContainerProcessor.h
@@ -15,8 +15,8 @@
 
 // Framework include files
 #include <DDDigi/DigiData.h>
-#include <DDDigi/DigiKernel.h>
-#include <DDDigi/DigiActionSequence.h>
+#include <DDDigi/DigiEventAction.h>
+#include <DDDigi/DigiParallelWorker.h>
 
 /// C/C++ include files
 #include <set>
@@ -27,47 +27,6 @@ namespace dd4hep {
   /// Namespace for the Digitization part of the AIDA detector description toolkit
   namespace digi {
 
-    /// Wrapper class to submit bulk actions
-    /**
-     *
-     *  \author  M.Frank
-     *  \version 1.0
-     *  \ingroup DD4HEP_SIMULATION
-     */
-    template <typename ACTION_TYPE, typename OPTIONS> 
-      class DigiParallelWorker : public DigiKernel::CallWrapper   {
-      ACTION_TYPE* processor  { nullptr };
-    public:
-      OPTIONS options;
-
-    public:
-      DigiParallelWorker(ACTION_TYPE* p, const OPTIONS& opts);
-      DigiParallelWorker() = default;
-      DigiParallelWorker(DigiParallelWorker&& copy) = default;
-      DigiParallelWorker(const DigiParallelWorker& copy) = delete;
-      DigiParallelWorker& operator=(DigiParallelWorker&& copy) = delete;
-      DigiParallelWorker& operator=(const DigiParallelWorker& copy) = delete;
-      virtual ~DigiParallelWorker();
-      const char* name()  const {  return processor->name().c_str(); }
-      virtual void operator()() const override final;
-    };
-
-    template <typename ACTION_TYPE, typename OPTIONS>
-      DigiParallelWorker<ACTION_TYPE, OPTIONS>::DigiParallelWorker(ACTION_TYPE* p, const OPTIONS& opts)
-      : processor(p), options(opts)
-    {
-      processor->addRef();
-    }
-
-    template <typename ACTION_TYPE, typename OPTIONS>
-      DigiParallelWorker<ACTION_TYPE, OPTIONS>::~DigiParallelWorker()   {
-      if ( processor )  {
-	processor->release();
-	processor = nullptr;
-      }
-    }
-
-
     /// Worker base class to analyse containers from the input segment in parallel
     class DigiContainerProcessor : public DigiAction   {
 
@@ -76,20 +35,21 @@ namespace dd4hep {
       
     public:
       /// 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     { };
       /// Item keys required by this worker
-      std::vector<Key> m_work_keys;
+      std::vector<Key> m_container_keys  { };
 
     public:
       /// Standard constructor
       DigiContainerProcessor(const DigiKernel& kernel, const std::string& name);
       /// Main functional callback if specific work is known
       virtual void execute(DigiContext& context, WorkItems& work)  const;
+      /// Check if the work item is for us
+      bool use_container(Key key)  const;
     };
 
-
     /// Sequencer class to analyse containers from the input segment in parallel
     /**
      *
@@ -100,26 +60,22 @@ namespace dd4hep {
     class DigiMultiContainerProcessor : public DigiEventAction   {
     public:
       using WorkItems = DigiContainerProcessor::WorkItems;
-      struct ProcessorOptions  {
-	DigiContext*     context { nullptr };
-	WorkItems*       work    { nullptr };
-	std::vector<Key> keys    { };
+      struct CallData  {
+	DigiContext& context;
+	WorkItems&   work;
       };
-      using Worker  = DigiParallelWorker<DigiContainerProcessor,ProcessorOptions>;
-      using Workers = std::vector<std::unique_ptr<Worker> >;
-      using Callers = std::vector<DigiKernel::CallWrapper*>;
+      using Worker    = DigiParallelWorker<DigiContainerProcessor,CallData,int>;
+      using Workers   = std::vector<DigiKernel::ParallelCall*>;
 
     protected:
       /// Property: Input data segment name
       std::string       m_input_segment { "inputs" };
       /// Property: event masks to be handled
       std::vector<int>  m_input_masks  { };
-      /// Property: Allow for multiple workers accessing same container
-      bool              m_allow_duplicates   { true };
 
       std::set<Key>     m_work_items;
+      /// Array of sub-workers
       Workers           m_workers;
-      Callers           m_callers;
 
     protected:
        /// Define standard assignments and constructors
diff --git a/DDDigi/include/DDDigi/DigiParallelWorker.h b/DDDigi/include/DDDigi/DigiParallelWorker.h
new file mode 100644
index 000000000..5319335be
--- /dev/null
+++ b/DDDigi/include/DDDigi/DigiParallelWorker.h
@@ -0,0 +1,81 @@
+//==========================================================================
+//  AIDA Detector description implementation 
+//--------------------------------------------------------------------------
+// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
+// All rights reserved.
+//
+// For the licensing terms see $DD4hepINSTALL/LICENSE.
+// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
+//
+// Author     : M.Frank
+//
+//==========================================================================
+#ifndef DDDIGI_DIGIPARALLELWORKER_H
+#define DDDIGI_DIGIPARALLELWORKER_H
+
+/// Framework include files
+#include <DDDigi/DigiKernel.h>
+
+/// Namespace for the AIDA detector description toolkit
+namespace dd4hep {
+
+  /// Namespace for the Digitization part of the AIDA detector description toolkit
+  namespace digi {
+
+    /// Wrapper class to submit bulk actions
+    /**
+     *
+     *  \author  M.Frank
+     *  \version 1.0
+     *  \ingroup DD4HEP_SIMULATION
+     */
+    template <typename ACTION_TYPE, typename CALLDATA, typename OPTIONS>
+      class DigiParallelWorker : public DigiKernel::ParallelCall   {
+    public:
+      using action_t = ACTION_TYPE;
+      using options_t = OPTIONS;
+      using calldata_t = CALLDATA;
+
+      action_t* action;
+      options_t options;
+
+    public:
+      /// Initializing constructor
+      DigiParallelWorker(ACTION_TYPE* p, const OPTIONS& opts);
+      /// Default constructor
+      DigiParallelWorker() = delete;
+      /// Move constructor
+      DigiParallelWorker(DigiParallelWorker&& copy) = default;
+      /// Inhibit copy constructor
+      DigiParallelWorker(const DigiParallelWorker& copy) = default;
+      /// Inhibit move assignment
+      DigiParallelWorker& operator=(DigiParallelWorker&& copy) = delete;
+      /// Inhibit copy assignment
+      DigiParallelWorker& operator=(const DigiParallelWorker& copy) = delete;
+      /// Default destructor
+      virtual ~DigiParallelWorker();
+      /// Access to processor name
+      const char* name()  const {  return action->name().c_str();   }
+      /// Callback on data
+      virtual void execute(void* data) const override;
+    };
+
+    /// Initializing constructor
+    template <typename ACTION_TYPE, typename CALLDATA, typename OPTIONS>
+      DigiParallelWorker<ACTION_TYPE, CALLDATA, OPTIONS>::DigiParallelWorker(ACTION_TYPE* proc, const OPTIONS& opts)
+      : ParallelCall(), action(proc), options(opts)
+    {
+      action->addRef();
+    }
+
+    /// Default destructor
+    template <typename ACTION_TYPE, typename CALLDATA, typename OPTIONS>
+      DigiParallelWorker<ACTION_TYPE, CALLDATA, OPTIONS>::~DigiParallelWorker()   {
+      if ( action )   {
+	action->release();
+	action = nullptr;
+      }
+    }
+  }    // End namespace digi
+}      // End namespace dd4hep
+#endif // DDDIGI_DIGIPARALLELWORKER_H
diff --git a/DDDigi/include/DDDigi/DigiSegmentAction.h b/DDDigi/include/DDDigi/DigiSegmentAction.h
index ab265c784..95bf318cf 100644
--- a/DDDigi/include/DDDigi/DigiSegmentAction.h
+++ b/DDDigi/include/DDDigi/DigiSegmentAction.h
@@ -16,6 +16,7 @@
 // Framework include files
 #include <DDDigi/DigiData.h>
 #include <DDDigi/DigiEventAction.h>
+#include <DDDigi/DigiSegmentationTool.h>
 
 /// Namespace for the AIDA detector description toolkit
 namespace dd4hep {
@@ -26,7 +27,7 @@ namespace dd4hep {
     /// Forward declarations
     class DigiSegmentAction;
     class DigiSegmentContext;
-    class DigiSegmentationSplitter;
+    class DigiSegmentSplitter;
 
     /// Default base class for all Digitizer actions and derivates thereof.
     /**
@@ -37,19 +38,13 @@ namespace dd4hep {
      *  \version 1.0
      *  \ingroup DD4HEP_SIMULATION
      */
-    class DigiSegmentAction : public DigiEventAction   {
-    private:
-      friend class DigiSegmentationSplitter;
-
-      /// Implementation declaration
-#if defined(G__ROOT) || defined(__CLING__) || defined(__ROOTCLING__)
-      typedef long internals_t;
-#else
-      class internals_t;
-#endif
-      /// Reference to the implementation
-      std::unique_ptr<internals_t> internals;
+    class DigiSegmentAction : virtual public DigiAction   {
+    protected:
+      friend class DigiSegmentSplitter;
 
+      /// Segmentation split context
+      DigiSegmentContext    segment  { };
+  
       /// Define standard assignments and constructors
       DDDIGI_DEFINE_ACTION_CONSTRUCTORS(DigiSegmentAction);
 
@@ -58,11 +53,8 @@ namespace dd4hep {
       DigiSegmentAction(const DigiKernel& kernel, const std::string& name);
       /// Default destructor
       virtual ~DigiSegmentAction();
-      /// Main functional callback
-      virtual void execute(DigiContext& context)  const  final;
       /// Main functional callback. Default implementnation is noop.
       virtual DepositVector handleSegment(DigiContext&              context,
-					  const DigiSegmentContext& segment,
 					  const DepositMapping&     deposits)  const;
     };
   }    // End namespace digi
diff --git a/DDDigi/include/DDDigi/DigiSegmentationSplitter.h b/DDDigi/include/DDDigi/DigiSegmentSplitter.h
similarity index 57%
rename from DDDigi/include/DDDigi/DigiSegmentationSplitter.h
rename to DDDigi/include/DDDigi/DigiSegmentSplitter.h
index f380de57e..54afcd398 100644
--- a/DDDigi/include/DDDigi/DigiSegmentationSplitter.h
+++ b/DDDigi/include/DDDigi/DigiSegmentSplitter.h
@@ -10,13 +10,14 @@
 // Author     : M.Frank
 //
 //==========================================================================
-#ifndef DDDIGI_DIGISEGMENTATIONSPLITTER_H
-#define DDDIGI_DIGISEGMENTATIONSPLITTER_H
+#ifndef DDDIGI_DIGISEGMENTSPLITTER_H
+#define DDDIGI_DIGISEGMENTSPLITTER_H
 
 // Framework include files
+#include <DDDigi/DigiEventAction.h>
 #include <DDDigi/DigiSegmentAction.h>
-#include <DDDigi/DigiActionSequence.h>
 #include <DDDigi/DigiSegmentationTool.h>
+#include <DDDigi/DigiParallelWorker.h>
 
 /// Namespace for the AIDA detector description toolkit
 namespace dd4hep {
@@ -33,51 +34,73 @@ namespace dd4hep {
      *  \version 1.0
      *  \ingroup DD4HEP_SIMULATION
      */
-    class DigiSegmentationSplitter : public DigiActionSequence   {
+    class DigiSegmentSplitter : public DigiEventAction   {
+    public:
+
+      struct CallData  {
+	DigiContext&    context;
+	DepositMapping& input;
+	DepositMapping* output;
+	const DigiSegmentSplitter* parent;
+      };
 
+      using Worker  = DigiParallelWorker<DigiSegmentAction,CallData,int>;
+      using Workers = std::vector<DigiKernel::ParallelCall*>;
+      using Splits  = std::map<VolumeID, std::pair<DetElement, VolumeID> >;
+      
     protected:
       /// Implementation declaration
       class internals_t;
       /// Reference to the implementation
       std::unique_ptr<internals_t> internals;
 
-      /// Property: Identifier of the input repository
-      std::string m_input_id;
       /// Property: Split element of the ID descriptor
-      std::string m_processor_type;
+      std::string          m_processor_type;
       /// Name of the subdetector to be handed
-      std::string m_detector_name;
+      std::string          m_detector_name;
       /// Splitter field in the segmentation description
-      std::string m_split_by;
+      std::string          m_split_by;
       /// Property: Flag if processors should be shared
-      bool        m_share_processor   { true };
+      bool                 m_share_processor   { true };
+
+      /// Property: Identifier of the input repository
+      std::string          m_input_id;
       /// Property: Input mask in the repository
-      int         m_input_mask;
+      int                  m_input_mask;
+      /// Property: Identifier of the input repository
+      std::string          m_output_id;
+      /// Property: Input mask in the repository
+      int                  m_output_mask;
 
       /// Segmentation too instance
-      DigiSegmentationTool  m_split_tool;
+      DigiSegmentationTool m_split_tool;
       /// Segmentation split context
-      DigiSegmentContext    m_split_context;
+      DigiSegmentContext   m_split_context;
 
       /// Split elements used to parallelize the processing
-      std::map<VolumeID, std::pair<DetElement, VolumeID> > m_splits;
+      Splits               m_splits;
       /// Input data keys: depend on dd4hep::Readout and the input mask(s)
-      std::vector<Key> m_data_keys;
+      std::vector<Key>     m_data_keys;
+
+      /// Array of sub-workers
+      Workers              m_workers;
+
+      mutable std::mutex   m_output_lock;
 
     protected:
       /// Default destructor
-      virtual ~DigiSegmentationSplitter();
-
+      virtual ~DigiSegmentSplitter();
       /// Initialization function
       void initialize();
 
     public:
       /// Standard constructor
-      DigiSegmentationSplitter(const DigiKernel& kernel, const std::string& name);
-
+      DigiSegmentSplitter(const DigiKernel& kernel, const std::string& name);
+      /// Handle result from segment callbacks
+      void register_output(DepositMapping& result, DepositVector&& output)  const;
       /// Main functional callback
       virtual void execute(DigiContext& context)  const;
     };
   }    // End namespace digi
 }      // End namespace dd4hep
-#endif // DDDIGI_DIGISEGMENTATIONSPLITTER_H
+#endif // DDDIGI_DIGISEGMENTSPLITTER_H
diff --git a/DDDigi/include/DDDigi/DigiSynchronize.h b/DDDigi/include/DDDigi/DigiSynchronize.h
index 9b69a0a05..8b3f4827d 100644
--- a/DDDigi/include/DDDigi/DigiSynchronize.h
+++ b/DDDigi/include/DDDigi/DigiSynchronize.h
@@ -15,6 +15,7 @@
 
 /// Framework incloude files
 #include <DDDigi/DigiEventAction.h>
+#include <DDDigi/DigiParallelWorker.h>
 
 /// Namespace for the AIDA detector description toolkit
 namespace dd4hep {
@@ -34,7 +35,10 @@ namespace dd4hep {
     class DigiSynchronize : public DigiEventAction {
     protected:
       /// The list of action objects to be called
-      Actors<DigiEventAction> m_actors;
+      //Actors<DigiEventAction> m_actors;
+      using Worker    = DigiParallelWorker<DigiEventAction,DigiContext,int>;
+      using Workers   = std::vector<DigiKernel::ParallelCall*>;
+      Workers m_actors;
 
     protected:
       /// Define standard assignments and constructors
@@ -45,21 +49,11 @@ namespace dd4hep {
       DigiSynchronize(const DigiKernel& kernel, const std::string& nam);
       /// Default destructor
       virtual ~DigiSynchronize();
-      /// Get an action member by name
-      DigiEventAction* get(const std::string& name) const;
-      /// Access the children
-      const Actors<DigiEventAction>& children()   const   {
-        return m_actors;
-      }
       /// Adopt a new action as part of the sequence. Sequence takes ownership.
       virtual void adopt(DigiEventAction* action);
       /// Begin-of-event callback
       virtual void execute(DigiContext& context)  const override;
-      ///
-      void analyze();
     };
-
   }    // End namespace digi
 }      // End namespace dd4hep
-
 #endif // DDDIGI_DIGISYNCHRONIZE_H
diff --git a/DDDigi/plugins/Components.cpp b/DDDigi/plugins/Components.cpp
index 9d998f509..f982f9cfa 100644
--- a/DDDigi/plugins/Components.cpp
+++ b/DDDigi/plugins/Components.cpp
@@ -53,9 +53,9 @@ DECLARE_DIGIEVENTACTION_NS(dd4hep::digi,DigiHitAttenuatorExp)
 #include <DDDigi/DigiContainerCombine.h>
 DECLARE_DIGIEVENTACTION_NS(dd4hep::digi,DigiContainerCombine)
 
-#include <DDDigi/DigiSegmentationSplitter.h>
+#include <DDDigi/DigiSegmentSplitter.h>
 DECLARE_DIGISEGMENTACTION_NS(dd4hep::digi,DigiSegmentAction)
-DECLARE_DIGIEVENTACTION_NS(dd4hep::digi,DigiSegmentationSplitter)
+DECLARE_DIGIEVENTACTION_NS(dd4hep::digi,DigiSegmentSplitter)
 
 #include <DDDigi/DigiMultiContainerProcessor.h>
 DECLARE_DIGIEVENTACTION_NS(dd4hep::digi,DigiMultiContainerProcessor)
diff --git a/DDDigi/plugins/DigiSegmentDepositPrint.cpp b/DDDigi/plugins/DigiSegmentDepositPrint.cpp
index c247267e0..9c4d7313b 100644
--- a/DDDigi/plugins/DigiSegmentDepositPrint.cpp
+++ b/DDDigi/plugins/DigiSegmentDepositPrint.cpp
@@ -13,7 +13,7 @@
 
 // Framework include files
 #include <DDDigi/DigiContext.h>
-#include <DDDigi/DigiSegmentationSplitter.h>
+#include <DDDigi/DigiSegmentSplitter.h>
 
 /// Namespace for the AIDA detector description toolkit
 namespace dd4hep {
@@ -28,15 +28,15 @@ namespace dd4hep {
      *  \version 1.0
      *  \ingroup DD4HEP_SIMULATION
      */
-    class DigiSegmentDepositPrint : public DigiSegmentAction   {
+    class DigiSegmentDepositPrint : virtual public DigiSegmentAction   {
     public:
-      /// Constructors used of base class
-      using DigiSegmentAction::DigiSegmentAction;
+      /// Standard constructor
+      DigiSegmentDepositPrint(const DigiKernel& kernel, const std::string& nam)
+	: DigiAction(kernel, nam), DigiSegmentAction(kernel, nam) {}
 
       /// Main functional callback
       virtual DepositVector 
       handleSegment(DigiContext&              context,
-		    const DigiSegmentContext& segment,
 		    const DepositMapping&     deposits)  const override final   {
 	char format[256];
 	::snprintf(format, sizeof(format), 
diff --git a/DDDigi/python/dddigi.py b/DDDigi/python/dddigi.py
index dfd1b041c..e055c4e2a 100644
--- a/DDDigi/python/dddigi.py
+++ b/DDDigi/python/dddigi.py
@@ -217,6 +217,7 @@ def Synchronize(kernel, nam, parallel=False):
 def _default_adopt(self, action):
   getattr(self, '__adopt')(action.get())
 
+
 def _setup(obj, call='adopt', py_call=_default_adopt):
   _import_class('digi', obj)
   cls = getattr(current, obj)
diff --git a/DDDigi/src/DigiData.cpp b/DDDigi/src/DigiData.cpp
index 68b7a933f..4c65d7b5d 100644
--- a/DDDigi/src/DigiData.cpp
+++ b/DDDigi/src/DigiData.cpp
@@ -71,6 +71,24 @@ std::size_t DepositVector::merge(DepositVector&& updates)    {
   return update_size;
 }
 
+/// Merge new deposit map onto existing map
+std::size_t DepositMapping::merge(DepositVector&& updates)    {
+  std::size_t update_size = updates.size();
+  for( auto& c : updates )    {
+    CellID         cell = c.first;
+    EnergyDeposit& depo = c.second;
+    auto iter = this->find(cell);
+    if ( iter == this->end() )   {
+      this->emplace(cell, std::move(depo));
+      continue;
+    }
+    auto& to_update = iter->second;
+    to_update.deposit += depo.deposit;
+    to_update.history.insert(to_update.history.end(), depo.history.begin(), depo.history.end());
+  }
+  return update_size;
+}
+
 /// Merge new deposit map onto existing map
 std::size_t DepositMapping::merge(DepositMapping&& updates)    {
   std::size_t update_size = updates.size();
diff --git a/DDDigi/src/DigiHandle.cpp b/DDDigi/src/DigiHandle.cpp
index 45f7e8e1d..25159394c 100644
--- a/DDDigi/src/DigiHandle.cpp
+++ b/DDDigi/src/DigiHandle.cpp
@@ -20,8 +20,8 @@
 #include <DDDigi/DigiKernel.h>
 #include <DDDigi/DigiInputAction.h>
 #include <DDDigi/DigiEventAction.h>
+#include <DDDigi/DigiSegmentAction.h>
 #include <DDDigi/DigiSignalProcessor.h>
-#include <DDDigi/DigiSegmentationSplitter.h>
 
 // C/C++ include files
 #include <stdexcept>
diff --git a/DDDigi/src/DigiKernel.cpp b/DDDigi/src/DigiKernel.cpp
index 32c5f044e..979865d50 100644
--- a/DDDigi/src/DigiKernel.cpp
+++ b/DDDigi/src/DigiKernel.cpp
@@ -100,12 +100,11 @@ public:
  *  \version 1.0
  *  \ingroup DD4HEP_DIGITIZATION
  */
-class DigiKernel::Wrapper : public CallWrapper {
+template<typename ACTION, typename ARG> class DigiKernel::Wrapper  {
 public:
-  DigiContext& context;
-  DigiEventAction*  action = 0;
-  Wrapper(DigiContext& c, DigiEventAction* a)
-    : context(c), action(a) {}
+  ACTION*  action = 0;
+  ARG   context;
+  Wrapper(ACTION* a, ARG c) : action(a), context(c) {}
   Wrapper(Wrapper&& copy) = default;
   Wrapper(const Wrapper& copy) = default;
   Wrapper& operator=(Wrapper&& copy) = delete;
@@ -147,7 +146,6 @@ public:
   }
 };
 
-
 /// Standard constructor
 DigiKernel::DigiKernel(Detector& description_ref)
   : m_detDesc(&description_ref)
@@ -318,27 +316,28 @@ DigiActionSequence& DigiKernel::outputAction() const    {
 }
 
 /// Submit a bunch of actions to be executed in parallel
-void DigiKernel::submit (const std::vector<CallWrapper*>& actions)  const    {
+void DigiKernel::submit (const std::vector<ParallelCall*>& algorithms, void* context)  const    {
 #ifdef DD4HEP_USE_TBB
   bool parallel = 0 != internals->tbbInit && internals->numThreads>0;
   if ( parallel )   {
     tbb::task_group que;
-    for ( auto* algo : actions )
-      que.run( *algo );
+    for( auto* algo : algorithms )
+      que.run( Wrapper<ParallelCall,void*>(algo, context) );
     que.wait();
     return;
   }
 #endif
-  for ( auto* algo : actions )
-    (*algo)();
+  for( auto* algo : algorithms )
+    algo->execute(context);
 }
 
 /// Submit a bunch of actions to be executed serially
-void DigiKernel::execute(const std::vector<CallWrapper*>& actions)  const    {
-  for ( auto* algo : actions )
-    (*algo)();
+void DigiKernel::execute(const std::vector<ParallelCall*>& algorithms, void* context)  const   {
+  for( auto* algo : algorithms )
+    algo->execute(context);
 }
 
+#if 0
 void DigiKernel::submit(const DigiAction::Actors<DigiEventAction>& actions, DigiContext& context)   const  {
   std::chrono::system_clock::time_point start = std::chrono::system_clock::now();
   bool parallel = 0 != internals->tbbInit && internals->numThreads>0;
@@ -346,7 +345,7 @@ void DigiKernel::submit(const DigiAction::Actors<DigiEventAction>& actions, Digi
   if ( parallel )   {
     tbb::task_group que;
     for ( auto* i : actions )
-      que.run( Wrapper(context, i) );
+      que.run( Wrapper<DigiEventAction,DigiContext&>(i, context) );
     que.wait();
     goto print_stamp;
   }
@@ -364,6 +363,7 @@ void DigiKernel::submit(const DigiAction::Actors<DigiEventAction>& actions, Digi
 void DigiKernel::execute(const DigiAction::Actors<DigiEventAction>& actions, DigiContext& context)   const  {
   actions(&DigiEventAction::execute,context);
 }
+#endif
 
 void DigiKernel::wait(DigiContext& context)   const  {
   if ( context.event ) {}
diff --git a/DDDigi/src/DigiMultiContainerProcessor.cpp b/DDDigi/src/DigiMultiContainerProcessor.cpp
index 006802179..36747442b 100644
--- a/DDDigi/src/DigiMultiContainerProcessor.cpp
+++ b/DDDigi/src/DigiMultiContainerProcessor.cpp
@@ -24,8 +24,11 @@
 
 using namespace dd4hep::digi;
 
-template <> void DigiParallelWorker<DigiContainerProcessor, DigiMultiContainerProcessor::ProcessorOptions>::operator()() const  {
-  processor->execute(*options.context, *options.work);
+template <> void DigiParallelWorker<DigiContainerProcessor,
+				    DigiMultiContainerProcessor::CallData,
+				    int>::execute(void* data) const  {
+  calldata_t* args = reinterpret_cast<calldata_t*>(data);
+  action->execute(args->context, args->work);
 }
 
 /// Standard constructor
@@ -34,12 +37,13 @@ DigiMultiContainerProcessor::DigiMultiContainerProcessor(const DigiKernel& krnl,
 {
   this->declareProperty("input_masks",      m_input_masks);
   this->declareProperty("input_segment",    m_input_segment);
-  this->declareProperty("allow_duplicates", m_allow_duplicates);
   InstanceCount::increment(this);
 }
 
 /// Default destructor
 DigiMultiContainerProcessor::~DigiMultiContainerProcessor() {
+  for(auto* w : m_workers ) detail::deletePtr(w);
+  m_workers.clear();
   InstanceCount::decrement(this);
 }
 
@@ -55,23 +59,12 @@ void DigiMultiContainerProcessor::adopt_processor(DigiContainerProcessor* action
   std::vector<Key> keys;
   for(const auto& c : containers)    {
     Key key(0x0, c);
-    if ( !m_allow_duplicates )    {
-      for(const auto& w : m_workers)   {
-	if ( std::find(m_work_items.begin(), m_work_items.end(), key.item()) != m_work_items.end() )   {
-	  error("+++ Container %s has already a worker action attached: %s",
-		c.c_str(), w->name());
-	  except("+++ Need to set property allow_duplicates=True to allow such behavior.");
-	}
-      }
-    }
     keys.push_back(key);
     m_work_items.insert(key.item());
     str << c << " ";
   }
-  action->m_work_keys = keys;
-  Worker* w = new Worker(action, {nullptr, nullptr, keys});
-  m_callers.emplace_back(new DigiKernel::CallWrapper(w));
-  m_workers.emplace_back(std::unique_ptr<Worker>(w));
+  action->m_container_keys = keys;
+  m_workers.emplace_back(new Worker(action, 0));
   info("+++ Use processor: %-32s for processing: %s", aname, str.str().c_str());
 }
 
@@ -94,11 +87,8 @@ void DigiMultiContainerProcessor::execute(DigiContext& context)  const    {
     }
   }
   if ( !work_items.empty() )   {
-    for(std::size_t i=0; i < m_workers.size(); ++i)   {
-      m_workers[i]->options.context = &context;
-      m_workers[i]->options.work = &work_items;
-    }
-    m_kernel.submit(m_callers);
+    CallData data { context, work_items };
+    m_kernel.submit(m_workers, &data);
   }
 }
 
@@ -110,7 +100,23 @@ DigiContainerProcessor::DigiContainerProcessor(const DigiKernel& kernel, const s
   this->declareProperty("input_segment",    m_input_segment);
 }
 
+/// Check if the work item is for us
+bool DigiContainerProcessor::use_container(Key key)   const    {
+  auto key_iter = std::find(m_container_keys.begin(), m_container_keys.end(), Key(key.item()));
+  if ( m_container_keys.empty() || key_iter != m_container_keys.end() )    {
+    auto mask_iter = std::find(m_input_masks.begin(), m_input_masks.end(), key.mask());
+    return m_input_masks.empty() || mask_iter != m_input_masks.end();
+  }
+  return false;
+}
+
 /// Main functional callback if specific work is known
-void DigiContainerProcessor::execute(DigiContext& context, WorkItems& data)  const    {
-  info("Hello there [Context:%p]  %p", (void*)&context, (void*)&data);
+void DigiContainerProcessor::execute(DigiContext& context, WorkItems& work)  const    {
+  for( const auto& item : work )  {
+    if ( use_container(item.first) )   {
+      Key key = item.first;
+      info("%s+++ %p Using container: %016lX  --> %04X %08X %s",
+	   context.event->id(), (void*)this, key.key, key.mask(), key.item(), Key::key_name(key).c_str());
+    }
+  }
 }
diff --git a/DDDigi/src/DigiSegmentAction.cpp b/DDDigi/src/DigiSegmentAction.cpp
new file mode 100644
index 000000000..66e1b7230
--- /dev/null
+++ b/DDDigi/src/DigiSegmentAction.cpp
@@ -0,0 +1,37 @@
+//==========================================================================
+//  AIDA Detector description implementation 
+//--------------------------------------------------------------------------
+// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
+// All rights reserved.
+//
+// For the licensing terms see $DD4hepINSTALL/LICENSE.
+// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
+//
+// Author     : M.Frank
+//
+//==========================================================================
+
+// Framework include files
+#include <DD4hep/InstanceCount.h>
+#include <DDDigi/DigiSegmentAction.h>
+
+using namespace dd4hep::digi;
+
+/// Standard constructor
+DigiSegmentAction::DigiSegmentAction(const DigiKernel& krnl, const std::string& nam)
+  : DigiAction(krnl, nam)
+{
+  InstanceCount::increment(this);
+}
+
+/// Default destructor
+DigiSegmentAction::~DigiSegmentAction() {
+  InstanceCount::decrement(this);
+}
+
+/// Main functional callback
+DepositVector
+DigiSegmentAction::handleSegment(DigiContext&              /* context */,
+				 const DepositMapping&     /* depos   */) const {
+  return {};
+}
diff --git a/DDDigi/src/DigiSegmentSplitter.cpp b/DDDigi/src/DigiSegmentSplitter.cpp
new file mode 100644
index 000000000..d6578d6a9
--- /dev/null
+++ b/DDDigi/src/DigiSegmentSplitter.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/Plugins.h>
+#include <DD4hep/InstanceCount.h>
+
+#include <DDDigi/DigiKernel.h>
+#include <DDDigi/DigiContext.h>
+#include <DDDigi/DigiSegmentSplitter.h>
+
+using namespace dd4hep::digi;
+
+class DigiSegmentSplitter::internals_t   {
+public:
+  /// Reference to master
+  DigiSegmentSplitter* split { nullptr };
+  /// Flag to check the initialization
+  bool inited  { false };
+  /// Default constructor
+  internals_t(DigiSegmentSplitter* s) : split(s)  {}
+  /// Initializing function: compute values which depend on properties
+  void initialize(DigiContext& context)   {
+    if ( !this->inited )   {
+      std::lock_guard<std::mutex> lock(context.initializer_lock());
+      if ( !this->inited )   {
+	this->split->initialize();
+	this->inited = true;
+      }
+    }
+  }
+};
+
+template <> void DigiParallelWorker<DigiSegmentAction,
+				    DigiSegmentSplitter::CallData,
+				    int>::execute(void* data) const  {
+  calldata_t* args = reinterpret_cast<calldata_t*>(data);
+  auto res = action->handleSegment(args->context, args->input);
+  if ( args->output && !res.empty() )   {
+    args->parent->register_output(*args->output, std::move(res));
+  }
+}
+
+/// Standard constructor
+DigiSegmentSplitter::DigiSegmentSplitter(const DigiKernel& kernel, const std::string& nam)
+  : DigiEventAction(kernel, nam),
+    m_split_tool(kernel.detectorDescription())
+{
+  this->internals = std::make_unique<internals_t>(this);
+  declareProperty("detector",        m_detector_name);
+  declareProperty("split_by",        m_split_by);
+  declareProperty("processor_type",  m_processor_type);
+  declareProperty("share_processor", m_share_processor = false);
+
+  declareProperty("input_segment",   m_input_id = "deposits");
+  declareProperty("input_mask",      m_input_mask);
+  declareProperty("output_segment",  m_output_id);
+  declareProperty("output_mask",     m_output_mask);
+  InstanceCount::increment(this);
+}
+
+/// Default destructor
+DigiSegmentSplitter::~DigiSegmentSplitter() {
+  for(auto* w : m_workers ) detail::deletePtr(w);
+  m_workers.clear();
+  InstanceCount::decrement(this);
+}
+
+
+/// Initialization function
+void DigiSegmentSplitter::initialize()   {
+  char text[256];
+  std::size_t count = 0;
+
+  m_split_tool.set_detector(m_detector_name);
+  m_split_context = m_split_tool.split_context(m_split_by);
+  m_data_keys = m_split_tool.collection_keys(m_input_mask);
+  m_splits = m_split_tool.split_segmentation(m_split_by);
+
+  /// Create the processors:
+  for( auto& p : m_splits )   {
+    ::snprintf(text, sizeof(text), "_%05X", m_split_context.split_id(p.first));
+    std::string nam = this->name() + text;
+    auto* proc = PluginService::Create<DigiSegmentAction*>(m_processor_type, &m_kernel, nam);
+    if ( !proc )   {
+      except("+++ Failed to create split worker: %s/%s", m_processor_type.c_str(), nam.c_str());
+    }
+    proc->segment          = m_split_context;
+    proc->segment.detector = p.second.first;
+    proc->segment.id       = p.second.second;
+    m_workers.emplace_back(new Worker(proc, 0));
+    ++count;
+  }
+  info("+++ Detector splitter is now fully initialized!");
+}
+
+/// Main functional callback
+void DigiSegmentSplitter::execute(DigiContext& context)  const    {
+  auto& input = context.event->get_segment(m_input_id);
+  this->internals->initialize(context);
+  for( auto k : m_data_keys )   {
+    auto* hits = input.pointer<DepositMapping>(k);
+    if ( hits )    {
+      /// prepare processors for execution
+      info("+++ Got hit collection %04X %08X. Prepare processors.", Key::mask(k), Key::item(k));
+      /// Now submit them
+      if ( m_output_id.empty() )   {
+	CallData data { context, *hits, nullptr, this };
+	m_kernel.submit(m_workers, &data);
+      }
+      else   {
+	DepositMapping result (m_name+"."+hits->name, m_output_mask);
+	CallData data { context, *hits, &result, this };
+	m_kernel.submit(m_workers, &data);
+	auto& output = context.event->get_segment(m_output_id);
+	output.emplace(result.key, std::move(result));
+      }
+    }
+  }
+}
+
+/// Handle result from segment callbacks
+void DigiSegmentSplitter::register_output(DepositMapping& result,
+					       DepositVector&& output)  const  {
+  std::lock_guard<std::mutex> lock(m_output_lock);
+  result.merge(std::move(output));
+}
+
diff --git a/DDDigi/src/DigiSegmentationSplitter.cpp b/DDDigi/src/DigiSegmentationSplitter.cpp
deleted file mode 100644
index 28d860af7..000000000
--- a/DDDigi/src/DigiSegmentationSplitter.cpp
+++ /dev/null
@@ -1,149 +0,0 @@
-//==========================================================================
-//  AIDA Detector description implementation 
-//--------------------------------------------------------------------------
-// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
-// All rights reserved.
-//
-// For the licensing terms see $DD4hepINSTALL/LICENSE.
-// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
-//
-// Author     : M.Frank
-//
-//==========================================================================
-
-// Framework include files
-#include <DD4hep/Plugins.h>
-#include <DD4hep/InstanceCount.h>
-
-#include <DDDigi/DigiKernel.h>
-#include <DDDigi/DigiContext.h>
-#include <DDDigi/DigiSegmentationSplitter.h>
-
-using namespace dd4hep::digi;
-
-class DigiSegmentAction::internals_t  {
-public:
-  DigiSegmentContext    split  { };
-  DepositVector         output { };
-  const DepositMapping* input  { nullptr };
-};
-
-class DigiSegmentationSplitter::internals_t   {
-public:
-  /// Reference to master
-  DigiSegmentationSplitter* split { nullptr };
-  /// Flag to check the initialization
-  bool inited  { false };
-  /// Default constructor
-  internals_t(DigiSegmentationSplitter* s) : split(s)  {}
-  /// Initializing function: compute values which depend on properties
-  void initialize(DigiContext& context)   {
-    if ( !this->inited )   {
-      std::lock_guard<std::mutex> lock(context.initializer_lock());
-      if ( !this->inited )   {
-	this->split->initialize();
-	this->inited = true;
-      }
-    }
-  }
-};
-
-/// Standard constructor
-DigiSegmentationSplitter::DigiSegmentationSplitter(const DigiKernel& kernel, const std::string& nam)
-  : DigiActionSequence(kernel, nam),
-    m_split_tool(kernel.detectorDescription())
-{
-  this->internals = std::make_unique<internals_t>(this);
-  declareProperty("detector",        this->m_detector_name);
-  declareProperty("split_by",        this->m_split_by);
-  declareProperty("input",           this->m_input_id = "deposits");
-  declareProperty("mask",            this->m_input_mask);
-  declareProperty("processor_type",  this->m_processor_type);
-  declareProperty("share_processor", this->m_share_processor = false);
-  InstanceCount::increment(this);
-}
-
-/// Default destructor
-DigiSegmentationSplitter::~DigiSegmentationSplitter() {
-  InstanceCount::decrement(this);
-}
-
-
-/// Initialization function
-void DigiSegmentationSplitter::initialize()   {
-  char text[256];
-  std::size_t count = 0;
-
-  this->m_split_tool.set_detector(this->m_detector_name);
-  this->m_split_context = this->m_split_tool.split_context(this->m_split_by);
-  this->m_data_keys = this->m_split_tool.collection_keys(this->m_input_mask);
-  this->m_splits = this->m_split_tool.split_segmentation(this->m_split_by);
-
-  /// Create the processors:
-  for( auto& p : this->m_splits )   {
-    ::snprintf(text, sizeof(text), "_%05X", m_split_context.split_id(p.first));
-    std::string nam = this->name() + text;
-    auto* eproc = PluginService::Create<DigiEventAction*>(m_processor_type, &m_kernel, nam);
-    if ( !eproc )   {
-      except("+++ Failed to create split worker: %s/%s", m_processor_type.c_str(), nam.c_str());
-    }
-    auto* proc = dynamic_cast<DigiSegmentAction*>(eproc);
-    if ( !proc )   {
-      except("+++ Split worker: %s/%s is not of type DigiSegmentAction!",
-	     m_processor_type.c_str(), nam.c_str());
-    }
-    proc->internals = std::make_unique<DigiSegmentAction::internals_t>();
-    proc->internals->split          = this->m_split_context;
-    proc->internals->split.detector = p.second.first;
-    proc->internals->split.id       = p.second.second;
-    this->DigiActionSequence::adopt(proc);
-    ++count;
-  }
-  info("+++ Detector splitter is now fully initialized!");
-}
-
-/// Main functional callback
-void DigiSegmentationSplitter::execute(DigiContext& context)  const    {
-  auto& input = context.event->get_segment(this->m_input_id);
-  this->internals->initialize(context);
-  for( auto k : this->m_data_keys )   {
-    auto* hits = input.pointer<DepositMapping>(k);
-    if ( hits )    {
-      /// prepare processors for execution
-      info("+++ Got hit collection %04X %08X. Prepare processors.",
-	   Key::mask(k), Key::item(k));
-      for ( auto* a : this->m_actors )   {
-	auto* proc  = (DigiSegmentAction*)a;
-	proc->internals->input = hits;
-      }
-      /// Now submit them
-      this->DigiActionSequence::execute(context);
-    }
-  }
-}
-
-/// Standard constructor
-DigiSegmentAction::DigiSegmentAction(const DigiKernel& krnl, const std::string& nam)
-  : DigiEventAction(krnl, nam)
-{
-  this->internals = std::make_unique<internals_t>();
-  InstanceCount::increment(this);
-}
-
-/// Default destructor
-DigiSegmentAction::~DigiSegmentAction() {
-  InstanceCount::decrement(this);
-}
-
-void DigiSegmentAction::execute(DigiContext& context)  const  {
-  auto& imp = *this->internals;
-  imp.output = this->handleSegment(context, imp.split, *imp.input);
-}
-
-/// Main functional callback
-DepositVector
-DigiSegmentAction::handleSegment(DigiContext&              /* context */,
-				 const DigiSegmentContext& /* segment */,
-				 const DepositMapping&     /* depos   */) const {
-  return {};
-}
diff --git a/DDDigi/src/DigiSynchronize.cpp b/DDDigi/src/DigiSynchronize.cpp
index 8f5a54fd6..bf01a5283 100644
--- a/DDDigi/src/DigiSynchronize.cpp
+++ b/DDDigi/src/DigiSynchronize.cpp
@@ -23,6 +23,13 @@
 using namespace std;
 using namespace dd4hep::digi;
 
+
+template <> void 
+DigiParallelWorker<DigiEventAction, DigiContext, int>::execute(void* data) const  {
+  calldata_t* args = reinterpret_cast<calldata_t*>(data);
+  action->execute(*args);
+}
+
 /// Standard constructor
 DigiSynchronize::DigiSynchronize(const DigiKernel& kernel, const string& nam)
   : DigiEventAction(kernel, nam)
@@ -32,23 +39,18 @@ DigiSynchronize::DigiSynchronize(const DigiKernel& kernel, const string& nam)
 
 /// Default destructor
 DigiSynchronize::~DigiSynchronize() {
-  m_actors(&DigiEventAction::release);
+  for(auto* w : m_actors ) detail::deletePtr(w);
   m_actors.clear();
   InstanceCount::decrement(this);
 }
 
-/// Get an action sequence member by name
-DigiEventAction* DigiSynchronize::get(const string& nam) const   {
-  return m_actors.get(FindByName(TypeName::split(nam).second));
-}
-
 /// Pre-track action callback
 void DigiSynchronize::execute(DigiContext& context)  const   {
   auto start = chrono::high_resolution_clock::now();
   if ( m_parallel )
-    m_kernel.submit(m_actors, context);
+    m_kernel.submit(m_actors, &context);
   else
-    m_kernel.execute(m_actors, context);
+    m_kernel.execute(m_actors, &context);
   chrono::duration<double> secs = chrono::high_resolution_clock::now() - start;
   debug("+++ Event: %8d (DigiSynchronize) Parallel: %-4s  %3ld actions [%8.3g sec]",
         context.event->eventNumber, yes_no(m_parallel), m_actors.size(),
@@ -58,14 +60,8 @@ void DigiSynchronize::execute(DigiContext& context)  const   {
 /// Add an actor responding to all callbacks. Sequence takes ownership.
 void DigiSynchronize::adopt(DigiEventAction* action) {
   if (action)    {
-    action->addRef();
-    m_actors.add(action);
+    m_actors.emplace_back(new Worker(action, 0));
     return;
   }
   except("DigiSynchronize","++ Attempt to add invalid actor!");
 }
-
-/// Add an actor responding to all callbacks. Sequence takes ownership.
-void DigiSynchronize::analyze() {
-  info("+++ Analyzing the algorithm sequence. Parallel: %s",yes_no(m_parallel));
-}
diff --git a/examples/DDDigi/scripts/DigiTest.py b/examples/DDDigi/scripts/DigiTest.py
index f47175518..371608fda 100644
--- a/examples/DDDigi/scripts/DigiTest.py
+++ b/examples/DDDigi/scripts/DigiTest.py
@@ -83,17 +83,15 @@ class Test(dddigi.Digitize):
     return list(self.attenuation.keys())
 
   def containers(self, count):
-    keys = list(self.attenuation.keys())
     conts = []
     result = []
-    cnt = 0
-    for i in range(count):
-      if cnt > count:
-        result.append(cont)
-        cont = []
-        cnt = 0
-      cont.append(keys[i])
-      cnt = cnt + 1
+    for key in list(self.attenuation.keys()):
+      conts.append(key)
+      if len(conts) == count:
+        result.append(conts)
+        conts = []
+    if len(conts) > 0:
+      result.append(conts)
     return result
 
   def check_creation(self, objs):
diff --git a/examples/DDDigi/scripts/TestMultiContainerParallel.py b/examples/DDDigi/scripts/TestMultiContainerParallel.py
index c491555b0..33ded1c59 100644
--- a/examples/DDDigi/scripts/TestMultiContainerParallel.py
+++ b/examples/DDDigi/scripts/TestMultiContainerParallel.py
@@ -11,29 +11,30 @@
 from __future__ import absolute_import
 import dddigi
 
+
 def run():
   import DigiTest
   digi = DigiTest.Test(geometry=None)
-  #digi.load_geo()
+  # digi.load_geo()
   input = digi.input_action('DigiParallelActionSequence/READER')
   # ========================================================================
   digi.info('Created SIGNAL input')
-  signal = input.adopt_action('DigiROOTInput/SignalReader', mask=0x0, input=[digi.next_input()])
+  signal = input.adopt_action('DigiROOTInput/SignalReader', mask=0xFEED, input=[digi.next_input()])
   digi.check_creation([signal])
   # ========================================================================
   event = digi.event_action('DigiSequentialActionSequence/EventAction')
   proc = event.adopt_action('DigiMultiContainerProcessor/ContainerProc',
-                            input_masks=[0x0, 0x1, 0x2, 0x3])
-  conts = digi.containers(3)
+                            input_masks=[0x0, 0x1, 0x2, 0x3, 0xFEED])
+  conts = digi.containers(2)
   for i in range(len(conts)):
-    merge = dddigi.Action(digi.kernel(), 'DigiContainerProcessor/SegmentPrint_%03d'%(i,));
+    merge = dddigi.Action(digi.kernel(), 'DigiContainerProcessor/SegmentPrint_%03d' % (i,))
     proc.adopt_processor(merge, conts[i])
 
-  #dump = event.adopt_action('DigiStoreDump/StoreDump')
-  #digi.check_creation([combine, dump, splitter])
-  #digi.info('Created event.dump')
+  # dump = event.adopt_action('DigiStoreDump/StoreDump')
+  # digi.check_creation([combine, dump, splitter])
+  # digi.info('Created event.dump')
   # ========================================================================
-  digi.run_checked(num_events=1, num_threads=5, parallel=3)
+  digi.run_checked(num_events=5, num_threads=15, parallel=3)
 
 
 if __name__ == '__main__':
diff --git a/examples/DDDigi/scripts/TestSegmentationSplit.py b/examples/DDDigi/scripts/TestSegmentationSplit.py
index 2707b1769..bbe09bc19 100644
--- a/examples/DDDigi/scripts/TestSegmentationSplit.py
+++ b/examples/DDDigi/scripts/TestSegmentationSplit.py
@@ -22,11 +22,13 @@ def run():
   digi.check_creation([signal])
   # ========================================================================
   event = digi.event_action('DigiSequentialActionSequence/EventAction')
-  combine = event.adopt_action('DigiContainerCombine/Combine', input_masks=[0x0, 0x1, 0x2, 0x3], deposit_mask=0xFEED)
+  combine = event.adopt_action('DigiContainerCombine/Combine', input_masks=[0x0], deposit_mask=0xFEED)
   combine.erase_combined = True  # Not thread-safe! only do in SequentialActionSequence
-  splitter = event.adopt_action('DigiSegmentationSplitter/Splitter',
-                                input='deposits',
-                                mask=0xFEED,
+  splitter = event.adopt_action('DigiSegmentSplitter/Splitter',
+                                input_segment='deposits',
+                                input_mask=0xFEED,
+                                output_segment='',
+                                output_mask=0xBABE,
                                 detector='SiTrackerBarrel',
                                 split_by='layer',
                                 processor_type='DigiSegmentDepositPrint')
-- 
GitLab