diff --git a/DDDigi/include/DDDigi/DigiInputAction.h b/DDDigi/include/DDDigi/DigiInputAction.h index acf5d75f88cfc4ab6c7b640d7aece68ce1def373..c5b1373be96df61542c1ac94bd1e81920b3cbd4c 100644 --- a/DDDigi/include/DDDigi/DigiInputAction.h +++ b/DDDigi/include/DDDigi/DigiInputAction.h @@ -42,6 +42,18 @@ namespace dd4hep { /// Most probably need some minimum cutoff: static constexpr double epsilon = std::numeric_limits<double>::epsilon(); + /// Input source base + class input_source { + public: + /// Event counter for current file + int event_count { 0 }; + }; + + /// Event frame base + class event_frame { + public: + }; + protected: /// Property: Input data specification std::vector<std::string> m_input_sources { }; @@ -55,9 +67,13 @@ namespace dd4hep { std::string m_input_segment { "inputs" }; /// Property: Mask to flag input source items int m_input_mask { NO_MASK }; + /// Property: Number of events to be read by file + int m_events_per_file { -1 }; /// Property: Loop on inputs and restart at end bool m_input_rescan { true }; - + /// Property: generate raw input history records to Digi store + bool m_keep_raw { true }; + protected: /// Define standard assignments and constructors DDDIGI_DEFINE_ACTION_CONSTRUCTORS(DigiInputAction); @@ -92,6 +108,13 @@ namespace dd4hep { const std::vector<std::string>& objects_disabled() const { return m_objects_disabled; } + /// Check if the number of events per file is reached + bool fileLimitReached(input_source& source) const; + /// Callback when a new file is opened + virtual void onOpenFile(input_source& source); + /// Callback when a new event is processed + virtual void onProcessEvent(input_source& source, event_frame& frame); + /// 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; diff --git a/DDDigi/io/DigiDDG4Input.cpp b/DDDigi/io/DigiDDG4Input.cpp index 54bf785afc0bc804cd0ba3a38ed8fdc58f22fcf2..88a1e1ae34884a1269c842f685cf40b21e837be2 100644 --- a/DDDigi/io/DigiDDG4Input.cpp +++ b/DDDigi/io/DigiDDG4Input.cpp @@ -33,9 +33,6 @@ namespace dd4hep { class DigiDDG4ROOT : public DigiROOTInput { public: - /// Property to generate extra history records - bool m_keep_raw { true }; - /// Class pointers of the objects to be imported TClass* m_trackerHitClass { nullptr }; TClass* m_caloHitClass { nullptr }; @@ -44,7 +41,6 @@ namespace dd4hep { public: /// Initializing constructor 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); diff --git a/DDDigi/io/DigiEdm4hepInput.cpp b/DDDigi/io/DigiEdm4hepInput.cpp index 1663fd1fee786749414a2920374cd275061508a2..ee06258c687353cfa614b2f3e5fdc1d3f63fa849 100644 --- a/DDDigi/io/DigiEdm4hepInput.cpp +++ b/DDDigi/io/DigiEdm4hepInput.cpp @@ -54,9 +54,7 @@ namespace dd4hep { std::string m_caloHitType { }; /// Type of particles container std::string m_particlesType { }; - /// Property to generate extra history records - bool m_keep_raw { true }; - + public: /// Initializing constructor DigiEdm4hepInput(const DigiKernel& krnl, const std::string& nam); @@ -120,9 +118,14 @@ namespace dd4hep { /// Namespace for the Digitization part of the AIDA detector description toolkit namespace digi { + class edm4hep_read_frame_t : public DigiInputAction::event_frame { + public: + podio::Frame frame { }; + edm4hep_read_frame_t(podio::Frame&& frm) : frame(std::move(frm)) {} + }; using reader_t = podio::ROOTFrameReader; - using frame_t = podio::Frame; - + using frame_t = edm4hep_read_frame_t; + /// EDM4HEP Digi input reader: Collection descriptor definition /** * @@ -159,7 +162,7 @@ namespace dd4hep { * \version 1.0 * \ingroup DD4HEP_DIGITIZATION */ - class DigiEdm4hepInput::inputsource_t { + class DigiEdm4hepInput::inputsource_t : public DigiInputAction::input_source { public: /// Reference to the reader object std::unique_ptr<reader_t> stream { }; @@ -217,7 +220,6 @@ namespace dd4hep { 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 @@ -247,6 +249,7 @@ namespace dd4hep { 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()); + m_parent->onOpenFile(*source); return source; } catch (const std::runtime_error& e) { @@ -258,13 +261,13 @@ namespace dd4hep { } std::shared_ptr<frame_t> DigiEdm4hepInput::internals_t::next() { - if ( !m_source || m_source->done() ) { + if ( !m_source || m_source->done() || m_parent->fileLimitReached(*m_source) ) { 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(); + auto table = frame->frame.getIDTable(); const auto& ids = table.ids(); for( int id : ids ) { std::string nam = table.name(id); @@ -274,13 +277,16 @@ namespace dd4hep { m_source->collections.emplace( key, collection_t(id, nam) ); } } + m_parent->onProcessEvent(*m_source, *frame); return frame; } m_parent->except("+++ No valid frame present in file."); } m_parent->except("+++ No open file present. Aborting processing"); } - return m_source->next(); + auto frame = m_source->next(); + m_parent->onProcessEvent(*m_source, *frame); + return frame; } /// Initializing constructor @@ -291,7 +297,6 @@ namespace dd4hep { 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); @@ -308,7 +313,7 @@ namespace dd4hep { for( auto& coll : internals->m_source->collections ) { const auto& nam = coll.second.name; - const podio::CollectionBase* collection = frame->get(nam); + const podio::CollectionBase* collection = frame->frame.get(nam); if ( collection ) { work_t work { context, coll, segment, collection }; (*this)(context, work); diff --git a/DDDigi/src/DigiInputAction.cpp b/DDDigi/src/DigiInputAction.cpp index 4a5d6358493964e5680c10a2ff49b0757f361f47..87561b45d656e693df44db36441aeaaaad608b85 100644 --- a/DDDigi/src/DigiInputAction.cpp +++ b/DDDigi/src/DigiInputAction.cpp @@ -11,19 +11,18 @@ // //========================================================================== -// Framework include files +/// Framework include files #include <DD4hep/InstanceCount.h> #include <DDDigi/DigiInputAction.h> -// C/C++ include files +/// C/C++ include files #include <stdexcept> #include <unistd.h> -using namespace std; using namespace dd4hep::digi; /// Standard constructor -DigiInputAction::DigiInputAction(const DigiKernel& kernel, const string& nam) +DigiInputAction::DigiInputAction(const DigiKernel& kernel, const std::string& nam) : DigiEventAction(kernel, nam) { declareProperty("input", m_input_sources); @@ -33,6 +32,8 @@ DigiInputAction::DigiInputAction(const DigiKernel& kernel, const string& nam) declareProperty("input_section", m_input_section); declareProperty("objects_enabled", m_objects_enabled); declareProperty("objects_disabled", m_objects_disabled); + declareProperty("events_per_file", m_events_per_file); + declareProperty("keep_raw", m_keep_raw); InstanceCount::increment(this); } @@ -41,6 +42,26 @@ DigiInputAction::~DigiInputAction() { InstanceCount::decrement(this); } +/// Check if the number of events per file is reached +bool DigiInputAction::fileLimitReached(input_source& source) const { + if ( m_events_per_file > 0 ) { + if ( source.event_count > m_events_per_file ) { + return true; + } + } + return false; +} + +/// Callback when a new file is opened +void DigiInputAction::onOpenFile(input_source& source) { + source.event_count = 0; +} + +/// Callback when a new event is processed +void DigiInputAction::onProcessEvent(input_source& source, event_frame& /* frame */) { + ++source.event_count = 0; +} + /// 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 diff --git a/DDDigi/src/DigiROOTInput.cpp b/DDDigi/src/DigiROOTInput.cpp index 5d64df5569775d745944f6938ce8e1775a6c7f9b..b7bc81b8dcee2a56d0a27d3bbf01990cb056838d 100644 --- a/DDDigi/src/DigiROOTInput.cpp +++ b/DDDigi/src/DigiROOTInput.cpp @@ -28,16 +28,19 @@ using namespace dd4hep::digi; -class DigiROOTInput::inputsource_t { +class DigiROOTInput::inputsource_t + : public DigiInputAction::input_source, + public DigiInputAction::event_frame +{ public: /// Branches present in the current file std::map<Key, container_t> branches { }; /// Reference to the current ROOT file to be read - TFile* file { nullptr }; + TFile* file { nullptr }; /// Reference to the ROOT tree to be read - TTree* tree { nullptr }; + TTree* tree { nullptr }; /// Current entry inside the current input source - Long64_t entry { -1 }; + Long64_t entry { -1 }; public: inputsource_t() = default; @@ -66,11 +69,11 @@ class DigiROOTInput::internals_t { public: using handle_t = std::unique_ptr<inputsource_t>; /// Reference to parent action - DigiROOTInput* m_parent { nullptr }; + DigiROOTInput* m_parent { nullptr }; /// Handle to input source - handle_t m_input_handle; + handle_t m_source { }; /// Pointer to current input source - int m_curr_input { INPUT_START }; + int m_curr_input { INPUT_START }; public: /// Default constructor @@ -89,24 +92,12 @@ DigiROOTInput::internals_t::internals_t (DigiROOTInput* p) { } -DigiROOTInput::inputsource_t& DigiROOTInput::internals_t::next() { - if ( !m_input_handle ) { - m_input_handle = open_next_data_source(); - } - Int_t total = m_input_handle->tree->GetEntries(); - if ( (1+m_input_handle->entry) >= total ) { - m_input_handle.reset(); - m_input_handle = open_next_data_source(); - } - return m_input_handle->next(); -} - std::unique_ptr<DigiROOTInput::inputsource_t> DigiROOTInput::internals_t::open_next_data_source() { - const auto& inputs = m_parent->inputs(); + 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; while ( (m_curr_input+1) < len ) { const auto& fname = inputs[++m_curr_input]; @@ -149,6 +140,7 @@ DigiROOTInput::internals_t::open_next_data_source() { if ( source->branches.empty() ) { m_parent->except("+++ No branches to be loaded. Configuration error!"); } + m_parent->onOpenFile(*source); return source; } } @@ -156,6 +148,20 @@ DigiROOTInput::internals_t::open_next_data_source() { throw std::runtime_error("+++ No open file present"); } +DigiROOTInput::inputsource_t& DigiROOTInput::internals_t::next() { + if ( !m_source || m_parent->fileLimitReached(*m_source) ) { + m_source = open_next_data_source(); + } + Int_t total = m_source->tree->GetEntries(); + if ( (1+m_source->entry) >= total ) { + m_source.reset(); + m_source = open_next_data_source(); + } + auto& src = m_source->next(); + m_parent->onProcessEvent(src, src); + return src; +} + /// Standard constructor DigiROOTInput::DigiROOTInput(const DigiKernel& kernel, const std::string& nam) : DigiInputAction(kernel, nam) diff --git a/examples/DDDigi/scripts/TestEdm4hepOutput.py b/examples/DDDigi/scripts/TestEdm4hepOutput.py new file mode 100644 index 0000000000000000000000000000000000000000..2b0fafcf45b805ef7cbe52da358cb709766967df --- /dev/null +++ b/examples/DDDigi/scripts/TestEdm4hepOutput.py @@ -0,0 +1,38 @@ +# ========================================================================== +# AIDA Detector description implementation +# -------------------------------------------------------------------------- +# Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN) +# All rights reserved. +# +# For the licensing terms see $DD4hepINSTALL/LICENSE. +# For the list of contributors see $DD4hepINSTALL/doc/CREDITS. +# +# ========================================================================== +from __future__ import absolute_import + + +# --------------------------------------------------------------------------- +def run(): + import DigiTest + digi = DigiTest.Test(geometry=None) + read = digi.input_action('DigiDDG4ROOT/SignalReader', mask=0x0, input=[digi.next_input()]) + dump = digi.event_action('DigiStoreDump/StoreDump', parallel=False) + writ = digi.output_action('Digi2edm4hepWriter/Writer', + parallel=True, + input_mask=0x0, + input_segment='input', + output='MiniTel_DDDigi_edm4hep_data.root') + proc = digi.create_action('Digi2edm4hepProcessor/edm4hep') + hit_type = 'TrackerHits' + if digi.hit_type: + hit_type = digi.hit_type + cont = [c + '/' + hit_type for c in digi.containers()] + writ.adopt_container_processor(proc, cont) + writ.adopt_container_processor(proc, 'MCParticles/MCParticles') + digi.check_creation([read, dump]) + digi.run_checked(num_events=10, num_threads=10, parallel=3) + + +# --------------------------------------------------------------------------- +if __name__ == '__main__': + run()