From da15d446dfa997957ac18cdadc08bb194708bf56 Mon Sep 17 00:00:00 2001
From: Markus Frank <Markus.Frank@cern.ch>
Date: Mon, 16 Jan 2023 14:54:41 +0100
Subject: [PATCH] Make DDDigi I/O interface more common and add edm4hep
 write/read examples

---
 DDDigi/CMakeLists.txt                       |   2 +-
 DDDigi/include/DDDigi/DigiInputAction.h     |  26 ++
 DDDigi/include/DDDigi/DigiROOTInput.h       |  34 +-
 DDDigi/io/DigiDDG4Input.cpp                 |  75 ++--
 DDDigi/io/DigiEdm4hepInput.cpp              | 371 ++++++++++++++++----
 DDDigi/io/DigiIO.cpp                        | 116 +++++-
 DDDigi/src/DigiInputAction.cpp              |  35 +-
 DDDigi/src/DigiROOTInput.cpp                |  70 ++--
 examples/ClientTests/CMakeLists.txt         |   4 +-
 examples/DDDigi/CMakeLists.txt              |  52 +--
 examples/DDDigi/scripts/TestEdm4hepInput.py |  11 +-
 examples/DDDigi/scripts/TestWriteEdm4hep.py |   2 +-
 12 files changed, 579 insertions(+), 219 deletions(-)

diff --git a/DDDigi/CMakeLists.txt b/DDDigi/CMakeLists.txt
index 7f0e28b15..17f6ac27a 100644
--- a/DDDigi/CMakeLists.txt
+++ b/DDDigi/CMakeLists.txt
@@ -67,7 +67,7 @@ else()
 endif()
 #
 if(DD4HEP_USE_EDM4HEP)
-  list(APPEND DDDigiIO_SOURCES      io/Digi2edm4hep.cpp)
+  list(APPEND DDDigiIO_SOURCES      "io/Digi2edm4hep.cpp;io/DigiEdm4hepInput.cpp;io/Edm4hepFrame.cpp")
   list(APPEND DDDigiIO_DEFINITIONS  "DD4HEP_USE_EDM4HEP=1")
   list(APPEND DDDigiIO_USES         "EDM4HEP::edm4hep;EDM4HEP::edm4hepDict;podio::podio;podio::podioDict;podio::podioRootIO")
 else()
diff --git a/DDDigi/include/DDDigi/DigiInputAction.h b/DDDigi/include/DDDigi/DigiInputAction.h
index bb605b417..acf5d75f8 100644
--- a/DDDigi/include/DDDigi/DigiInputAction.h
+++ b/DDDigi/include/DDDigi/DigiInputAction.h
@@ -16,6 +16,9 @@
 /// Framework include files
 #include <DDDigi/DigiEventAction.h>
 
+/// C/C++ include files
+#include <limits>
+
 /// Namespace for the AIDA detector description toolkit
 namespace dd4hep {
 
@@ -36,10 +39,18 @@ namespace dd4hep {
     public:
       enum { INPUT_START = -1  };
       enum { NO_MASK     = 0x0 };
+      /// Most probably need some minimum cutoff:
+      static constexpr double epsilon = std::numeric_limits<double>::epsilon();
 
     protected:
       /// Property: Input data specification
       std::vector<std::string> m_input_sources { };
+      /// Property: Container names to be loaded
+      std::vector<std::string> m_objects_enabled  { };
+      /// Property: Container names to be ignored for loading
+      std::vector<std::string> m_objects_disabled  { };
+      /// Property: Option to specify event section in the input data (tree, table etc.)
+      std::string              m_input_section { "EVENT" };
       /// Property: Input data segment name
       std::string              m_input_segment { "inputs" };
       /// Property: Mask to flag input source items
@@ -69,6 +80,21 @@ namespace dd4hep {
       int input_mask()  const   {
 	return m_input_mask;
       }
+      /// Access to input section name containing the event data
+      const std::string& input_section()  const   {
+	return m_input_section;
+      }
+      /// Access to container names containing data
+      const std::vector<std::string>& objects_enabled()  const   {
+	return m_objects_enabled;
+      }
+      /// Access to container names containing data
+      const std::vector<std::string>& objects_disabled()  const   {
+	return m_objects_disabled;
+      }
+      /// Check if a event object should be loaded: Default YES unless inhibited by selection or veto
+      bool object_loading_is_enabled(const std::string& nam)  const;
+
       /// Callback to read event input
       virtual void execute(context_t& context)  const override;
     };
diff --git a/DDDigi/include/DDDigi/DigiROOTInput.h b/DDDigi/include/DDDigi/DigiROOTInput.h
index ee5d6fced..f2612156d 100644
--- a/DDDigi/include/DDDigi/DigiROOTInput.h
+++ b/DDDigi/include/DDDigi/DigiROOTInput.h
@@ -16,11 +16,12 @@
 /// Framework include files
 #include <DDDigi/DigiInputAction.h>
 
-// C/C++ include files
+/// C/C++ include files
 #include <memory>
 
 /// Forward declarations
 class TBranch;
+class TClass;
 
 /// Namespace for the AIDA detector description toolkit
 namespace dd4hep {
@@ -44,26 +45,24 @@ namespace dd4hep {
       /// Helper classes
       class internals_t;
       class inputsource_t;
-
-      class work_t   {
+      class container_t  {
       public:
-	DataSegment& input_segment;
-	Key          input_key;
+	Key          key;
 	TBranch&     branch;
-	TClass&      cl;
+	TClass&      clazz;
+      container_t(Key k, TBranch& b, TClass& c) : key(k), branch(b), clazz(c) {}
+      };
+      class work_t   {
+      public:
+	DataSegment& segment;
+	container_t& container;
       };
 
+
     protected:
-      /// Property: Name of the tree to connect to
-      std::string                    m_tree_name   { };
-      /// Property: Container names to be loaded
-      std::vector<std::string>       m_containers  { };
       /// Connection parameters to the "current" input source
       mutable std::unique_ptr<internals_t> imp;
 
-      /// Open new input file
-      void open_new_file()  const;
-
     protected:
       /// Define standard assignments and constructors
       DDDIGI_DEFINE_ACTION_CONSTRUCTORS(DigiROOTInput);
@@ -74,15 +73,6 @@ namespace dd4hep {
       /// Default destructor
       virtual ~DigiROOTInput();
 
-      /// Access to tree name containing data
-      const std::string& tree_name()  const   {
-	return m_tree_name;
-      }
-      /// Access to container names containing data
-      const std::vector<std::string>& container_names()  const   {
-	return m_containers;
-      }
-
       /// Callback to read event input
       virtual void execute(DigiContext& context)  const override;
       /// Callback to handle single branch
diff --git a/DDDigi/io/DigiDDG4Input.cpp b/DDDigi/io/DigiDDG4Input.cpp
index cdbda2200..54bf785af 100644
--- a/DDDigi/io/DigiDDG4Input.cpp
+++ b/DDDigi/io/DigiDDG4Input.cpp
@@ -13,7 +13,6 @@
 
 // Framework include files
 #include <DDDigi/DigiROOTInput.h>
-#include <DDDigi/DigiFactories.h>
 #include "DigiIO.h"
 
 #include <DDG4/Geant4Data.h>
@@ -22,8 +21,7 @@
 // ROOT include files
 #include <TBranch.h>
 #include <TClass.h>
-
-// C/C++ include files
+#include <TROOT.h>
 
 /// Namespace for the AIDA detector description toolkit
 namespace dd4hep {
@@ -35,42 +33,34 @@ namespace dd4hep {
 
     class DigiDDG4ROOT : public DigiROOTInput    {
     public:
-      static constexpr double epsilon = std::numeric_limits<double>::epsilon();
-
       /// Property to generate extra history records
-      bool m_keep_raw          { true };
-      mutable TClass* m_trackerHitClass { nullptr };
-      mutable TClass* m_caloHitClass    { nullptr };
-      mutable TClass* m_particlesClass  { nullptr };
+      bool    m_keep_raw        { true };
 
-      TClass* get_class(TClass* c)  const   {
-	if ( c == m_particlesClass || c == m_trackerHitClass || c == m_caloHitClass )
-	  return c;
-	const char* nam = c->GetName();
-	if ( strstr(nam, "vector<dd4hep::sim::Geant4Particle*") ) 
-	  return m_particlesClass  = c;
-	else if ( strstr(nam, "vector<dd4hep::sim::Geant4Tracker::Hit*") ) 
-	  return m_trackerHitClass = c;
-	else if ( strstr(nam, "vector<dd4hep::sim::Geant4Calorimeter::Hit*") ) 
-	  return m_caloHitClass    = c;
-	except("Unknown data class: %s Cannot be handled", nam);
-	return c;
-      }
+      /// Class pointers of the objects to be imported
+      TClass* m_trackerHitClass { nullptr };
+      TClass* m_caloHitClass    { nullptr };
+      TClass* m_particlesClass  { nullptr };
 
     public:
       /// Initializing constructor
-      DigiDDG4ROOT(const DigiKernel& krnl, const std::string& nam)
-	: DigiROOTInput(krnl, nam)
-      {
+      DigiDDG4ROOT(const DigiKernel& krnl, const std::string& nam) : DigiROOTInput(krnl, nam)      {
 	declareProperty("keep_raw", m_keep_raw);
+	m_particlesClass  = gROOT->GetClass(typeid(std::vector<dd4hep::sim::Geant4Particle*>), kTRUE);
+	m_trackerHitClass = gROOT->GetClass(typeid(std::vector<dd4hep::sim::Geant4Tracker::Hit*>), kTRUE);
+	m_caloHitClass    = gROOT->GetClass(typeid(std::vector<dd4hep::sim::Geant4Calorimeter::Hit*>), kTRUE);
+	assert(m_particlesClass != 0);
+	assert(m_trackerHitClass != 0);
+	assert(m_caloHitClass != 0);
       }
 
+      /// Convert DDG4 hit collections collection
       template <typename T>
-      void conv_hits(DigiContext& context, DataSegment& segment,
-		     const std::string& tag,
-		     Key::mask_type mask,
-		     const char* nam,
-		     void* ptr)   const
+      void from_dd4g4(DigiContext& context,
+		      DataSegment& segment,
+		      const std::string& tag,
+		      Key::mask_type mask,
+		      const char* nam,
+		      void* ptr)   const
       {
 	DepositVector out(nam, mask, SegmentEntry::UNKNOWN);
 	std::map<CellID, std::shared_ptr<T> > hits;
@@ -90,9 +80,12 @@ namespace dd4hep {
 	  put_data(segment, Key(std::string(nam)+".ddg4", mask, segment.id), hits);
 	}
       }
-
-      void conv_particles(DigiContext& context, DataSegment& segment,
-			  int mask, const std::string& nam, void* ptr)   const
+      /// Convert DDG4 MC particle collection
+      void from_dd4g4(DigiContext& context,
+		      DataSegment& segment,
+		      int mask,
+		      const std::string& nam,
+		      void* ptr)   const
       {
 	ParticleMapping particles(nam, mask);
 	if ( ptr )   {
@@ -106,18 +99,19 @@ namespace dd4hep {
 
       /// Callback to handle single branch
       virtual void operator()(DigiContext& context, work_t& work)  const  override  {
-	TBranch& br = work.branch;
-	int     msk = work.input_key.mask();
-	auto&   seg = work.input_segment;
+	TBranch& br = work.container.branch;
 	void**  add = (void**)br.GetAddress();
-	TClass* cls = get_class(&work.cl);
+	int     msk = work.container.key.mask();
+	TClass* cls = &work.container.clazz;
+	auto&   seg = work.segment;
 	const char* nam = br.GetName();
+
 	if ( cls == m_caloHitClass )
-	  conv_hits<sim::Geant4Calorimeter::Hit>(context, seg, "calorimeter", msk, nam, *add);
+	  from_dd4g4<sim::Geant4Calorimeter::Hit>(context, seg, "calorimeter", msk, nam, *add);
 	else if ( cls == m_trackerHitClass )
-	  conv_hits<sim::Geant4Tracker::Hit>(context, seg, "tracker", msk, nam, *add);
+	  from_dd4g4<sim::Geant4Tracker::Hit>(context, seg, "tracker", msk, nam, *add);
 	else if ( cls == m_particlesClass )
-	  conv_particles(context, seg, msk, nam, *add);
+	  from_dd4g4(context, seg, msk, nam, *add);
 	else
 	  except("Unknown data type encountered in branch: %s", nam);
       }
@@ -126,4 +120,5 @@ namespace dd4hep {
 }      // End namespace dd4hep
 
 /// Factory instantiation
+#include <DDDigi/DigiFactories.h>
 DECLARE_DIGIACTION_NS(dd4hep::digi,DigiDDG4ROOT)
diff --git a/DDDigi/io/DigiEdm4hepInput.cpp b/DDDigi/io/DigiEdm4hepInput.cpp
index 977fc3acf..1663fd1fe 100644
--- a/DDDigi/io/DigiEdm4hepInput.cpp
+++ b/DDDigi/io/DigiEdm4hepInput.cpp
@@ -12,115 +12,338 @@
 //==========================================================================
 
 // Framework include files
-#include <DDDigi/DigiROOTInput.h>
-#include <DDDigi/DigiFactories.h>
+#include <DDDigi/DigiInputAction.h>
+#include <DDDigi/DigiData.h>
 #include "DigiIO.h"
 
-#include <DDG4/Geant4Data.h>
-
-// ROOT include files
-#include <TBranch.h>
-#include <TClass.h>
-
 // C/C++ include files
 
+/// Forward declarations
+namespace podio {  class CollectionBase; }
+
 /// Namespace for the AIDA detector description toolkit
 namespace dd4hep {
 
   /// Namespace for the Digitization part of the AIDA detector description toolkit
   namespace digi {
     
-    using namespace std::placeholders;
-
-    class DigiEdm4hepInput : public DigiROOTInput    {
+    /// EDM4HEP Digi input reader
+    /**
+     *
+     *  \author  M.Frank
+     *  \version 1.0
+     *  \ingroup DD4HEP_DIGITIZATION
+     */
+    class DigiEdm4hepInput : public DigiInputAction    {
     public:
       static constexpr double epsilon = std::numeric_limits<double>::epsilon();
 
+      /// Forward declarations
+      class internals_t;
+      class inputsource_t;
+      class collection_t;
+      class work_t;
+      using podio_coll_t = const podio::CollectionBase;
+      using descriptor_t = std::pair<const Key, collection_t>;
+
+      /// Reference to internal data
+      std::unique_ptr<internals_t> internals;
+      /// Type of tracker hit container
+      std::string m_trackerHitType { };
+      /// Type of calorimenter hit container
+      std::string m_caloHitType    { };
+      /// Type of particles container
+      std::string m_particlesType  { };
       /// Property to generate extra history records
-      bool m_keep_raw          { true };
-      mutable TClass* m_trackerHitClass { nullptr };
-      mutable TClass* m_caloHitClass    { nullptr };
-      mutable TClass* m_particlesClass  { nullptr };
-
-      TClass* get_class(TClass* c)  const   {
-	if ( c == m_particlesClass || c == m_trackerHitClass || c == m_caloHitClass )
-	  return c;
-	const char* nam = c->GetName();
-	if ( strstr(nam, "vector<dd4hep::sim::Geant4Particle*") ) 
-	  return m_particlesClass  = c;
-	else if ( strstr(nam, "vector<dd4hep::sim::Geant4Tracker::Hit*") ) 
-	  return m_trackerHitClass = c;
-	else if ( strstr(nam, "vector<dd4hep::sim::Geant4Calorimeter::Hit*") ) 
-	  return m_caloHitClass    = c;
-	except("Unknown data class: %s Cannot be handled", nam);
-	return c;
-      }
+      bool        m_keep_raw       { true };
 
     public:
       /// Initializing constructor
-      DigiEdm4hepInput(const DigiKernel& krnl, const std::string& nam)
-	: DigiROOTInput(krnl, nam)
-      {
-	declareProperty("keep_raw", m_keep_raw);
-      }
+      DigiEdm4hepInput(const DigiKernel& krnl, const std::string& nam);
 
-      template <typename T>
-      void conv_hits(DigiContext& context, DataSegment& segment,
-		     const std::string& tag,
-		     Key::mask_type mask,
-		     const char* nam,
-		     void* ptr)   const
+      template <typename T, typename COLL>
+      void from_edm4hep(DigiContext&       context,
+			DataSegment&       segment,
+			Key::mask_type     mask,
+			const std::string& nam,
+			const COLL*        collection)   const
       {
 	DepositVector out(nam, mask, SegmentEntry::UNKNOWN);
-	std::map<CellID, std::shared_ptr<T> > hits;
+	std::map<CellID, T> hits;
 	std::size_t len = 0;
-	if ( ptr )   {
-	  input_data<T> data(ptr);
-	  const DepositPredicate<EnergyCut> predicate ({ this->epsilon });
-	  len = data.size();
-	  data_io<ddg4_input>()._to_digi_if(data.get(), hits, predicate);
-	  data_io<ddg4_input>()._to_digi(Key(nam, segment.id, mask), hits, out);
-	  data.clear();
-	}
-	info("%s+++ %-24s Converted %6ld Edm4hep %-14s hits to %6ld cell deposits",
-	     context.event->id(), nam, len, tag.c_str(), out.size());
+	const DepositPredicate<EnergyCut> predicate ( { this->epsilon } );
+	len = collection->size();
+	data_io<edm4hep_input>()._to_digi_if(*collection, hits, predicate);
+	data_io<edm4hep_input>()._to_digi(Key(nam, segment.id, mask), hits, out);
+	info("%s+++ %-24s Converted %6ld Edm4hep %-14s to %6ld cell deposits",
+	     context.event->id(), nam.c_str(), len, collection->getValueTypeName().c_str(), out.size());
 	put_data(segment, Key(out.name, mask), out);
 	if ( m_keep_raw )   {
-	  put_data(segment, Key(std::string(nam)+".ddg4", mask, segment.id), hits);
+	  put_data(segment, Key(nam+".edm4hep", mask, segment.id), hits);
 	}
       }
 
-      void conv_particles(DigiContext& context, DataSegment& segment,
-			  int mask, const std::string& nam, void* ptr)   const
+      template <typename COLL>
+      void from_edm4hep(DigiContext&       context,
+			DataSegment&       segment,
+			int                mask,
+			const std::string& nam,
+			const COLL*        collection)   const
       {
 	ParticleMapping particles(nam, mask);
-	if ( ptr )   {
-	  input_data<sim::Geant4Particle> data(ptr);
-	  data_io<ddg4_input>()._to_digi(Key(nam, segment.id, mask), data.get(), particles);
-	  data.clear();
-	}
+	data_io<edm4hep_input>()._to_digi(Key(nam, segment.id, mask), *collection, particles);
 	debug("%s+++ Converted %ld Edm4hep particles", context.event->id(), particles.size());
 	put_data(segment, Key(nam, mask), particles);
       }
 
       /// Callback to handle single branch
-      virtual void operator()(DigiContext& context, work_t& work)  const  override  {
-	TBranch& br = work.branch;
-	int     msk = work.input_key.mask();
-	auto&   seg = work.input_segment;
-	void**  add = (void**)br.GetAddress();
-	TClass* cls = get_class(&work.cl);
-	const char* nam = br.GetName();
-	if ( cls == m_caloHitClass )
-	  conv_hits<sim::Geant4Calorimeter::Hit>(context, seg, "calorimeter", msk, nam, *add);
-	else if ( cls == m_trackerHitClass )
-	  conv_hits<sim::Geant4Tracker::Hit>(context, seg, "tracker", msk, nam, *add);
-	else if ( cls == m_particlesClass )
-	  conv_particles(context, seg, msk, nam, *add);
-	else
-	  except("Unknown data type encountered in branch: %s", nam);
+      virtual void operator()(DigiContext& context, work_t& work)  const;
+      /// Event action callback
+      virtual void execute(DigiContext& context)  const  override;
+    };
+  }    // End namespace digi
+}      // End namespace dd4hep
+
+#include "DigiFrame.h"
+#include <podio/ROOTFrameReader.h>
+#include <edm4hep/SimTrackerHit.h>
+#include <edm4hep/SimCalorimeterHit.h>
+#include <edm4hep/MCParticleCollection.h>
+#include <edm4hep/SimTrackerHitCollection.h>
+#include <edm4hep/EventHeaderCollection.h>
+#include <edm4hep/SimCalorimeterHitCollection.h>
+#include <edm4hep/CaloHitContributionCollection.h>
+
+/// Namespace for the AIDA detector description toolkit
+namespace dd4hep {
+
+  /// Namespace for the Digitization part of the AIDA detector description toolkit
+  namespace digi {
+
+    using reader_t = podio::ROOTFrameReader;
+    using frame_t  = podio::Frame;
+
+    /// EDM4HEP Digi input reader: Collection descriptor definition
+    /**
+     *
+     *  \author  M.Frank
+     *  \version 1.0
+     *  \ingroup DD4HEP_DIGITIZATION
+     */
+    class DigiEdm4hepInput::collection_t   {
+    public:
+      int           id;
+      std::string   name;
+      collection_t(int i, const std::string& n) : id(i), name(n) { }
+    };
+
+    /// EDM4HEP Digi input reader: Work item definition
+    /**
+     *
+     *  \author  M.Frank
+     *  \version 1.0
+     *  \ingroup DD4HEP_DIGITIZATION
+     */
+    class DigiEdm4hepInput::work_t   {
+    public:
+      DigiContext&  context;
+      descriptor_t& descriptor;
+      DataSegment&  segment;
+      podio_coll_t* collection;
+    };
+
+    /// EDM4HEP Digi input reader: Input source definition
+    /**
+     *
+     *  \author  M.Frank
+     *  \version 1.0
+     *  \ingroup DD4HEP_DIGITIZATION
+     */
+    class DigiEdm4hepInput::inputsource_t   {
+    public:
+      /// Reference to the reader object
+      std::unique_ptr<reader_t>   stream      { };
+      /// Collections present in the current file
+      std::map<Key, collection_t> collections { };
+      /// Input source section
+      std::string                 section     { };
+      /// Current entry inside the current input source
+      uint64_t                    entry       { 0 };
+
+    public:
+      /// Initializing constructor
+      inputsource_t(const std::string& s, std::unique_ptr<reader_t>&& str) 
+	: stream(std::move(str)), section(s)  {
+      }
+      /// Default destructor
+      ~inputsource_t()   {
+	if ( stream )    {
+	  stream.reset();
+	}
+      }
+      /// Check for end of the event sequence
+      bool done() const   {
+	auto total = stream->getEntries(section);
+	if ( (1+entry) >= total )   {
+	  return true;
+	}
+	return false;
+      }
+      /// Access the next data frame in the input sequence
+      std::shared_ptr<frame_t> next()   {
+	auto data = stream->readNextEntry(section);
+	if ( data )   {
+	  ++entry;
+	  return std::make_shared<frame_t>(std::move(data));
+	}
+	return {};
       }
     };
+
+    /// EDM4HEP Digi input reader: Internal data definition
+    /**
+     *
+     *  \author  M.Frank
+     *  \version 1.0
+     *  \ingroup DD4HEP_DIGITIZATION
+     */
+    class DigiEdm4hepInput::internals_t  {
+    public:
+      using input_t = std::unique_ptr<inputsource_t>;
+
+      /// Reference to the parent object
+      DigiEdm4hepInput* m_parent { nullptr };
+      /// Handle to input source
+      input_t           m_source { };
+      /// Pointer to current input source
+      int               m_curr_input   { INPUT_START };
+      std::size_t       m_curr_event   { 0 };
+
+    public:
+      /// Initializing constructor
+      internals_t(DigiEdm4hepInput* parent);
+      /// Open new input stream
+      std::unique_ptr<inputsource_t> open_next_data_source();
+      /// Access the next event from the sequence of input files
+      std::shared_ptr<frame_t> next();
+    };
+
+    /// Initializing constructor
+    DigiEdm4hepInput::internals_t::internals_t(DigiEdm4hepInput* parent)
+      : m_parent(parent)
+    {
+    }
+
+    std::unique_ptr<DigiEdm4hepInput::inputsource_t>
+    DigiEdm4hepInput::internals_t::open_next_data_source()   {
+      const auto& inputs = m_parent->inputs();
+      int len = inputs.size();
+      if ( inputs.empty() ) m_curr_input = 0;
+      while ( (m_curr_input+1) < len )   {
+	const auto& fname = inputs[++m_curr_input];
+	auto stream = std::make_unique<reader_t>();
+	try  {
+	  auto sec = m_parent->input_section();
+	  stream->openFile(fname);
+	  auto source = std::make_unique<inputsource_t>(sec, std::move(stream));
+	  m_parent->info("+++ Opened EDM4HEP input file %s.", fname.c_str());
+	  return source;
+	}
+	catch (const std::runtime_error& e)   {
+	  m_parent->error("OpenInput ++ Failed to open input source %s [%s]", fname.c_str(), e.what());
+	}
+      }
+      m_parent->except("+++ No open file present. Configuration error?");
+      throw std::runtime_error("+++ No open file present");
+    }
+
+    std::shared_ptr<frame_t> DigiEdm4hepInput::internals_t::next()   {
+      if ( !m_source || m_source->done() )    {
+	int mask = m_parent->input_mask();
+	m_source = open_next_data_source();
+	if ( m_source )   {
+	  auto frame = m_source->next();
+	  if ( frame )   {
+	    auto table = frame->getIDTable();
+	    const auto& ids = table.ids();
+	    for( int id : ids )   {
+	      std::string nam = table.name(id);
+	      m_parent->info("+++ Collection id: %04X --> '%s'", id, nam.c_str());
+	      if ( m_parent->object_loading_is_enabled(nam) )   {
+		Key key(nam, mask);
+		m_source->collections.emplace( key, collection_t(id, nam) );
+	      }
+	    }
+	    return frame;
+	  }
+	  m_parent->except("+++ No valid frame present in file.");
+	}
+	m_parent->except("+++ No open file present. Aborting processing");
+      }
+      return m_source->next();
+    }
+
+    /// Initializing constructor
+    DigiEdm4hepInput::DigiEdm4hepInput(const DigiKernel& krnl, const std::string& nam)
+      : DigiInputAction(krnl, nam)
+    {
+      internals        = std::make_unique<internals_t>(this);
+      m_trackerHitType = typeName(typeid(edm4hep::SimTrackerHitCollection));
+      m_caloHitType    = typeName(typeid(edm4hep::SimCalorimeterHitCollection));
+      m_particlesType  = typeName(typeid(edm4hep::MCParticleCollection));
+      declareProperty("keep_raw",              m_keep_raw);
+      declareProperty("tracker_hits_type",     m_trackerHitType);
+      declareProperty("calorimeter_hits_type", m_caloHitType);
+      declareProperty("particles_hits_type",   m_particlesType);
+      m_input_section = "events";
+    }
+
+    /// Pre-track action callback
+    void DigiEdm4hepInput::execute(DigiContext& context)  const   {
+      //  Lock all ROOT based actions. SEGV otherwise.
+      std::lock_guard<std::mutex> lock(context.global_io_lock());
+      auto& event = context.event;
+      auto  frame = internals->next();
+      DataSegment& segment = event->get_segment(m_input_segment);
+
+      for( auto& coll : internals->m_source->collections )    {
+	const auto& nam = coll.second.name;
+	const podio::CollectionBase* collection = frame->get(nam);
+	if ( collection )   {
+	  work_t work { context, coll, segment, collection };
+	  (*this)(context, work);
+	  continue;
+	}
+	error("%s+++ Failed to load collection %s from edm4hep frame.",
+	      event->id(), nam.c_str());
+      }
+      /// Add frame to segment: Need to keep reference of the input data!
+      std::any frm(std::move(frame));
+      segment.emplace_any(Key("podio_frame", input_mask()), std::move(frm));
+      info("%s+++ Read event ", event->id());
+    }
+
+    /// Callback to handle single branch
+    void DigiEdm4hepInput::operator()(DigiContext& context, work_t& work)  const  {
+      auto& seg  = work.segment;
+      auto& nam  = work.descriptor.second.name;
+      int   msk  = work.descriptor.first.mask();
+      const auto* col = work.collection;
+      const auto& typ = col->getTypeName();
+
+      if ( typ == m_caloHitType )
+	from_edm4hep<edm4hep::SimCalorimeterHit>(context, seg, msk, nam, static_cast<const edm4hep::SimCalorimeterHitCollection*>(col));
+      else if ( typ == m_trackerHitType )
+	from_edm4hep<edm4hep::SimTrackerHit>(context, seg, msk, nam, static_cast<const edm4hep::SimTrackerHitCollection*>(col));
+      else if ( typ == m_particlesType )
+	from_edm4hep(context, seg, msk, nam, static_cast<const edm4hep::MCParticleCollection*>(col));
+      else
+	except("Unknown data type encountered in branch: %s", nam.c_str());
+    }
+
   }    // End namespace digi
 }      // End namespace dd4hep
+
+/// Factory instantiation
+#include <DDDigi/DigiFactories.h>
 DECLARE_DIGIACTION_NS(dd4hep::digi,DigiEdm4hepInput)
diff --git a/DDDigi/io/DigiIO.cpp b/DDDigi/io/DigiIO.cpp
index b48a10dbb..be6b3c84a 100644
--- a/DDDigi/io/DigiIO.cpp
+++ b/DDDigi/io/DigiIO.cpp
@@ -102,6 +102,11 @@ namespace dd4hep {
     edm4hep::Vector3f _toVectorF(const dd4hep::Position& ep)  {
       return { float(ep.x()), float(ep.y()), float(ep.z()) };
     }
+
+    template <typename POSITION> Position _toPosition(const POSITION& pos)  {
+      return { pos.x, pos.y, pos.z };
+    }
+
     namespace {
       template <typename DATA> bool internal_can_handle(const DATA&, const std::type_info&)   {
         return true;
@@ -255,6 +260,111 @@ namespace dd4hep {
       hit.setEnergyError( dep_error );
       hit.setPosition( _toVectorF(de.position) );
     }
+
+    template <> template <>
+    void data_io<edm4hep_input>::_to_digi(Key key, 
+					  const edm4hep::MCParticleCollection& input,
+					  ParticleMapping& particles)
+    {
+      Key mkey = key;
+      for( std::size_t i=0, n=input.size(); i<n; ++i )  {
+	Particle part {};
+	edm4hep::MCParticle p = input.at(i);
+        part.start_position = _toPosition(p.getVertex());
+        part.end_position   = _toPosition(p.getEndpoint());
+        part.momentum       = _toPosition(p.getMomentum());
+        part.pdgID          = p.getPDG();
+        part.charge         = 3.0*p.getCharge();
+        part.mass           = p.getMass();
+        part.time           = p.getTime();
+        mkey.set_item(particles.size());
+        part.source = std::make_any<edm4hep::MCParticle>(std::move(p));
+        particles.push(mkey, std::move(part));
+      }
+    }
+
+    template <> template <>
+    bool DepositPredicate<EnergyCut>::operator()(edm4hep::SimTrackerHit h)  const   {
+      return h.getEDep() > data.cutoff;
+    }
+
+    template <> template <>
+    void data_io<edm4hep_input>::_to_digi_if(const edm4hep::SimTrackerHitCollection& input,
+					     std::map<CellID, edm4hep::SimTrackerHit>& hits,
+					     const DepositPredicate<EnergyCut>& predicate)   {
+      for( std::size_t i=0, n=input.size(); i<n; ++i )  {
+	auto p = input.at(i);
+        if ( predicate(p) )   {
+          CellID cell = p.getCellID();
+          hits.emplace(cell, std::move(p));
+        }
+      }
+    }
+
+    template <> template <>
+    void data_io<edm4hep_input>::_to_digi(Key key,
+					  const std::map<CellID, edm4hep::SimTrackerHit>& hits,
+					  DepositVector& out)  {
+      out.data_type = SegmentEntry::CALORIMETER_HITS;
+      for( const auto& depo : hits )   {
+	Key history_key;
+	EnergyDeposit dep { };
+	const auto& h = depo.second;
+	dep.flag = h.getQuality();
+	dep.time = h.getTime();
+	dep.length = h.getPathLength();
+	dep.deposit = h.getEDep();
+	dep.position = _toPosition(h.getPosition());
+	dep.momentum = _toPosition(h.getMomentum());
+	history_key.set_mask(key.mask());
+	history_key.set_item(out.size());
+	history_key.set_segment(key.segment());
+	dep.history.hits.emplace_back(history_key, dep.deposit);
+	//add_particle_history(h, history_key, dep.history);
+	out.emplace(depo.first, std::move(dep));
+      }
+    }
+
+    template <> template <>
+    bool DepositPredicate<EnergyCut>::operator()(edm4hep::SimCalorimeterHit h)  const   {
+      return h.getEnergy() > data.cutoff;
+    }
+
+    template <> template <>
+    void data_io<edm4hep_input>::_to_digi_if(const edm4hep::SimCalorimeterHitCollection& input,
+					     std::map<CellID, edm4hep::SimCalorimeterHit>& hits,
+					     const DepositPredicate<EnergyCut>& predicate)   {
+      for( std::size_t i=0, n=input.size(); i<n; ++i )  {
+	auto p = input.at(i);
+        if ( predicate(p) )   {
+          CellID cell = p.getCellID();
+          hits.emplace(cell, std::move(p));
+        }
+      }
+    }
+
+    template <> template <>
+    void data_io<edm4hep_input>::_to_digi(Key key,
+					  const std::map<CellID, edm4hep::SimCalorimeterHit>& hits,
+					  DepositVector& out)  {
+      out.data_type = SegmentEntry::CALORIMETER_HITS;
+      for( const auto& depo : hits )  {
+	Key history_key;
+	EnergyDeposit dep { };
+	const auto& h = depo.second;
+	dep.flag = 0;
+	
+	dep.deposit = h.getEnergy();
+	dep.position = _toPosition(h.getPosition());
+	history_key.set_mask(key.mask());
+	history_key.set_item(out.size());
+	history_key.set_segment(key.segment());
+	dep.history.hits.emplace_back(history_key, dep.deposit);
+	//add_particle_history(h, history_key, dep.history);
+	out.emplace(depo.first, std::move(dep));
+      }
+    }
+
   }     // End namespace digi
 }       // End namespace dd4hep
 #endif  // DD4HEP_USE_EDM4HEP
@@ -346,7 +456,7 @@ namespace dd4hep {
     }
 
     template <typename T>
-    static void cnv_to_digi(Key key,
+    static void ddg4_cnv_to_digi(Key key,
                             const std::pair<const CellID, std::shared_ptr<T> >& depo,
                             DepositVector& out)     {
       Key history_key;
@@ -373,7 +483,7 @@ namespace dd4hep {
                                        DepositVector& out)  {
       out.data_type = SegmentEntry::CALORIMETER_HITS;
       for( const auto& p : hits )
-        cnv_to_digi(key, p, out);
+        ddg4_cnv_to_digi(key, p, out);
     }
 
     template <> template <>
@@ -382,7 +492,7 @@ namespace dd4hep {
                                        DepositVector& out)  {
       out.data_type = SegmentEntry::TRACKER_HITS;
       for( const auto& p : hits )
-        cnv_to_digi(key, p, out);
+        ddg4_cnv_to_digi(key, p, out);
     }
   }     // End namespace digi
 }       // End namespace dd4hep
diff --git a/DDDigi/src/DigiInputAction.cpp b/DDDigi/src/DigiInputAction.cpp
index 5ea068401..4a5d63584 100644
--- a/DDDigi/src/DigiInputAction.cpp
+++ b/DDDigi/src/DigiInputAction.cpp
@@ -26,10 +26,13 @@ using namespace dd4hep::digi;
 DigiInputAction::DigiInputAction(const DigiKernel& kernel, const string& nam)
   : DigiEventAction(kernel, nam)
 {
-  declareProperty("input",   m_input_sources);
-  declareProperty("segment", m_input_segment);
-  declareProperty("mask",    m_input_mask);
-  declareProperty("rescan",  m_input_rescan);
+  declareProperty("input",            m_input_sources);
+  declareProperty("segment",          m_input_segment);
+  declareProperty("mask",             m_input_mask);
+  declareProperty("rescan",           m_input_rescan);
+  declareProperty("input_section",    m_input_section);
+  declareProperty("objects_enabled",  m_objects_enabled);
+  declareProperty("objects_disabled", m_objects_disabled);
   InstanceCount::increment(this);
 }
 
@@ -38,6 +41,30 @@ DigiInputAction::~DigiInputAction()   {
   InstanceCount::decrement(this);
 }
 
+/// Check if a event object should be loaded: Default YES unless inhibited by selection or veto
+bool DigiInputAction::object_loading_is_enabled(const std::string& nam)  const   {
+  /// If there are no required branches, we convert everything
+  if ( m_objects_enabled.empty() && m_objects_disabled.empty() )    {
+    return true;
+  }
+  /// Check for disabled collections:
+  for( const auto& bname : m_objects_disabled )    {
+    if ( bname == nam )
+      return false;
+  }
+  /// No selection to be performed: take them all
+  if ( m_objects_enabled.empty() )    {
+    return true;
+  }
+  /// .... Otherwise only the entities asked for
+  for( const auto& bname : m_objects_enabled )    {
+    if ( bname == nam )   {
+      return true;
+    }
+  }
+  return false;
+}
+
 /// Pre-track action callback
 void DigiInputAction::execute(DigiContext& /* context */)  const   {
   info("+++ Virtual method execute() --- Should not be called");
diff --git a/DDDigi/src/DigiROOTInput.cpp b/DDDigi/src/DigiROOTInput.cpp
index 5a8382ee4..5d64df556 100644
--- a/DDDigi/src/DigiROOTInput.cpp
+++ b/DDDigi/src/DigiROOTInput.cpp
@@ -29,16 +29,9 @@
 using namespace dd4hep::digi;
 
 class DigiROOTInput::inputsource_t   {
-public:
-  class converter_t   {
-  public:
-    TBranch* branch   { nullptr };
-    TClass*  cls      { nullptr };
-  };
-
 public:
   /// Branches present in the current file
-  std::map<Key, converter_t>  branches  { };
+  std::map<Key, container_t>  branches  { };
   /// Reference to the current ROOT file to be read
   TFile*     file   { nullptr };
   /// Reference to the ROOT tree to be read
@@ -72,12 +65,12 @@ public:
 class DigiROOTInput::internals_t   {
 public:
   using handle_t = std::unique_ptr<inputsource_t>;
-  /// Pointer to current input source
-  int            m_curr_input  { INPUT_START };
+  /// Reference to parent action
+  DigiROOTInput* m_parent  { nullptr };
   /// Handle to input source
   handle_t       m_input_handle;
-  /// Reference to parent action
-  DigiROOTInput* m_input_action  { nullptr };
+  /// Pointer to current input source
+  int            m_curr_input  { INPUT_START };
 
 public:
   /// Default constructor
@@ -92,7 +85,7 @@ public:
 
 /// Default constructor
 DigiROOTInput::internals_t::internals_t (DigiROOTInput* p)
-  : m_input_action(p)
+  : m_parent(p)
 {
 }
 
@@ -110,8 +103,8 @@ DigiROOTInput::inputsource_t& DigiROOTInput::internals_t::next()   {
 
 std::unique_ptr<DigiROOTInput::inputsource_t>
 DigiROOTInput::internals_t::open_next_data_source()   {
-  const auto& inputs = m_input_action->inputs();
-  const auto& tree_name = m_input_action->tree_name();
+  const auto& inputs = m_parent->inputs();
+  const auto& tree_name = m_parent->input_section();
 
   int len = inputs.size();
   if ( inputs.empty() ) m_curr_input = 0;
@@ -121,56 +114,45 @@ DigiROOTInput::internals_t::open_next_data_source()   {
     if ( file && file->IsZombie() )  {
       delete file;
       file = nullptr;
-      m_input_action->error("OpenInput ++ Failed to open input source %s", fname.c_str());
+      m_parent->error("OpenInput ++ Failed to open input source %s", fname.c_str());
     }
     else if ( file )  {
       auto* tree = (TTree*)file->Get(tree_name.c_str());
       if ( !tree )   {
-	m_input_action->error("OpenInput ++ Failed to access tree: %s in input: %s", 
-			      tree_name.c_str(), fname.c_str());
+	m_parent->error("OpenInput ++ Failed to access tree: %s in input: %s", 
+			tree_name.c_str(), fname.c_str());
 	continue;
       }
       Int_t total = tree->GetEntries();
       if ( total <= 0 )   {
-	m_input_action->error("OpenInput ++ TTree %s exists, but has no data. input: %s", 
-			      tree_name.c_str(), fname.c_str());
+	m_parent->error("OpenInput ++ TTree %s exists, but has no data. input: %s", 
+			tree_name.c_str(), fname.c_str());
 	continue;
       }
       auto source = std::make_unique<inputsource_t>();
       source->branches.clear();
-      source->file = file;
-      source->tree = tree;
+      source->file  = file;
+      source->tree  = tree;
       source->entry = -1;
 
       auto* branches = tree->GetListOfBranches();
-      const auto& containers = m_input_action->container_names();
-      int mask = m_input_action->input_mask();
+      int mask = m_parent->input_mask();
       TObjArrayIter it(branches);
       for(Int_t i=0; i < branches->GetEntriesFast(); ++i)   {
 	TBranch*  b = (TBranch*)branches->At(i);
-	TClass* cls = gROOT->GetClass( b->GetClassName(), kTRUE );
-	/// If there are no required branches, we convert everything
-	if ( containers.empty() )    {
+	if ( m_parent->object_loading_is_enabled(b->GetName()) )   {
+	  TClass* cls = gROOT->GetClass( b->GetClassName(), kTRUE );
 	  Key key(b->GetName(), mask);
-	  source->branches[key] = {b, cls};
-	  continue;
-	}
-	/// Otherwise only the entities asked for
-	for( const auto& bname : containers )    {
-	  if ( bname == b->GetName() )   {
-	    Key key(b->GetName(), mask);
-	    source->branches[key] = {b, cls};
-	    break;
-	  }
+	  source->branches.emplace(key, container_t(key, *b, *cls));
 	}
       }
       if ( source->branches.empty() )    {
-	m_input_action->except("+++ No branches to be loaded. Configuration error!");
+	m_parent->except("+++ No branches to be loaded. Configuration error!");
       }
       return source;
     }
   }
-  m_input_action->except("+++ No open file present. Configuration error?");
+  m_parent->except("+++ No open file present. Configuration error?");
   throw std::runtime_error("+++ No open file present");
 }
 
@@ -179,8 +161,6 @@ DigiROOTInput::DigiROOTInput(const DigiKernel& kernel, const std::string& nam)
   : DigiInputAction(kernel, nam)
 {
   imp = std::make_unique<internals_t>(this);
-  declareProperty("tree", m_tree_name = "EVENT");
-  declareProperty("containers", m_containers);
   InstanceCount::increment(this);
 }
 
@@ -201,16 +181,16 @@ void DigiROOTInput::execute(DigiContext& context)  const   {
   std::size_t input_len = 0;
 
   /// We only get here with a valid input
-  DataSegment& segment = event->get_segment(this->m_input_segment);
+  DataSegment& segment = event->get_segment(m_input_segment);
   for( auto& b : source.branches )    {
     auto& ent = b.second;
-    Long64_t bytes = ent.branch->GetEntry( source.entry );
+    Long64_t bytes = ent.branch.GetEntry( source.entry );
     if ( bytes > 0 )  {
-      work_t work { segment, b.first, *ent.branch, *ent.cls };
+      work_t work { segment, ent };
       (*this)(context, work);
       input_len += bytes;
     }
-    debug("%s+++ Loaded %8ld bytes from branch %s", event->id(), bytes, ent.branch->GetName());
+    debug("%s+++ Loaded %8ld bytes from branch %s", event->id(), bytes, ent.branch.GetName());
   }
   info("%s+++ Read event %6ld [%ld bytes] from tree %s file: %s",
        event->id(), source.entry, input_len, source.tree->GetName(), source.file->GetName());
diff --git a/examples/ClientTests/CMakeLists.txt b/examples/ClientTests/CMakeLists.txt
index 77c521b3e..31e9120dc 100644
--- a/examples/ClientTests/CMakeLists.txt
+++ b/examples/ClientTests/CMakeLists.txt
@@ -491,8 +491,8 @@ if (DD4HEP_USE_GEANT4)
     # Test EDM4HEP write (needs to be expanded)
     dd4hep_add_test_reg(ClientTests_sim_MinitTel_edm4hep_write
       COMMAND    "${CMAKE_INSTALL_PREFIX}/bin/run_test_ClientTests.sh"
-      EXEC_ARGS  ${Python_EXECUTABLE} ${ClientTestsEx_INSTALL}/scripts/MiniTelEdm4hepWrite.py
-                 -batch -events 5
+      EXEC_ARGS  ${Python_EXECUTABLE} ${ClientTestsEx_INSTALL}/scripts/MiniTelGenerate.py
+                 -batch -events 5 -output MiniTel_ddg4_edm4hep.edm4hep.root
       REGEX_PASS "\\+\\+\\+ Finished run 0 after 5 events \\(5 events in total\\)"
       REGEX_FAIL "Error;ERROR;Exception"
     )
diff --git a/examples/DDDigi/CMakeLists.txt b/examples/DDDigi/CMakeLists.txt
index 6aeda661a..d03210604 100644
--- a/examples/DDDigi/CMakeLists.txt
+++ b/examples/DDDigi/CMakeLists.txt
@@ -63,7 +63,7 @@ dd4hep_add_test_reg(DDDigi_properties
 #
 if (DD4HEP_USE_GEANT4)
   # Generate test data
-  dd4hep_add_test_reg(DDDigi_generate_data
+  dd4hep_add_test_reg(DDDigi_generate_ddg4_data
     COMMAND    "${CMAKE_INSTALL_PREFIX}/bin/run_test_DDDigi.sh"
     EXEC_ARGS  ${Python_EXECUTABLE} ${CMAKE_INSTALL_PREFIX}/examples/ClientTests/scripts/MiniTelGenerate.py
          -batch -events 30 -runs 8
@@ -74,7 +74,7 @@ if (DD4HEP_USE_GEANT4)
   dd4hep_add_test_reg(DDDigi_test_input_reading
     COMMAND    "${CMAKE_INSTALL_PREFIX}/bin/run_test_DDDigi.sh"
     EXEC_ARGS  ${Python_EXECUTABLE} ${CMAKE_INSTALL_PREFIX}/examples/DDDigi/scripts/TestInput.py
-    DEPENDS    DDDigi_generate_data
+    DEPENDS    DDDigi_generate_ddg4_data
     REGEX_PASS "\\+\\+\\+ 5 Events out of 5 processed"
     REGEX_FAIL "Error;ERROR;Exception"
   )
@@ -83,14 +83,14 @@ if (DD4HEP_USE_GEANT4)
     COMMAND    "${CMAKE_INSTALL_PREFIX}/bin/run_test_DDDigi.sh"
     EXEC_ARGS  ${Python_EXECUTABLE} ${CMAKE_INSTALL_PREFIX}/examples/DDDigi/scripts/TestInput.py
                -num_events 1000
-    DEPENDS    DDDigi_generate_data
+    DEPENDS    DDDigi_generate_ddg4_data
     REGEX_PASS "\\+\\+ Terminate Digi and delete associated actions."
   )
   # Test signal attenuation for spillover
   dd4hep_add_test_reg(DDDigi_test_attenuate
     COMMAND    "${CMAKE_INSTALL_PREFIX}/bin/run_test_DDDigi.sh"
     EXEC_ARGS  ${Python_EXECUTABLE} ${CMAKE_INSTALL_PREFIX}/examples/DDDigi/scripts/TestAttenuate.py
-    DEPENDS    DDDigi_generate_data
+    DEPENDS    DDDigi_generate_ddg4_data
     REGEX_PASS "\\+\\+\\+ 5 Events out of 5 processed"
     REGEX_FAIL "Error;ERROR;Exception"
   )
@@ -98,7 +98,7 @@ if (DD4HEP_USE_GEANT4)
   dd4hep_add_test_reg(DDDigi_test_move_IP
     COMMAND    "${CMAKE_INSTALL_PREFIX}/bin/run_test_DDDigi.sh"
     EXEC_ARGS  ${Python_EXECUTABLE} ${CMAKE_INSTALL_PREFIX}/examples/DDDigi/scripts/TestIPMove.py
-    DEPENDS    DDDigi_generate_data
+    DEPENDS    DDDigi_generate_ddg4_data
     REGEX_PASS "\\+\\+\\+ 5 Events out of 5 processed"
     REGEX_FAIL "Error;ERROR;Exception"
   )
@@ -106,7 +106,7 @@ if (DD4HEP_USE_GEANT4)
   dd4hep_add_test_reg(DDDigi_test_deposit_count
     COMMAND    "${CMAKE_INSTALL_PREFIX}/bin/run_test_DDDigi.sh"
     EXEC_ARGS  ${Python_EXECUTABLE} ${CMAKE_INSTALL_PREFIX}/examples/DDDigi/scripts/TestDepositCount.py
-    DEPENDS    DDDigi_generate_data
+    DEPENDS    DDDigi_generate_ddg4_data
     REGEX_PASS "\\+\\+\\+ 5 Events out of 5 processed"
     REGEX_FAIL "Error;ERROR;Exception"
   )
@@ -114,7 +114,7 @@ if (DD4HEP_USE_GEANT4)
   dd4hep_add_test_reg(DDDigi_test_weighted_deposit_overlay
     COMMAND    "${CMAKE_INSTALL_PREFIX}/bin/run_test_DDDigi.sh"
     EXEC_ARGS  ${Python_EXECUTABLE} ${CMAKE_INSTALL_PREFIX}/examples/DDDigi/scripts/TestDepositWeighted.py
-    DEPENDS    DDDigi_generate_data
+    DEPENDS    DDDigi_generate_ddg4_data
     REGEX_PASS "\\+\\+\\+ 5 Events out of 5 processed"
     REGEX_FAIL "Error;ERROR;Exception"
   )
@@ -122,7 +122,7 @@ if (DD4HEP_USE_GEANT4)
   dd4hep_add_test_reg(DDDigi_test_deposit_smear_energy
     COMMAND    "${CMAKE_INSTALL_PREFIX}/bin/run_test_DDDigi.sh"
     EXEC_ARGS  ${Python_EXECUTABLE} ${CMAKE_INSTALL_PREFIX}/examples/DDDigi/scripts/TestDepositSmearEnergy.py
-    DEPENDS    DDDigi_generate_data
+    DEPENDS    DDDigi_generate_ddg4_data
     REGEX_PASS "\\+\\+\\+ 5 Events out of 5 processed"
     REGEX_FAIL "Error;ERROR;Exception"
   )
@@ -130,7 +130,7 @@ if (DD4HEP_USE_GEANT4)
   dd4hep_add_test_reg(DDDigi_test_deposit_smear_time
     COMMAND    "${CMAKE_INSTALL_PREFIX}/bin/run_test_DDDigi.sh"
     EXEC_ARGS  ${Python_EXECUTABLE} ${CMAKE_INSTALL_PREFIX}/examples/DDDigi/scripts/TestDepositSmearTime.py
-    DEPENDS    DDDigi_generate_data
+    DEPENDS    DDDigi_generate_ddg4_data
     REGEX_PASS "\\+\\+\\+ 5 Events out of 5 processed"
     REGEX_FAIL "Error;ERROR;Exception"
   )
@@ -138,7 +138,7 @@ if (DD4HEP_USE_GEANT4)
   dd4hep_add_test_reg(DDDigi_test_smear_position
     COMMAND    "${CMAKE_INSTALL_PREFIX}/bin/run_test_DDDigi.sh"
     EXEC_ARGS  ${Python_EXECUTABLE} ${CMAKE_INSTALL_PREFIX}/examples/DDDigi/scripts/TestPositionSmearResolution.py
-    DEPENDS    DDDigi_generate_data
+    DEPENDS    DDDigi_generate_ddg4_data
     REGEX_PASS "\\+\\+\\+ 5 Events out of 5 processed"
     REGEX_FAIL "Error;ERROR;Exception"
   )
@@ -146,7 +146,7 @@ if (DD4HEP_USE_GEANT4)
   dd4hep_add_test_reg(DDDigi_test_smear_track
     COMMAND    "${CMAKE_INSTALL_PREFIX}/bin/run_test_DDDigi.sh"
     EXEC_ARGS  ${Python_EXECUTABLE} ${CMAKE_INSTALL_PREFIX}/examples/DDDigi/scripts/TestPositionSmearTrack.py
-    DEPENDS    DDDigi_generate_data
+    DEPENDS    DDDigi_generate_ddg4_data
     REGEX_PASS "\\+\\+\\+ 5 Events out of 5 processed"
     REGEX_FAIL "Error;ERROR;Exception"
   )
@@ -154,7 +154,7 @@ if (DD4HEP_USE_GEANT4)
   dd4hep_add_test_reg(DDDigi_test_multi_interactions
     COMMAND    "${CMAKE_INSTALL_PREFIX}/bin/run_test_DDDigi.sh"
     EXEC_ARGS  ${Python_EXECUTABLE} ${CMAKE_INSTALL_PREFIX}/examples/DDDigi/scripts/TestMultiInteractions.py
-    DEPENDS    DDDigi_generate_data
+    DEPENDS    DDDigi_generate_ddg4_data
     REGEX_PASS "\\+\\+\\+ 5 Events out of 5 processed"
     REGEX_FAIL "Error;ERROR;Exception"
   )
@@ -162,7 +162,7 @@ if (DD4HEP_USE_GEANT4)
   dd4hep_add_test_reg(DDDigi_test_spillover
     COMMAND    "${CMAKE_INSTALL_PREFIX}/bin/run_test_DDDigi.sh"
     EXEC_ARGS  ${Python_EXECUTABLE} ${CMAKE_INSTALL_PREFIX}/examples/DDDigi/scripts/TestSpillover.py
-    DEPENDS    DDDigi_generate_data
+    DEPENDS    DDDigi_generate_ddg4_data
     REGEX_PASS "\\+\\+\\+ 5 Events out of 5 processed"
     REGEX_FAIL "Error;ERROR;Exception"
   )
@@ -170,7 +170,7 @@ if (DD4HEP_USE_GEANT4)
   dd4hep_add_test_reg(DDDigi_test_containers_parallel
     COMMAND    "${CMAKE_INSTALL_PREFIX}/bin/run_test_DDDigi.sh"
     EXEC_ARGS  ${Python_EXECUTABLE} ${CMAKE_INSTALL_PREFIX}/examples/DDDigi/scripts/TestMultiContainerParallel.py
-    DEPENDS    DDDigi_generate_data
+    DEPENDS    DDDigi_generate_ddg4_data
     REGEX_PASS "\\+\\+\\+ 5 Events out of 5 processed"
     REGEX_FAIL "Error;ERROR;Exception"
   )
@@ -178,7 +178,7 @@ if (DD4HEP_USE_GEANT4)
   dd4hep_add_test_reg(DDDigi_test_detector_resegmentation
     COMMAND    "${CMAKE_INSTALL_PREFIX}/bin/run_test_DDDigi.sh"
     EXEC_ARGS  ${Python_EXECUTABLE} ${CMAKE_INSTALL_PREFIX}/examples/DDDigi/scripts/TestResegmentation.py
-    DEPENDS    DDDigi_generate_data
+    DEPENDS    DDDigi_generate_ddg4_data
     REGEX_PASS "\\+\\+\\+ 5 Events out of 5 processed"
     REGEX_FAIL "Error;ERROR;Exception"
   )
@@ -186,7 +186,7 @@ if (DD4HEP_USE_GEANT4)
   dd4hep_add_test_reg(DDDigi_test_segmentation_split_1
     COMMAND    "${CMAKE_INSTALL_PREFIX}/bin/run_test_DDDigi.sh"
     EXEC_ARGS  ${Python_EXECUTABLE} ${CMAKE_INSTALL_PREFIX}/examples/DDDigi/scripts/TestSegmentationSplit.py
-    DEPENDS    DDDigi_generate_data
+    DEPENDS    DDDigi_generate_ddg4_data
     REGEX_PASS "\\+\\+\\+ 5 Events out of 5 processed"
     REGEX_FAIL "Error;ERROR;Exception"
   )
@@ -194,7 +194,7 @@ if (DD4HEP_USE_GEANT4)
   dd4hep_add_test_reg(DDDigi_test_segmentation_split_2
     COMMAND    "${CMAKE_INSTALL_PREFIX}/bin/run_test_DDDigi.sh"
     EXEC_ARGS  ${Python_EXECUTABLE} ${CMAKE_INSTALL_PREFIX}/examples/DDDigi/scripts/TestSegmentationSplit2.py
-    DEPENDS    DDDigi_generate_data
+    DEPENDS    DDDigi_generate_ddg4_data
     REGEX_PASS "\\+\\+\\+ 5 Events out of 5 processed"
     REGEX_FAIL "Error;ERROR;Exception"
   )
@@ -202,7 +202,7 @@ if (DD4HEP_USE_GEANT4)
   dd4hep_add_test_reg(DDDigi_test_simple_adc_response
     COMMAND    "${CMAKE_INSTALL_PREFIX}/bin/run_test_DDDigi.sh"
     EXEC_ARGS  ${Python_EXECUTABLE} ${CMAKE_INSTALL_PREFIX}/examples/DDDigi/scripts/TestSimpleADCResponse.py
-    DEPENDS    DDDigi_generate_data
+    DEPENDS    DDDigi_generate_ddg4_data
     REGEX_PASS "\\+\\+\\+ 5 Events out of 5 processed"
     REGEX_FAIL "Error;ERROR;Exception"
   )
@@ -211,19 +211,27 @@ if (DD4HEP_USE_GEANT4)
   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
+    DEPENDS    DDDigi_generate_ddg4_data
     REGEX_PASS "\\+\\+\\+ Closing ROOT output file dddigi_write_digi_00000000.root after 5 events"
     REGEX_FAIL "Error;ERROR;Exception"
   )
   #
   # Test EDM4HEP output module
   if (DD4HEP_USE_EDM4HEP)
-    # Test EDM4HEP write (needs to be expanded)
+    # Generate test data
+    dd4hep_add_test_reg(DDDigi_generate_edm4hep_data
+      COMMAND    "${CMAKE_INSTALL_PREFIX}/bin/run_test_DDDigi.sh"
+      EXEC_ARGS  ${Python_EXECUTABLE} ${CMAKE_INSTALL_PREFIX}/examples/ClientTests/scripts/MiniTelGenerate.py
+      -batch -events 30 -runs 3 -output MiniTel_edm4hep_DDG4_data.root
+      REGEX_PASS "\\+\\+\\+ Finished run 2 after 30 events \\(90 events in total\\)."
+      REGEX_FAIL "Error;ERROR;Exception"
+    )
+    # Test EDM4HEP write from ddg4 input (needs to be expanded)
     dd4hep_add_test_reg(DDDigi_test_edm4hep_write
       COMMAND    "${CMAKE_INSTALL_PREFIX}/bin/run_test_DDDigi.sh"
       EXEC_ARGS  ${Python_EXECUTABLE} ${CMAKE_INSTALL_PREFIX}/examples/DDDigi/scripts/TestWriteEdm4hep.py
-                 -num_events 5 -num_threads 10 -events_parallel 4
-      DEPENDS    DDDigi_generate_data
+                   -num_events 5 -num_threads 10 -events_parallel 4
+      DEPENDS    DDDigi_generate_ddg4_data
       REGEX_PASS "\\+\\+\\+ 5 Events out of 5 processed."
       REGEX_FAIL "Error;ERROR;Exception"
     )
diff --git a/examples/DDDigi/scripts/TestEdm4hepInput.py b/examples/DDDigi/scripts/TestEdm4hepInput.py
index 22232a0b3..9f8bf8b68 100644
--- a/examples/DDDigi/scripts/TestEdm4hepInput.py
+++ b/examples/DDDigi/scripts/TestEdm4hepInput.py
@@ -13,13 +13,14 @@ from __future__ import absolute_import
 
 def run():
   import DigiTest
-  digi = DigiTest.Test(geometry=None)
+  digi = DigiTest.Test(geometry=None, process_data=False)
   read = digi.input_action('DigiEdm4hepInput/SignalReader',
                            mask=0x0,
-                           input=['../ClientTests/MiniTel_ddg4_edm4hep.root'])
-  dump = digi.event_action('DigiStoreDump/StoreDump', parallel=False)
-  digi.check_creation([read, dump])
-  digi.run_checked(num_events=5, num_threads=5, parallel=3)
+                           input=['MiniTel_edm4hep_DDG4_data.run00000000.root'])
+  read.input_section = 'events'
+  read.objects_disabled = ['EventHeader']
+  digi.event_action('DigiStoreDump/StoreDump', parallel=False)
+  digi.run_checked(num_events=5, num_threads=1, parallel=1)
 
 
 if __name__ == '__main__':
diff --git a/examples/DDDigi/scripts/TestWriteEdm4hep.py b/examples/DDDigi/scripts/TestWriteEdm4hep.py
index b91f12253..bfe859479 100644
--- a/examples/DDDigi/scripts/TestWriteEdm4hep.py
+++ b/examples/DDDigi/scripts/TestWriteEdm4hep.py
@@ -21,7 +21,7 @@ def run():
                             parallel=True,
                             input_mask=0x0,
                             input_segment='input',
-                            output='dddigi_write_edm4hep.root')
+                            output='MiniTel_dddigi_edm4hep.root')
   proc = digi.create_action('Digi2edm4hepProcessor/edm4hep')
   hit_type = 'TrackerHits'
   if digi.hit_type:
-- 
GitLab