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