diff --git a/DDDigi/include/DDDigi/DigiOutputAction.h b/DDDigi/include/DDDigi/DigiOutputAction.h
index fb2013ceb0cbba8922d1cfda4564fc9899074826..9931520bb174125479d61a8179a6e9e2ad97f523 100644
--- a/DDDigi/include/DDDigi/DigiOutputAction.h
+++ b/DDDigi/include/DDDigi/DigiOutputAction.h
@@ -14,7 +14,7 @@
 #define DDDIGI_DIGIOUTPUTACTION_H
 
 /// Framework include files
-#include <DDDigi/DigiEventAction.h>
+#include <DDDigi/DigiContainerProcessor.h>
 
 /// Namespace for the AIDA detector description toolkit
 namespace dd4hep {
@@ -32,34 +32,68 @@ namespace dd4hep {
      *  \version 1.0
      *  \ingroup DD4HEP_DIGITIZATION
      */
-    class DigiOutputAction : public DigiEventAction {
+    class DigiOutputAction : public DigiContainerSequenceAction {
     public:
-      enum { OUTPUT_START = -1  };
-      enum { NO_MASK     = 0x0 };
-
     protected:
-      /// Array of data containers to be saved
-      std::vector<std::string> m_containers { };
+      /// Property: Processor type to manage containers
+      std::string                        m_processor_type  { };
+      /// Property: Container / data type mapping
+      std::map<std::string, std::string> m_containers  { };
       /// Property: Output data specification
-      std::string              m_output { };
-      /// Property: Mask to flag output source items
-      int                      m_mask   { NO_MASK };
+      std::string                        m_output { };
+      /// Property: Create stream names with sequence numbers
+      bool                               m_sequence_streams  {  true };
+
+      /// Total numbe rof events to be processed
+      long num_events  { -1 };
+      /// Running event counter
+      long event_count {  0 };
+      /// Stream sequence counter
+      long fseq_count  {  0 };
 
     protected:
       /// Define standard assignments and constructors
       DDDIGI_DEFINE_ACTION_CONSTRUCTORS(DigiOutputAction);
 
+      /// Default destructor
+      virtual ~DigiOutputAction();
+
     public:
       /// Standard constructor
       DigiOutputAction(const kernel_t& kernel, const std::string& nam);
 
-      /// Default destructor
-      virtual ~DigiOutputAction();
+      /// Initialization callback
+      virtual void initialize();
+
+      /// Finalization callback
+      virtual void finalize();
+
+      /// Check for valid output stream
+      virtual bool have_output()  const = 0;
+
+      /// Open new output stream
+      virtual void open_output() const = 0;
+
+      /// Close current output stream
+      virtual void close_output() const = 0;
+
+      /// Commit event data to output stream
+      virtual void commit_output() const = 0;
+
+      /// Create new output stream name
+      virtual std::string next_stream_name();
+
+      /// Adopt new parallel worker
+      virtual void adopt_processor(DigiContainerProcessor* action,
+                                   const std::string& container)  override;
+
+      /// Adopt new parallel worker acting on multiple containers
+      virtual void adopt_processor(DigiContainerProcessor* action,
+                                   const std::vector<std::string>& containers);
 
       /// Callback to read event output
       virtual void execute(context_t& context)  const override;
     };
-
   }    // End namespace digi
 }      // End namespace dd4hep
 #endif // DDDIGI_DIGIOUTPUTACTION_H
diff --git a/DDDigi/include/DDDigi/DigiROOTOutput.h b/DDDigi/include/DDDigi/DigiROOTOutput.h
deleted file mode 100644
index b3a9bdb943b2e30d2f7eccc22c47609cc252dfd0..0000000000000000000000000000000000000000
--- a/DDDigi/include/DDDigi/DigiROOTOutput.h
+++ /dev/null
@@ -1,79 +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
-//
-//==========================================================================
-#ifndef DDDIGI_DIGIROOTOUTPUT_H
-#define DDDIGI_DIGIROOTOUTPUT_H
-
-/// Framework include files
-#include <DDDigi/DigiOutputAction.h>
-
-/// C/C++ include files
-#include <memory>
-
-/// Forward declarations
-class TFile;
-class TTree;
-class TBranch;
-
-
-/// Namespace for the AIDA detector description toolkit
-namespace dd4hep {
-
-  /// Namespace for the Digitization part of the AIDA detector description toolkit
-  namespace digi {
-
-    // Forward declarations
-    class DigiROOTOutput;
-
-    /// Base class for output actions to the digitization
-    /**
-     *
-     *  \author  M.Frank
-     *  \version 1.0
-     *  \ingroup DD4HEP_DIGITIZATION
-     */
-    class DigiROOTOutput : public DigiOutputAction {
-
-    protected:
-      /// Helper classes
-      class internals_t;
-      /// Property: Name of the tree to connect to
-      std::string m_tree_name       { };
-      /// Property: Segment name to place output data default: outputs
-      std::string m_location        { };
-      /// Property: name of the event tree
-      std::string m_section         { };
-      /// Property: File size limit
-      std::size_t m_max_file_size   { std::numeric_limits<std::size_t>::max() };
-      /// Property: vector with disabled collections
-      std::vector<std::string> m_disabledCollections { };
-      /// Property: vector with disabled collections
-      bool  m_disableParticles      { false };
-
-      /// Connection parameters to the "current" output source
-      std::unique_ptr<internals_t> imp;
-
-    protected:
-      /// Define standard assignments and constructors
-      DDDIGI_DEFINE_ACTION_CONSTRUCTORS(DigiROOTOutput);
-
-    public:
-      /// Standard constructor
-      DigiROOTOutput(const DigiKernel& kernel, const std::string& nam);
-      /// Default destructor
-      virtual ~DigiROOTOutput();
-      /// Callback to read event output
-      virtual void execute(DigiContext& context)  const override;
-    };
-  }    // End namespace digi
-}      // End namespace dd4hep
-#endif // DDDIGI_DIGIROOTOUTPUT_H
diff --git a/DDDigi/io/Digi2ROOT.cpp b/DDDigi/io/Digi2ROOT.cpp
index 6fadb41e738b6fbe19cb1112b7a1c6453aed8d50..ef0cd7e9f94ff03472719494ac35a8c479a56d92 100644
--- a/DDDigi/io/Digi2ROOT.cpp
+++ b/DDDigi/io/Digi2ROOT.cpp
@@ -14,7 +14,7 @@
 #define DIGI_DIGI2ROOT_H
 
 // Framework include files
-#include <DDDigi/DigiContainerProcessor.h>
+#include <DDDigi/DigiOutputAction.h>
 #include <DDDigi/DigiData.h>
 
 /// Namespace for the AIDA detector description toolkit
@@ -26,25 +26,18 @@ namespace dd4hep {
     /// Event action to support edm4hep output format from DDDigi
     /**
      *  Supported output containers types are:
-     *  - edm4hep::MCParticles aka "MCParticles"
-     *  - edm4hep::CalorimeterHitCollection  aka "CalorimeterHits"
-     *  - edm4hep::TrackerHitCollection aka "TracketHits"
+     *  - MCParticles aka "MCParticles"
+     *  - EnergyDeposits
      *
      *  \author  M.Frank
      *  \version 1.0
      *  \ingroup DD4HEP_DIGITIZATION
      */
-    class Digi2ROOTWriter : public  DigiContainerSequenceAction  {
+    class Digi2ROOTWriter : public  DigiOutputAction  {
     public:
       class internals_t;
 
     protected:
-      /// Property: Container names to be loaded
-      std::string m_output;
-      /// Property: Processor type to manage containers
-      std::string m_processor_type;
-      /// Property: Container / data type mapping
-      std::map<std::string, std::string> m_containers  { };
       /// Reference to internals
       std::shared_ptr<internals_t> internals;
 
@@ -57,32 +50,16 @@ namespace dd4hep {
     public:
       /// Standard constructor
       Digi2ROOTWriter(const kernel_t& kernel, const std::string& nam);
-
       /// Initialization callback
       virtual void initialize();
-
-      /// Finalization callback
-      virtual void finalize();
-
-      /// Adopt new parallel worker
-      virtual void adopt_processor(DigiContainerProcessor* action,
-                                   const std::string& container)  override final;
-
-      /// Adopt new parallel worker acting on multiple containers
-      virtual void adopt_processor(DigiContainerProcessor* action,
-                                   const std::vector<std::string>& containers);
-
-      /// Callback to store the run information
-      void beginRun();
-
-      /// Callback to store the run information
-      void endRun();
-
-      /// Callback to store the Geant4 run information
-      void saveRun();
-
-      /// Main functional callback
-      virtual void execute(context_t& context)  const;
+      /// Check for valid output stream
+      virtual bool have_output()  const  override final;
+      /// Open new output stream
+      virtual void open_output() const  override final;
+      /// Close possible open stream
+      virtual void close_output()  const  override final;
+      /// Commit event data to output stream
+      virtual void commit_output() const  override final;
     };
 
     /// Actor to save individual data containers to edm4hep
@@ -96,7 +73,6 @@ namespace dd4hep {
      */
     class Digi2ROOTProcessor : public DigiContainerProcessor   {
       friend class Digi2ROOTWriter;
-
     protected:
       /// Reference to the edm4hep engine
       std::shared_ptr<Digi2ROOTWriter::internals_t> internals;
@@ -104,14 +80,13 @@ namespace dd4hep {
     public:
       /// Standard constructor
       Digi2ROOTProcessor(const DigiKernel& krnl, const std::string& nam);
-
       /// Standard destructor
       virtual ~Digi2ROOTProcessor() = default;
 
-      void convert_particles(DigiContext& context, const ParticleMapping& cont)  const;
-      void convert_deposits(DigiContext& context, const DepositVector& cont, const predicate_t& predicate)  const;
-      void convert_deposits(DigiContext& context, const DepositMapping& cont, const predicate_t& predicate)  const;
-      void convert_history(DigiContext& context, const DepositsHistory& cont, work_t& work, const predicate_t& predicate)  const;
+      void convert_particles(DigiContext& context, ParticleMapping& cont)  const;
+      void convert_deposits(DigiContext& context, DepositVector& cont, const predicate_t& predicate)  const;
+      void convert_deposits(DigiContext& context, DepositMapping& cont, const predicate_t& predicate)  const;
+      void convert_history(DigiContext& context, DepositsHistory& cont, work_t& work, const predicate_t& predicate)  const;
 
       /// Main functional callback
       virtual void execute(DigiContext& context, work_t& work, const predicate_t& predicate)  const override final;
@@ -141,9 +116,10 @@ namespace dd4hep {
 #include "DigiIO.h"
 
 /// ROOT include files
-#include <TClass.h>
 #include <TFile.h>
 #include <TTree.h>
+#include <TROOT.h>
+#include <TClass.h>
 #include <TBranch.h>
 
 #include <vector>
@@ -154,6 +130,9 @@ namespace dd4hep {
   /// Namespace for the Digitization part of the AIDA detector description toolkit
   namespace digi {
 
+    using persistent_particles_t = std::vector<std::pair<Key::key_type, Particle*> >;
+    using persistent_deposits_t  = std::vector<std::pair<CellID, EnergyDeposit*> >;
+
     /// Helper class to create output in edm4hep format
     /** Helper class to create output in edm4hep format
      *
@@ -161,35 +140,41 @@ namespace dd4hep {
      *  \version 1.0
      *  \ingroup DD4HEP_DIGITIZATION
      */
-    class Digi2ROOTWriter::internals_t {
+    class Digi2ROOTWriter::internals_t  final {
     public:
       struct BranchWrapper   {
+	TClass*  clazz = nullptr;
 	TBranch* branch = nullptr;
 	void*    address = nullptr;
 	void (*fcn_clear)(void* addr) = 0;
-	void clear()  { this->fcn_clear(this->address); }
-	template <typename T> T* get() { return (T*)this->address; }
+	void (*fcn_del)(void* addr) = 0;
+	void clear()                    { this->fcn_clear(this->address); }
+	void del()                      { this->fcn_del(this->address);   }
+	template <typename T> T* get()  { return (T*)this->address;       }
+	template <typename T> void set(T* ptr);
+      };
+      template <typename O> struct _wrapper_handler  {
+	static void clear(void* ptr)  {  O* c = (O*)ptr; c->clear();  }
+	static void del(void* ptr)    {  O* c = (O*)ptr; delete c;    }
       };
-      Digi2ROOTWriter* m_parent                       { nullptr };
       typedef std::map<std::string, BranchWrapper> Collections;
-      typedef std::map<std::string, TTree*> Sections;
-      /// Known file sections
-      Sections m_sections;
+
+      /// Reference to the parent
+      Digi2ROOTWriter*         m_parent       { nullptr };
       /// Collections in the event tree
-      Collections m_collections;
+      Collections              m_collections  { };
       /// Reference to the ROOT file to open
-      std::unique_ptr<TFile> m_file;
+      std::unique_ptr<TFile>   m_file         { };
       /// Reference to the event data tree
-      TTree* m_tree;
+      TTree*                   m_tree         { nullptr };
+
       /// Property: name of the event tree
-      std::string m_section;
-      /// Property: vector with disabled collections
-      std::vector<std::string> m_disabledCollections;
+      std::string              m_section      { "EVENT" };
 
-      /// Total numbe rof events to be processed
-      long num_events  { -1 };
-      /// Running event counter
-      long event_count {  0 };
+      /// Default basket size
+      Int_t                    m_basket_size  { 32000 };
+      /// Default split level
+      Int_t                    m_split_level  {    99 };
 
     private:
       /// Helper to register single collection
@@ -197,14 +182,16 @@ namespace dd4hep {
 
     public:
       /// Default constructor
-      internals_t() = default;
+      internals_t(Digi2ROOTWriter* parent);
       /// Default destructor
-      ~internals_t() = default;
+      ~internals_t();
 
-      /// Commit data at end of filling procedure
-      void commit();
+      /// Open output file
+      void open();
       /// Commit data to disk and close output stream
       void close();
+      /// Commit data at end of filling procedure
+      void commit();
 
       /// Create all collections according to the parent setup (locked)
       void create_collections();
@@ -214,11 +201,33 @@ namespace dd4hep {
       template <typename T> BranchWrapper& get_collection(const T&);
     };
 
+    template <typename T> void Digi2ROOTWriter::internals_t::BranchWrapper::set(T* ptr)   {
+      clazz     = gROOT->GetClass(typeid(*ptr), kTRUE);
+      branch    = nullptr;
+      address   = ptr;
+      fcn_clear = _wrapper_handler<T>::clear;
+      fcn_del   = _wrapper_handler<T>::del;
+    }
+
+    /// Default constructor
+    Digi2ROOTWriter::internals_t::internals_t(Digi2ROOTWriter* parent) : m_parent(parent)
+    {
+    }
+
+    /// Default destructor
+    Digi2ROOTWriter::internals_t::~internals_t()    {
+      m_parent->info("Releasing allocated resources.");
+      if ( m_file ) close();
+      for( auto& coll : m_collections )   {
+	coll.second.clear();
+	coll.second.del();
+      }
+      m_collections.clear();
+    }
+
     template <typename T> T* Digi2ROOTWriter::internals_t::register_collection(const std::string& nam, T* coll)   {
-      struct _do_clear  {
-	static void clear(void* ptr)  {  T* c = (T*)ptr; c->clear();  }
-      };
-      BranchWrapper bw = { nullptr, (void*)coll, _do_clear::clear };
+      BranchWrapper bw;
+      bw.set(coll);
       m_collections.emplace(nam, bw);
       m_parent->debug("+++ created collection %s <%s>", nam.c_str(), typeName(typeid(T)).c_str());
       return coll;
@@ -227,17 +236,16 @@ namespace dd4hep {
     /// Create all collections according to the parent setup
     void Digi2ROOTWriter::internals_t::create_collections()    {
       if ( m_collections.empty() )   {
-        std::string fname = m_parent->m_output;
-        m_file.reset(new TFile(fname.c_str(), "RECREATE", "DDDigi data"));
         for( auto& cont : m_parent->m_containers )   {
           const std::string& nam = cont.first;
           const std::string& typ = cont.second;
-          if ( typ == "MCParticles" )
-            register_collection(nam, new std::vector<Particle*>());
-          else
-            register_collection(nam, new std::vector<EnergyDeposit*>());
+          if ( typ == "MCParticles" )   {
+            register_collection(nam, new persistent_particles_t());
+	  }
+          else   {
+            register_collection(nam, new persistent_deposits_t());
+	  }
         }
-        m_parent->info("+++ Will save %ld events to %s", num_events, m_parent->m_output.c_str());
       }
     }
 
@@ -257,27 +265,38 @@ namespace dd4hep {
 	coll.second.clear();
     }
 
-    /// Commit data at end of filling procedure
-    void Digi2ROOTWriter::internals_t::commit()   {
+    /// Open output file
+    void Digi2ROOTWriter::internals_t::open()   {
       if ( m_file )   {
-	for( auto& coll : m_collections )    {
-	  coll.second.branch->Write();
-	}
-        clearCollections();
-        return;
+	close();
       }
-      m_parent->except("+++ Failed to write output file. [Stream is not open]");
+      std::string fname = m_parent->next_stream_name();
+      m_file.reset(TFile::Open(fname.c_str(), "RECREATE", "DDDigi data"));
+      m_tree = new TTree(m_section.c_str(), "DDDigi data", m_split_level, m_file.get());
+      m_parent->info("+++ Opened ROOT output file %s", m_file->GetName());
+      for( auto& coll : m_collections )    {
+	auto& dsc = coll.second;
+	dsc.branch = m_tree->Branch(coll.first.c_str(),
+				    dsc.clazz->GetName(),
+				    &dsc.address,
+				    m_basket_size,
+				    m_split_level);
+	dsc.branch->SetAutoDelete(kFALSE);
+      }
+      m_parent->info("+++ Will save %ld events to %s",
+		     m_parent->num_events, m_parent->m_output.c_str());
     }
 
     /// Commit data to disk and close output stream
     void Digi2ROOTWriter::internals_t::close()   {
       if ( m_file )    {
 	TDirectory::TContext ctxt(m_file.get());
-	Sections::iterator i = m_sections.find(m_section);
-	m_parent->info("+++ Closing ROOT output file %s", m_file->GetName());
-	if ( i != m_sections.end() )
-	  m_sections.erase(i);
-	m_collections.clear();
+	m_parent->info("+++ Closing ROOT output file %s after %ld events and %ld bytes",
+		       m_file->GetName(), m_tree->GetEntries(), m_file->GetBytesWritten());
+	for( auto& coll : m_collections )   {
+	  coll.second.branch->ResetAddress();
+	  coll.second.branch = nullptr;
+	}
 	m_tree->Write();
 	m_file->Close();
 	m_tree = nullptr;
@@ -285,168 +304,132 @@ namespace dd4hep {
       m_file.reset();
     }
 
+    /// Commit data at end of filling procedure
+    void Digi2ROOTWriter::internals_t::commit()   {
+      if ( m_tree )   {
+	m_tree->Fill();
+        clearCollections();
+	++m_parent->event_count;
+	if ( m_parent->m_sequence_streams )  {
+	  if ( 0 == (m_parent->event_count%m_parent->num_events) )  {
+	    close();
+	  }
+	}
+        return;
+      }
+      m_parent->except("+++ Failed to write output file. [Stream is not open]");
+    }
+
     /// Standard constructor
     Digi2ROOTWriter::Digi2ROOTWriter(const DigiKernel& krnl, const std::string& nam)
-      : DigiContainerSequenceAction(krnl, nam)
+      : DigiOutputAction(krnl, nam)
     {
-      internals = std::make_shared<internals_t>();
-      declareProperty("output",         m_output);
-      declareProperty("containers",     m_containers);
-      declareProperty("processor_type", m_processor_type = "Digi2ROOTProcessor");
-      internals->m_parent = this;
+      internals = std::make_shared<internals_t>(this);
+      m_processor_type = "Digi2ROOTProcessor";
+      declareProperty("basket_size",    internals->m_basket_size);
+      declareProperty("split_level",    internals->m_split_level);
       InstanceCount::increment(this);
     }
 
     /// Default destructor
-    Digi2ROOTWriter::~Digi2ROOTWriter()   {{
-        std::lock_guard<std::mutex> lock(m_kernel.global_io_lock());
-        internals->close();
-      }
+    Digi2ROOTWriter::~Digi2ROOTWriter()   {
       internals.reset();
       InstanceCount::decrement(this);
     }
 
     /// Initialization callback
     void Digi2ROOTWriter::initialize()   {
-      if ( m_containers.empty() )   {
-        warning("+++ No input containers given for attenuation action -- no action taken");
-        return;
-      }
-      internals->num_events = m_kernel.property("numEvents").value<long>();
-      for ( const auto& c : m_containers )   {
-        Key key(c.first, 0, 0);
-        auto it = m_registered_processors.find(key);
-        if ( it == m_registered_processors.end() )   {
-          std::string nam = name() + ".E4H." + c.first;
-          auto* conv = createAction<DigiContainerProcessor>(m_processor_type, m_kernel, nam);
-          if ( !conv )   {
-            except("+++ Failed to create edm4hep processor: %s of type: %s",
-                   nam.c_str(), m_processor_type.c_str());
-          }
-          conv->property("OutputLevel").set(int(outputLevel()));
-          adopt_processor(conv, c.first);
-          conv->release(); // Release processor **after** adoption.
-        }
-      }
-      std::lock_guard<std::mutex> lock(m_kernel.global_io_lock());
-      m_parallel = false;
-      internals->create_collections();
-      this->DigiContainerSequenceAction::initialize();
-    }
-
-    /// Finalization callback
-    void Digi2ROOTWriter::finalize()   {
-      internals->close();
-    }
-
-    /// Adopt new parallel worker
-    void Digi2ROOTWriter::adopt_processor(DigiContainerProcessor* action,
-					  const std::string& container)
-    {
-      std::size_t idx = container.find('/');
-      if ( idx != std::string::npos )   {
-        std::string nam = container.substr(0, idx);
-        std::string typ = container.substr(idx+1);
-        auto* act = dynamic_cast<Digi2ROOTProcessor*>(action);
+      this->DigiOutputAction::initialize();
+      for ( auto& c : m_registered_processors )   {
+        auto* act = dynamic_cast<Digi2ROOTProcessor*>(c.second);
         if ( act )   { // This is not nice! Need to think about something better.
           act->internals = this->internals;
+	  continue;
         }
-        this->DigiContainerSequenceAction::adopt_processor(action, nam);
-        m_containers.emplace(nam, typ);
-        return;
+	except("Error: Invalid processor type for ROOT output: %s", c.second->c_name());
       }
-      except("+++ Invalid container specification: %s. %s",
-             container.c_str(), "Specify container as tuple: \"<name>/<type>\" !");
+      m_parallel = false;
+      internals->create_collections();
     }
 
-    /// Adopt new parallel worker acting on multiple containers
-    void Digi2ROOTWriter::adopt_processor(DigiContainerProcessor* action, 
-					  const std::vector<std::string>& containers)
-    {
-      DigiContainerSequenceAction::adopt_processor(action, containers);
+    /// Check for valid output stream
+    bool Digi2ROOTWriter::have_output()  const  {
+      return internals->m_file.get() != nullptr;
     }
 
-    /// Main functional callback
-    void Digi2ROOTWriter::execute(DigiContext& context)  const    {
-      std::lock_guard<std::mutex> lock(context.global_io_lock());
-      this->DigiContainerSequenceAction::execute(context);
-      this->internals->commit();
-      if ( ++internals->event_count == internals->num_events )  {
-        internals->close();
-      }
+    /// Open new output stream
+    void Digi2ROOTWriter::open_output() const   {
+      internals->open();
     }
 
-    /// Callback to store the run information
-    void Digi2ROOTWriter::beginRun()  {
-      saveRun();
-    }
-
-    /// Callback to store the run information
-    void Digi2ROOTWriter::endRun()  {
-      // saveRun(run);
+    /// Close possible open stream
+    void Digi2ROOTWriter::close_output()  const  {
+      internals->close();
     }
 
-    /// Callback to store the Geant4 run information
-    void Digi2ROOTWriter::saveRun()  {
-      warning("saveRun(): RunHeader not implemented in EDM4hep, nothing written ...");
+    /// Commit event data to output stream
+    void Digi2ROOTWriter::commit_output() const  {
+      internals->commit();
     }
 
-
     /// Standard constructor
     Digi2ROOTProcessor::Digi2ROOTProcessor(const DigiKernel& krnl, const std::string& nam)
       : DigiContainerProcessor(krnl, nam)
     {
     }
 
-    void Digi2ROOTProcessor::convert_particles(DigiContext& ctxt,
-					       const ParticleMapping& cont)  const
+    void Digi2ROOTProcessor::convert_particles(DigiContext&     ctxt,
+					       ParticleMapping& cont)  const
     {
       auto& coll = internals->get_collection(cont);
-      auto* vec = coll.get<std::vector<const ParticleMapping::value_type*> >();
+      auto* vec = coll.get<persistent_particles_t>();
+      vec->clear();
       vec->reserve(cont.size());
-      for( const auto& p : cont )   {
-	vec->emplace_back(&p);
+      for( auto& p : cont )   {
+	vec->emplace_back(std::make_pair(p.first, &p.second));
       }
       info("%s+++ %-24s added %6ld entries from mask: %04X",
            ctxt.event->id(), cont.name.c_str(), vec->size(), cont.key.mask());
     }
 
-    void Digi2ROOTProcessor::convert_deposits(DigiContext&          ctxt,
-					      const DepositMapping& cont,
-					      const predicate_t&    predicate)  const
+    void Digi2ROOTProcessor::convert_deposits(DigiContext&       ctxt,
+					      DepositMapping&    cont,
+					      const predicate_t& predicate)  const
     {
       auto& coll = internals->get_collection(cont);
-      auto* vec  = coll.get<std::vector<const DepositMapping::value_type*> >();
+      auto* vec  = coll.get<persistent_deposits_t>();
+      vec->clear();
       vec->reserve(cont.size());
-      for ( const auto& depo : cont )   {
+      for ( auto& depo : cont )   {
 	if ( predicate(depo) )   {
-	  vec->emplace_back(&depo);
+	  vec->emplace_back(std::make_pair(depo.first, &depo.second));
 	}
       }
       info("%s+++ %-24s added %6ld entries from mask: %04X",
            ctxt.event->id(), cont.name.c_str(), vec->size(), cont.key.mask());
     }
 
-    void Digi2ROOTProcessor::convert_deposits(DigiContext&          ctxt,
-					      const DepositVector&  cont,
-					      const predicate_t&    predicate)  const
+    void Digi2ROOTProcessor::convert_deposits(DigiContext&       ctxt,
+					      DepositVector&     cont,
+					      const predicate_t& predicate)  const
     {
       auto& coll = internals->get_collection(cont);
-      auto* vec  = coll.get<std::vector<const DepositVector::value_type*> >();
+      auto* vec  = coll.get<persistent_deposits_t>();
+      vec->clear();
       vec->reserve(cont.size());
-      for ( const auto& depo : cont )   {
+      for ( auto& depo : cont )   {
 	if ( predicate(depo) )   {
-	  vec->emplace_back(&depo);
+	  vec->emplace_back(std::make_pair(depo.first, &depo.second));
 	}
       }
       info("%s+++ %-24s added %6ld entries from mask: %04X",
            ctxt.event->id(), cont.name.c_str(), vec->size(), cont.key.mask());
     }
 
-    void Digi2ROOTProcessor::convert_history(DigiContext&           ctxt,
-					     const DepositsHistory& cont,
-					     work_t&                work,
-					     const predicate_t&     predicate)  const
+    void Digi2ROOTProcessor::convert_history(DigiContext&       ctxt,
+					     DepositsHistory&   cont,
+					     work_t&            work,
+					     const predicate_t& predicate)  const
     {
       info("%s+++ %-32s Segment: %d Predicate:%s Conversion to edm4hep not implemented!",
            ctxt.event->id(), cont.name.c_str(), int(work.input.segment->id),
@@ -455,13 +438,13 @@ namespace dd4hep {
 
     /// Main functional callback
     void Digi2ROOTProcessor::execute(DigiContext& ctxt, work_t& work, const predicate_t& predicate)  const  {
-      if ( const auto* p = work.get_input<ParticleMapping>() )
+      if ( auto* p = work.get_input<ParticleMapping>() )
         convert_particles(ctxt, *p);
-      else if ( const auto* m = work.get_input<DepositMapping>() )
+      else if ( auto* m = work.get_input<DepositMapping>() )
         convert_deposits(ctxt, *m, predicate);
-      else if ( const auto* v = work.get_input<DepositVector>() )
+      else if ( auto* v = work.get_input<DepositVector>() )
         convert_deposits(ctxt, *v, predicate);
-      else if ( const auto* h = work.get_input<DepositsHistory>() )
+      else if ( auto* h = work.get_input<DepositsHistory>() )
         convert_history(ctxt, *h, work, predicate);
       else
         except("Request to handle unknown data type: %s", work.input_type_name().c_str());
diff --git a/DDDigi/io/Digi2edm4hep.cpp b/DDDigi/io/Digi2edm4hep.cpp
index 745f6b5c36ac6e732db8e820175c25d8c9c153a6..677dc51e53bfbfb8301d47b00bb361775977a648 100644
--- a/DDDigi/io/Digi2edm4hep.cpp
+++ b/DDDigi/io/Digi2edm4hep.cpp
@@ -14,7 +14,7 @@
 #define DIGI_DIGI2EDM4HEP_H
 
 // Framework include files
-#include <DDDigi/DigiContainerProcessor.h>
+#include <DDDigi/DigiOutputAction.h>
 
 /// C/C++ include files
 
@@ -40,17 +40,10 @@ namespace dd4hep {
      *  \version 1.0
      *  \ingroup DD4HEP_DIGITIZATION
      */
-    class Digi2edm4hepWriter : public  DigiContainerSequenceAction  {
+    class Digi2edm4hepWriter : public  DigiOutputAction  {
     public:
       class internals_t;
-
     protected:
-      /// Property: Container names to be loaded
-      std::string m_output;
-      /// Property: Processor type to manage containers
-      std::string m_processor_type;
-      /// Property: Container / data type mapping
-      std::map<std::string, std::string> m_containers  { };
       /// Reference to internals
       std::shared_ptr<internals_t> internals;
 
@@ -63,32 +56,16 @@ namespace dd4hep {
     public:
       /// Standard constructor
       Digi2edm4hepWriter(const kernel_t& kernel, const std::string& nam);
-
       /// Initialization callback
       virtual void initialize();
-
-      /// Finalization callback
-      virtual void finalize();
-
-      /// Adopt new parallel worker
-      virtual void adopt_processor(DigiContainerProcessor* action,
-                                   const std::string& container)  override final;
-
-      /// Adopt new parallel worker acting on multiple containers
-      virtual void adopt_processor(DigiContainerProcessor* action,
-                                   const std::vector<std::string>& containers);
-
-      /// Callback to store the run information
-      void beginRun();
-
-      /// Callback to store the run information
-      void endRun();
-
-      /// Callback to store the Geant4 run information
-      void saveRun();
-
-      /// Main functional callback
-      virtual void execute(context_t& context)  const;
+      /// Check for valid output stream
+      virtual bool have_output()  const  override final;
+      /// Open new output stream
+      virtual void open_output() const  override final;
+      /// Close possible open stream
+      virtual void close_output()  const  override final;
+      /// Commit event data to output stream
+      virtual void commit_output() const  override final;
     };
 
     /// Actor to save individual data containers to edm4hep
@@ -209,12 +186,14 @@ namespace dd4hep {
 
     public:
       /// Default constructor
-      internals_t() = default;
+      internals_t(Digi2edm4hepWriter* parent);
       /// Default destructor
-      ~internals_t() = default;
+      ~internals_t();
 
       /// Commit data at end of filling procedure
       void commit();
+      /// Open new output stream
+      void open();
       /// Commit data to disk and close output stream
       void close();
 
@@ -224,10 +203,21 @@ namespace dd4hep {
       template <typename T> podio::CollectionBase* get_collection(const T&);
     };
 
+    /// Default constructor
+    Digi2edm4hepWriter::internals_t::internals_t(Digi2edm4hepWriter* parent) : m_parent(parent)
+    {
+      m_store  = std::make_unique<podio::EventStore>();
+    }
+
+    /// Default destructor
+    Digi2edm4hepWriter::internals_t::~internals_t()    {
+      if ( m_file ) close();
+      m_store.reset();
+    }
+
     template <typename T> T* Digi2edm4hepWriter::internals_t::register_collection(const std::string& nam, T* coll)   {
       m_collections.emplace(nam, coll);
       m_store->registerCollection(nam, coll);
-      m_file->registerForWrite(nam);
       m_parent->debug("+++ created collection %s <%s>", nam.c_str(), coll->getTypeName().c_str());
       return coll;
     }
@@ -235,9 +225,6 @@ namespace dd4hep {
     /// Create all collections according to the parent setup
     void Digi2edm4hepWriter::internals_t::create_collections()    {
       if ( nullptr == m_header )   {
-        std::string fname = m_parent->m_output;
-        m_store  = std::make_unique<podio::EventStore>();
-        m_file   = std::make_unique<podio::ROOTWriter>(fname, m_store.get());
         m_header = register_collection("EventHeader", new edm4hep::EventHeaderCollection());
         for( auto& cont : m_parent->m_containers )   {
           const std::string& nam = cont.first;
@@ -276,122 +263,78 @@ namespace dd4hep {
       m_parent->except("+++ Failed to write output file. [Stream is not open]");
     }
 
+      /// Open new output stream
+    void Digi2edm4hepWriter::internals_t::open()    {
+      if ( m_file )   {
+        close();
+      }
+      m_file.reset();
+      std::string fname = m_parent->next_stream_name();
+      m_file = std::make_unique<podio::ROOTWriter>(fname, m_store.get());
+      m_parent->info("+++ Opened EDM4HEP output file %s", fname.c_str());
+     for( const auto& c : m_collections )   {
+	m_file->registerForWrite(c.first);
+      }
+    }
+
     /// Commit data to disk and close output stream
     void Digi2edm4hepWriter::internals_t::close()   {
+      m_parent->info("+++ Closing EDM4HEP output file.");
       if ( m_file )   {
         m_file->finish();
       }
       m_file.reset();
-      m_store.reset();
     }
 
     /// Standard constructor
     Digi2edm4hepWriter::Digi2edm4hepWriter(const DigiKernel& krnl, const std::string& nam)
-      : DigiContainerSequenceAction(krnl, nam)
+      : DigiOutputAction(krnl, nam)
     {
-      internals = std::make_shared<internals_t>();
-      declareProperty("output",         m_output);
-      declareProperty("containers",     m_containers);
-      declareProperty("processor_type", m_processor_type = "Digi2edm4hepProcessor");
-      internals->m_parent = this;
+      internals = std::make_shared<internals_t>(this);
       InstanceCount::increment(this);
     }
 
     /// Default destructor
-    Digi2edm4hepWriter::~Digi2edm4hepWriter()   {{
-        std::lock_guard<std::mutex> lock(m_kernel.global_io_lock());
-        internals->close();
-      }
+    Digi2edm4hepWriter::~Digi2edm4hepWriter()   {
       internals.reset();
       InstanceCount::decrement(this);
     }
 
     /// Initialization callback
     void Digi2edm4hepWriter::initialize()   {
-      if ( m_containers.empty() )   {
-        warning("+++ No input containers given for attenuation action -- no action taken");
-        return;
-      }
-      internals->num_events = m_kernel.property("numEvents").value<long>();
-      for ( const auto& c : m_containers )   {
-        Key key(c.first, 0, 0);
-        auto it = m_registered_processors.find(key);
-        if ( it == m_registered_processors.end() )   {
-          std::string nam = name() + ".E4H." + c.first;
-          auto* conv = createAction<DigiContainerProcessor>(m_processor_type, m_kernel, nam);
-          if ( !conv )   {
-            except("+++ Failed to create edm4hep processor: %s of type: %s",
-                   nam.c_str(), m_processor_type.c_str());
-          }
-          conv->property("OutputLevel").set(int(outputLevel()));
-          adopt_processor(conv, c.first);
-          conv->release(); // Release processor **after** adoption.
-        }
-      }
-      std::lock_guard<std::mutex> lock(m_kernel.global_io_lock());
-      m_parallel = false;
-      internals->create_collections();
-      this->DigiContainerSequenceAction::initialize();
-    }
-
-    /// Finalization callback
-    void Digi2edm4hepWriter::finalize()   {
-      internals->close();
-    }
-
-    /// Adopt new parallel worker
-    void Digi2edm4hepWriter::adopt_processor(DigiContainerProcessor* action,
-                                             const std::string& container)
-    {
-      std::size_t idx = container.find('/');
-      if ( idx != std::string::npos )   {
-        std::string nam = container.substr(0, idx);
-        std::string typ = container.substr(idx+1);
-        auto* act = dynamic_cast<Digi2edm4hepProcessor*>(action);
+      this->DigiOutputAction::initialize();
+      for ( auto& c : m_registered_processors )   {
+        auto* act = dynamic_cast<Digi2edm4hepProcessor*>(c.second);
         if ( act )   { // This is not nice! Need to think about something better.
           act->internals = this->internals;
+	  continue;
         }
-        this->DigiContainerSequenceAction::adopt_processor(action, nam);
-        m_containers.emplace(nam, typ);
-        return;
+	except("Error: Invalid processor type for EDM4HEP output: %s", c.second->c_name());
       }
-      except("+++ Invalid container specification: %s. %s",
-             container.c_str(), "Specify container as tuple: \"<name>/<type>\" !");
-    }
-
-    /// Adopt new parallel worker acting on multiple containers
-    void Digi2edm4hepWriter::adopt_processor(DigiContainerProcessor* action, 
-                                             const std::vector<std::string>& containers)
-    {
-      DigiContainerSequenceAction::adopt_processor(action, containers);
+      m_parallel = false;
+      internals->create_collections();
     }
 
-    /// Main functional callback
-    void Digi2edm4hepWriter::execute(DigiContext& context)  const    {
-      std::lock_guard<std::mutex> lock(context.global_io_lock());
-      this->DigiContainerSequenceAction::execute(context);
-      this->internals->commit();
-      if ( ++internals->event_count == internals->num_events )  {
-        internals->close();
-      }
+     /// Check for valid output stream
+    bool Digi2edm4hepWriter::have_output()  const  {
+      return internals->m_file.get() != nullptr;
     }
 
-    /// Callback to store the run information
-    void Digi2edm4hepWriter::beginRun()  {
-      saveRun();
+    /// Open new output stream
+    void Digi2edm4hepWriter::open_output() const   {
+      internals->open();
     }
 
-    /// Callback to store the run information
-    void Digi2edm4hepWriter::endRun()  {
-      // saveRun(run);
+    /// Close possible open stream
+    void Digi2edm4hepWriter::close_output()  const  {
+      internals->close();
     }
 
-    /// Callback to store the Geant4 run information
-    void Digi2edm4hepWriter::saveRun()  {
-      warning("saveRun(): RunHeader not implemented in EDM4hep, nothing written ...");
+    /// Commit event data to output stream
+    void Digi2edm4hepWriter::commit_output() const  {
+      internals->commit();
     }
 
-
     /// Standard constructor
     Digi2edm4hepProcessor::Digi2edm4hepProcessor(const DigiKernel& krnl, const std::string& nam)
       : DigiContainerProcessor(krnl, nam)
diff --git a/DDDigi/io/DigiIO.cpp b/DDDigi/io/DigiIO.cpp
index b70cadfb22b9c6bc9a333c3562f51ba101e20187..c06a998294e9a4447e07ee4e1ef187068c86f09a 100644
--- a/DDDigi/io/DigiIO.cpp
+++ b/DDDigi/io/DigiIO.cpp
@@ -233,7 +233,7 @@ namespace dd4hep {
       hit.setCellID( dep.first );
       hit.setEDep( de.deposit );
       hit.setEDepError( dep_error );
-      hit.setEdx( de.deposit/de.length );
+      //hit.setEdx( de.deposit/de.length );
       hit.setPosition( _toVectorD(de.position) );
     }
 
diff --git a/DDDigi/plugins/Components.cpp b/DDDigi/plugins/Components.cpp
index c976ba968796a886bbcded903e4045214a3e9094..a6fce560ad35d411595e57f945275c9b40a82856 100644
--- a/DDDigi/plugins/Components.cpp
+++ b/DDDigi/plugins/Components.cpp
@@ -24,12 +24,6 @@
 #include <DDDigi/DigiInputAction.h>
 DECLARE_DIGIACTION_NS(dd4hep::digi,DigiInputAction)
 
-#include <DDDigi/DigiOutputAction.h>
-DECLARE_DIGIACTION_NS(dd4hep::digi,DigiOutputAction)
-
-#include <DDDigi/DigiROOTOutput.h>
-DECLARE_DIGIACTION_NS(dd4hep::digi,DigiROOTOutput)
-
 #include <DDDigi/DigiSynchronize.h>
 DECLARE_DIGIACTION_NS(dd4hep::digi,DigiSynchronize)
 
diff --git a/DDDigi/python/DDDigiDict.C b/DDDigi/python/DDDigiDict.C
index 5346ef08c00133274c53902c30348375656ce12a..108ff020aa01beb6acde8ab690e08a8e98765a35 100644
--- a/DDDigi/python/DDDigiDict.C
+++ b/DDDigi/python/DDDigiDict.C
@@ -200,15 +200,16 @@ namespace dd4hep {
 //#pragma link C++ class dd4hep::digi::Key;
 #pragma link C++ class std::pair<dd4hep::digi::Key::key_type, dd4hep::digi::Particle>+;
 #pragma link C++ class std::map<dd4hep::digi::Key::key_type, dd4hep::digi::Particle>+;
+#pragma link C++ class std::map<dd4hep::digi::Key::key_type, dd4hep::digi::Particle*>+;
 #pragma link C++ class std::vector<std::pair<dd4hep::digi::Key::key_type, dd4hep::digi::Particle> >+;
-
-#pragma link C++ class std::pair<dd4hep::digi::Key::key_type, dd4hep::digi::Particle>;
-#pragma link C++ class std::map<dd4hep::digi::Key::key_type, dd4hep::digi::Particle>;
-#pragma link C++ class std::vector<std::pair<dd4hep::digi::Key::key_type, dd4hep::digi::Particle> >;
+#pragma link C++ class std::vector<std::pair<dd4hep::digi::Key::key_type, dd4hep::digi::Particle*> >+;
 
 #pragma link C++ class std::pair<dd4hep::CellID, dd4hep::digi::EnergyDeposit>+;
+#pragma link C++ class std::pair<dd4hep::CellID, dd4hep::digi::EnergyDeposit*>+;
 #pragma link C++ class std::map<dd4hep::CellID, dd4hep::digi::EnergyDeposit>+;
+#pragma link C++ class std::map<dd4hep::CellID, dd4hep::digi::EnergyDeposit*>+;
 #pragma link C++ class std::vector<std::pair<dd4hep::CellID, dd4hep::digi::EnergyDeposit> >+;
+#pragma link C++ class std::vector<std::pair<dd4hep::CellID, dd4hep::digi::EnergyDeposit*> >+;
 
 #pragma link C++ class dd4hep::digi::History+;
 #pragma link C++ class dd4hep::digi::Particle+;
diff --git a/DDDigi/src/DigiOutputAction.cpp b/DDDigi/src/DigiOutputAction.cpp
index ad23ac4b6df3abd809160c1dcf4366ebbb494c12..81b12ed7a7c0b7a520685979e2b00544af71c545 100644
--- a/DDDigi/src/DigiOutputAction.cpp
+++ b/DDDigi/src/DigiOutputAction.cpp
@@ -14,21 +14,23 @@
 // Framework include files
 #include <DD4hep/InstanceCount.h>
 #include <DDDigi/DigiOutputAction.h>
+#include <DDDigi/DigiContext.h>
+#include <DDDigi/DigiPlugins.h>
+#include <DDDigi/DigiKernel.h>
 
 // C/C++ include files
 #include <stdexcept>
-#include <unistd.h>
 
-using namespace std;
 using namespace dd4hep::digi;
 
 /// Standard constructor
-DigiOutputAction::DigiOutputAction(const DigiKernel& kernel, const string& nam)
-  : DigiEventAction(kernel, nam)
+DigiOutputAction::DigiOutputAction(const DigiKernel& kernel, const std::string& nam)
+  : DigiContainerSequenceAction(kernel, nam)
 {
-  declareProperty("containers", m_containers);
-  declareProperty("output",     m_output);
-  declareProperty("mask",       m_mask);
+  declareProperty("sequence_streams", m_sequence_streams);
+  declareProperty("processor_type", m_processor_type);
+  declareProperty("containers",     m_containers);
+  declareProperty("output",         m_output);
   InstanceCount::increment(this);
 }
 
@@ -37,8 +39,85 @@ DigiOutputAction::~DigiOutputAction()   {
   InstanceCount::decrement(this);
 }
 
+/// Create new output stream name
+std::string DigiOutputAction::next_stream_name()   {
+  if ( m_sequence_streams )   {
+    std::size_t idx = m_output.rfind(".");
+    std::stringstream str;
+    if ( idx != std::string::npos )  {
+      std::string fname = m_output.substr(0, idx);
+      std::string ftype = m_output.substr(idx+1);
+      str << fname << '_' << std::dec << std::setfill('0') << std::setw(8) << fseq_count << "." << ftype;
+      return str.str();
+    }
+    str << m_output << '_' << std::dec << std::setfill('0') << std::setw(8) << fseq_count;
+    return str.str();
+  }
+  return m_output;
+}
+/// Initialization callback
+void DigiOutputAction::initialize()   {
+  if ( m_containers.empty() )   {
+    warning("+++ No input containers given for attenuation action -- no action taken");
+    return;
+  }
+  num_events = m_kernel.property("numEvents").value<long>();
+  for ( const auto& c : m_containers )   {
+    Key key(c.first, 0, 0);
+    auto it = m_registered_processors.find(key);
+    if ( it == m_registered_processors.end() )   {
+      std::string nam = name() + ".E4H." + c.first;
+      auto* conv = createAction<DigiContainerProcessor>(m_processor_type, m_kernel, nam);
+      if ( !conv )   {
+	except("+++ Failed to create edm4hep processor: %s of type: %s",
+	       nam.c_str(), m_processor_type.c_str());
+      }
+      conv->property("OutputLevel").set(int(outputLevel()));
+      adopt_processor(conv, c.first);
+      conv->release(); // Release processor **after** adoption.
+    }
+  }
+  std::lock_guard<std::mutex> lock(m_kernel.global_io_lock());
+  this->DigiContainerSequenceAction::initialize();
+}
+
+/// Finalization callback
+void DigiOutputAction::finalize()   {
+  close_output();
+  this->DigiContainerSequenceAction::finalize();
+}
+
+/// Adopt new parallel worker
+void DigiOutputAction::adopt_processor(DigiContainerProcessor* action,
+				       const std::string& container)
+{
+  std::size_t idx = container.find('/');
+  if ( idx != std::string::npos )   {
+    std::string nam = container.substr(0, idx);
+    std::string typ = container.substr(idx+1);
+    this->DigiContainerSequenceAction::adopt_processor(action, nam);
+    m_containers.emplace(nam, typ);
+    return;
+  }
+  except("+++ Invalid container specification: %s. %s",
+	 container.c_str(), "Specify container as tuple: \"<name>/<type>\" !");
+}
+
+/// Adopt new parallel worker acting on multiple containers
+void DigiOutputAction::adopt_processor(DigiContainerProcessor* action, 
+				       const std::vector<std::string>& containers)
+{
+  DigiContainerSequenceAction::adopt_processor(action, containers);
+}
+
 /// Pre-track action callback
-void DigiOutputAction::execute(DigiContext& /* context */)  const   {
-  info("+++ Virtual method execute() --- Should not be called");
-  ::sleep(1);
+void DigiOutputAction::execute(DigiContext& context)  const   {
+  std::lock_guard<std::mutex> lock(context.global_io_lock());
+  /// Check for valid output stream. If not: open new stream
+  if ( !have_output() )   {
+    open_output();
+  }
+  this->DigiContainerSequenceAction::execute(context);
+  /// Commit data. Close stream if necessary
+  commit_output();
 }
diff --git a/DDDigi/src/DigiROOTOutput.cpp b/DDDigi/src/DigiROOTOutput.cpp
deleted file mode 100644
index 3929794e72888167caacd64ea2e8ee2f34f68297..0000000000000000000000000000000000000000
--- a/DDDigi/src/DigiROOTOutput.cpp
+++ /dev/null
@@ -1,237 +0,0 @@
-//==========================================================================
-//  AIDA Detector description implementation 
-//--------------------------------------------------------------------------
-// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
-// All rights reserved.
-//
-// For the licensing terms see $DD4hepINSTALL/LICENSE.
-// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
-//
-// Author     : M.Frank
-//
-//==========================================================================
-
-/// Framework include files
-#include <DD4hep/InstanceCount.h>
-#include <DDDigi/DigiROOTOutput.h>
-
-/// ROOT include files
-#include <TFile.h>
-#include <TTree.h>
-#include <TBranch.h>
-
-/// C/C++ include files
-#include <stdexcept>
-#include <unistd.h>
-
-using namespace std;
-using namespace dd4hep::digi;
-
-class DigiROOTOutput::internals_t  {
-public:
-  typedef std::map<std::string, TBranch*> Branches;
-  typedef std::map<std::string, TTree*> Sections;
-  /// Reference to the ROOT file to open
-  TFile* m_file   { nullptr };
-  /// Reference to the event data tree
-  TTree* m_tree   { nullptr };
-  /// Known file sections
-  Sections m_sections;
-  /// Branches in the event tree
-  Branches m_branches;
-  DigiROOTOutput* output { nullptr };
-
-public:
-  internals_t(DigiROOTOutput* o) 
-    : output(o) 
-  {
-  }
-  ~internals_t()    {
-    if (m_file) {
-      TDirectory::TContext ctxt(m_file);
-      m_tree->Write();
-      m_file->Close();
-      m_tree = 0;
-      detail::deletePtr (m_file);
-    }
-  }
-  /// Create/access tree by name for non collection user data
-  TTree* section(const std::string& nam)   {
-    auto i = m_sections.find(nam);
-    if ( i == m_sections.end() ) {
-      TDirectory::TContext ctxt(m_file);
-      TTree* t = new TTree(nam.c_str(), ("Digitization " + nam + " information").c_str());
-      m_sections.emplace(nam, t);
-      return t;
-    }
-    return i->second;
-  }
-  /// Commit data at end of filling procedure
-  void commit()   {
-    if ( m_file ) {
-      TObjArray* a = m_tree->GetListOfBranches();
-      Long64_t evt = m_tree->GetEntries() + 1;
-      Int_t nb = a->GetEntriesFast();
-      /// Fill NULL pointers to all branches, which have less entries than the Event branch
-      for (Int_t i = 0; i < nb; ++i) {
-	TBranch* br_ptr = (TBranch*) a->UncheckedAt(i);
-	Long64_t br_evt = br_ptr->GetEntries();
-	if (br_evt < evt) {
-	  Long64_t num = evt - br_evt;
-	  br_ptr->SetAddress(0);
-	  while (num > 0) {
-	    br_ptr->Fill();
-	    --num;
-	  }
-	}
-      }
-      m_tree->SetEntries(evt);
-    }
-  }
-  /// Fill single EVENT branch entry (Geant4 collection data)
-  int fill(const string& nam, const std::type_info& type, void* ptr) {
-    if (m_file) {
-      TBranch* b = 0;
-      auto i = m_branches.find(nam);
-      if (i == m_branches.end()) {
-	TClass* cl = TBuffer::GetClass(type);
-	if (cl) {
-	  b = m_tree->Branch(nam.c_str(), cl->GetName(), (void*) 0);
-	  b->SetAutoDelete(false);
-	  m_branches.emplace(nam, b);
-	}
-	else {
-	  throw runtime_error("No ROOT TClass object availible for object type:" + typeName(type));
-	}
-      }
-      else {
-	b = (*i).second;
-      }
-      Long64_t evt = b->GetEntries(), nevt = b->GetTree()->GetEntries(), num = nevt - evt;
-      if (nevt > evt) {
-	b->SetAddress(0);
-	while (num > 0) {
-	  b->Fill();
-	  --num;
-	}
-      }
-      b->SetAddress(&ptr);
-      int nbytes = b->Fill();
-      if (nbytes < 0) {
-	throw runtime_error("Failed to write ROOT collection:" + nam + "!");
-      }
-      return nbytes;
-    }
-    return 0;
-  }
-  /// Callback to store the Geant4 event
-  void saveEvent(DigiContext& /* ctxt */) {
-    if ( !output->m_disableParticles )  {
-#if 0
-      Geant4ParticleMap* parts = context()->event().extension<Geant4ParticleMap>();
-      if ( parts )   {
-	typedef Geant4HitWrapper::HitManipulator Manip;
-	typedef Geant4ParticleMap::ParticleMap ParticleMap;
-	Manip* manipulator = Geant4HitWrapper::manipulator<Geant4Particle>();
-	const ParticleMap& pm = parts->particles();
-	vector<void*> particles;
-	particles.reserve(pm.size());
-	for ( const auto& i : pm )   {
-	  particles.emplace_back((ParticleMap::mapped_type*)i.second);
-	}
-	fill("MCParticles",manipulator->vec_type,&particles);
-      }
-#endif
-    }
-  }
-};
-
-/// Standard constructor
-DigiROOTOutput::DigiROOTOutput(const DigiKernel& kernel, const std::string& nam)
-  : DigiOutputAction(kernel, nam)
-{
-  imp = std::make_unique<internals_t>(this);
-  declareProperty("section",              m_section = "EVENT");
-  declareProperty("max_file_size",        m_max_file_size);
-  declareProperty("disabled_collections", m_disabledCollections);
-  declareProperty("disable_particles",    m_disableParticles);
-  InstanceCount::increment(this);
-}
-
-/// Default destructor
-DigiROOTOutput::~DigiROOTOutput() {
-  imp.reset();
-  InstanceCount::decrement(this);
-}
-
-/// Pre-track action callback
-void DigiROOTOutput::execute(DigiContext& context)  const   {
-  imp->saveEvent(context);
-#if 0
-  for (int i = 0; i < nCol; ++i) {
-    G4VHitsCollection* hc = hce->GetHC(i);
-    saveCollection(ctxt, hc);
-  }
-#endif
-}
-
-#if 0
-/// Callback to store the Geant4 run information
-void DigiROOTOutput::beginRun(const G4Run* run) {
-  if (!m_file && !m_output.empty()) {
-    TDirectory::TContext ctxt(TDirectory::CurrentDirectory());
-    m_file = TFile::Open(m_output.c_str(), "RECREATE", "DD4hep digitization data");
-    if (m_file->IsZombie()) {
-      detail::deletePtr (m_file);
-      except("+++ Failed to open ROOT output file:'" + m_output + "'");
-    }
-    m_tree = section("EVENT");
-  }
-  Geant4OutputAction::beginRun(run);
-}
-
-
-
-/// Callback to store each Geant4 hit collection
-void DigiROOTOutput::saveCollection(DigiContext& /* ctxt */, G4VHitsCollection* collection) {
-  Geant4HitCollection* coll = dynamic_cast<Geant4HitCollection*>(collection);
-  string hc_nam = collection->GetName();
-  for(const auto& n : m_disabledCollections)  {
-    if ( n == hc_nam )   {
-      return;
-    }
-  }
-  if (coll) {
-    vector<void*> hits;
-    coll->getHitsUnchecked(hits);
-    size_t nhits = coll->GetSize();
-    if ( m_handleMCTruth && m_truth && nhits > 0 )   {
-      hits.reserve(nhits);
-      try  {
-        for(size_t i=0; i<nhits; ++i)   {
-          Geant4HitData* h = coll->hit(i);
-          Geant4Tracker::Hit* trk_hit = dynamic_cast<Geant4Tracker::Hit*>(h);
-          if ( 0 != trk_hit )   {
-            Geant4HitData::Contribution& t = trk_hit->truth;
-            int trackID = t.trackID;
-            t.trackID = m_truth->particleID(trackID);
-          }
-          Geant4Calorimeter::Hit* cal_hit = dynamic_cast<Geant4Calorimeter::Hit*>(h);
-          if ( 0 != cal_hit )   {
-            Geant4HitData::Contributions& c = cal_hit->truth;
-            for(Geant4HitData::Contributions::iterator j=c.begin(); j!=c.end(); ++j)  {
-              Geant4HitData::Contribution& t = *j;
-              int trackID = t.trackID;
-              t.trackID = m_truth->particleID(trackID);
-            }
-          }
-        }
-      }
-      catch(...)   {
-        printout(ERROR,name(),"+++ Exception while saving collection %s.",hc_nam.c_str());
-      }
-    }
-    fill(hc_nam, coll->vector_type(), &hits);
-  }
-}
-#endif
diff --git a/examples/DDDigi/CMakeLists.txt b/examples/DDDigi/CMakeLists.txt
index 7d3028138e2897aa7bfb673e1c77621d93308d33..392d557afb2b31928105581c961875114bf8f8fc 100644
--- a/examples/DDDigi/CMakeLists.txt
+++ b/examples/DDDigi/CMakeLists.txt
@@ -207,6 +207,15 @@ if (DD4HEP_USE_GEANT4)
     REGEX_FAIL "Error;ERROR;Exception"
   )
   #
+  # Test raw digi write
+  dd4hep_add_test_reg(DDDigi_test_digi_root_write
+    COMMAND    "${CMAKE_INSTALL_PREFIX}/bin/run_test_DDDigi.sh"
+    EXEC_ARGS  ${Python_EXECUTABLE} ${CMAKE_INSTALL_PREFIX}/examples/DDDigi/scripts/TestWriteDigi.py
+    DEPENDS    DDDigi_generate_data
+    REGEX_PASS "\\+\\+\\+ Closing ROOT output file dddigi_write_digi_00000000.root after 5 events"
+    REGEX_FAIL "Error;ERROR;Exception"
+  )
+  #
   if (DD4HEP_USE_EDM4HEP)
     # Test edm4hep write (needs to be expanded)
     dd4hep_add_test_reg(DDDigi_test_edm4hep_write
diff --git a/examples/DDDigi/scripts/TestWriteDigi.py b/examples/DDDigi/scripts/TestWriteDigi.py
index 4f764a32d595c1c2c7239f7a20c512594e733f64..1aa5bb4d0a6c565c962b1feb5a70e79d253431ea 100644
--- a/examples/DDDigi/scripts/TestWriteDigi.py
+++ b/examples/DDDigi/scripts/TestWriteDigi.py
@@ -30,7 +30,7 @@ def run():
   writ.adopt_container_processor(proc, cont)
   writ.adopt_container_processor(proc, 'MCParticles/MCParticles')
   digi.check_creation([read, dump])
-  digi.run_checked(num_events=10, num_threads=10, parallel=3)
+  digi.run_checked(num_events=5, num_threads=10, parallel=5)
 
 
 # ---------------------------------------------------------------------------