diff --git a/DDCore/include/DD4hep/Callback.h b/DDCore/include/DD4hep/Callback.h index 2eed558655e6ed26434057b530fe70107225d6e2..3c48d9391dc586eff3025483d45cf799a7563784 100644 --- a/DDCore/include/DD4hep/Callback.h +++ b/DDCore/include/DD4hep/Callback.h @@ -365,6 +365,10 @@ namespace dd4hep { else callbacks.insert(callbacks.end(),cb); } + /// Generically Add a new callback to the sequence depending on the location arguments + void add(const Callback& cb) { + callbacks.insert(callbacks.end(),cb); + } /// Execution overload for callbacks with no arguments void operator()() const; /// Execution overload for callbacks with 1 argument diff --git a/DDCore/include/DD4hep/PluginCreators.h b/DDCore/include/DD4hep/PluginCreators.h index f18783ae40ee9363a55e62a056def67049142d93..b045158aa5683597610b64432786f6faba554253 100644 --- a/DDCore/include/DD4hep/PluginCreators.h +++ b/DDCore/include/DD4hep/PluginCreators.h @@ -16,7 +16,7 @@ #define DD4HEP_PLUGINCREATORS_H 1 // Framework include files -#include "DD4hep/Primitives.h" +#include <DD4hep/Primitives.h> // C/C++ include files #include <string> diff --git a/DDCore/include/DD4hep/Plugins.h b/DDCore/include/DD4hep/Plugins.h index e29df7410aaae288e446817939a21c8488fac8aa..143628f9bb07727a8be2bc12012663a5cc009b0f 100644 --- a/DDCore/include/DD4hep/Plugins.h +++ b/DDCore/include/DD4hep/Plugins.h @@ -14,7 +14,7 @@ #define DD4HEP_PLUGINS_H // Framework include files -#include "DD4hep/config.h" +#include <DD4hep/config.h> // ROOT include files #ifndef __CINT__ @@ -36,7 +36,7 @@ namespace std { #endif #ifndef DD4HEP_PARSERS_NO_ROOT -#include "RVersion.h" +#include <RVersion.h> #endif /// Namespace for the AIDA detector description toolkit diff --git a/DDCore/src/PluginCreators.cpp b/DDCore/src/PluginCreators.cpp index 262a986f7b95121cbe2fe7dbdc3bb3728be94aea..1c9f48a1175ddc820a46b8729bdecc2d7f7c3ff5 100644 --- a/DDCore/src/PluginCreators.cpp +++ b/DDCore/src/PluginCreators.cpp @@ -12,10 +12,10 @@ //========================================================================== // Framework include files -#include "DD4hep/PluginCreators.h" -#include "DD4hep/Primitives.h" -#include "DD4hep/Printout.h" -#include "DD4hep/Plugins.h" +#include <DD4hep/PluginCreators.h> +#include <DD4hep/Primitives.h> +#include <DD4hep/Printout.h> +#include <DD4hep/Plugins.h> // C/C++ include files #include <cstring> @@ -73,7 +73,7 @@ namespace dd4hep { PluginDebug dbg; object = PluginService::Create<void*>(factory, &description, argc, argv); if ( !object ) { - except("ConditionsManager","dd4hep-plugins: Failed to locate plugin %s. \n%s.", + except("createPlugin","dd4hep-plugins: Failed to locate plugin %s. \n%s.", factory.c_str(), dbg.missingFactory(factory).c_str()); } } diff --git a/DDDigi/ddg4/DigiDDG4Input.cpp b/DDDigi/ddg4/DigiDDG4Input.cpp index a50fbdaa0564e9c1a2826eea760c5e60dda16f76..5366b7ba25f758ae96ca69697e1779d4487a8a64 100644 --- a/DDDigi/ddg4/DigiDDG4Input.cpp +++ b/DDDigi/ddg4/DigiDDG4Input.cpp @@ -27,8 +27,9 @@ #include <any> using namespace dd4hep; +using namespace dd4hep::digi; -typedef std::function<std::any(int, const char*, void*)> func_t; +typedef std::function<void(DataSegment& segment, int, const char*, void*)> func_t; namespace { @@ -40,30 +41,39 @@ namespace { template <typename T> void* ddg4_hit_convert_function(const char* desc) { std::string tag = desc; - func_t* cnv = new func_t([tag] (int mask, const char* name, void* ptr) { + func_t* cnv = new func_t([tag] (DataSegment& segment, int mask, const char* name, void* ptr) { using wrap_t = std::shared_ptr<sim::Geant4HitData>; std::size_t len = 0; - digi::DepositMapping out(name, mask); + std::string nam = name; + std::vector<wrap_t> particles; + DepositVector out(name, mask); if ( ptr ) { + Key history_key; input_data<T> data(ptr); - digi::Key::mask_type msk = digi::Key::mask_type(mask); - for( auto* p : *data.items ) { - auto it = out.find(p->cellID); - if ( it == out.end() ) { - digi::EnergyDeposit dep(p->energyDeposit); - dep.history.emplace_back(std::any(wrap_t(p)), msk); - out.emplace(p->cellID, std::move(dep)); - continue; - } - (*it).second.history.emplace_back(std::any(wrap_t(p)), msk); - (*it).second.deposit += p->energyDeposit; + history_key.set_mask(Key::mask_type(mask)); + for(size_t i=0; i < data.items->size(); ++i) { + auto* p = (*data.items)[i]; + EnergyDeposit dep { }; + dep.flag = p->flag; + dep.deposit = p->energyDeposit; + dep.position = p->position; + + history_key.set_item(i); + dep.hit_history.emplace_back(history_key, 1.0); + history_key.set_item(p->g4ID); + dep.particle_history.emplace_back(history_key, 1.0); + out.emplace(p->cellID, std::move(dep)); + particles.emplace_back(wrap_t(p)); } len = data.items->size(); data.items->clear(); } printout(DEBUG,"DDG4Converter","++ Converted %ld %s to %ld cell deposits", len, tag.c_str(), out.size()); - return std::make_any<digi::DepositMapping>(std::move(out)); + Key depo_key(nam, mask); + segment.emplace(depo_key, std::make_any<DepositVector>(std::move(out))); + Key src_key(nam+".ddg4", mask); + segment.emplace(src_key, std::make_any<std::vector<wrap_t>>(std::move(particles))); }); return cnv; } @@ -80,23 +90,31 @@ static void* convert_sim_geant4tracker_hits() { DECLARE_CREATE(DD4hep_DDDigiConverter_vector_dd4hep_sim_Geant4Tracker_Hit_,convert_sim_geant4tracker_hits); static void* convert_sim_geant4particles() { - func_t* cnv = new func_t([] (int mask, const char* name, void* ptr) { - std::any res = std::make_any<digi::ParticleMapping>(name, mask); - digi::ParticleMapping* out = std::any_cast<digi::ParticleMapping>(&res); + func_t* cnv = new func_t([] (DataSegment& segment, int mask, const char* name, void* ptr) { + std::any res = std::make_any<ParticleMapping>(name, mask); + ParticleMapping* out = std::any_cast<ParticleMapping>(&res); if ( ptr ) { using wrap_t = std::shared_ptr<sim::Geant4Particle>; auto* items = (std::vector<sim::Geant4Particle*>*)ptr; for( auto* p : *items ) { - digi::Key key(0); - key.values.mask = mask; - key.values.item = out->size(); + Key key(0); + Particle part; + key.set_mask(mask); + key.set_item(out->size()); p->mask = mask; - out->push(key.key, {std::make_any<wrap_t>(p)}); + part.start_position = Position(p->vsx, p->vsy, p->vsz); + part.end_position = Position(p->vex, p->vey, p->vez); + part.momentum = Direction(p->psx, p->psy, p->psz); + part.charge = p->charge; + part.mass = p->mass; + part.history = std::make_any<wrap_t>(p); + out->push(key.key, std::move(part)); } items->clear(); } printout(DEBUG,"DDG4Converter","++ Converted %ld DDG4 particles", out->size()); - return res; + Key part_key(name, mask); + segment.emplace(part_key, std::move(res)); }); return cnv; } diff --git a/DDDigi/include/DDDigi/DigiAction.h b/DDDigi/include/DDDigi/DigiAction.h index 7c6daae6439260fe15380a90c012dabf5c73f833..dcb1ed3bf22317ed2d38483cc5e5b92195599fa6 100644 --- a/DDDigi/include/DDDigi/DigiAction.h +++ b/DDDigi/include/DDDigi/DigiAction.h @@ -15,7 +15,6 @@ // Framework include files #include <DD4hep/Printout.h> -#include <DD4hep/Callback.h> #include <DD4hep/ComponentProperties.h> #include <DDDigi/DigiContext.h> @@ -48,15 +47,6 @@ namespace dd4hep { /// Namespace for the Digitization part of the AIDA detector description toolkit namespace digi { - /// Cast operator - template <typename TO, typename FROM> TO fast_cast(FROM from) { -#ifdef USE_FASTCAST - return static_cast<TO>(from); -#else - return dynamic_cast<TO>(from); -#endif - } - /// Helper class to handle strings of the format "type/name" /** * \author M.Frank @@ -90,7 +80,7 @@ namespace dd4hep { * * \author M.Frank * \version 1.0 - * \ingroup DD4HEP_SIMULATION + * \ingroup DD4HEP_DIGITIZATION */ class DigiAction { friend class DigiKernel; @@ -117,121 +107,6 @@ namespace dd4hep { int m_outputLevel = 3; protected: - - /// Functor to access elements by name - struct FindByName { - std::string _n; - FindByName(const std::string& n) : _n(n) {} - bool operator()(const DigiAction* a) { return a->name() == _n; } - }; - /// Actor class to manipulate action groups - /** - * \author M.Frank - * \version 1.0 - * \ingroup DD4HEP_SIMULATION - */ - template <typename T> class Actors { - public: - typedef typename std::vector<T*> _V; - _V m_v; - Actors() = default; - ~Actors() = default; - size_t size() const { return m_v.size(); } - void clear() { m_v.clear(); } - void add(T* obj) { m_v.emplace_back(obj); } - void add_front(T* obj) { m_v.insert(m_v.begin(), obj); } - const typename _V::value_type& operator[](size_t i) const - { return m_v[i];} - typename _V::value_type& operator[](size_t i) { return m_v[i];} - operator const _V&() const { return m_v; } - operator _V&() { return m_v; } - const _V* operator->() const { return &m_v; } - _V* operator->() { return &m_v; } - typename _V::iterator begin() { return m_v.begin(); } - typename _V::iterator end() { return m_v.end(); } - typename _V::const_iterator begin() const { return m_v.begin(); } - typename _V::const_iterator end() const { return m_v.end(); } - - /// Context updates - void updateContext(DigiContext* ctxt) { - (*this)(&T::updateContext,ctxt); - } - /// Element access by name - template <typename F> typename _V::value_type get(const F& f) const { - if (!m_v.empty()) { - typename _V::const_iterator i=std::find_if(m_v.begin(),m_v.end(),f); - return i==m_v.end() ? 0 : (*i); - } - return 0; - } - /// NON-CONST actions - template <typename R, typename Q> void operator()(R (Q::*pmf)()) { - if (m_v.empty()) - return; - for (typename _V::iterator i = m_v.begin(); i != m_v.end(); ++i) - ((*i)->*pmf)(); - } - template <typename R, typename Q, typename A0> void operator()(R (Q::*pmf)(A0&), A0& a0) { - if (m_v.empty()) - return; - for (typename _V::iterator i = m_v.begin(); i != m_v.end(); ++i) - ((*i)->*pmf)(a0); - } - template <typename R, typename Q, typename A0, typename A1> void operator()(R (Q::*pmf)(A0, A1), A0 a0, A1 a1) { - if (m_v.empty()) - return; - for (typename _V::iterator i = m_v.begin(); i != m_v.end(); ++i) - ((*i)->*pmf)(a0, a1); - } - /// CONST actions - template <typename R, typename Q> void operator()(R (Q::*pmf)() const) const { - if (m_v.empty()) - return; - for (typename _V::const_iterator i = m_v.begin(); i != m_v.end(); ++i) - ((*i)->*pmf)(); - } - template <typename R, typename Q, typename A0> void operator()(R (Q::*pmf)(A0&) const, A0& a0) const { - if (m_v.empty()) - return; - for (typename _V::const_iterator i = m_v.begin(); i != m_v.end(); ++i) - ((*i)->*pmf)(a0); - } - template <typename R, typename Q, typename A0, typename A1> void operator()(R (Q::*pmf)(A0, A1) const, A0 a0, - A1 a1) const { - if (m_v.empty()) - return; - for (typename _V::const_iterator i = m_v.begin(); i != m_v.end(); ++i) - ((*i)->*pmf)(a0, a1); - } - /// CONST filters - template <typename Q> bool filter(bool (Q::*pmf)() const) const { - if (!m_v.empty()) - return true; - for (typename _V::const_iterator i = m_v.begin(); i != m_v.end(); ++i) - if (!((*i)->*pmf)()) - return false; - return true; - } - template <typename Q, typename A0> bool filter(bool (Q::*pmf)(A0) const, A0 a0) const { - if (m_v.empty()) - return true; - for (typename _V::const_iterator i = m_v.begin(); i != m_v.end(); ++i) - if (!((*i)->*pmf)(a0)) - return false; - return true; - } - template <typename Q, typename A0, typename A1> bool filter(bool (Q::*pmf)(A0, A1) const, A0 a0, A1 a1) const { - if (m_v.empty()) - return true; - for (typename _V::const_iterator i = m_v.begin(); i != m_v.end(); ++i) - if (!((*i)->*pmf)(a0, a1)) - return false; - return true; - } - }; - - protected: - /// Define standard assignments and constructors DDDIGI_DEFINE_ACTION_CONSTRUCTORS(DigiAction); @@ -276,17 +151,9 @@ namespace dd4hep { bool hasProperty(const std::string& name) const; /// Access single property Property& property(const std::string& name); + /// Support for messages with variable output level using output level void print(const char* fmt, ...) const; - /// Support for messages with variable output level using output level-1 - void printM1(const char* fmt, ...) const; - /// Support for messages with variable output level using output level-2 - void printM2(const char* fmt, ...) const; - /// Support for messages with variable output level using output level+1 - void printP1(const char* fmt, ...) const; - /// Support for messages with variable output level using output level+2 - void printP2(const char* fmt, ...) const; - /// Support for building formatted messages std::string format(const char* fmt, ...) const; /// Support of debug messages. @@ -303,9 +170,6 @@ namespace dd4hep { void fatal(const char* fmt, ...) const; /// Support of exceptions: Print fatal message and throw runtime_error. void except(const char* fmt, ...) const; - - /// Optional action initialization if required - virtual void initialize(); }; /// Declare property diff --git a/DDDigi/include/DDDigi/DigiActionSequence.h b/DDDigi/include/DDDigi/DigiActionSequence.h index cefd19fac792d1a930a0062789bb9146d864cb84..548294422c86619d02fa64bffd26df94f8d0fcd5 100644 --- a/DDDigi/include/DDDigi/DigiActionSequence.h +++ b/DDDigi/include/DDDigi/DigiActionSequence.h @@ -14,6 +14,7 @@ #define DDDIGI_DIGIACTIONSEQUENCE_H // Framework include files +#include <DD4hep/Callback.h> #include <DDDigi/DigiSynchronize.h> /// Namespace for the AIDA detector description toolkit diff --git a/DDDigi/include/DDDigi/DigiSegmentAction.h b/DDDigi/include/DDDigi/DigiAttenuatorSequenceAction.h similarity index 50% rename from DDDigi/include/DDDigi/DigiSegmentAction.h rename to DDDigi/include/DDDigi/DigiAttenuatorSequenceAction.h index 95bf318cf52f73bba1332d6049fb2c1cc9511d1b..3e27c14bb596027546355a444e38606f83a0ea45 100644 --- a/DDDigi/include/DDDigi/DigiSegmentAction.h +++ b/DDDigi/include/DDDigi/DigiAttenuatorSequenceAction.h @@ -10,13 +10,11 @@ // Author : M.Frank // //========================================================================== -#ifndef DDDIGI_DIGISEGMENTACTION_H -#define DDDIGI_DIGISEGMENTACTION_H +#ifndef DDDIGI_DIGIATTENUATORSEQUENCEACTION_H +#define DDDIGI_DIGIATTENUATORSEQUENCEACTION_H // Framework include files -#include <DDDigi/DigiData.h> #include <DDDigi/DigiEventAction.h> -#include <DDDigi/DigiSegmentationTool.h> /// Namespace for the AIDA detector description toolkit namespace dd4hep { @@ -24,11 +22,6 @@ namespace dd4hep { /// Namespace for the Digitization part of the AIDA detector description toolkit namespace digi { - /// Forward declarations - class DigiSegmentAction; - class DigiSegmentContext; - class DigiSegmentSplitter; - /// Default base class for all Digitizer actions and derivates thereof. /** * This is a utility class supporting properties, output and access to @@ -36,27 +29,38 @@ namespace dd4hep { * * \author M.Frank * \version 1.0 - * \ingroup DD4HEP_SIMULATION + * \ingroup DD4HEP_DIGITIZATION */ - class DigiSegmentAction : virtual public DigiAction { + class DigiAttenuatorSequenceAction : public DigiEventAction { protected: - friend class DigiSegmentSplitter; + /// Property: Input data segment name + std::string m_processor_name { }; + /// Property: Input data segment name + std::string m_input_segment { }; + /// Property: Container names to be loaded + std::map<std::string, double> m_container_attenuation { }; + /// Property: event mask to be handled + int m_mask { 0 }; + /// Property: T0 with respect to central crossing + double m_t0 { 0e0 }; + + /// Keys of all containers to be manipulated + std::map<Key, double> m_attenuation { }; - /// Segmentation split context - DigiSegmentContext segment { }; - + protected: /// Define standard assignments and constructors - DDDIGI_DEFINE_ACTION_CONSTRUCTORS(DigiSegmentAction); + DDDIGI_DEFINE_ACTION_CONSTRUCTORS(DigiAttenuatorSequenceAction); + /// Default destructor + virtual ~DigiAttenuatorSequenceAction(); public: /// Standard constructor - DigiSegmentAction(const DigiKernel& kernel, const std::string& name); - /// Default destructor - virtual ~DigiSegmentAction(); - /// Main functional callback. Default implementnation is noop. - virtual DepositVector handleSegment(DigiContext& context, - const DepositMapping& deposits) const; + DigiAttenuatorSequenceAction(const DigiKernel& kernel, const std::string& nam); + /// Initialization callback + virtual void initialize(); + /// Main functional callback + virtual void execute(DigiContext& context) const; }; } // End namespace digi } // End namespace dd4hep -#endif // DDDIGI_DIGISEGMENTACTION_H +#endif // DDDIGI_DIGIATTENUATORSEQUENCEACTION_H diff --git a/DDDigi/include/DDDigi/DigiContainerCombine.h b/DDDigi/include/DDDigi/DigiContainerCombine.h index a4bc569068d72196f43a597f2061ae86974d5c25..60393ba2d84c00e15f7262e77dfd7452099a49a8 100644 --- a/DDDigi/include/DDDigi/DigiContainerCombine.h +++ b/DDDigi/include/DDDigi/DigiContainerCombine.h @@ -13,8 +13,12 @@ #ifndef DDDIGI_DIGICONTAINERCOMBINE_H #define DDDIGI_DIGICONTAINERCOMBINE_H -// Framework include files +/// Framework include files #include <DDDigi/DigiEventAction.h> +#include <DDDigi/DigiParallelWorker.h> + +/// C/C++ include files +#include <functional> /// Namespace for the AIDA detector description toolkit namespace dd4hep { @@ -29,15 +33,38 @@ namespace dd4hep { * * \author M.Frank * \version 1.0 - * \ingroup DD4HEP_SIMULATION + * \ingroup DD4HEP_DIGITIZATION */ class DigiContainerCombine : public DigiEventAction { + public: + class work_definition_t; + using self_t = DigiContainerCombine; + using Worker = DigiParallelWorker<self_t,work_definition_t>; + using Workers = DigiParallelWorkers<Worker>; + protected: - /// Implementation declaration - class internals_t; + /// Property: Container names to be loaded + std::vector<std::string> m_containers { }; + /// Property: Output container dressing + std::string m_output_name_flag; + /// Property: Input data segment name + std::string m_input; + /// Property: event masks to be handled + std::vector<int> m_input_masks { }; + /// Property: Output data segment name + std::string m_output; + /// Property: mask of the deposit + int m_deposit_mask { 0 }; + /// Property: Flag to erase already combined containers (not thread-safe!!!) + bool m_erase_combined { false }; + + /// Fully qualified keys of all containers to be manipulated + std::set<Key::key_type> m_keys { }; + /// Container keys of all containers to be manipulated + std::set<Key::key_type> m_cont_keys { }; - /// Reference to the implementation - std::unique_ptr<internals_t> internals; + /// Worker objects to be submitted to TBB each performing part of the job + Workers m_workers; protected: /// Define standard assignments and constructors @@ -46,12 +73,19 @@ namespace dd4hep { /// Default destructor virtual ~DigiContainerCombine(); + /// Initializing function: compute values which depend on properties + void initialize(); + + /// Check if we have sufficient workers + void have_workers(size_t len) const; + /// Combine selected containers to one single deposit container - template <typename PREDICATE> - std::size_t combine_containers(DigiEvent& event, - DataSegment& inputs, - DataSegment& outputs, - const PREDICATE& predicate) const; + std::size_t combine_containers(DigiEvent& event, + DataSegment& inputs, + DataSegment& outputs) const; + + /// Decide if a continer is to merged based on the properties + virtual bool use_key(Key key) const; public: /// Standard constructor diff --git a/DDDigi/include/DDDigi/DigiContainerProcessor.h b/DDDigi/include/DDDigi/DigiContainerProcessor.h new file mode 100644 index 0000000000000000000000000000000000000000..d90741c311f833da7c4ca7a56bc5f3bb580ff9a3 --- /dev/null +++ b/DDDigi/include/DDDigi/DigiContainerProcessor.h @@ -0,0 +1,248 @@ +//========================================================================== +// AIDA Detector description implementation +//-------------------------------------------------------------------------- +// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN) +// All rights reserved. +// +// For the licensing terms see $DD4hepINSTALL/LICENSE. +// For the list of contributors see $DD4hepINSTALL/doc/CREDITS. +// +// Author : M.Frank +// +//========================================================================== +#ifndef DDDIGI_DIGIMULTICONTAINERPROCESSOR_H +#define DDDIGI_DIGIMULTICONTAINERPROCESSOR_H + +// Framework include files +#include <DDDigi/DigiData.h> +#include <DDDigi/DigiEventAction.h> +#include <DDDigi/DigiParallelWorker.h> + +/// C/C++ include files +#include <set> + +/// Namespace for the AIDA detector description toolkit +namespace dd4hep { + + /// Namespace for the Digitization part of the AIDA detector description toolkit + namespace digi { + + /// Forward declarations + class DigiContainerProcessor; + class DigiContainerSequence; + class DigiContainerSequenceAction; + class DigiMultiContainerProcessor; + + /// Worker base class to analyse containers from the input segment in parallel + /** + * + * \author M.Frank + * \version 1.0 + * \ingroup DD4HEP_DIGITIZATION + */ + class DigiContainerProcessor : public DigiAction { + public: + struct work_t { + /// Event processing context + DigiContext& context; + /// Input data key + Key key; + /// Input deposits + std::any& input; + /// Lock for secure output merging + std::mutex& output_lock; + /// Handle to output + std::any& output; + + /// Merge output data (thread safe, locked) + void merge_output(DepositVector&& data); + /// Merge output data (thread safe, locked) + void emplace_output(CellID cell, EnergyDeposit&& deposit); + }; + protected: + /// Define standard assignments and constructors + DDDIGI_DEFINE_ACTION_CONSTRUCTORS(DigiContainerProcessor); + + private: + /// Main functional callback if specific work is known. + virtual void execute(DigiContext& context, Key key, std::any& data) const; + + public: + /// Standard constructor + DigiContainerProcessor(const DigiKernel& kernel, const std::string& name); + /// Default destructor + virtual ~DigiContainerProcessor(); + /// Main functional callback adapter + virtual void execute(DigiContext& context, work_t& work) const; + }; + + /// Worker class act on containers in an event identified by input masks and container name + /** + * The sequencer calls all registered processors for the contaiers registered. + * + * \author M.Frank + * \version 1.0 + * \ingroup DD4HEP_DIGITIZATION + */ + class DigiContainerSequence : public DigiContainerProcessor { + protected: + /// Property to steer parallel processing + bool m_parallel { false }; + + protected: + using self_t = DigiContainerSequence; + using processor_t = DigiContainerProcessor; + using worker_t = DigiParallelWorker<processor_t,work_t>; + using workers_t = DigiParallelWorkers<worker_t>; + friend class DigiParallelWorker<processor_t,work_t>; + + /// Array of sub-workers + workers_t m_workers; + + /// Lock for output merging + mutable std::mutex m_output_lock; + + protected: + /// Define standard assignments and constructors + DDDIGI_DEFINE_ACTION_CONSTRUCTORS(DigiContainerSequence); + /// Default destructor + virtual ~DigiContainerSequence(); + + public: + /// Standard constructor + DigiContainerSequence(const DigiKernel& kernel, const std::string& name); + /// Adopt new parallel worker + virtual void adopt_processor(DigiContainerProcessor* action); + /// Main functional callback adapter + virtual void execute(DigiContext& context, work_t& work) const; + }; + + /// Worker base class to analyse containers from the input segment in parallel + /** + * Depending on the adopted processors, the full input record is scanned and + * the registered processors are called. + * + * \author M.Frank + * \version 1.0 + * \ingroup DD4HEP_DIGITIZATION + */ + class DigiContainerSequenceAction : public DigiEventAction { + + protected: + /// Argument structure for client calls + using self_t = DigiContainerSequenceAction; + using processor_t = DigiContainerProcessor; + struct work_item_t { + Key key; + std::any* data; + }; + struct work_t { + DigiContext& context; + std::vector<work_item_t> input_items; + /// Lock for secure output merging + std::mutex& output_lock; + std::any output; + const self_t* parent; + }; + using worker_t = DigiParallelWorker<processor_t, work_t>; + using workers_t = DigiParallelWorkers<worker_t>; + using reg_workers_t = std::map<Key, worker_t*>; + using reg_processors_t = std::map<Key, processor_t*>; + friend class DigiParallelWorker<processor_t, work_t>; + + /// Array of sub-workers + workers_t m_workers; + /// Registered action map + reg_processors_t m_registered_processors; + /// Registered worker map + reg_workers_t m_registered_workers; + + /// Property: Input data segment name + std::string m_input_segment { "inputs" }; + /// Property: Input mask to be handled + int m_mask { 0x0 }; + + /// Lock for output merging + mutable std::mutex m_output_lock; + + protected: + /// Define standard assignments and constructors + DDDIGI_DEFINE_ACTION_CONSTRUCTORS(DigiContainerSequenceAction); + + /// Default destructor + virtual ~DigiContainerSequenceAction(); + /// Initialization callback + void initialize(); + + public: + /// Standard constructor + DigiContainerSequenceAction(const DigiKernel& kernel, const std::string& name); + /// Adopt new parallel worker + void adopt_processor(DigiContainerProcessor* action, const std::string& container); + /// Main functional callback if specific work is known + virtual void execute(DigiContext& context) const override; + }; + + /// Sequencer class to analyse containers from the input segment in parallel + /** + * + * \author M.Frank + * \version 1.0 + * \ingroup DD4HEP_DIGITIZATION + */ + class DigiMultiContainerProcessor : virtual public DigiEventAction { + protected: + using self_t = DigiMultiContainerProcessor; + using processor_t = DigiContainerProcessor; + using work_items_t = std::vector<std::pair<Key, std::any*> >; + /// Argument structure for client calls + struct work_t { + DigiContext& context; + work_items_t& items; + std::mutex& output_lock; + std::any output; + const self_t* parent; + }; + using worker_t = DigiParallelWorker<processor_t, work_t>; + using workers_t = DigiParallelWorkers<worker_t>; + friend class DigiParallelWorker<processor_t, work_t>; + + protected: + /// Property: Input data segment name + std::string m_input_segment { "inputs" }; + /// Property: event masks to be handled + std::vector<int> m_input_masks { }; + + /// Set of work items to be processed and passed to clients + std::set<Key> m_work_items; + + std::vector<std::vector<Key> > m_worker_keys; + /// Array of sub-workers + workers_t m_workers; + + /// Lock for output merging + mutable std::mutex m_output_lock; + + protected: + /// Define standard assignments and constructors + DDDIGI_DEFINE_ACTION_CONSTRUCTORS(DigiMultiContainerProcessor); + /// Default destructor + virtual ~DigiMultiContainerProcessor(); + + public: + /// Standard constructor + DigiMultiContainerProcessor(const DigiKernel& kernel, const std::string& name); + const std::vector<Key>& worker_keys(size_t worker_id) const { + return this->m_worker_keys.at(worker_id); + } + const std::vector<int>& input_masks() const { + return this->m_input_masks; + } + /// Adopt new parallel worker + void adopt_processor(DigiContainerProcessor* action, const std::vector<std::string>& containers); + /// Main functional callback + virtual void execute(DigiContext& context) const; + }; + } // End namespace digi +} // End namespace dd4hep +#endif // DDDIGI_DIGIMULTICONTAINERPROCESSOR_H diff --git a/DDDigi/include/DDDigi/DigiData.h b/DDDigi/include/DDDigi/DigiData.h index 55d30ca12a16a14447f1122941b0ec7977b405cb..519f9210a78b668e0e99440350f1ebc18dfe8cd0 100644 --- a/DDDigi/include/DDDigi/DigiData.h +++ b/DDDigi/include/DDDigi/DigiData.h @@ -14,7 +14,7 @@ #define DDDIGI_DIGIDATA_H /// Framework include files -#include <DD4hep/Primitives.h> +#include <DD4hep/Objects.h> /// C/C++ include files #include <cstdint> @@ -38,6 +38,9 @@ namespace dd4hep { class DigiEvent; class DataSegment; + using Position = dd4hep::Position; + using Direction = dd4hep::Direction; + /// Key defintion to access the event data /** * Helper to convert item and mask to a 64 bit integer @@ -71,8 +74,10 @@ namespace dd4hep { Key(const Key&); /// Initializaing constructor (fast) Key(key_type full_mask); - /// Initializaing constructor with key generation using hash algorithm - Key(mask_type mask, const std::string& item); + /// Initializing constructor with key generation using hash algorithm + Key(const char* item, mask_type mask); + /// Initializing constructor with key generation using hash algorithm + Key(const std::string& item, mask_type mask); /// Assignment operator Key& operator = (const Key&); /// Move assignment operator @@ -117,6 +122,10 @@ namespace dd4hep { itemkey_type item() { return this->values.item; } + /// Set key item identifier + void set_item(itemkey_type i) { + this->values.item = i; + } /// Project the mask part of the key static itemkey_type item(key_type k) { return Key(k).values.item; @@ -150,7 +159,12 @@ namespace dd4hep { } /// Initializaing constructor with key generation using hash algorithm - inline Key::Key(mask_type mask, const std::string& item) { + inline Key::Key(const char* item, mask_type mask) { + this->set(item, mask); + } + + /// Initializaing constructor with key generation using hash algorithm + inline Key::Key(const std::string& item, mask_type mask) { this->set(item, mask); } @@ -181,6 +195,34 @@ namespace dd4hep { return this->key > other.key; } + class SegmentEntry { + public: + std::string name { }; + Key key { 0x0 }; + public: + /// Initializing constructor + SegmentEntry(const std::string& name, Key::mask_type mask); + /// Default constructor + SegmentEntry() = default; + /// Disable move constructor + SegmentEntry(SegmentEntry&& copy) = default; + /// Disable copy constructor + SegmentEntry(const SegmentEntry& copy) = default; + /// Default destructor + virtual ~SegmentEntry() = default; + /// Disable move assignment + SegmentEntry& operator=(SegmentEntry&& copy) = default; + /// Disable copy assignment + SegmentEntry& operator=(const SegmentEntry& copy) = default; + }; + + /// Initializing constructor + inline SegmentEntry::SegmentEntry(const std::string& nam, Key::mask_type msk) + : name(nam) + { + key.set_mask(msk); + } + /// Particle definition for digitization /** Particle definition for digitization * @@ -190,6 +232,11 @@ namespace dd4hep { */ class Particle { public: + Position start_position { }; + Position end_position { }; + Direction momentum { }; + double mass { 0e0 }; + char charge { 0 }; /// Source contributing std::any history; @@ -223,10 +270,15 @@ namespace dd4hep { * \version 1.0 * \ingroup DD4HEP_DIGITIZATION */ - class ParticleMapping : public std::map<Key::key_type, Particle> { - public: - std::string name { }; - Key::mask_type mask { 0x0 }; + class ParticleMapping : public SegmentEntry { + using container_t = std::map<Key::key_type, Particle>; + using value_type = container_t::value_type; + using mapped_type = container_t::mapped_type; + using key_type = container_t::key_type; + using iterator = container_t::iterator; + using const_iterator = container_t::const_iterator; + + container_t data; public: /// Initializing constructor @@ -248,11 +300,29 @@ namespace dd4hep { std::size_t merge(ParticleMapping&& updates); /// Add new entry to the particle mapping (not thread safe!) void push(Key key, Particle&& particle); + + /// Access container size + std::size_t size() const { return this->data.size(); } + /// Check container if empty + bool empty() const { return this->data.empty(); } + /// Insert new entry + //std::pair<iterator, bool> emplace(key_type entry_key, mapped_type&& entry_data); + void emplace(Key entry_key, Particle&& entry_data); + + /** Iteration support */ + /// Begin iteration + iterator begin() { return this->data.begin(); } + /// End iteration + iterator end() { return this->data.end(); } + /// Begin iteration (CONST) + const_iterator begin() const { return this->data.begin(); } + /// End iteration (CONST) + const_iterator end() const { return this->data.end(); } }; /// Initializing constructor - inline ParticleMapping::ParticleMapping(const std::string& n, Key::mask_type m) - : name(n), mask(m) + inline ParticleMapping::ParticleMapping(const std::string& nam, Key::mask_type msk) + : SegmentEntry(nam, msk) { } @@ -265,14 +335,23 @@ namespace dd4hep { */ class EnergyDeposit { public: + /// Hit position + Position position { }; + /// Hit direction + Direction momentum { }; + /// Length of the track segment contributing to this hit + double length { 0 }; /// Total energy deposit - double deposit { 0 }; + double deposit { 0 }; + + long flag { 0 }; + Key::mask_type mask { 0 }; + /// Sources contributing to this deposit - std::vector<std::pair<std::any, Key::mask_type> > history; + std::vector<std::pair<Key, double> > hit_history; + std::vector<std::pair<Key, double> > particle_history; public: - /// Initializing constructor - EnergyDeposit(double ene); /// Default constructor EnergyDeposit() = default; /// Disable move constructor @@ -288,12 +367,6 @@ namespace dd4hep { }; - /// Initializing constructor - inline EnergyDeposit::EnergyDeposit(double ene) - : deposit(ene) - { - } - /// Energy deposit vector definition for digitization /** Energy deposit vector definition for digitization * @@ -301,10 +374,13 @@ namespace dd4hep { * \version 1.0 * \ingroup DD4HEP_DIGITIZATION */ - class DepositVector : public std::vector<std::pair<CellID, EnergyDeposit> > { + class DepositVector : public SegmentEntry { public: - std::string name { }; - Key key { 0x0 }; + using container_t = std::vector<std::pair<CellID, EnergyDeposit> >; + using iterator = container_t::iterator; + using const_iterator = container_t::const_iterator; + + container_t data { }; public: /// Initializing constructor @@ -323,14 +399,38 @@ namespace dd4hep { DepositVector& operator=(const DepositVector& copy) = default; /// Merge new deposit map onto existing map (not thread safe!) std::size_t merge(DepositVector&& updates); + /// Merge new deposit map onto existing map (keep inputs. not thread safe!) + std::size_t insert(const DepositVector& updates); + /// Emplace entry + void emplace(CellID cell, EnergyDeposit&& deposit); + + /// Access container size + std::size_t size() const { return this->data.size(); } + /// Check container if empty + bool empty() const { return this->data.empty(); } + + /** Iteration support */ + /// Begin iteration + iterator begin() { return this->data.begin(); } + /// End iteration + iterator end() { return this->data.end(); } + /// Begin iteration (CONST) + const_iterator begin() const { return this->data.begin(); } + /// End iteration (CONST) + const_iterator end() const { return this->data.end(); } }; /// Initializing constructor - inline DepositVector::DepositVector(const std::string& n, Key::mask_type mask) - : name(n), key(mask, n) + inline DepositVector::DepositVector(const std::string& nam, Key::mask_type msk) + : SegmentEntry(nam, msk) { } + /// Emplace entry + inline void DepositVector::emplace(CellID cell, EnergyDeposit&& deposit) { + this->data.emplace_back(cell, std::move(deposit)); + } + /// Energy deposit mapping definition for digitization /** Energy deposit mapping definition for digitization * @@ -338,10 +438,13 @@ namespace dd4hep { * \version 1.0 * \ingroup DD4HEP_DIGITIZATION */ - class DepositMapping : public std::map<CellID, EnergyDeposit> { + class DepositMapping : public SegmentEntry { public: - std::string name { }; - Key key { 0x0 }; + using container_t = std::multimap<CellID, EnergyDeposit>; + using iterator = container_t::iterator; + using const_iterator = container_t::const_iterator; + + container_t data { }; public: /// Initializing constructor @@ -362,11 +465,36 @@ namespace dd4hep { std::size_t merge(DepositMapping&& updates); /// Merge new deposit map onto existing map (not thread safe!) std::size_t merge(DepositVector&& updates); + /// Merge new deposit map onto existing map (not thread safe!) + std::size_t insert(const DepositMapping& updates); + /// Merge new deposit map onto existing map (not thread safe!) + std::size_t insert(const DepositVector& updates); + + /// Access container size + std::size_t size() const { return this->data.size(); } + /// Check container if empty + bool empty() const { return this->data.empty(); } + + /** Iteration support */ + /// Begin iteration + iterator begin() { return this->data.begin(); } + /// End iteration + iterator end() { return this->data.end(); } + /// Begin iteration (CONST) + const_iterator begin() const { return this->data.begin(); } + /// End iteration (CONST) + const_iterator end() const { return this->data.end(); } + + /** Direct element access by key */ + /// Find entry by cell + //iterator find(CellID cell) { return this->data.find(cell); } + /// Find entry by cell + //const_iterator find(CellID cell) const { return this->data.find(cell); } }; /// Initializing constructor - inline DepositMapping::DepositMapping(const std::string& n, Key::mask_type mask) - : name(n), key(mask, n) + inline DepositMapping::DepositMapping(const std::string& nam, Key::mask_type msk) + : SegmentEntry(nam, msk) { } @@ -425,6 +553,11 @@ namespace dd4hep { void print_keys() const; /** Unlocked operations */ + /// Access data by key. If not existing, nullptr is returned + std::any* entry(Key key) { return this->get_item(key, false); } + /// Access data by key. If not existing, nullptr is returned + const std::any* entry(Key key) const { return this->get_item(key, false); } + /// Access data as reference by key. If not existing, an exception is thrown template<typename T> T& get(Key key); /// Access data as reference by key. If not existing, an exception is thrown diff --git a/DDDigi/include/DDDigi/DigiEventAction.h b/DDDigi/include/DDDigi/DigiEventAction.h index 9611312e48565fe1634db13ad13e4c3cd886c690..313b7e6104c14a5775403ac8ccc6cc48aead2abd 100644 --- a/DDDigi/include/DDDigi/DigiEventAction.h +++ b/DDDigi/include/DDDigi/DigiEventAction.h @@ -32,7 +32,7 @@ namespace dd4hep { * * \author M.Frank * \version 1.0 - * \ingroup DD4HEP_SIMULATION + * \ingroup DD4HEP_DIGITIZATION */ class DigiEventAction : public DigiAction { friend class DigiKernel; diff --git a/DDDigi/include/DDDigi/DigiFactories.h b/DDDigi/include/DDDigi/DigiFactories.h index 9116f745c653739e83f189eb77c3592927b4bcae..f64ba2e51873e31e211e4a07dee2e01c60df1505 100644 --- a/DDDigi/include/DDDigi/DigiFactories.h +++ b/DDDigi/include/DDDigi/DigiFactories.h @@ -36,9 +36,10 @@ namespace dd4hep { class DigiAction; class DigiInputAction; class DigiEventAction; - class DigiSegmentAction; class DigiCellScanner; class DigiSignalProcessor; + class DigiSegmentProcessor; + class DigiContainerProcessor; } } @@ -48,12 +49,15 @@ namespace { /// Factory to create Digi action objects DD4HEP_PLUGIN_FACTORY_ARGS_2(DS::DigiAction*,const DS::DigiKernel*, std::string) { return new P(*a0,a1); } +#if 0 /// Factory to create Digi action objects DD4HEP_PLUGIN_FACTORY_ARGS_2(DS::DigiEventAction*,const DS::DigiKernel*, std::string) { return new P(*a0,a1); } /// Factory to create Digi action objects - DD4HEP_PLUGIN_FACTORY_ARGS_2(DS::DigiSegmentAction*,const DS::DigiKernel*, std::string) + DD4HEP_PLUGIN_FACTORY_ARGS_2(DS::DigiSegmentProcessor*,const DS::DigiKernel*, std::string) { return new P(*a0,a1); } +#endif + /// Factory to create Digi signal processor objects DD4HEP_PLUGIN_FACTORY_ARGS_2(DS::DigiSignalProcessor*,const DS::DigiKernel*, std::string) { return new P(*a0,a1); } @@ -69,6 +73,8 @@ namespace { /// Plugin defintion to create DigiAction objects #define DECLARE_DIGIACTION(name) DECLARE_DIGIACTION_NS(dd4hep::digi,name) + +#if 0 /// Plugin defintion to create DigiAction objects #define DECLARE_DIGIEVENTACTION_NS(name_space,name) namespace {\ using name_space::name; \ @@ -77,11 +83,14 @@ namespace { #define DECLARE_DIGIEVENTACTION(name) DECLARE_DIGIEVENTACTION_NS(dd4hep::digi,name) /// Plugin defintion to create DigiAction objects -#define DECLARE_DIGISEGMENTACTION_NS(name_space,name) namespace {\ +#define DECLARE_DIGISEGMENTPROCESSOR_NS(name_space,name) namespace {\ using name_space::name; \ - DD4HEP_PLUGINSVC_FACTORY(name,name,dd4hep::digi::DigiSegmentAction*(const DS::DigiKernel*,std::string),__LINE__) } + DD4HEP_PLUGINSVC_FACTORY(name,name,dd4hep::digi::DigiSegmentProcessor*(const DS::DigiKernel*,std::string),__LINE__) } /// Plugin defintion to create DigiAction objects -#define DECLARE_DIGISEGMENTACTION(name) DECLARE_DIGISEGMENTACTION_NS(dd4hep::digi,name) +#define DECLARE_DIGISEGMENTPROCESSOR(name) DECLARE_DIGISEGMENTPROCESSOR_NS(dd4hep::digi,name) +#endif + + #define DECLARE_DIGISIGNALPROCESSOR_NS(name_space,name) namespace { \ using name_space::name; \ diff --git a/DDDigi/include/DDDigi/DigiHandle.h b/DDDigi/include/DDDigi/DigiHandle.h index 80ebf49f28541ca0502b350f21b8c1bf9491b3b7..b2fedc28350560b5f7ba0232ae6d4e14d24ab1ad 100644 --- a/DDDigi/include/DDDigi/DigiHandle.h +++ b/DDDigi/include/DDDigi/DigiHandle.h @@ -37,7 +37,7 @@ namespace dd4hep { /** * \author M.Frank * \version 1.0 - * \ingroup DD4HEP_SIMULATION + * \ingroup DD4HEP_DIGITIZATION */ class KernelHandle { public: @@ -67,7 +67,7 @@ namespace dd4hep { /** * \author M.Frank * \version 1.0 - * \ingroup DD4HEP_SIMULATION + * \ingroup DD4HEP_DIGITIZATION */ template <typename TYPE> class DigiHandle { protected: diff --git a/DDDigi/include/DDDigi/DigiHitAttenuatorExp.h b/DDDigi/include/DDDigi/DigiHitAttenuatorExp.h index 598962b0e202024165f3215721e1e8c9099bf04b..faadc0bff55f10b80ccee1402e8cbc0978253d78 100644 --- a/DDDigi/include/DDDigi/DigiHitAttenuatorExp.h +++ b/DDDigi/include/DDDigi/DigiHitAttenuatorExp.h @@ -16,7 +16,6 @@ // Framework include files #include <DDDigi/DigiEventAction.h> - /// Namespace for the AIDA detector description toolkit namespace dd4hep { @@ -30,25 +29,35 @@ namespace dd4hep { * * \author M.Frank * \version 1.0 - * \ingroup DD4HEP_SIMULATION + * \ingroup DD4HEP_DIGITIZATION */ class DigiHitAttenuatorExp : public DigiEventAction { protected: - /// Implementation declaration - class internals_t; - /// Reference to the actual implementation - std::unique_ptr<internals_t> internals; + /// Property: Input data segment name + std::string m_input_segment { }; + /// Property: Container names to be loaded + std::map<std::string, double> m_container_attenuation { }; + /// Property: event masks to be handled + std::vector<int> m_masks { }; + /// Property: T0 with respect to central crossing + double m_t0 { 0e0 }; + + /// Keys of all containers to be manipulated + std::map<unsigned long, double> m_attenuation { }; protected: /// Define standard assignments and constructors DDDIGI_DEFINE_ACTION_CONSTRUCTORS(DigiHitAttenuatorExp); - /// Default destructor virtual ~DigiHitAttenuatorExp(); + /// Attenuator callback for single container + template <typename T> std::size_t attenuate(T* cont, double factor) const; public: /// Standard constructor DigiHitAttenuatorExp(const DigiKernel& kernel, const std::string& nam); + /// Initialization callback + virtual void initialize(); /// Main functional callback virtual void execute(DigiContext& context) const; }; diff --git a/DDDigi/include/DDDigi/DigiKernel.h b/DDDigi/include/DDDigi/DigiKernel.h index 6cc5b9129d3d646810606cf19e4b34808d62509d..e5984b99a8f2a6b07ed9e08acaf15f44f69f7654 100644 --- a/DDDigi/include/DDDigi/DigiKernel.h +++ b/DDDigi/include/DDDigi/DigiKernel.h @@ -14,7 +14,9 @@ #define DDDIGI_DIGIKERNEL_H // Framework include files +#include <DD4hep/Callback.h> #include <DDDigi/DigiEventAction.h> +#include <DDDigi/DigiParallelWorker.h> // C/C++ include files #include <mutex> @@ -43,18 +45,6 @@ namespace dd4hep { typedef std::map<std::string,int> ClientOutputLevels; typedef std::pair<void*, const std::type_info*> UserFramework; - class ParallelCall { - public: - ParallelCall(ParallelCall* p, void* a); - ParallelCall() = default; - ParallelCall(ParallelCall&& copy) = default; - ParallelCall(const ParallelCall& copy) = default; - ParallelCall& operator=(ParallelCall&& copy) = default; - ParallelCall& operator=(const ParallelCall& copy) = default; - virtual ~ParallelCall() = default; - virtual void execute(void* args) const = 0; - }; - private: class Internals; class Processor; @@ -141,18 +131,29 @@ namespace dd4hep { /// Access current number of events processing (events in flight) std::size_t events_processing() const; + /// Register configure callback. Signature: (function)() + void register_configure(const Callback& callback) const; + /// Register initialize callback. Signature: (function)() + void register_initialize(const Callback& callback) const; + /// Register terminate callback. Signature: (function)() + void register_terminate(const Callback& callback) const; + /// Register start event callback. Signature: (function)(DigiContext*) + void register_start_event(const Callback& callback) const; + /// Register end event callback. Signature: (function)(DigiContext*) + void register_end_event(const Callback& callback) const; + /// Construct detector geometry using description plugin virtual void loadGeometry(const std::string& compact_file); /// Load XML file virtual void loadXML(const char* fname); - /// Run the simulation: Configure Digi + /// Configure the digitization: call all registered configurators virtual int configure(); - /// Run the simulation: Initialize Digi + /// Initialize the digitization: call all registered initializers virtual int initialize(); - /// Run the simulation: Simulate the number of events given by the property "NumEvents" + /// Run the digitization sequence over the requested number of events virtual int run(); - /// Run the simulation: Terminate Digi + /// Terminate the digitization: call all registered terminators and release the allocated resources virtual int terminate(); /// Access to the main input action sequence from the kernel object @@ -163,15 +164,11 @@ namespace dd4hep { DigiActionSequence& outputAction() const; /// Submit a bunch of actions to be executed in parallel - virtual void submit (const std::vector<ParallelCall*>& algorithms, void* data) const; - /// Submit a bunch of actions to be executed serially - virtual void execute(const std::vector<ParallelCall*>& algorithms, void* data) const; -#if 0 + virtual void submit (ParallelCall*const algorithms[], std::size_t count, void* data, bool parallel=true) const; + /// Submit a bunch of actions to be executed in parallel - virtual void submit (const DigiAction::Actors<DigiEventAction>& algorithms, DigiContext& context) const; - /// Submit a bunch of actions to be executed serially - virtual void execute(const DigiAction::Actors<DigiEventAction>& algorithms, DigiContext& context) const; -#endif + virtual void submit (const std::vector<ParallelCall*>& algorithms, void* data, bool parallel=true) const; + /// If running multithreaded: wait until the thread-group finished execution virtual void wait(DigiContext& context) const; diff --git a/DDDigi/include/DDDigi/DigiMultiContainerProcessor.h b/DDDigi/include/DDDigi/DigiMultiContainerProcessor.h deleted file mode 100644 index 4784853e5b4507b11367295daa2ab0ca8f5dfa6a..0000000000000000000000000000000000000000 --- a/DDDigi/include/DDDigi/DigiMultiContainerProcessor.h +++ /dev/null @@ -1,96 +0,0 @@ -//========================================================================== -// AIDA Detector description implementation -//-------------------------------------------------------------------------- -// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN) -// All rights reserved. -// -// For the licensing terms see $DD4hepINSTALL/LICENSE. -// For the list of contributors see $DD4hepINSTALL/doc/CREDITS. -// -// Author : M.Frank -// -//========================================================================== -#ifndef DDDIGI_DIGIMULTICONTAINERPROCESSOR_H -#define DDDIGI_DIGIMULTICONTAINERPROCESSOR_H - -// Framework include files -#include <DDDigi/DigiData.h> -#include <DDDigi/DigiEventAction.h> -#include <DDDigi/DigiParallelWorker.h> - -/// C/C++ include files -#include <set> - -/// Namespace for the AIDA detector description toolkit -namespace dd4hep { - - /// Namespace for the Digitization part of the AIDA detector description toolkit - namespace digi { - - /// Worker base class to analyse containers from the input segment in parallel - class DigiContainerProcessor : public DigiAction { - - public: - using WorkItems = std::vector<std::pair<Key, std::any*> >; - - public: - /// Property: Input data segment name - std::string m_input_segment { "inputs" }; - /// Property: event masks to be handled - std::vector<int> m_input_masks { }; - /// Item keys required by this worker - std::vector<Key> m_container_keys { }; - - public: - /// Standard constructor - DigiContainerProcessor(const DigiKernel& kernel, const std::string& name); - /// Main functional callback if specific work is known - virtual void execute(DigiContext& context, WorkItems& work) const; - /// Check if the work item is for us - bool use_container(Key key) const; - }; - - /// Sequencer class to analyse containers from the input segment in parallel - /** - * - * \author M.Frank - * \version 1.0 - * \ingroup DD4HEP_SIMULATION - */ - class DigiMultiContainerProcessor : public DigiEventAction { - public: - using WorkItems = DigiContainerProcessor::WorkItems; - struct CallData { - DigiContext& context; - WorkItems& work; - }; - using Worker = DigiParallelWorker<DigiContainerProcessor,CallData,int>; - using Workers = std::vector<DigiKernel::ParallelCall*>; - - protected: - /// Property: Input data segment name - std::string m_input_segment { "inputs" }; - /// Property: event masks to be handled - std::vector<int> m_input_masks { }; - - std::set<Key> m_work_items; - /// Array of sub-workers - Workers m_workers; - - protected: - /// Define standard assignments and constructors - DDDIGI_DEFINE_ACTION_CONSTRUCTORS(DigiMultiContainerProcessor); - /// Default destructor - virtual ~DigiMultiContainerProcessor(); - - public: - /// Standard constructor - DigiMultiContainerProcessor(const DigiKernel& kernel, const std::string& name); - /// Adopt new parallel worker - void adopt_processor(DigiContainerProcessor* action, const std::vector<std::string>& containers); - /// Main functional callback - virtual void execute(DigiContext& context) const; - }; - } // End namespace digi -} // End namespace dd4hep -#endif // DDDIGI_DIGIMULTICONTAINERPROCESSOR_H diff --git a/DDDigi/include/DDDigi/DigiParallelWorker.h b/DDDigi/include/DDDigi/DigiParallelWorker.h index 5319335bedcc22e9d0d21942f43475ca05b170c1..e22cba7800e0ffe179fc0e390f72a980abcd8fb4 100644 --- a/DDDigi/include/DDDigi/DigiParallelWorker.h +++ b/DDDigi/include/DDDigi/DigiParallelWorker.h @@ -13,9 +13,6 @@ #ifndef DDDIGI_DIGIPARALLELWORKER_H #define DDDIGI_DIGIPARALLELWORKER_H -/// Framework include files -#include <DDDigi/DigiKernel.h> - /// Namespace for the AIDA detector description toolkit namespace dd4hep { @@ -27,45 +24,64 @@ namespace dd4hep { * * \author M.Frank * \version 1.0 - * \ingroup DD4HEP_SIMULATION + * \ingroup DD4HEP_DIGITIZATION */ - template <typename ACTION_TYPE, typename CALLDATA, typename OPTIONS> - class DigiParallelWorker : public DigiKernel::ParallelCall { + class ParallelWorker { public: - using action_t = ACTION_TYPE; - using options_t = OPTIONS; - using calldata_t = CALLDATA; + /// Default constructor + ParallelWorker() = default; + ParallelWorker(ParallelWorker&& copy) = default; + ParallelWorker(const ParallelWorker& copy) = default; + ParallelWorker& operator=(ParallelWorker&& copy) = default; + ParallelWorker& operator=(const ParallelWorker& copy) = default; + virtual ~ParallelWorker() = default; + virtual void execute(void* args) const = 0; + }; - action_t* action; - options_t options; + /// Wrapper class to submit bulk actions + /** + * + * \author M.Frank + * \version 1.0 + * \ingroup DD4HEP_DIGITIZATION + */ + template <typename ACTION_TYPE, typename CALLDATA, typename OPTIONS=std::size_t> + class DigiParallelWorker : public ParallelWorker { + public: + using action_t = ACTION_TYPE; + using options_t = OPTIONS; + using calldata_t = CALLDATA; + + action_t* action { nullptr }; + options_t options { nullptr }; public: - /// Initializing constructor - DigiParallelWorker(ACTION_TYPE* p, const OPTIONS& opts); - /// Default constructor - DigiParallelWorker() = delete; - /// Move constructor - DigiParallelWorker(DigiParallelWorker&& copy) = default; - /// Inhibit copy constructor - DigiParallelWorker(const DigiParallelWorker& copy) = default; - /// Inhibit move assignment - DigiParallelWorker& operator=(DigiParallelWorker&& copy) = delete; - /// Inhibit copy assignment - DigiParallelWorker& operator=(const DigiParallelWorker& copy) = delete; - /// Default destructor - virtual ~DigiParallelWorker(); - /// Access to processor name - const char* name() const { return action->name().c_str(); } - /// Callback on data - virtual void execute(void* data) const override; + /// Initializing constructor + DigiParallelWorker(ACTION_TYPE* p, const OPTIONS& opts); + /// Default constructor + DigiParallelWorker() = delete; + /// Move constructor + DigiParallelWorker(DigiParallelWorker&& copy) = default; + /// Inhibit copy constructor + DigiParallelWorker(const DigiParallelWorker& copy) = default; + /// Inhibit move assignment + DigiParallelWorker& operator=(DigiParallelWorker&& copy) = delete; + /// Inhibit copy assignment + DigiParallelWorker& operator=(const DigiParallelWorker& copy) = delete; + /// Default destructor + virtual ~DigiParallelWorker(); + /// Access to processor name + const char* name() const { return action->name().c_str(); } + /// Callback on data + virtual void execute(void* data) const override; }; /// Initializing constructor template <typename ACTION_TYPE, typename CALLDATA, typename OPTIONS> DigiParallelWorker<ACTION_TYPE, CALLDATA, OPTIONS>::DigiParallelWorker(ACTION_TYPE* proc, const OPTIONS& opts) - : ParallelCall(), action(proc), options(opts) + : ParallelWorker(), action(proc), options(opts) { - action->addRef(); + if ( action ) action->addRef(); } /// Default destructor @@ -76,6 +92,12 @@ namespace dd4hep { action = nullptr; } } + + typedef ParallelWorker ParallelCall; } // End namespace digi } // End namespace dd4hep + +#include <DDDigi/DigiParallelWorkers.h> +#include <DDDigi/DigiParallelWorkerGroup.h> + #endif // DDDIGI_DIGIPARALLELWORKER_H diff --git a/DDDigi/include/DDDigi/DigiParallelWorkerGroup.h b/DDDigi/include/DDDigi/DigiParallelWorkerGroup.h new file mode 100644 index 0000000000000000000000000000000000000000..ebebd2a56049dc907fd5998dede35c73d43d49e9 --- /dev/null +++ b/DDDigi/include/DDDigi/DigiParallelWorkerGroup.h @@ -0,0 +1,78 @@ +//========================================================================== +// AIDA Detector description implementation +//-------------------------------------------------------------------------- +// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN) +// All rights reserved. +// +// For the licensing terms see $DD4hepINSTALL/LICENSE. +// For the list of contributors see $DD4hepINSTALL/doc/CREDITS. +// +// Author : M.Frank +// +//========================================================================== +#ifndef DDDIGI_DIGIPARALLELWORKERGROUP_H +#define DDDIGI_DIGIPARALLELWORKERGROUP_H + +/// Framework include files + +/// C/C++ include files + +/// Namespace for the AIDA detector description toolkit +namespace dd4hep { + + /// Namespace for the Digitization part of the AIDA detector description toolkit + namespace digi { + + /// Forward declarations + template <typename T> class DigiParallelWorkers; + template <typename T> class DigiParallelWorkerGroup; + + /// Wrapper class to submit bulk actions + /** + * + * \author M.Frank + * \version 1.0 + * \ingroup DD4HEP_DIGITIZATION + */ + template <typename T> class DigiParallelWorkerGroup { + /// Reference to worker collection with semaphore + const DigiParallelWorkers<T>& workers; + + public: + /// Initializin constructor: aquire worker's semaphore + DigiParallelWorkerGroup(const DigiParallelWorkers<T>& workers); + /// Inhibit Move constructor + DigiParallelWorkerGroup(DigiParallelWorkerGroup&& copy) = delete; + /// Inhibit copy constructor + DigiParallelWorkerGroup(const DigiParallelWorkerGroup& copy) = delete; + /// Inhibit move assignment + DigiParallelWorkerGroup& operator=(DigiParallelWorkerGroup&& copy) = delete; + /// Inhibit copy assignment + DigiParallelWorkerGroup& operator=(const DigiParallelWorkerGroup& copy) = delete; + /// Default destructor. Releasing semaphore + ~DigiParallelWorkerGroup(); + /// Access the worker array. As long as the object persists it shall not be altered + operator ParallelCall*const* (); + }; + + /// Initializin constructor: aquire worker's semaphore + template <typename T> inline + DigiParallelWorkerGroup<T>::DigiParallelWorkerGroup(const DigiParallelWorkers<T>& w) + : workers(w) + { + workers.semaphore.aquire(); + } + + /// Default destructor. Releasing semaphore + template <typename T> inline DigiParallelWorkerGroup<T>::~DigiParallelWorkerGroup() { + workers.semaphore.release(); + } + + /// Access the worker array. As long as the object persists the array stays intact + template <typename T> inline DigiParallelWorkerGroup<T>::operator ParallelCall*const* () { + return (ParallelCall**)&this->workers.actors.at(0); + } + + } // End namespace digi +} // End namespace dd4hep +#endif // DDDIGI_DIGIPARALLELWORKERGROUP_H diff --git a/DDDigi/include/DDDigi/DigiParallelWorkers.h b/DDDigi/include/DDDigi/DigiParallelWorkers.h new file mode 100644 index 0000000000000000000000000000000000000000..ea2cbd76f204599ea30a5228ba2cb55ba5e1a94b --- /dev/null +++ b/DDDigi/include/DDDigi/DigiParallelWorkers.h @@ -0,0 +1,121 @@ +//========================================================================== +// AIDA Detector description implementation +//-------------------------------------------------------------------------- +// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN) +// All rights reserved. +// +// For the licensing terms see $DD4hepINSTALL/LICENSE. +// For the list of contributors see $DD4hepINSTALL/doc/CREDITS. +// +// Author : M.Frank +// +//========================================================================== +#ifndef DDDIGI_DIGIPARALLELWORKERS_H +#define DDDIGI_DIGIPARALLELWORKERS_H + +/// Framework include files +#include <DDDigi/DigiSemaphore.h> +#include <DDDigi/DigiParallelWorkerGroup.h> + +/// C/C++ include files + +/// Namespace for the AIDA detector description toolkit +namespace dd4hep { + + /// Namespace for the Digitization part of the AIDA detector description toolkit + namespace digi { + + /// Forward declarations + class ParallelWorker; + template <typename T, typename A, typename O> class DigiParallelWorker; + template <typename T> class DigiParallelWorkers; + template <typename T> class DigiParallelWorkerGroup; + + /// Wrapper class to submit bulk actions + /** + * + * \author M.Frank + * \version 1.0 + * \ingroup DD4HEP_DIGITIZATION + */ + template <typename T> class DigiParallelWorkers { + public: + typedef T worker_t; + typedef DigiParallelWorkers<T> self_t; + typedef DigiParallelWorkerGroup<T> group_t; + + friend class DigiParallelWorkerGroup<worker_t>; + + private: + mutable std::vector<worker_t*> actors; + mutable DigiSemaphore semaphore; + + public: + /// Default constructor + DigiParallelWorkers() = default; + /// Inhibit Move constructor + DigiParallelWorkers(DigiParallelWorkers&& copy) = delete; + /// Inhibit copy constructor + DigiParallelWorkers(const DigiParallelWorkers& copy) = delete; + /// Inhibit move assignment + DigiParallelWorkers& operator=(DigiParallelWorkers&& copy) = delete; + /// Inhibit copy assignment + DigiParallelWorkers& operator=(const DigiParallelWorkers& copy) = delete; + /// Default destructor + virtual ~DigiParallelWorkers(); + + std::unique_lock<std::mutex> can_modify() const; + /// Return array protected worker group + group_t get_group() const; + + /// NOT thread-safe stuff. Do not use during event processing unless you are sequential + const std::vector<worker_t*>& get() const { return actors; } + std::size_t size() const; + bool empty() const; + bool insert(worker_t* entry) const; + ParallelCall*const* get_calls() const; + }; + + template <typename T> inline + DigiParallelWorkers<T>::~DigiParallelWorkers() { + for(auto* w : actors) + delete w; + actors.clear(); + } + + template <typename T> inline + std::unique_lock<std::mutex> DigiParallelWorkers<T>::can_modify() const { + return this->semaphore.wait_null(); + } + + template <typename T> inline + bool DigiParallelWorkers<T>::insert(worker_t* entry) const { + if ( entry ) { + actors.emplace_back(entry); + return true; + } + return false; + } + + template <typename T> inline + std::size_t DigiParallelWorkers<T>::size() const { + return actors.size(); + } + + template <typename T> inline + bool DigiParallelWorkers<T>::empty() const { + return actors.empty(); + } + + template <typename T> inline + ParallelWorker*const* DigiParallelWorkers<T>::get_calls() const { + return (ParallelWorker**)&this->actors.at(0); + } + + template <typename T> inline typename DigiParallelWorkers<T>::group_t + DigiParallelWorkers<T>::get_group() const { + return group_t(*this); + } + } // End namespace digi +} // End namespace dd4hep +#endif // DDDIGI_DIGIPARALLELWORKERS_H diff --git a/DDDigi/include/DDDigi/DigiPlugins.h b/DDDigi/include/DDDigi/DigiPlugins.h new file mode 100644 index 0000000000000000000000000000000000000000..5e36625ab8a32337ef1255c2c3e362199071e2be --- /dev/null +++ b/DDDigi/include/DDDigi/DigiPlugins.h @@ -0,0 +1,46 @@ +//========================================================================== +// AIDA Detector description implementation +//-------------------------------------------------------------------------- +// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN) +// All rights reserved. +// +// For the licensing terms see $DD4hepINSTALL/LICENSE. +// For the list of contributors see $DD4hepINSTALL/doc/CREDITS. +// +// Author : M.Frank +// +//========================================================================== +#ifndef DDDIGI_DIGIPLUGINS_H +#define DDDIGI_DIGIPLUGINS_H + +/// Framework include files +#include <DD4hep/Primitives.h> + +/// C/C++ include files +#include <string> + +/// Namespace for the AIDA detector description toolkit +namespace dd4hep { + + /// Namespace for the Digitization part of the AIDA detector description toolkit + namespace digi { + + /// Forward declarations + class DigiKernel; + + void* create_action(const std::string& factory, + const DigiKernel& kernel, + const std::string& arg, + void* (*cast)(void*)); + + /// Handler for factories of type: ConstructionFactory with casted return type + template <typename T> T* createAction(const std::string& factory, + const DigiKernel& kernel, + const std::string& arg) + { + struct __cast{ static void* cast(void* p) { return &dynamic_cast<T&>(*(T*)p); } }; + return (T*)create_action(factory, kernel, arg, __cast::cast); + } + } // End namespace digi +} // End namespace dd4hep +#endif // DDDIGI_DIGIPLUGINS_H diff --git a/DDDigi/include/DDDigi/DigiSegmentProcessor.h b/DDDigi/include/DDDigi/DigiSegmentProcessor.h new file mode 100644 index 0000000000000000000000000000000000000000..cde4ceb93553372d9db67fa464c0703f9bd83179 --- /dev/null +++ b/DDDigi/include/DDDigi/DigiSegmentProcessor.h @@ -0,0 +1,105 @@ +//========================================================================== +// AIDA Detector description implementation +//-------------------------------------------------------------------------- +// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN) +// All rights reserved. +// +// For the licensing terms see $DD4hepINSTALL/LICENSE. +// For the list of contributors see $DD4hepINSTALL/doc/CREDITS. +// +// Author : M.Frank +// +//========================================================================== +#ifndef DDDIGI_DIGISEGMENTPROCESSOR_H +#define DDDIGI_DIGISEGMENTPROCESSOR_H + +// Framework include files +#include <DDDigi/DigiData.h> +#include <DDDigi/DigiContainerProcessor.h> +#include <DDDigi/DigiSegmentationTool.h> + +/// Namespace for the AIDA detector description toolkit +namespace dd4hep { + + /// Namespace for the Digitization part of the AIDA detector description toolkit + namespace digi { + + /// Forward declarations + class DigiSegmentProcessor; + class DigiSegmentSequence; + + /// Default base class to process parts of a subdetector segmentation data + /** + * This is a utility class supporting properties, output and access to + * event and run objects through the context. + * + * Default base class to process parts of a subdetector segmentation data. + * + * \author M.Frank + * \version 1.0 + * \ingroup DD4HEP_DIGITAZATION + */ + class DigiSegmentProcessor : public DigiContainerProcessor { + public: + /// Segmentation split context + DigiSegmentContext segment { }; + + protected: + /// Define standard assignments and constructors + DDDIGI_DEFINE_ACTION_CONSTRUCTORS(DigiSegmentProcessor); + + public: + /// Standard constructor + DigiSegmentProcessor(const DigiKernel& kernel, const std::string& name); + /// Default destructor + virtual ~DigiSegmentProcessor(); + /// Main functional callback if specific work is known + virtual void handle_segment(DigiContext& context, work_t& data) const; + }; + + /// Sequencer class to process parts of a subdetector segmentation data + /** + * This is a utility class supporting properties, output and access to + * event and run objects through the context. + * + * The sequencer calls all registered processors for the contaiers registered. + * The sequencer manages a set of workers all acting on the same data segment + * being a part of the data of a collection + * + * \author M.Frank + * \version 1.0 + * \ingroup DD4HEP_DIGITIZATION + */ + class DigiSegmentSequence : public DigiSegmentProcessor { + protected: + /// Property to steer parallel processing + bool m_parallel { false }; + + protected: + using self_t = DigiSegmentSequence; + using processor_t = DigiSegmentProcessor; + using worker_t = DigiParallelWorker<processor_t,work_t,VolumeID>; + using workers_t = DigiParallelWorkers<worker_t>; + friend class DigiParallelWorker<processor_t,work_t,VolumeID>; + + /// Array of sub-workers + workers_t m_workers; + + protected: + /// Define standard assignments and constructors + DDDIGI_DEFINE_ACTION_CONSTRUCTORS(DigiSegmentSequence); + /// Default destructor + virtual ~DigiSegmentSequence(); + + public: + /// Standard constructor + DigiSegmentSequence(const DigiKernel& kernel, const std::string& name); + /// Adopt new parallel worker + virtual void adopt_processor(DigiContainerProcessor* action); + /// Main functional callback if specific work is known + virtual void handle_segment(DigiContext& context, work_t& work) const; + }; + + } // End namespace digi +} // End namespace dd4hep +#endif // DDDIGI_DIGISEGMENTPROCESSOR_H diff --git a/DDDigi/include/DDDigi/DigiSegmentSplitter.h b/DDDigi/include/DDDigi/DigiSegmentSplitter.h index 54afcd398fe45e7163c91b59c011294150770243..25c7a9fd971b3dfd68df20487e4fe4519a4744ce 100644 --- a/DDDigi/include/DDDigi/DigiSegmentSplitter.h +++ b/DDDigi/include/DDDigi/DigiSegmentSplitter.h @@ -15,7 +15,7 @@ // Framework include files #include <DDDigi/DigiEventAction.h> -#include <DDDigi/DigiSegmentAction.h> +#include <DDDigi/DigiSegmentProcessor.h> #include <DDDigi/DigiSegmentationTool.h> #include <DDDigi/DigiParallelWorker.h> @@ -32,28 +32,20 @@ namespace dd4hep { * * \author M.Frank * \version 1.0 - * \ingroup DD4HEP_SIMULATION + * \ingroup DD4HEP_DIGITIZATION */ - class DigiSegmentSplitter : public DigiEventAction { - public: - - struct CallData { - DigiContext& context; - DepositMapping& input; - DepositMapping* output; - const DigiSegmentSplitter* parent; - }; - - using Worker = DigiParallelWorker<DigiSegmentAction,CallData,int>; - using Workers = std::vector<DigiKernel::ParallelCall*>; - using Splits = std::map<VolumeID, std::pair<DetElement, VolumeID> >; + class DigiSegmentSplitter : public DigiContainerSequence { + protected: + using self_t = DigiSegmentSplitter; + using processor_t = DigiSegmentProcessor; + using work_t = processor_t::work_t; + using worker_t = DigiParallelWorker<processor_t, work_t, VolumeID>; + using workers_t = DigiParallelWorkers<worker_t>; + using split_t = std::pair<DetElement, VolumeID>; + using splits_t = std::map<VolumeID, split_t>; + friend class DigiParallelWorker<processor_t, work_t, VolumeID>; protected: - /// Implementation declaration - class internals_t; - /// Reference to the implementation - std::unique_ptr<internals_t> internals; - /// Property: Split element of the ID descriptor std::string m_processor_type; /// Name of the subdetector to be handed @@ -63,43 +55,34 @@ namespace dd4hep { /// Property: Flag if processors should be shared bool m_share_processor { true }; - /// Property: Identifier of the input repository - std::string m_input_id; - /// Property: Input mask in the repository - int m_input_mask; - /// Property: Identifier of the input repository - std::string m_output_id; - /// Property: Input mask in the repository - int m_output_mask; - + /** Member variables */ /// Segmentation too instance DigiSegmentationTool m_split_tool; /// Segmentation split context DigiSegmentContext m_split_context; - + /// Data keys from the readout collection names + std::vector<Key> m_keys; /// Split elements used to parallelize the processing - Splits m_splits; - /// Input data keys: depend on dd4hep::Readout and the input mask(s) - std::vector<Key> m_data_keys; - + splits_t m_splits; /// Array of sub-workers - Workers m_workers; - + workers_t m_workers; + /// Need a lock for possible output merging mutable std::mutex m_output_lock; protected: /// Default destructor virtual ~DigiSegmentSplitter(); + /// Initialization function void initialize(); + /// Adopt new parallel worker: INHIBITED: will throw exception + virtual void adopt_processor(DigiContainerProcessor* action) override final; public: /// Standard constructor DigiSegmentSplitter(const DigiKernel& kernel, const std::string& name); - /// Handle result from segment callbacks - void register_output(DepositMapping& result, DepositVector&& output) const; /// Main functional callback - virtual void execute(DigiContext& context) const; + virtual void execute(DigiContext& context, work_t& work) const override; }; } // End namespace digi } // End namespace dd4hep diff --git a/DDDigi/include/DDDigi/DigiSegmentationTool.h b/DDDigi/include/DDDigi/DigiSegmentationTool.h index 0e4858ab1b19b32e54b21ae48324815ea6154c68..eb2702b343c7f5a2aba4d2f5aaef1e48e1118e7d 100644 --- a/DDDigi/include/DDDigi/DigiSegmentationTool.h +++ b/DDDigi/include/DDDigi/DigiSegmentationTool.h @@ -35,7 +35,7 @@ namespace dd4hep { * * \author M.Frank * \version 1.0 - * \ingroup DD4HEP_SIMULATION + * \ingroup DD4HEP_DIGITIZATION */ class DigiSegmentContext { public: @@ -80,7 +80,7 @@ namespace dd4hep { * * \author M.Frank * \version 1.0 - * \ingroup DD4HEP_SIMULATION + * \ingroup DD4HEP_DIGITIZATION */ class DigiSegmentationTool { public: diff --git a/DDDigi/include/DDDigi/DigiSemaphore.h b/DDDigi/include/DDDigi/DigiSemaphore.h new file mode 100644 index 0000000000000000000000000000000000000000..21fc04eb7ac3c200cbd6c0dc049a25a4d728c6c0 --- /dev/null +++ b/DDDigi/include/DDDigi/DigiSemaphore.h @@ -0,0 +1,75 @@ +//========================================================================== +// AIDA Detector description implementation +//-------------------------------------------------------------------------- +// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN) +// All rights reserved. +// +// For the licensing terms see $DD4hepINSTALL/LICENSE. +// For the list of contributors see $DD4hepINSTALL/doc/CREDITS. +// +// Author : M.Frank +// +//========================================================================== +#ifndef DDDIGI_DIGISEMAPHORE_H +#define DDDIGI_DIGISEMAPHORE_H + +/// Framework include files + +/// C/C++ include files +#include <mutex> +#include <atomic> +#include <condition_variable> + +/// Namespace for the AIDA detector description toolkit +namespace dd4hep { + + /// Namespace for the Digitization part of the AIDA detector description toolkit + namespace digi { + + /// Forward declarations + class DigiSemaphore; + + /// Semaphore implementation, where object get notified when the reference count reaches NULL + /** Semaphore implementation + * object get notified when the reference count reaches NULL + * + * \author M.Frank + * \version 1.0 + * \ingroup DD4HEP_DIGITIZATION + */ + class DigiSemaphore final { + private: + /// Reference count + std::atomic<std::size_t> reference_count { 0UL }; + /// Condition variable to wait until reference count is NULL + std::condition_variable reference_count_is_null; + /// Lock to handle condition variable + std::mutex lock; + + public: + /// Default constructor: the one and only one + DigiSemaphore() = default; + /// Inhibit Move constructor + DigiSemaphore(DigiSemaphore&& copy) = delete; + /// Inhibit copy constructor + DigiSemaphore(const DigiSemaphore& copy) = delete; + /// Inhibit move assignment + DigiSemaphore& operator=(DigiSemaphore&& copy) = delete; + /// Inhibit copy assignment + DigiSemaphore& operator=(const DigiSemaphore& copy) = delete; + /// Default destructor. Decreasing reference count. + ~DigiSemaphore() = default; + + public: + /// Wait until reference count is NULL. + /** @return unique_lock [out] The semaphore is locks as long as the returned lock is held + */ + std::unique_lock<std::mutex> wait_null(); + /// Aquire semaphore count + void aquire(); + /// Release semaphore count + void release(); + }; + } // End namespace digi +} // End namespace dd4hep +#endif // DDDIGI_DIGISEMAPHORE_H diff --git a/DDDigi/include/DDDigi/DigiStoreDump.h b/DDDigi/include/DDDigi/DigiStoreDump.h index ea814049ab33de08ec8274f5708ed3f1b2422b68..507b434d383138f25fdeaee14fcf6f145a0333fd 100644 --- a/DDDigi/include/DDDigi/DigiStoreDump.h +++ b/DDDigi/include/DDDigi/DigiStoreDump.h @@ -32,7 +32,7 @@ namespace dd4hep { * * \author M.Frank * \version 1.0 - * \ingroup DD4HEP_SIMULATION + * \ingroup DD4HEP_DIGITIZATION */ class DigiStoreDump : public DigiEventAction { protected: diff --git a/DDDigi/include/DDDigi/DigiSynchronize.h b/DDDigi/include/DDDigi/DigiSynchronize.h index 8b3f4827de73f1538ccee32ac62906fe85077841..3c4c565b8b3176a1f5f95dceb72322df464ccc5d 100644 --- a/DDDigi/include/DDDigi/DigiSynchronize.h +++ b/DDDigi/include/DDDigi/DigiSynchronize.h @@ -34,10 +34,9 @@ namespace dd4hep { */ class DigiSynchronize : public DigiEventAction { protected: - /// The list of action objects to be called - //Actors<DigiEventAction> m_actors; using Worker = DigiParallelWorker<DigiEventAction,DigiContext,int>; - using Workers = std::vector<DigiKernel::ParallelCall*>; + using Workers = DigiParallelWorkers<Worker>; + /// The list of action objects to be called Workers m_actors; protected: diff --git a/DDDigi/include/DDDigi/noise/DigiSignalProcessorSequence.h b/DDDigi/include/DDDigi/noise/DigiSignalProcessorSequence.h index 3a137477ee8b1725968f8d010647ee6575f6c289..4dd7f980cc703967db07d46db7a6916f532a98d8 100644 --- a/DDDigi/include/DDDigi/noise/DigiSignalProcessorSequence.h +++ b/DDDigi/include/DDDigi/noise/DigiSignalProcessorSequence.h @@ -14,6 +14,7 @@ #define DDDIGI_NOISE_DIGISIGNALPROCESSORSEQUENCE_H // Framework include files +#include <DDDigi/DigiParallelWorker.h> #include <DDDigi/DigiSignalProcessor.h> /// Namespace for the AIDA detector description toolkit @@ -41,9 +42,16 @@ namespace dd4hep { * \ingroup DD4HEP_DIGITIZATION */ class DigiSignalProcessorSequence : public DigiSignalProcessor { + public: + struct CallData { + DigiCellContext& context; + double value; + }; protected: + using Worker = DigiParallelWorker<DigiSignalProcessor,CallData,int>; + using Workers = DigiParallelWorkers<Worker>; /// The list of action objects to be called - Actors<DigiSignalProcessor> m_actors; + Workers m_actors; protected: /// Define standard assignments and constructors diff --git a/DDDigi/include/DDDigi/noise/DigiSubdetectorSequence.h b/DDDigi/include/DDDigi/noise/DigiSubdetectorSequence.h index c2a68bdafeb14b60fe90fba24f2364aa104049ec..4a11413ee3f86c32fff239dc8be1b476acba5728 100644 --- a/DDDigi/include/DDDigi/noise/DigiSubdetectorSequence.h +++ b/DDDigi/include/DDDigi/noise/DigiSubdetectorSequence.h @@ -103,7 +103,7 @@ namespace dd4hep { /// Default destructor virtual ~DigiSubdetectorSequence(); /// Iniitalize subdetector sequencer - virtual void initialize() override; + virtual void initialize(); /// Begin-of-event callback virtual void execute(DigiContext& context) const override; }; diff --git a/DDDigi/plugins/Components.cpp b/DDDigi/plugins/Components.cpp index f982f9cfaf461be4c42fe8a87412df3e1d34d2f2..30a0234786375778fc8a63b2cdbd12e7c2b47ce2 100644 --- a/DDDigi/plugins/Components.cpp +++ b/DDDigi/plugins/Components.cpp @@ -22,44 +22,49 @@ #include <sstream> #include <DDDigi/DigiInputAction.h> -DECLARE_DIGIEVENTACTION_NS(dd4hep::digi,DigiInputAction) +DECLARE_DIGIACTION_NS(dd4hep::digi,DigiInputAction) #include <DDDigi/DigiROOTInput.h> -DECLARE_DIGIEVENTACTION_NS(dd4hep::digi,DigiROOTInput) +DECLARE_DIGIACTION_NS(dd4hep::digi,DigiROOTInput) #include <DDDigi/DigiSynchronize.h> -DECLARE_DIGIEVENTACTION_NS(dd4hep::digi,DigiSynchronize) +DECLARE_DIGIACTION_NS(dd4hep::digi,DigiSynchronize) #include <DDDigi/DigiActionSequence.h> -DECLARE_DIGIEVENTACTION_NS(dd4hep::digi,DigiActionSequence) -DECLARE_DIGIEVENTACTION_NS(dd4hep::digi,DigiParallelActionSequence) -DECLARE_DIGIEVENTACTION_NS(dd4hep::digi,DigiSequentialActionSequence) +DECLARE_DIGIACTION_NS(dd4hep::digi,DigiActionSequence) +DECLARE_DIGIACTION_NS(dd4hep::digi,DigiParallelActionSequence) +DECLARE_DIGIACTION_NS(dd4hep::digi,DigiSequentialActionSequence) //#include <DDDigi/DigiSubdetectorSequence.h> // DECLARE_DIGIEVENTACTION_NS(dd4hep::digi,DigiSubdetectorSequence) #include <DDDigi/DigiLockedAction.h> -DECLARE_DIGIEVENTACTION_NS(dd4hep::digi,DigiLockedAction) +DECLARE_DIGIACTION_NS(dd4hep::digi,DigiLockedAction) //#include <DDDigi/DigiSignalProcessorSequence.h> // DECLARE_DIGISIGNALPROCESSOR_NS(dd4hep::digi,DigiSignalProcessorSequence) #include <DDDigi/DigiStoreDump.h> -DECLARE_DIGIEVENTACTION_NS(dd4hep::digi,DigiStoreDump) +DECLARE_DIGIACTION_NS(dd4hep::digi,DigiStoreDump) #include <DDDigi/DigiHitAttenuatorExp.h> -DECLARE_DIGIEVENTACTION_NS(dd4hep::digi,DigiHitAttenuatorExp) +DECLARE_DIGIACTION_NS(dd4hep::digi,DigiHitAttenuatorExp) #include <DDDigi/DigiContainerCombine.h> -DECLARE_DIGIEVENTACTION_NS(dd4hep::digi,DigiContainerCombine) +DECLARE_DIGIACTION_NS(dd4hep::digi,DigiContainerCombine) + +#include <DDDigi/DigiSegmentProcessor.h> +DECLARE_DIGIACTION_NS(dd4hep::digi,DigiSegmentProcessor) +DECLARE_DIGIACTION_NS(dd4hep::digi,DigiSegmentSequence) #include <DDDigi/DigiSegmentSplitter.h> -DECLARE_DIGISEGMENTACTION_NS(dd4hep::digi,DigiSegmentAction) -DECLARE_DIGIEVENTACTION_NS(dd4hep::digi,DigiSegmentSplitter) +DECLARE_DIGIACTION_NS(dd4hep::digi,DigiSegmentSplitter) -#include <DDDigi/DigiMultiContainerProcessor.h> -DECLARE_DIGIEVENTACTION_NS(dd4hep::digi,DigiMultiContainerProcessor) +#include <DDDigi/DigiContainerProcessor.h> +DECLARE_DIGIACTION_NS(dd4hep::digi,DigiMultiContainerProcessor) +DECLARE_DIGIACTION_NS(dd4hep::digi,DigiContainerSequence) DECLARE_DIGIACTION_NS(dd4hep::digi,DigiContainerProcessor) +DECLARE_DIGIACTION_NS(dd4hep::digi,DigiContainerSequenceAction) /// Basic entry point static long dummy(dd4hep::Detector&, int, char**) { diff --git a/DDDigi/plugins/DigiHitHistoryDrop.cpp b/DDDigi/plugins/DigiHitHistoryDrop.cpp index c3dd1b30675d99ccec490d465d0d847a032d5c1c..b4da3d172a1ce476cd96a860d4494e0fcdfcf923 100644 --- a/DDDigi/plugins/DigiHitHistoryDrop.cpp +++ b/DDDigi/plugins/DigiHitHistoryDrop.cpp @@ -31,7 +31,7 @@ namespace dd4hep { * * \author M.Frank * \version 1.0 - * \ingroup DD4HEP_SIMULATION + * \ingroup DD4HEP_DIGITIZATION */ class DigiHitHistoryDrop : public DigiEventAction { protected: @@ -62,27 +62,36 @@ namespace dd4hep { /// Main functional callback virtual void execute(DigiContext& context) const final { auto& inputs = context.event->get_segment(m_input); - std::size_t num_drop = 0; + std::size_t num_drop_hit = 0; + std::size_t num_drop_particle = 0; for ( auto& i : inputs ) { Key key(i.first); - auto im = std::find(m_masks.begin(), m_masks.end(), key.values.mask); + auto im = std::find(m_masks.begin(), m_masks.end(), key.mask()); if ( im != m_masks.end() ) { - std::any& obj = i.second; - DepositMapping* m = std::any_cast<DepositMapping>(&obj); - if ( m ) { + if ( DepositMapping* m = std::any_cast<DepositMapping>(&i.second) ) { for( auto& c : *m ) { - num_drop += c.second.history.size(); - c.second.history.clear(); + num_drop_hit += c.second.hit_history.size(); + c.second.hit_history.clear(); + num_drop_particle += c.second.particle_history.size(); + c.second.particle_history.clear(); + } + } + if ( DepositVector* m = std::any_cast<DepositVector>(&i.second) ) { + for( auto& c : *m ) { + num_drop_hit += c.second.hit_history.size(); + c.second.hit_history.clear(); + num_drop_particle += c.second.particle_history.size(); + c.second.particle_history.clear(); } } } } - info("%s+++ Dropped history of %6ld hits", context.event->id(), num_drop); + info("%s+++ Dropped history of %6ld hits %6ld particles", + context.event->id(), num_drop_hit, num_drop_particle); } }; } // End namespace digi } // End namespace dd4hep - #include <DDDigi/DigiFactories.h> -DECLARE_DIGIEVENTACTION_NS(dd4hep::digi,DigiHitHistoryDrop) +DECLARE_DIGIACTION_NS(dd4hep::digi,DigiHitHistoryDrop) diff --git a/DDDigi/plugins/DigiIPRandomizer.cpp b/DDDigi/plugins/DigiIPRandomizer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..39ec5180874262474c9e1adfa71ad81dd40ddff5 --- /dev/null +++ b/DDDigi/plugins/DigiIPRandomizer.cpp @@ -0,0 +1,131 @@ +//========================================================================== +// AIDA Detector description implementation +//-------------------------------------------------------------------------- +// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN) +// All rights reserved. +// +// For the licensing terms see $DD4hepINSTALL/LICENSE. +// For the list of contributors see $DD4hepINSTALL/doc/CREDITS. +// +// Author : M.Frank +// +//========================================================================== + +// Framework include files +#include <DD4hep/InstanceCount.h> +#include <DDDigi/DigiData.h> +#include <DDDigi/DigiContext.h> +#include <DDDigi/DigiEventAction.h> +#include <DDDigi/DigiParallelWorker.h> + + +/// Namespace for the AIDA detector description toolkit +namespace dd4hep { + + /// Namespace for the Digitization part of the AIDA detector description toolkit + namespace digi { + + /// Default base class for all Digitizer actions and derivates thereof. + /** + * This is a utility class supporting properties, output and access to + * event and run objects through the context. + * + * \author M.Frank + * \version 1.0 + * \ingroup DD4HEP_DIGITIZATION + */ + class DigiIPRandomizer : public DigiEventAction { + protected: + /// Property: Masks to act on + int m_mask { 0 }; + /// Property: Input data segment name + std::string m_input { }; + + struct worker_args { + std::size_t num_hit { 0 }; + std::size_t num_particle { 0 }; + std::any* container { nullptr }; + worker_args(std::any* p) : container(p) {} + }; + struct work_t { + DigiContext& context; + Position ip_move; + std::vector<worker_args> args; + }; + class work_definition_t; + using self_t = DigiIPRandomizer; + using Worker = DigiParallelWorker<self_t,work_t>; + using Workers = DigiParallelWorkers<Worker>; + + /// Worker objects to be submitted to the kernel + Workers m_workers; + + protected: + /// Define standard assignments and constructors + DDDIGI_DEFINE_ACTION_CONSTRUCTORS(DigiIPRandomizer); + + /// Default destructor + virtual ~DigiIPRandomizer() { + InstanceCount::decrement(this); + } + + Position ip_displacement() const { + return Position(0,0,0); + } + + public: + /// Standard constructor + DigiIPRandomizer(const DigiKernel& krnl, const std::string& nam) + : DigiEventAction(krnl, nam) + { + declareProperty("mask", m_mask); + declareProperty("input_segment", m_input = "inputs"); + InstanceCount::increment(this); + } + /// Main functional callback + virtual void execute(DigiContext& context) const final { + auto& inputs = context.event->get_segment(m_input); + std::vector<worker_args> collection_args; + collection_args.reserve(inputs.size()); + for ( auto& i : inputs ) { + Key key(i.first); + if ( key.mask() == m_mask ) { + collection_args.emplace_back(worker_args(&i.second)); + } + } + work_t data { context, ip_displacement(), collection_args }; + for( auto& c : collection_args ) { + if ( DepositMapping* m = std::any_cast<DepositMapping>(c.container) ) { + for( auto& dep : *m ) + dep.second.position += data.ip_move; + c.num_hit += m->size(); + } + else if ( DepositVector* v = std::any_cast<DepositVector>(c.container) ) { + for( auto& dep : *v ) + dep.second.position += data.ip_move; + c.num_hit += v->size(); + } + else if ( ParticleMapping* parts = std::any_cast<ParticleMapping>(c.container) ) { + for( auto& p : *parts ) { + auto& part = p.second; + part.end_position += data.ip_move; + part.start_position += data.ip_move; + } + c.num_particle += parts->size(); + } + } + std::size_t num_hit = 0; + std::size_t num_particle = 0; + for( const auto& c : collection_args ) { + num_hit += c.num_hit; + num_particle += c.num_particle; + } + info("%s+++ Moved coordinates of %6ld hits ans %6ld particles", + context.event->id(), num_hit, num_particle); + } + }; + } // End namespace digi +} // End namespace dd4hep + +#include <DDDigi/DigiFactories.h> +DECLARE_DIGIACTION_NS(dd4hep::digi,DigiIPRandomizer) diff --git a/DDDigi/plugins/DigiRandomNoise.cpp b/DDDigi/plugins/DigiRandomNoise.cpp index 7055249a9d57de28ecb8c3f1f4f2edc076e40747..72b435c80ac93d1010cbb332bb2d242c1c324ea7 100644 --- a/DDDigi/plugins/DigiRandomNoise.cpp +++ b/DDDigi/plugins/DigiRandomNoise.cpp @@ -85,7 +85,7 @@ namespace dd4hep { using namespace std; using namespace dd4hep::digi; -DECLARE_DIGIEVENTACTION_NS(dd4hep::digi,DigiRandomNoise) +DECLARE_DIGIACTION_NS(dd4hep::digi,DigiRandomNoise) /// Standard constructor DigiRandomNoise::DigiRandomNoise(const DigiKernel& kernel, const string& nam) diff --git a/DDDigi/plugins/DigiSegmentDepositExtractor.cpp b/DDDigi/plugins/DigiSegmentDepositExtractor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2f0999ddfeb1531b5e6cfb7e9afdc5276d02662d --- /dev/null +++ b/DDDigi/plugins/DigiSegmentDepositExtractor.cpp @@ -0,0 +1,55 @@ +//========================================================================== +// AIDA Detector description implementation +//-------------------------------------------------------------------------- +// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN) +// All rights reserved. +// +// For the licensing terms see $DD4hepINSTALL/LICENSE. +// For the list of contributors see $DD4hepINSTALL/doc/CREDITS. +// +// Author : M.Frank +// +//========================================================================== + +// Framework include files +#include <DDDigi/DigiContext.h> +#include <DDDigi/DigiSegmentProcessor.h> + +/// Namespace for the AIDA detector description toolkit +namespace dd4hep { + + /// Namespace for the Digitization part of the AIDA detector description toolkit + namespace digi { + + /// Actor to select energy deposits according to the supplied segmentation + /** Actor to select energy deposits according to the supplied segmentation + * + * The selected deposits are placed in the output container + * supplied by the arguments. + * + * \author M.Frank + * \version 1.0 + * \ingroup DD4HEP_DIGITIZATION + */ + class DigiSegmentDepositExtractor : public DigiSegmentProcessor { + public: + /// Standard constructor + DigiSegmentDepositExtractor(const DigiKernel& kernel, const std::string& nam) + : DigiSegmentProcessor(kernel, nam) {} + + /// Main functional callback + virtual void handle_segment(DigiContext&, work_t& work) const override final { + for( const auto& d : work.input ) { + if ( segment.matches(d.first) ) { + CellID cell = d.first; + EnergyDeposit depo = d.second; + work.emplace_output(cell, std::move(depo)); + } + } + } + }; + } // End namespace digi +} // End namespace dd4hep + +#include <DDDigi/DigiFactories.h> +DECLARE_DIGIACTION_NS(dd4hep::digi,DigiSegmentDepositExtractor) diff --git a/DDDigi/plugins/DigiSegmentDepositPrint.cpp b/DDDigi/plugins/DigiSegmentDepositPrint.cpp index 9c4d7313bee6b070bab121e1e04209e9a0b7aa8d..6a5bd23cfc07b5ae6cc139031e55701cddd623ba 100644 --- a/DDDigi/plugins/DigiSegmentDepositPrint.cpp +++ b/DDDigi/plugins/DigiSegmentDepositPrint.cpp @@ -13,7 +13,7 @@ // Framework include files #include <DDDigi/DigiContext.h> -#include <DDDigi/DigiSegmentSplitter.h> +#include <DDDigi/DigiSegmentProcessor.h> /// Namespace for the AIDA detector description toolkit namespace dd4hep { @@ -28,32 +28,43 @@ namespace dd4hep { * \version 1.0 * \ingroup DD4HEP_SIMULATION */ - class DigiSegmentDepositPrint : virtual public DigiSegmentAction { + class DigiSegmentDepositPrint : public DigiSegmentProcessor { public: /// Standard constructor DigiSegmentDepositPrint(const DigiKernel& kernel, const std::string& nam) - : DigiAction(kernel, nam), DigiSegmentAction(kernel, nam) {} + : DigiSegmentProcessor(kernel, nam) {} + void print_deposit(const char* format, CellID cell, const EnergyDeposit& depo) const { + info(format, segment.split_id(cell), cell, + depo.hit_history.size(), + depo.particle_history.size(), + depo.deposit); + } /// Main functional callback - virtual DepositVector - handleSegment(DigiContext& context, - const DepositMapping& deposits) const override final { + virtual void handle_segment(DigiContext& context, work_t& work) const override final { char format[256]; ::snprintf(format, sizeof(format), - "%s[%s] %s-id: %%d [processor:%d] Cell: %%016lX mask: %016lX hist:%%4ld entries deposit: %%f", + "%s[%s] %s-id: %%d [processor:%d] Cell: %%016lX mask: %016lX hist:%%4ld hits %%4ld parts. entries deposit: %%f", context.event->id(), segment.idspec.name(), segment.cname(), segment.id, segment.split_mask); - for( const auto& d : deposits ) { - if ( segment.matches(d.first) ) { - auto cell = d.first; - auto& depo = d.second; - info(format, segment.split_id(cell), cell, depo.history.size(), depo.deposit); + if ( const auto* m = std::any_cast<DepositMapping>(&work.input) ) { + for( const auto& d : *m ) { + if ( segment.matches(d.first) ) + print_deposit(format, d.first, d.second); + } + } + else if ( const auto* v = std::any_cast<DepositVector>(&work.input) ) { + for( const auto& d : *v ) { + if ( segment.matches(d.first) ) + print_deposit(format, d.first, d.second); } } - return {}; + else { + error("+++ Request to dump an invalid container %s", Key::key_name(work.key.item())); + } } }; } // End namespace digi } // End namespace dd4hep #include <DDDigi/DigiFactories.h> -DECLARE_DIGISEGMENTACTION_NS(dd4hep::digi,DigiSegmentDepositPrint) +DECLARE_DIGIACTION_NS(dd4hep::digi,DigiSegmentDepositPrint) diff --git a/DDDigi/python/DDDigiDict.C b/DDDigi/python/DDDigiDict.C index 4eb4e9a4c2b79aec77d5f138c1a809584f7458e2..83f196af506c48b90180ea77d618630db5a018f1 100644 --- a/DDDigi/python/DDDigiDict.C +++ b/DDDigi/python/DDDigiDict.C @@ -36,13 +36,8 @@ #include <DDDigi/DigiKernel.h> #include <DDDigi/DigiContext.h> #include <DDDigi/DigiAction.h> -#include <DDDigi/DigiSynchronize.h> #include <DDDigi/DigiEventAction.h> -#include <DDDigi/DigiInputAction.h> -#include <DDDigi/DigiSegmentAction.h> -#include <DDDigi/DigiActionSequence.h> -#include <DDDigi/DigiMultiContainerProcessor.h> -#include <DDDigi/DigiSignalProcessor.h> +#include <DDDigi/DigiContainerProcessor.h> struct DDDigiDict {}; @@ -62,20 +57,14 @@ namespace dd4hep { operator dd4hep::digi::Digi##x* () const { return action; } \ Digi##x* operator->() const { return action; } \ Digi##x* get() const { return action; } \ + Digi##x* I_am_a_ROOT_interface_handle() const { return action; } \ KernelHandle kernel() const { \ auto* k = const_cast<DigiKernel*>(action->kernel()); \ return KernelHandle(k); \ } \ } - ACTIONHANDLE(SignalProcessor); ACTIONHANDLE(Action); - ACTIONHANDLE(EventAction); - ACTIONHANDLE(InputAction); - ACTIONHANDLE(SegmentAction); - ACTIONHANDLE(ContainerProcessor); - ACTIONHANDLE(ActionSequence); - ACTIONHANDLE(Synchronize); struct PropertyResult { std::string data; @@ -93,12 +82,65 @@ namespace dd4hep { H handle(action.get()); return handle; } + template <typename T,typename H> static H* cst(T* in) { + auto* out = dynamic_cast<H*>(in); + if ( out ) return out; + if ( in ) + except("DigiAction","Invalid cast of action '%s' [type:%s] to type %s!", + in->c_name(), typeName(typeid(T)).c_str(), typeName(typeid(H)).c_str()); + except("DigiAction","Invalid cast of NULL [type:%s] to type %s!", + typeName(typeid(T)).c_str(), typeName(typeid(H)).c_str()); + return nullptr; + } + + static PropertyResult getProperty(DigiAction* action, const std::string& name) { + if ( action->hasProperty(name) ) { + return PropertyResult(action->property(name).str(),1); + } + return PropertyResult("",0); + } + static int setProperty(DigiAction* action, const std::string& name, const std::string& value) { + if ( action->hasProperty(name) ) { + action->property(name).str(value); + return 1; + } + return 0; + } + static PropertyResult getPropertyKernel(DigiKernel* kernel, const std::string& name) { + if ( kernel->hasProperty(name) ) { + return PropertyResult(kernel->property(name).str(),1); + } + return PropertyResult("",0); + } + static int setPropertyKernel(DigiKernel* kernel, const std::string& name, const std::string& value) { + if ( kernel->hasProperty(name) ) { + kernel->property(name).str(value); + return 1; + } + return 0; + } + static KernelHandle createKernel(DigiAction* action) { auto* k = const_cast<DigiKernel*>(action->kernel()); return KernelHandle(k); } static ActionHandle createAction(KernelHandle& kernel, const std::string& name_type) { return cr<ActionHandle,DigiHandle<DigiAction> >(kernel,name_type); } + static DigiAction* toAction(DigiAction* f) { return f; } + static DigiAction* toAction(ActionHandle f) { return f.action; } + + static DigiEventAction* toEventAction(DigiAction* a) { return cst<DigiAction,DigiEventAction>(a); } + static DigiContainerProcessor* toContainerProcessor(DigiAction* a) { return cst<DigiAction,DigiContainerProcessor>(a); } + +#if 0 + static DigiEventAction* toEventAction(DigiEventAction* a) { return a; } + ACTIONHANDLE(SignalProcessor); + ACTIONHANDLE(EventAction); + ACTIONHANDLE(InputAction); + ACTIONHANDLE(SegmentProcessor); + ACTIONHANDLE(ContainerProcessor); + ACTIONHANDLE(ActionSequence); + ACTIONHANDLE(Synchronize); static EventActionHandle createEventAction(KernelHandle& kernel, const std::string& name_type) { return cr<EventActionHandle,DigiHandle<DigiEventAction> >(kernel,name_type); } @@ -106,8 +148,8 @@ namespace dd4hep { static InputActionHandle createInputAction(KernelHandle& kernel, const std::string& name_type) { return cr<InputActionHandle,DigiHandle<DigiInputAction> >(kernel,name_type); } - static SegmentActionHandle createSegmentAction(KernelHandle& kernel, const std::string& name_type) - { return cr<SegmentActionHandle,DigiHandle<DigiSegmentAction> >(kernel,name_type); } + static SegmentProcessorHandle createSegmentProcessor(KernelHandle& kernel, const std::string& name_type) + { return cr<SegmentProcessorHandle,DigiHandle<DigiSegmentProcessor> >(kernel,name_type); } static ActionSequenceHandle createSequence(KernelHandle& kernel, const std::string& name_type) { return cr<ActionSequenceHandle,DigiHandle<DigiActionSequence> >(kernel,name_type); } @@ -115,54 +157,31 @@ namespace dd4hep { static SynchronizeHandle createSync(KernelHandle& kernel, const std::string& name_type) { return cr<SynchronizeHandle,DigiHandle<DigiSynchronize> >(kernel,name_type); } - static DigiAction* toAction(DigiAction* f) { return f; } -#if 0 static DigiAction* toAction(DigiEventAction* f) { return f; } static DigiAction* toAction(DigiInputAction* f) { return f; } - static DigiAction* toAction(DigiSegmentAction* f) { return f; } + static DigiAction* toAction(DigiSegmentProcessor* f) { return f; } static DigiAction* toAction(DigiContainerProcessor* f) { return f; } static DigiAction* toAction(DigiActionSequence* f) { return f; } static DigiAction* toAction(DigiSynchronize* f) { return f; } static DigiAction* toAction(DigiSignalProcessor* f) { return f; } -#endif - static DigiAction* toAction(ActionHandle f) { return f.action; } + static DigiAction* toAction(EventActionHandle f) { return f.action; } static DigiAction* toAction(InputActionHandle f) { return f.action; } - static DigiAction* toAction(SegmentActionHandle f) { return f.action; } + static DigiAction* toAction(SegmentProcessorHandle f) { return f.action; } static DigiAction* toAction(ActionSequenceHandle f) { return f.action; } static DigiAction* toAction(SynchronizeHandle f) { return f.action; } static DigiAction* toAction(SignalProcessorHandle f) { return f.action; } - - static PropertyResult getProperty(DigiAction* action, const std::string& name) { - if ( action->hasProperty(name) ) { - return PropertyResult(action->property(name).str(),1); - } - return PropertyResult("",0); - } - static int setProperty(DigiAction* action, const std::string& name, const std::string& value) { - if ( action->hasProperty(name) ) { - action->property(name).str(value); - return 1; - } - return 0; - } - static PropertyResult getPropertyKernel(DigiKernel* kernel, const std::string& name) { - if ( kernel->hasProperty(name) ) { - return PropertyResult(kernel->property(name).str(),1); - } - return PropertyResult("",0); - } - static int setPropertyKernel(DigiKernel* kernel, const std::string& name, const std::string& value) { - if ( kernel->hasProperty(name) ) { - kernel->property(name).str(value); - return 1; - } - return 0; - } +#endif }; } } +#include <DDDigi/DigiSynchronize.h> +#include <DDDigi/DigiInputAction.h> +#include <DDDigi/DigiSegmentProcessor.h> +#include <DDDigi/DigiActionSequence.h> +#include <DDDigi/DigiSignalProcessor.h> + // CINT configuration #if defined(__CINT__) || defined(__MAKECINT__) || defined(__CLING__) || defined(__ROOTCLING__) @@ -175,39 +194,37 @@ using namespace std; #pragma link C++ namespace dd4hep; #pragma link C++ namespace dd4hep::digi; +#pragma link C++ class dd4hep::digi::KernelHandle; +#pragma link C++ class dd4hep::digi::ActionHandle; + #pragma link C++ class dd4hep::digi::DigiActionCreation; #pragma link C++ class dd4hep::digi::DigiContext; - #pragma link C++ class dd4hep::digi::DigiKernel; -#pragma link C++ class dd4hep::digi::KernelHandle; - #pragma link C++ class dd4hep::digi::DigiAction; -#pragma link C++ class dd4hep::digi::ActionHandle; - #pragma link C++ class dd4hep::digi::DigiEventAction; -#pragma link C++ class dd4hep::digi::EventActionHandle; - #pragma link C++ class dd4hep::digi::DigiInputAction; -#pragma link C++ class dd4hep::digi::InputActionHandle; - -#pragma link C++ class dd4hep::digi::DigiSegmentAction; -#pragma link C++ class dd4hep::digi::SegmentActionHandle; - +#pragma link C++ class dd4hep::digi::DigiSegmentProcessor; #pragma link C++ class dd4hep::digi::DigiActionSequence; -#pragma link C++ class dd4hep::digi::ActionSequenceHandle; - #pragma link C++ class dd4hep::digi::DigiSynchronize; -#pragma link C++ class dd4hep::digi::SynchronizeHandle; - #pragma link C++ class dd4hep::digi::DigiSignalProcessor; -#pragma link C++ class dd4hep::digi::SignalProcessorHandle; - #pragma link C++ class dd4hep::digi::DigiContainerProcessor; +#pragma link C++ class dd4hep::digi::DigiContainerSequence; #pragma link C++ class dd4hep::digi::DigiMultiContainerProcessor; /// Digi data item wrappers -#pragma link C++ class dd4hep::digi::DigiEvent; +#pragma link C++ class dd4hep::digi::Particle+; #pragma link C++ class dd4hep::digi::EnergyDeposit+; +#pragma link C++ class dd4hep::digi::ParticleMapping+; #pragma link C++ class dd4hep::digi::DepositMapping+; +#pragma link C++ class dd4hep::digi::DepositVector+; + +#pragma link C++ class dd4hep::digi::DigiEvent; + +//#pragma link C++ class dd4hep::digi::EventActionHandle; +//#pragma link C++ class dd4hep::digi::InputActionHandle; +//#pragma link C++ class dd4hep::digi::SegmentProcessorHandle; +//#pragma link C++ class dd4hep::digi::ActionSequenceHandle; +//#pragma link C++ class dd4hep::digi::SignalProcessorHandle; +//#pragma link C++ class dd4hep::digi::SynchronizeHandle; #endif diff --git a/DDDigi/python/dddigi.py b/DDDigi/python/dddigi.py index cd22c7a73741d3e17865d8b75d9e37ade555808c..1e45a0dbf47b2a7c358d4d61c1c13ed29b289759 100644 --- a/DDDigi/python/dddigi.py +++ b/DDDigi/python/dddigi.py @@ -186,36 +186,45 @@ def Action(kernel, nam): # --------------------------------------------------------------------------- -def EventAction(kernel, nam, parallel=False): - obj = Interface.createEventAction(kernel, str(nam)) - obj.parallel = parallel - return obj +def _default_adopt(self, action): + getattr(self, '__adopt')(action.get()) # --------------------------------------------------------------------------- -def SegmentAction(kernel, nam, parallel=False): - obj = Interface.createSegmentAction(kernel, str(nam)) - obj.parallel = parallel - return obj +def _adopt_event_action(self, action): + " Helper to convert DigiActions objects to DigiEventAction " + getattr(self, '__adopt')(Interface.toEventAction(action.get())) # --------------------------------------------------------------------------- -def ActionSequence(kernel, nam, parallel=False): - obj = Interface.createSequence(kernel, str(nam)) - obj.parallel = parallel - return obj +def _adopt_processor_action(self, action, container): + " Helper to convert DigiActions objects to DigiEventAction " + print(str(action.__class__)) + attr = getattr(self, 'adopt_processor') + if hasattr(action,'I_am_a_ROOT_interface_handle'): + print('Entering handle branch') + proc = Interface.toContainerProcessor(action.get()) + attr(proc, container) + else: + attr(action, container) + print('ContainerProcessor succesfully adopted') # --------------------------------------------------------------------------- -def Synchronize(kernel, nam, parallel=False): - obj = Interface.createSync(kernel, str(nam)) - obj.parallel = parallel - return obj +def _adopt_sequence_action(self, name, **options): + " Helper to adopt DigiAction objects for DigiSynchronize " + kernel = Interface.createKernel(Interface.toAction(self)) + action = Action(kernel, name) + for option in options.items(): + setattr(action, option[0], option[1]) + self.adopt(action) + return action # --------------------------------------------------------------------------- -def _default_adopt(self, action): - getattr(self, '__adopt')(action.get()) +def _adopt_processor(self, action, containers): + getattr(self, '__adopt_processor')(action.get(), containers) +# --------------------------------------------------------------------------- def _setup(obj, call='adopt', py_call=_default_adopt): @@ -224,6 +233,7 @@ def _setup(obj, call='adopt', py_call=_default_adopt): setattr(cls, '__' + call, getattr(cls, call)) setattr(cls, call, py_call) return cls +# --------------------------------------------------------------------------- def _get(self, name): @@ -233,10 +243,11 @@ def _get(self, name): return ret.data elif hasattr(self.action, name): return getattr(self.action, name) - elif hasattr(a, name): + elif a.__class__ != self.__class__ and hasattr(a, name): return getattr(a, name) msg = 'DDDigiAction::GetProperty [Unhandled]: Cannot access property ' + a.name() + '.' + name raise KeyError(msg) +# --------------------------------------------------------------------------- def _set(self, name, value): @@ -249,6 +260,7 @@ def _set(self, name, value): return msg = 'DDDigiAction::SetProperty [Unhandled]: Cannot set ' + a.name() + '.' + name + ' = ' + value raise KeyError(msg) +# --------------------------------------------------------------------------- def _props(obj, **extensions): @@ -259,42 +271,33 @@ def _props(obj, **extensions): cls.__getattr__ = _get cls.__setattr__ = _set return cls +# --------------------------------------------------------------------------- + + +def _props2(obj, **extensions): + cls = getattr(current, obj) + for extension in extensions.items(): + setattr(cls, extension[0], extension[1]) + cls.__getattr__ = _get + cls.__setattr__ = _set + return cls +# --------------------------------------------------------------------------- -_setup('DigiActionSequence') -_setup('DigiSynchronize') +_setup('DigiSynchronize', py_call=_adopt_event_action) +_setup('DigiActionSequence', py_call=_adopt_event_action) _import_class('digi', 'DigiKernel') _import_class('digi', 'DigiContext') _import_class('digi', 'DigiAction') _import_class('digi', 'DigiEventAction') _import_class('digi', 'DigiInputAction') - _props('ActionHandle') -_props('EventActionHandle') -_props('InputActionHandle') -_props('ActionSequenceHandle') -_props('SynchronizeHandle') - - -def adopt_sequence_action(self, name, **options): - kernel = Interface.createKernel(Interface.toAction(self)) - action = EventAction(kernel, name) - for option in options.items(): - setattr(action, option[0], option[1]) - self.adopt(action) - return action - - -def _adopt_processor(self, action, containers): - getattr(self, '__adopt_processor')(action.get(), containers) - - -_props('DigiSynchronize') -_props('DigiActionSequence', adopt_action=adopt_sequence_action) -_props('DigiParallelActionSequence', adopt_action=adopt_sequence_action) -_props('DigiSequentialActionSequence', adopt_action=adopt_sequence_action) - +_props('DigiSynchronize', adopt_action=_adopt_sequence_action) +_props('DigiActionSequence', adopt_action=_adopt_sequence_action) +_props('DigiParallelActionSequence', adopt_action=_adopt_sequence_action) +_props('DigiSequentialActionSequence', adopt_action=_adopt_sequence_action) +_props('DigiContainerSequenceAction', adopt_container_processor=_adopt_processor_action) _setup('DigiMultiContainerProcessor', call='adopt_processor', py_call=_adopt_processor) diff --git a/DDDigi/python/digitize.py b/DDDigi/python/digitize.py index b77dfe6cd5a33b4d562836a3c391af930e2e3720..b22c00dbc25c45274fb4aaca323619b0df2a5e69 100644 --- a/DDDigi/python/digitize.py +++ b/DDDigi/python/digitize.py @@ -48,23 +48,20 @@ class Digitize(dd4hep.Logger): def kernel(self): return self._kernel - def main_sequencer(self): - if not self._main_processor: - self._main_processor = dddigi.Synchronize(self._kernel, 'DigiSynchronize/MainDigitizer', self._parallel) - self._main_processor.parallel = self._parallel - return self._main_processor - def create_action(self, name, **options): action = dddigi.Action(self._kernel, name) for option in options.items(): setattr(action, option[0], option[1]) return action - def new_action(self, name, **options): - action = dddigi.EventAction(self._kernel, name) - for option in options.items(): - setattr(action, option[0], option[1]) - return action + def main_sequencer(self): + """ + Create main digitization sequencer + """ + if not self._main_processor: + self._main_processor = self.create_action('DigiSynchronize/MainDigitizer', parallel=self._parallel) + self._main_processor.parallel = self._parallel + return self._main_processor def input_action(self, name=None, **options): """ @@ -77,7 +74,7 @@ class Digitize(dd4hep.Logger): if not name: return self._input_processor - act = self.new_action(name, **options) + act = self.create_action(name, **options) self._input_processor.adopt(act) return act @@ -92,7 +89,7 @@ class Digitize(dd4hep.Logger): if not name: return self._event_processor - action = self.new_action(name, **options) + action = self.create_action(name, **options) if register: self._event_processor.adopt(action) return action @@ -108,7 +105,7 @@ class Digitize(dd4hep.Logger): if not name: return self._output_processor - act = self.new_action(name, **options) + act = self.create_action(name, **options) self._output_processor.adopt(act) return act @@ -139,8 +136,9 @@ class Digitize(dd4hep.Logger): self.kernel().configure() self.kernel().initialize() self.kernel().run() + done = krnl.events_done() self.kernel().terminate() - return self + return done def activeDetectors(self): detectors = [] @@ -183,5 +181,7 @@ class Digitize(dd4hep.Logger): krnl.numEvents = num_events krnl.numThreads = num_threads # = number of concurrent threads krnl.maxEventsParallel = parallel + krnl.configure() + krnl.initialize() krnl.run() return krnl.events_done() diff --git a/DDDigi/src/DigiAction.cpp b/DDDigi/src/DigiAction.cpp index 4e1aaee7ab5492ed41a7c64bb8c7440d94fc6cee..4443ba1379fd4f514eb54e513903c2001c97cabe 100644 --- a/DDDigi/src/DigiAction.cpp +++ b/DDDigi/src/DigiAction.cpp @@ -59,8 +59,8 @@ long DigiAction::addRef() { long DigiAction::release() { long count = --m_refCount; if (m_refCount <= 0) { - printM1("DigiAction: Deleting object %s of type %s Pointer:%p", - m_name.c_str(),typeName(typeid(*this)).c_str(),(void*)this); + info("Deleting object %s of type %s Pointer:%p", + m_name.c_str(),typeName(typeid(*this)).c_str(),(void*)this); delete this; } return count; @@ -94,50 +94,6 @@ void DigiAction::print(const char* fmt, ...) const { } } -/// Support for messages with variable output level using output level-1 -void DigiAction::printM1(const char* fmt, ...) const { - int level = std::max(outputLevel()-1,(int)VERBOSE); - if ( level >= printLevel() ) { - va_list args; - va_start(args, fmt); - dd4hep::printout((PrintLevel)level, m_name.c_str(), fmt, args); - va_end(args); - } -} - -/// Support for messages with variable output level using output level-2 -void DigiAction::printM2(const char* fmt, ...) const { - int level = std::max(outputLevel()-2,(int)VERBOSE); - if ( level >= printLevel() ) { - va_list args; - va_start(args, fmt); - dd4hep::printout((PrintLevel)level, m_name.c_str(), fmt, args); - va_end(args); - } -} - -/// Support for messages with variable output level using output level-1 -void DigiAction::printP1(const char* fmt, ...) const { - int level = std::min(outputLevel()+1,(int)FATAL); - if ( level >= printLevel() ) { - va_list args; - va_start(args, fmt); - dd4hep::printout((PrintLevel)level, m_name.c_str(), fmt, args); - va_end(args); - } -} - -/// Support for messages with variable output level using output level-2 -void DigiAction::printP2(const char* fmt, ...) const { - int level = std::min(outputLevel()+2,(int)FATAL); - if ( level >= printLevel() ) { - va_list args; - va_start(args, fmt); - dd4hep::printout((PrintLevel)level, m_name.c_str(), fmt, args); - va_end(args); - } -} - /// Support of debug messages. std::string DigiAction::format(const char* fmt, ...) const { va_list args; @@ -205,8 +161,3 @@ void DigiAction::except(const char* fmt, ...) const { va_end(args); throw std::runtime_error(err); } - -/// Optional action initialization if required -void DigiAction::initialize() { -} - diff --git a/DDDigi/src/DigiAttenuatorSequenceAction.cpp b/DDDigi/src/DigiAttenuatorSequenceAction.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8df1448b9300e75ab723c71da5cb51bcf498f9eb --- /dev/null +++ b/DDDigi/src/DigiAttenuatorSequenceAction.cpp @@ -0,0 +1,75 @@ +//========================================================================== +// AIDA Detector description implementation +//-------------------------------------------------------------------------- +// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN) +// All rights reserved. +// +// For the licensing terms see $DD4hepINSTALL/LICENSE. +// For the list of contributors see $DD4hepINSTALL/doc/CREDITS. +// +// Author : M.Frank +// +//========================================================================== + + +/// TODO ! + + +// Framework include files +#include <DD4hep/InstanceCount.h> + +#include <DDDigi/DigiData.h> +#include <DDDigi/DigiKernel.h> +#include <DDDigi/DigiContext.h> +#include <DDDigi/DigiAttenuatorSequenceAction.h> + +/// C/C++ include files +#include <cmath> + +/// Standard constructor +dd4hep::digi::DigiAttenuatorSequenceAction::DigiAttenuatorSequenceAction(const DigiKernel& krnl, const std::string& nam) + : DigiEventAction(krnl, nam) +{ + declareProperty("input", m_input_segment = "inputs"); + declareProperty("processor", m_processor_name); + declareProperty("containers", m_container_attenuation); + declareProperty("mask", m_mask); + declareProperty("t0", m_t0); + m_kernel.register_initialize(Callback(this).make(&DigiAttenuatorSequenceAction::initialize)); + InstanceCount::increment(this); +} + +/// Default destructor +dd4hep::digi::DigiAttenuatorSequenceAction::~DigiAttenuatorSequenceAction() { + InstanceCount::decrement(this); +} + +/// Initialization callback +void dd4hep::digi::DigiAttenuatorSequenceAction::initialize() { + for ( const auto& c : m_container_attenuation ) { + double factor = std::exp(-1e0 * m_t0/c.second); + m_attenuation.emplace(Key(c.first, m_mask), factor); + } +} + +/// Main functional callback +void dd4hep::digi::DigiAttenuatorSequenceAction::execute(DigiContext& context) const { + std::size_t count = 0, cnt = 0, cont = 0; + auto& event = *context.event; + auto& inputs = event.get_segment(m_input_segment); + for ( const auto& k : m_attenuation ) { + Key key = k.first; + auto* data = inputs.entry(key); + if ( auto* m = std::any_cast<DepositMapping>(data) ) + ++cont; + else if ( auto* v = std::any_cast<DepositVector>(data) ) + cnt++, ++cont; + count += cnt; + std::string nam = Key::key_name(key)+":"; + debug("%s+++ %-32s mask:%04X item: %08X Attenuated exponentially %6ld hits by %8.5f", + event.id(), nam.c_str(), key.mask(), key.item(), cnt, k.second); + } + info("%s+++ Attenuated exponentially %6ld hits from %4ld containers from segment %s", + event.id(), count, cont, m_input_segment.c_str()); +} + diff --git a/DDDigi/src/DigiContainerCombine.cpp b/DDDigi/src/DigiContainerCombine.cpp index 0bfdd89e8e6073fd8261282d0ce62b4e7bf75efd..0de723b764f6c285e59ffbe63b8678789cb1b7c3 100644 --- a/DDDigi/src/DigiContainerCombine.cpp +++ b/DDDigi/src/DigiContainerCombine.cpp @@ -13,212 +13,226 @@ // Framework include files #include <DD4hep/InstanceCount.h> - #include <DDDigi/DigiData.h> +#include <DDDigi/DigiKernel.h> #include <DDDigi/DigiContext.h> #include <DDDigi/DigiContainerCombine.h> /// C/C++ include files #include <set> -using dd4hep::digi::DigiContainerCombine; +using namespace dd4hep::digi; -class DigiContainerCombine::internals_t { +class DigiContainerCombine::work_definition_t { public: - /// Property: Container names to be loaded - std::vector<std::string> containers { }; - /// Property: event masks to be handled - std::vector<int> input_masks { }; - /// Property: Output container dressing - std::string output_name_flag; - /// Property: Input data segment name - std::string input; - /// Property: Output data segment name - std::string output; - /// Property: mask of the deposit - int deposit_mask { 0 }; - /// Property: Flag to erase already combined containers (not thread-safe!!!) - bool erase_combined { false }; - - /// Fully qualified keys of all containers to be manipulated - std::set<Key::key_type> keys { }; - /// Container keys of all containers to be manipulated - std::set<Key::key_type> cont_keys { }; - - /// Predicate function to select containers for merging - std::function<bool(Key::key_type)> container_selector; - /// Flag to check the initialization - bool inited { false }; - /// Initializing function: compute values which depend on properties - void initialize(DigiContext& context) { - if ( !this->inited ) { - std::lock_guard<std::mutex> lock(context.initializer_lock()); - if ( !this->inited ) { - this->inited = true; - - for ( const auto& c : this->containers ) { - Key key(0x0, c); - this->cont_keys.emplace(key.key); - if ( this->input_masks.empty() ) { - this->keys.emplace(key.key); - continue; - } - for ( int m : this->input_masks ) { - key.values.mask = m; - this->keys.emplace(key.key); - } - } - - this->container_selector = [this](Key::key_type k) { - const auto& m = this->input_masks; - bool use = m.empty() || this->keys.empty(); - if ( !use ) { - if ( !this->cont_keys.empty() ) - return this->cont_keys.find(Key::item(k)) != this->cont_keys.end(); - return std::find(m.begin(), m.end(), Key::mask(k)) != m.end(); - } - return true; - }; + const DigiContainerCombine* combine; + std::size_t cnt_conts = 0; + std::size_t cnt_depos = 0; + std::size_t cnt_parts = 0; + /// Printout format string + char format[128]; + + std::vector<Key> keys; + std::vector<std::any*> work; + std::set<Key::itemkey_type> items; + + DigiEvent& event; + DataSegment& inputs; + DataSegment& outputs; + + /// Initializing constructor + work_definition_t(const DigiContainerCombine* c, DigiEvent& ev, DataSegment& in, DataSegment& out) + : combine(c), event(ev), inputs(in), outputs(out) + { + keys.reserve(inputs.size()); + work.reserve(inputs.size()); + for( auto& i : inputs ) { + Key key = i.first; + if ( combine->use_key(key) ) { + keys.emplace_back(key); + work.emplace_back(&i.second); + items.insert(key.item()); + } + } + ::snprintf(format, sizeof(format), + "%s+++%%2d++ %%-32s Mask: $%04X Input: $%%04X Merged %%6ld %%s", + event.id(), combine->m_deposit_mask); + format[sizeof(format)-1] = 0; + } + + template<typename T> void merge_depos(DepositMapping& output, T& input, int thr) { + std::size_t cnt = 0; + if ( combine->m_erase_combined ) + cnt = output.merge(std::move(input)); + else + cnt = output.insert(input); + combine->info(this->format, thr, input.name.c_str(), input.key.values.mask, cnt, "deposits"); + this->cnt_depos += cnt; + this->cnt_conts++; + } + + void merge(const std::string& nam, size_t start, int thr) { + Key key = keys[start]; + DepositMapping out(nam, combine->m_deposit_mask); + for( std::size_t j = start; j < keys.size(); ++j ) { + if ( keys[j].item() == key.item() ) { + if ( DepositMapping* m = std::any_cast<DepositMapping>(work[j]) ) + merge_depos(out, *m, thr); + else if ( DepositVector* v = std::any_cast<DepositVector>(work[j]) ) + merge_depos(out, *v, thr); + else + continue; + this->work[j]->reset(); + } + } + key.set_mask(combine->m_deposit_mask); + outputs.emplace(key, std::move(out)); + } + + void merge_parts(const std::string& nam, size_t start, int thr) { + Key key = keys[start]; + ParticleMapping out(nam, combine->m_deposit_mask); + for( std::size_t j=start; j < keys.size(); ++j ) { + if ( keys[j].item() == key.item() ) { + ParticleMapping* next = std::any_cast<ParticleMapping>(work[j]); + std::size_t cnt = out.merge(std::move(*next)); + combine->info(format, thr, next->name.c_str(), keys[j].mask(), cnt, "particles"); + cnt_parts += cnt; + cnt_conts++; + work[j]->reset(); + } + } + key.set_mask(combine->m_deposit_mask); + outputs.emplace(key, std::move(out)); + } + + void merge_one(Key::itemkey_type itm, int thr) { + const std::string& opt = combine->m_output_name_flag; + for( std::size_t i=0; i < keys.size(); ++i ) { + if ( keys[i].values.item != itm ) + continue; + /// Merge deposit mapping + if ( DepositMapping* depom = std::any_cast<DepositMapping>(work[i]) ) { + merge(depom->name+opt, i, thr); + break; + } + /// Merge deposit vector + else if ( DepositVector* depov = std::any_cast<DepositVector>(work[i]) ) { + merge(depov->name+opt, i, thr); + break; + } + /// Merge particle container + else if ( ParticleMapping* parts = std::any_cast<ParticleMapping>(work[i]) ) { + merge_parts(parts->name+opt, i, thr); + break; } } } + + void merge_all() { + for( auto itm : items ) + merge_one(itm, 0); + } }; +template <> void DigiParallelWorker<DigiContainerCombine, + DigiContainerCombine::work_definition_t, + std::size_t>::execute(void* data) const { + calldata_t* args = reinterpret_cast<calldata_t*>(data); + std::size_t cnt = 0; + for( auto itm : args->items ) { + if ( cnt == this->options ) { + args->merge_one(itm, this->options); + return; + } + ++cnt; + } +} + /// Standard constructor -dd4hep::digi::DigiContainerCombine::DigiContainerCombine(const DigiKernel& krnl, const std::string& nam) +DigiContainerCombine::DigiContainerCombine(const DigiKernel& krnl, const std::string& nam) : DigiEventAction(krnl, nam) { - this->internals = std::make_unique<internals_t>(); - this->declareProperty("containers", this->internals->containers); - this->declareProperty("input_masks", this->internals->input_masks); - this->declareProperty("input_segment", this->internals->input = "inputs"); - this->declareProperty("output_segment", this->internals->output = "deposits"); - this->declareProperty("deposit_mask", this->internals->deposit_mask); - this->declareProperty("output_name_flag", this->internals->output_name_flag); - this->declareProperty("erase_combined", this->internals->erase_combined); + declareProperty("containers", m_containers); + declareProperty("input_masks", m_input_masks); + declareProperty("input_segment", m_input = "inputs"); + declareProperty("output_segment", m_output = "deposits"); + declareProperty("deposit_mask", m_deposit_mask); + declareProperty("output_name_flag", m_output_name_flag); + declareProperty("erase_combined", m_erase_combined); + m_kernel.register_initialize(Callback(this).make(&DigiContainerCombine::initialize)); InstanceCount::increment(this); } /// Default destructor -dd4hep::digi::DigiContainerCombine::~DigiContainerCombine() { +DigiContainerCombine::~DigiContainerCombine() { InstanceCount::decrement(this); } -struct work_definition { - using Key = dd4hep::digi::Key; - using DigiEvent = dd4hep::digi::DigiEvent; - using DataSegment = dd4hep::digi::DataSegment; - std::size_t cnt_depos = 0; - std::size_t cnt_parts = 0; - std::size_t cnt_conts = 0; - std::vector<Key> keys; - std::vector<std::any*> work; - std::set<Key::itemkey_type> items; - Key depo_key; - char format[128]; - DigiEvent& event; - DataSegment& inputs; - DataSegment& outputs; - work_definition(DigiEvent& e, DataSegment& i, DataSegment& o) - : event(e), inputs(i), outputs(o) {} -}; -struct DigiCombineAction : public dd4hep::digi::DigiEventAction { -public: - work_definition work; -}; - -/// Combine selected containers to one single deposit container -template <typename PREDICATE> std::size_t -dd4hep::digi::DigiContainerCombine::combine_containers(DigiEvent& event, - DataSegment& inputs, - DataSegment& outputs, - const PREDICATE& predicate) const -{ - std::set<Key::itemkey_type> items; - work_definition def(event, inputs, outputs); - def.depo_key.values.mask = internals->deposit_mask; - def.keys.reserve(inputs.size()); - def.work.reserve(inputs.size()); - for( auto& i : def.inputs ) { - if ( predicate(i.first) ) { - def.keys.emplace_back(i.first); - def.work.emplace_back(&i.second); - items.insert(Key(i.first).values.item); +/// Initializing function: compute values which depend on properties +void DigiContainerCombine::initialize() { + for ( const auto& cont : m_containers ) { + Key key(cont, 0x0); + m_cont_keys.emplace(key.key); + if ( m_input_masks.empty() ) { + m_keys.emplace(key.key); + continue; + } + for ( int m : m_input_masks ) { + key.values.mask = m; + m_keys.emplace(key.key); } } + if ( !m_output_name_flag.empty() ) + m_output_name_flag += '/'; +} - ::snprintf(def.format, sizeof(def.format), - "%s+++ %%-32s Mask: $%04X Input: $%%04X Merged %%6ld %%s", - event.id(), def.depo_key.values.mask); +/// Initializing function: compute values which depend on properties +void DigiContainerCombine::have_workers(size_t count) const { + if ( m_workers.size() < count ) { + auto lock = m_workers.can_modify(); + for(size_t i=m_workers.size(); i <= count; ++i) + m_workers.insert(new Worker(nullptr, i)); + } +} - for(auto itm : items) { - for( std::size_t i=0; i < def.keys.size(); ++i ) { - if ( def.keys[i].values.item != itm ) - continue; - auto* output = def.work[i]; - def.depo_key.values.item = itm; +/// Decide if a continer is to merged based on the properties +bool DigiContainerCombine::use_key(Key key) const { + const auto& m = m_input_masks; + bool use = m.empty() || m_keys.empty(); + if ( !use ) { + if ( !m_cont_keys.empty() ) + return m_cont_keys.find(key.item()) != m_cont_keys.end(); + return std::find(m.begin(), m.end(), key.mask()) != m.end(); + } + return true; +} - /// Merge deposit mapping - if ( DepositMapping* depos = std::any_cast<DepositMapping>(output) ) { - if ( !internals->output_name_flag.empty() ) - depos->name = depos->name+"/"+internals->output_name_flag; - def.cnt_depos += depos->size(); - def.cnt_conts++; - this->info(def.format, depos->name.c_str(), - def.keys[i].values.mask, depos->size(), "deposits"); - for( std::size_t j=i+1; j < def.keys.size(); ++j ) { - if ( def.keys[j].values.item == itm ) { - DepositMapping* next = std::any_cast<DepositMapping>(def.work[j]); - std::size_t cnt = depos->merge(std::move(*next)); - this->info(def.format, next->name.c_str(), - def.keys[j].values.mask, cnt, "deposits"); - def.cnt_depos += cnt; - def.cnt_conts++; - def.work[j]->reset(); - } - } - def.outputs.emplace(def.depo_key, std::move(*output)); - break; - } - /// Merge particle container - else if ( ParticleMapping* parts = std::any_cast<ParticleMapping>(output) ) { - if ( !internals->output_name_flag.empty() ) - parts->name = parts->name+"/"+internals->output_name_flag; - def.cnt_parts += parts->size(); - def.cnt_conts++; - - this->info(def.format, parts->name.c_str(), - def.keys[i].values.mask, parts->size(), "particles"); - for( std::size_t j=i+1; j < def.keys.size(); ++j ) { - if ( def.keys[j].values.item == itm ) { - ParticleMapping* next = std::any_cast<ParticleMapping>(def.work[j]); - std::size_t cnt = parts->merge(std::move(*next)); - this->info(def.format, next->name.c_str(), - def.keys[j].values.mask, cnt, "particles"); - def.cnt_parts += cnt; - def.cnt_conts++; - def.work[j]->reset(); - } - } - def.outputs.emplace(def.depo_key, std::move(*output)); - break; - } - } +/// Combine selected containers to one single deposit container +std::size_t DigiContainerCombine::combine_containers(DigiEvent& event, + DataSegment& inputs, + DataSegment& outputs) const +{ + work_definition_t def(this, event, inputs, outputs); + if ( m_parallel ) { + have_workers(def.items.size()); + m_kernel.submit(m_workers.get_group(), def.items.size(), &def); + } + else { + def.merge_all(); } - if ( this->internals->erase_combined ) { + if ( m_erase_combined ) { inputs.erase(def.keys); } - this->info("%s+++ Merged %ld particles and %ld deposits from %ld containers", - event.id(), def.cnt_parts, def.cnt_depos, def.cnt_conts); + info("%s+++ Merged %ld particles and %ld deposits from segment '%s' to segment '%s'", + event.id(), def.cnt_parts, def.cnt_depos, m_input.c_str(), m_output.c_str()); return def.cnt_depos; } /// Main functional callback -void dd4hep::digi::DigiContainerCombine::execute(DigiContext& context) const { - this->internals->initialize(context); +void DigiContainerCombine::execute(DigiContext& context) const { auto& event = *context.event; - auto& inputs = event.get_segment(this->internals->input); - auto& outputs = event.get_segment(this->internals->output); - auto& selector = this->internals->container_selector; - this->combine_containers(event, inputs, outputs, selector); + auto& inputs = event.get_segment(m_input); + auto& outputs = event.get_segment(m_output); + combine_containers(event, inputs, outputs); } diff --git a/DDDigi/src/DigiContainerProcessor.cpp b/DDDigi/src/DigiContainerProcessor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b3eaa9f10ce690952d4f77de43185f69f7256a24 --- /dev/null +++ b/DDDigi/src/DigiContainerProcessor.cpp @@ -0,0 +1,237 @@ +//========================================================================== +// AIDA Detector description implementation +//-------------------------------------------------------------------------- +// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN) +// All rights reserved. +// +// For the licensing terms see $DD4hepINSTALL/LICENSE. +// For the list of contributors see $DD4hepINSTALL/doc/CREDITS. +// +// Author : M.Frank +// +//========================================================================== + +// Framework include files +#include <DD4hep/InstanceCount.h> +#include <DDDigi/DigiData.h> +#include <DDDigi/DigiKernel.h> +#include <DDDigi/DigiContext.h> +#include <DDDigi/DigiContainerProcessor.h> + +/// C/C++ include files +#include <sstream> + +using namespace dd4hep::digi; + +/// Standard constructor +DigiContainerProcessor::DigiContainerProcessor(const DigiKernel& kernel, const std::string& name) + : DigiAction(kernel, name) +{ + InstanceCount::increment(this); +} + +/// Default destructor +DigiContainerProcessor::~DigiContainerProcessor() { + InstanceCount::decrement(this); +} + +/// Main functional callback +void DigiContainerProcessor::execute(DigiContext& context, work_t& work) const { + this->execute(context, work.key, work.input); +} + +/// Main functional callback if specific work is known +void DigiContainerProcessor::execute(DigiContext& context, Key key, std::any& /* data */) const { + info("%s+++ %p Using container: %016lX --> %04X %08X %s", + context.event->id(), (void*)this, key.key, key.mask(), key.item(), Key::key_name(key).c_str()); +} + +/// Standard constructor +DigiContainerSequence::DigiContainerSequence(const DigiKernel& krnl, const std::string& nam) + : DigiContainerProcessor(krnl, nam) +{ + declareProperty("parallel", m_parallel = false); + InstanceCount::increment(this); +} + +/// Default destructor +DigiContainerSequence::~DigiContainerSequence() { + InstanceCount::decrement(this); +} + +/// Adopt new parallel worker +void DigiContainerSequence::adopt_processor(DigiContainerProcessor* action) { + if ( !action ) { + except("+++ FAILED: attempt to add invalid processor!"); + return; + } + m_workers.insert(new worker_t(action, m_workers.size())); +} + +/// Main functional callback if specific work is known +void DigiContainerSequence::execute(DigiContext& /* context */, work_t& work) const { + m_kernel.submit(m_workers.get_calls(), m_workers.size(), &work, m_parallel); +} + +/// Worker adaptor for caller DigiContainerSequence +template <> void DigiParallelWorker<DigiContainerProcessor, + DigiContainerSequence::work_t, + std::size_t>::execute(void* data) const { + calldata_t* args = reinterpret_cast<calldata_t*>(data); + action->execute(args->context, *args); +} + +/// Standard constructor +DigiContainerSequenceAction::DigiContainerSequenceAction(const DigiKernel& krnl, const std::string& nam) + : DigiEventAction(krnl, nam) +{ + declareProperty("mask", m_mask); + declareProperty("input_segment", m_input_segment); + m_kernel.register_initialize(Callback(this).make(&DigiContainerSequenceAction::initialize)); + InstanceCount::increment(this); +} + +/// Default destructor +DigiContainerSequenceAction::~DigiContainerSequenceAction() { + InstanceCount::decrement(this); +} + +/// Initialization callback +void dd4hep::digi::DigiContainerSequenceAction::initialize() { + size_t count = 0; + for( auto& ent : m_registered_processors ) { + Key key = ent.first; + key.set_mask(m_mask); + worker_t* w = new worker_t(ent.second, count++); + m_registered_workers.emplace(key, w); + m_workers.insert(w); + } +} + +/// Adopt new parallel worker +void DigiContainerSequenceAction::adopt_processor(DigiContainerProcessor* action, const std::string& container) { + Key key(container, 0x0); + auto it = m_registered_processors.find(key); + if ( it != m_registered_processors.end() ) { + except("+++ The action %s was already registered to mask:%04X container:%s!", + action->c_name(), m_mask, container.c_str()); + return; + } + action->addRef(); + m_registered_processors.emplace(key, action); +} + +/// Main functional callback if specific work is known +void DigiContainerSequenceAction::execute(DigiContext& context) const { + auto& event = *context.event; + auto& inputs = event.get_segment(m_input_segment); + std::vector<ParallelWorker*> event_workers; + work_t args { context, {}, m_output_lock, {}, this }; + + args.input_items.resize(m_workers.size(), {0, nullptr}); + event_workers.reserve(inputs.size()); + for( auto& i : inputs ) { + Key key(i.first); + auto it = m_registered_workers.find(key); + if ( it != m_registered_workers.end() ) { + worker_t* w = it->second; + //work_item_t itm { key, &(i.second) }; + event_workers.emplace_back(w); + args.input_items[w->options] = { key, &(i.second) }; + } + } + m_kernel.submit(&event_workers.at(0), event_workers.size(), &args, m_parallel); +} + +/// Worker adaptor for caller DigiContainerSequenceAction +template <> void DigiParallelWorker<DigiContainerProcessor, + DigiContainerSequenceAction::work_t, + std::size_t>::execute(void* data) const { + calldata_t* args = reinterpret_cast<calldata_t*>(data); + auto& item = args->input_items[this->options]; + DigiContainerProcessor::work_t work { args->context, item.key, *item.data, args->output_lock, args->output}; + action->execute(args->context, work); +} + +/// Standard constructor +DigiMultiContainerProcessor::DigiMultiContainerProcessor(const DigiKernel& krnl, const std::string& nam) + : DigiEventAction(krnl, nam) +{ + this->declareProperty("input_masks", m_input_masks); + this->declareProperty("input_segment", m_input_segment); + InstanceCount::increment(this); +} + +/// Default destructor +DigiMultiContainerProcessor::~DigiMultiContainerProcessor() { + InstanceCount::decrement(this); +} + +void DigiMultiContainerProcessor::adopt_processor(DigiContainerProcessor* action, const std::vector<std::string>& containers) { + if ( !action ) { + except("+++ Attempt to use invalid processor. Request FAILED."); + } + else if ( containers.empty() ) { + except("+++ Processor %s is defined, but no workload was assigned. Request FAILED."); + } + std::stringstream str; + std::vector<Key> keys; + str << "[ "; + for(const auto& cont : containers) { + Key key(cont, 0x0); + keys.push_back(key); + m_work_items.insert(key.item()); + str << cont << " "; + } + str << " "; + m_workers.insert(new worker_t(action, m_workers.size())); + m_worker_keys.emplace_back(std::move(keys)); + info("+++ Use processor: %-32s for processing: %s", action->c_name(), str.str().c_str()); +} + +/// Main functional callback +void DigiMultiContainerProcessor::execute(DigiContext& context) const { + work_items_t work_items; + auto& msk = m_input_masks; + auto& event = *context.event; + auto& inputs = event.get_segment(m_input_segment); + + work_items.reserve(inputs.size()); + for( auto& i : inputs ) { + Key in_key(i.first); + bool use = msk.empty() || std::find(msk.begin(), msk.end(), in_key.mask()) != msk.end(); + if ( use ) { + use = m_work_items.empty() || m_work_items.find(in_key.item()) != m_work_items.end(); + if ( use ) { + work_items.emplace_back(std::make_pair(i.first, &i.second)); + } + } + } + if ( !work_items.empty() ) { + work_t args { context, work_items, m_output_lock, {}, this }; + m_kernel.submit(m_workers.get_calls(), m_workers.size(), &args, m_parallel); + } +} + +/// Worker adaptor for caller DigiMultiContainerProcessor +template <> void DigiParallelWorker<DigiContainerProcessor, + DigiMultiContainerProcessor::work_t, + std::size_t>::execute(void* data) const { + calldata_t* arg = reinterpret_cast<calldata_t*>(data); + const auto& keys = arg->parent->worker_keys(this->options); + const auto& masks = arg->parent->input_masks(); + for( const auto& item : arg->items ) { + Key key = item.first; + if ( masks.empty() || std::find(masks.begin(), masks.end(), key.mask()) != masks.end() ) { + if ( keys.empty() ) { + DigiContainerProcessor::work_t work {arg->context, key, *item.second, arg->output_lock, arg->output }; + action->execute(arg->context, work); + } + else if ( std::find(keys.begin(), keys.end(), Key(key.item())) != keys.end() ) { + DigiContainerProcessor::work_t work {arg->context, key, *item.second, arg->output_lock, arg->output }; + action->execute(arg->context, work); + } + } + } +} + diff --git a/DDDigi/src/DigiData.cpp b/DDDigi/src/DigiData.cpp index 4c65d7b5d00538b885971ec78f3678406295c5b8..2caea66de57ec34771106d2e7a2042d19915ccdb 100644 --- a/DDDigi/src/DigiData.cpp +++ b/DDDigi/src/DigiData.cpp @@ -66,7 +66,16 @@ std::string Key::key_name(const Key& k) { std::size_t DepositVector::merge(DepositVector&& updates) { std::size_t update_size = updates.size(); for( auto& c : updates ) { - this->emplace_back(c); + data.emplace_back(c); + } + return update_size; +} + +/// Merge new deposit map onto existing map (keep inputs) +std::size_t DepositVector::insert(const DepositVector& updates) { + std::size_t update_size = updates.size(); + for( const auto& c : updates ) { + data.emplace_back(c); } return update_size; } @@ -75,16 +84,24 @@ std::size_t DepositVector::merge(DepositVector&& updates) { std::size_t DepositMapping::merge(DepositVector&& updates) { std::size_t update_size = updates.size(); for( auto& c : updates ) { + data.emplace(std::move(c)); +#if 0 CellID cell = c.first; EnergyDeposit& depo = c.second; - auto iter = this->find(cell); - if ( iter == this->end() ) { - this->emplace(cell, std::move(depo)); + auto iter = data.find(cell); + if ( iter == data.end() ) { + data.emplace(cell, std::move(depo)); continue; } auto& to_update = iter->second; to_update.deposit += depo.deposit; - to_update.history.insert(to_update.history.end(), depo.history.begin(), depo.history.end()); + to_update.hit_history.insert(to_update.hit_history.end(), + depo.hit_history.begin(), + depo.hit_history.end()); + to_update.particle_history.insert(to_update.particle_history.end(), + depo.particle_history.begin(), + depo.particle_history.end()); +#endif } return update_size; } @@ -93,16 +110,42 @@ std::size_t DepositMapping::merge(DepositVector&& updates) { std::size_t DepositMapping::merge(DepositMapping&& updates) { std::size_t update_size = updates.size(); for( auto& c : updates ) { + data.emplace(std::move(c)); +#if 0 CellID cell = c.first; EnergyDeposit& depo = c.second; - auto iter = this->find(cell); - if ( iter == this->end() ) { - this->emplace(cell, std::move(depo)); + auto iter = data.find(cell); + if ( iter == data.end() ) { + data.emplace(cell, std::move(depo)); continue; } auto& to_update = iter->second; to_update.deposit += depo.deposit; - to_update.history.insert(to_update.history.end(), depo.history.begin(), depo.history.end()); + to_update.hit_history.insert(to_update.hit_history.end(), + depo.hit_history.begin(), + depo.hit_history.end()); + to_update.particle_history.insert(to_update.particle_history.end(), + depo.particle_history.begin(), + depo.particle_history.end()); +#endif + } + return update_size; +} + +/// Merge new deposit map onto existing map (keep inputs) +std::size_t DepositMapping::insert(const DepositVector& updates) { + std::size_t update_size = updates.size(); + for( const auto& c : updates ) { + data.emplace(c); + } + return update_size; +} + +/// Merge new deposit map onto existing map (keep inputs) +std::size_t DepositMapping::insert(const DepositMapping& updates) { + std::size_t update_size = updates.size(); + for( const auto& c : updates ) { + data.emplace(c); } return update_size; } @@ -119,19 +162,28 @@ std::size_t ParticleMapping::merge(ParticleMapping&& updates) { return update_size; } -void ParticleMapping::push(Key key, Particle&& part) { +void ParticleMapping::push(Key particle_key, Particle&& particle_data) { #if defined(__GNUC__) && (__GNUC__ < 10) /// Lower compiler version have a bad implementation of std::any bool ret = false; #else - bool ret = this->emplace(key.key, std::move(part)).second; + bool ret = data.emplace(particle_key.key, std::move(particle_data)).second; #endif if ( !ret ) { except("ParticleMapping","Error in particle map. Duplicate ID: mask:%04X Number:%d History:%s", - key.values.mask, key.values.item, yes_no(part.history.has_value())); + particle_key.mask(), particle_key.item(), yes_no(particle_data.history.has_value())); } } +/// Insert new entry +void ParticleMapping::emplace(Key particle_key, Particle&& particle_data) { +#if defined(__GNUC__) && (__GNUC__ < 10) + //return std::make_pair(false); +#else + data.emplace(particle_key.key, std::move(particle_data)).second; +#endif +} + /// Initializing constructor DataSegment::DataSegment(std::mutex& l) : lock(l) { diff --git a/DDDigi/src/DigiHandle.cpp b/DDDigi/src/DigiHandle.cpp index 25159394cf5da747ce2cb7d7f38c698d8614ad67..64aefbab59217828a77bcd755a13c4564999b6c4 100644 --- a/DDDigi/src/DigiHandle.cpp +++ b/DDDigi/src/DigiHandle.cpp @@ -20,7 +20,7 @@ #include <DDDigi/DigiKernel.h> #include <DDDigi/DigiInputAction.h> #include <DDDigi/DigiEventAction.h> -#include <DDDigi/DigiSegmentAction.h> +#include <DDDigi/DigiSegmentProcessor.h> #include <DDDigi/DigiSignalProcessor.h> // C/C++ include files @@ -69,8 +69,8 @@ namespace dd4hep { return PluginService::Create<DigiAction*>(t, &kernel, n); } - template <> DigiSegmentAction* _raw_create<DigiSegmentAction>(const std::string& t, const DigiKernel& kernel, const std::string& n) { - return PluginService::Create<DigiSegmentAction*>(t, &kernel, n); + template <> DigiSegmentProcessor* _raw_create<DigiSegmentProcessor>(const std::string& t, const DigiKernel& kernel, const std::string& n) { + return PluginService::Create<DigiSegmentProcessor*>(t, &kernel, n); } template <> DigiSignalProcessor* _raw_create<DigiSignalProcessor>(const std::string& t, const DigiKernel& kernel, const std::string& n) { @@ -202,7 +202,7 @@ namespace dd4hep { template class DigiHandle<DigiAction>; template class DigiHandle<DigiInputAction>; template class DigiHandle<DigiEventAction>; - template class DigiHandle<DigiSegmentAction>; + template class DigiHandle<DigiSegmentProcessor>; template class DigiHandle<DigiSynchronize>; template class DigiHandle<DigiActionSequence>; template class DigiHandle<DigiSignalProcessor>; diff --git a/DDDigi/src/DigiHitAttenuatorExp.cpp b/DDDigi/src/DigiHitAttenuatorExp.cpp index 16ae3b2be864ae804e16711f7e05359bd6169697..ffdae21a5cca9b1c3bfe382564193210a18d7ca0 100644 --- a/DDDigi/src/DigiHitAttenuatorExp.cpp +++ b/DDDigi/src/DigiHitAttenuatorExp.cpp @@ -15,54 +15,22 @@ #include <DD4hep/InstanceCount.h> #include <DDDigi/DigiData.h> +#include <DDDigi/DigiKernel.h> #include <DDDigi/DigiContext.h> #include <DDDigi/DigiHitAttenuatorExp.h> /// C/C++ include files #include <cmath> - - -class dd4hep::digi::DigiHitAttenuatorExp::internals_t { -public: - /// Property: Input data segment name - std::string input { }; - /// Property: Container names to be loaded - std::map<std::string, double> container_attenuation { }; - /// Property: event masks to be handled - std::vector<int> masks { }; - /// Property: T0 with respect to central crossing - double t0 { 0e0 }; - - /// Keys of all containers to be manipulated - std::map<unsigned long, double> attenuation { }; - - void initialize(DigiContext& context) { - if ( this->attenuation.empty() ) { - std::lock_guard<std::mutex> lock(context.initializer_lock()); - if ( this->attenuation.empty() ) { - for ( const auto& c : this->container_attenuation ) { - Key key(0x0, c.first); - for ( int m : this->masks ) { - double factor = std::exp(-1e0 * this->t0/c.second); - key.values.mask = m; - this->attenuation.emplace(key.key, factor); - } - } - } - } - } -}; - /// Standard constructor dd4hep::digi::DigiHitAttenuatorExp::DigiHitAttenuatorExp(const DigiKernel& krnl, const std::string& nam) : DigiEventAction(krnl, nam) { - internals = std::make_unique<internals_t>(); - declareProperty("input", internals->input = "inputs"); - declareProperty("containers", internals->container_attenuation); - declareProperty("masks", internals->masks); - declareProperty("t0", internals->t0); + declareProperty("input", m_input_segment = "inputs"); + declareProperty("containers", m_container_attenuation); + declareProperty("masks", m_masks); + declareProperty("t0", m_t0); + m_kernel.register_initialize(Callback(this).make(&DigiHitAttenuatorExp::initialize)); InstanceCount::increment(this); } @@ -71,27 +39,44 @@ dd4hep::digi::DigiHitAttenuatorExp::~DigiHitAttenuatorExp() { InstanceCount::decrement(this); } +/// Initialization callback +void dd4hep::digi::DigiHitAttenuatorExp::initialize() { + for ( const auto& c : m_container_attenuation ) { + Key key(c.first, 0x0); + for ( int m : m_masks ) { + double factor = std::exp(-1e0 * m_t0/c.second); + key.set_mask(m); + m_attenuation.emplace(key.key, factor); + } + } +} + +/// Attenuator callback for single container +template <typename T> std::size_t +dd4hep::digi::DigiHitAttenuatorExp::attenuate(T* cont, double factor) const { + for( auto& c : *cont ) + c.second.deposit *= factor; + return cont->size(); +} + /// Main functional callback void dd4hep::digi::DigiHitAttenuatorExp::execute(DigiContext& context) const { - internals->initialize(context); - std::size_t count = 0; + std::size_t count = 0, cnt = 0, cont = 0; auto& event = *context.event; - auto& inputs = event.get_segment(internals->input); - for ( const auto& k : internals->attenuation ) { - DepositMapping* m = inputs.pointer<DepositMapping>(k.first); - if ( m ) { - double factor = k.second; - for( auto& c : *m ) { - c.second.deposit *= factor; - } - count += m->size(); - std::string nam = Key::key_name(k.first)+":"; - debug("%s+++ %-32s mask:%04X item: %08X Attenuated exponentially %6ld hits by %8.5f", - event.id(), nam.c_str(), m->key.values.mask, m->key.values.item, - m->size(), factor); - continue; - } + auto& inputs = event.get_segment(m_input_segment); + for ( const auto& k : m_attenuation ) { + Key key = k.first; + auto* data = inputs.entry(key); + if ( auto* m = std::any_cast<DepositMapping>(data) ) + cnt += this->attenuate(m, k.second), ++cont; + else if ( auto* v = std::any_cast<DepositVector>(data) ) + cnt += this->attenuate(v, k.second), ++cont; + count += cnt; + std::string nam = Key::key_name(key)+":"; + debug("%s+++ %-32s mask:%04X item: %08X Attenuated exponentially %6ld hits by %8.5f", + event.id(), nam.c_str(), key.mask(), key.item(), cnt, k.second); } - info("%s+++ Attenuated exponentially %6ld hits", event.id(), count); + info("%s+++ Attenuated exponentially %6ld hits from %4ld containers from segment %s", + event.id(), count, cont, m_input_segment.c_str()); } diff --git a/DDDigi/src/DigiKernel.cpp b/DDDigi/src/DigiKernel.cpp index 979865d50bbf1cb37480566af611190998bdea75..3c480bedcf8e09aed575f14e985556a7591c2c10 100644 --- a/DDDigi/src/DigiKernel.cpp +++ b/DDDigi/src/DigiKernel.cpp @@ -71,14 +71,25 @@ public: /// Lock for global output logging std::mutex global_output_lock { }; + /// Configure callbacks + CallbackSequence configurators { }; + /// Initialize callbacks + CallbackSequence initializers { }; + //// Termination callback + CallbackSequence terminators { }; + /// Register start event callback + CallbackSequence start_event { }; + /// Register end event callback + CallbackSequence end_event { }; + /// The main data input action sequence - DigiActionSequence* inputAction = 0; + DigiActionSequence* inputAction { nullptr }; /// The main event action sequence - DigiActionSequence* eventAction = 0; + DigiActionSequence* eventAction { nullptr }; /// The main data output action sequence - DigiActionSequence* outputAction = 0; + DigiActionSequence* outputAction { nullptr }; /// TBB initializer (If TBB is used) - void* tbbInit = 0; + void* tbbInit { nullptr }; /// Property: Output level int outputLevel; /// Property: maximum number of events to be processed (if < 0: infinite) @@ -292,12 +303,44 @@ void DigiKernel::loadXML(const char* fname) { m_detDesc->apply("DD4hep_XMLLoader", 1, (char**) args); } +/// Configure the digitization: call all registered configurators int DigiKernel::configure() { - return 1;//DigiExec::configure(*this); + internals->configurators(); + return 1; } +/// Initialize the digitization: call all registered initializers int DigiKernel::initialize() { - return 1;//DigiExec::initialize(*this); + internals->initializers(); + return 1; +} + +/// Register configure callback +void DigiKernel::register_configure(const Callback& callback) const { + std::lock_guard<std::mutex> lock(initializer_lock()); + internals->configurators.add(callback); +} + +/// Register initialize callback +void DigiKernel::register_initialize(const Callback& callback) const { + std::lock_guard<std::mutex> lock(initializer_lock()); + internals->initializers.add(callback); +} + +/// Register terminate callback +void DigiKernel::register_terminate(const Callback& callback) const { + std::lock_guard<std::mutex> lock(initializer_lock()); + internals->terminators.add(callback); +} + +/// Register start event callback +void DigiKernel::register_start_event(const Callback& callback) const { + internals->start_event.add(callback); +} + +/// Register end event callback +void DigiKernel::register_end_event(const Callback& callback) const { + internals->end_event.add(callback); } /// Access to the main input action sequence from the kernel object @@ -316,54 +359,27 @@ DigiActionSequence& DigiKernel::outputAction() const { } /// Submit a bunch of actions to be executed in parallel -void DigiKernel::submit (const std::vector<ParallelCall*>& algorithms, void* context) const { +void DigiKernel::submit (ParallelCall*const algorithms[], std::size_t count, void* context, bool parallel) const { #ifdef DD4HEP_USE_TBB - bool parallel = 0 != internals->tbbInit && internals->numThreads>0; - if ( parallel ) { + bool para = parallel && (0 != internals->tbbInit && internals->numThreads>0); + if ( para ) { tbb::task_group que; - for( auto* algo : algorithms ) - que.run( Wrapper<ParallelCall,void*>(algo, context) ); + printout(INFO,"DigiKernel","+++ Executing chunk of %ld execution entries in parallel", count); + for( std::size_t i=0; i<count; ++i) + que.run( Wrapper<ParallelCall,void*>(algorithms[i], context) ); que.wait(); return; } #endif - for( auto* algo : algorithms ) - algo->execute(context); + printout(INFO,"DigiKernel","+++ Executing chunk of %ld execution entries sequentially", count); + for( std::size_t i=0; i<count; ++i) + algorithms[i]->execute(context); } -/// Submit a bunch of actions to be executed serially -void DigiKernel::execute(const std::vector<ParallelCall*>& algorithms, void* context) const { - for( auto* algo : algorithms ) - algo->execute(context); -} - -#if 0 -void DigiKernel::submit(const DigiAction::Actors<DigiEventAction>& actions, DigiContext& context) const { - std::chrono::system_clock::time_point start = std::chrono::system_clock::now(); - bool parallel = 0 != internals->tbbInit && internals->numThreads>0; -#ifdef DD4HEP_USE_TBB - if ( parallel ) { - tbb::task_group que; - for ( auto* i : actions ) - que.run( Wrapper<DigiEventAction,DigiContext&>(i, context) ); - que.wait(); - goto print_stamp; - } -#endif - actions(&DigiEventAction::execute,context); - goto print_stamp; - - print_stamp: - std::chrono::duration<double> secs = std::chrono::system_clock::now() - start; - printout(DEBUG, "DigiKernel", "+++ Event: %8d Executed %s task group with %3ld members [%8.3g sec]", - context.event->eventNumber, parallel ? "parallel" : "serial", actions.size(), - secs.count()); -} - -void DigiKernel::execute(const DigiAction::Actors<DigiEventAction>& actions, DigiContext& context) const { - actions(&DigiEventAction::execute,context); +/// Submit a bunch of actions to be executed in parallel +void DigiKernel::submit (const std::vector<ParallelCall*>& algorithms, void* data, bool parallel) const { + this->submit(&algorithms[0], algorithms.size(), data, parallel); } -#endif void DigiKernel::wait(DigiContext& context) const { if ( context.event ) {} @@ -373,9 +389,11 @@ void DigiKernel::wait(DigiContext& context) const { void DigiKernel::executeEvent(std::unique_ptr<DigiContext>&& context) { DigiContext& refContext = *context; try { + internals->start_event(&refContext); inputAction().execute(refContext); eventAction().execute(refContext); outputAction().execute(refContext); + internals->end_event(&refContext); notify(std::move(context)); } catch(const std::exception& e) { @@ -383,6 +401,7 @@ void DigiKernel::executeEvent(std::unique_ptr<DigiContext>&& context) { } } +/// Notify kernel that the execution of one single event finished void DigiKernel::notify(std::unique_ptr<DigiContext>&& context) { if ( context ) { context->event.reset(); @@ -391,6 +410,7 @@ void DigiKernel::notify(std::unique_ptr<DigiContext>&& context) { ++internals->eventsFinished; } +/// Notify kernel that the execution of one single event finished void DigiKernel::notify(std::unique_ptr<DigiContext>&& context, const std::exception& e) { internals->stop = true; printout(ERROR,"DigiKernel","+++ Exception during event processing [Shall stop the event loop]"); @@ -398,6 +418,7 @@ void DigiKernel::notify(std::unique_ptr<DigiContext>&& context, const std::excep notify(std::move(context)); } +/// Run the digitization sequence over the requested number of events int DigiKernel::run() { std::chrono::system_clock::time_point start = std::chrono::system_clock::now(); internals->stop = false; @@ -438,8 +459,10 @@ int DigiKernel::run() { return 1; } +/// Terminate the digitization: call all registered terminators and release the allocated resources int DigiKernel::terminate() { printout(INFO, "DigiKernel", "++ Terminate Digi and delete associated actions."); + internals->terminators(); m_detDesc->destroyInstance(); m_detDesc = 0; return 1; diff --git a/DDDigi/src/DigiMultiContainerProcessor.cpp b/DDDigi/src/DigiMultiContainerProcessor.cpp deleted file mode 100644 index 454cc862034a62d5d6ac9c6ebacf30ef91f2e866..0000000000000000000000000000000000000000 --- a/DDDigi/src/DigiMultiContainerProcessor.cpp +++ /dev/null @@ -1,121 +0,0 @@ -//========================================================================== -// AIDA Detector description implementation -//-------------------------------------------------------------------------- -// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN) -// All rights reserved. -// -// For the licensing terms see $DD4hepINSTALL/LICENSE. -// For the list of contributors see $DD4hepINSTALL/doc/CREDITS. -// -// Author : M.Frank -// -//========================================================================== - -// Framework include files -#include <DD4hep/InstanceCount.h> - -#include <DDDigi/DigiData.h> -#include <DDDigi/DigiContext.h> -#include <DDDigi/DigiMultiContainerProcessor.h> - -/// C/C++ include files -#include <set> -#include <sstream> - -using namespace dd4hep::digi; - -template <> void DigiParallelWorker<DigiContainerProcessor, - DigiMultiContainerProcessor::CallData, - int>::execute(void* data) const { - calldata_t* args = reinterpret_cast<calldata_t*>(data); - action->execute(args->context, args->work); -} - -/// Standard constructor -DigiMultiContainerProcessor::DigiMultiContainerProcessor(const DigiKernel& krnl, const std::string& nam) - : DigiEventAction(krnl, nam) -{ - this->declareProperty("input_masks", m_input_masks); - this->declareProperty("input_segment", m_input_segment); - InstanceCount::increment(this); -} - -/// Default destructor -DigiMultiContainerProcessor::~DigiMultiContainerProcessor() { - for(auto* w : m_workers ) detail::deletePtr(w); - m_workers.clear(); - InstanceCount::decrement(this); -} - -void DigiMultiContainerProcessor::adopt_processor(DigiContainerProcessor* action, const std::vector<std::string>& containers) { - if ( !action ) { - except("+++ Attempt to use invalid processor. Request FAILED."); - } - else if ( containers.empty() ) { - except("+++ Processor %s is defined, but no workload was assigned. Request FAILED."); - } - std::stringstream str; - std::vector<Key> keys; - for(const auto& c : containers) { - Key key(0x0, c); - keys.push_back(key); - m_work_items.insert(key.item()); - str << c << " "; - } - action->m_container_keys = std::move(keys); - m_workers.emplace_back(new Worker(action, 0)); - info("+++ Use processor: %-32s for processing: %s", action->c_name(), str.str().c_str()); -} - -/// Main functional callback -void DigiMultiContainerProcessor::execute(DigiContext& context) const { - WorkItems work_items; - auto& msk = m_input_masks; - auto& event = *context.event; - auto& inputs = event.get_segment(m_input_segment); - - work_items.reserve(inputs.size()); - for( auto& i : inputs ) { - Key in_key(i.first); - bool use = msk.empty() || std::find(msk.begin(), msk.end(), in_key.mask()) != msk.end(); - if ( use ) { - use = m_work_items.find(in_key.item()) != m_work_items.end(); - if ( use ) { - work_items.emplace_back(std::make_pair(i.first, &i.second)); - } - } - } - if ( !work_items.empty() ) { - CallData data { context, work_items }; - m_kernel.submit(m_workers, &data); - } -} - -/// Standard constructor -DigiContainerProcessor::DigiContainerProcessor(const DigiKernel& kernel, const std::string& name) - : DigiAction(kernel, name) -{ - this->declareProperty("input_masks", m_input_masks); - this->declareProperty("input_segment", m_input_segment); -} - -/// Check if the work item is for us -bool DigiContainerProcessor::use_container(Key key) const { - auto key_iter = std::find(m_container_keys.begin(), m_container_keys.end(), Key(key.item())); - if ( m_container_keys.empty() || key_iter != m_container_keys.end() ) { - auto mask_iter = std::find(m_input_masks.begin(), m_input_masks.end(), key.mask()); - return m_input_masks.empty() || mask_iter != m_input_masks.end(); - } - return false; -} - -/// Main functional callback if specific work is known -void DigiContainerProcessor::execute(DigiContext& context, WorkItems& work) const { - for( const auto& item : work ) { - if ( use_container(item.first) ) { - Key key = item.first; - info("%s+++ %p Using container: %016lX --> %04X %08X %s", - context.event->id(), (void*)this, key.key, key.mask(), key.item(), Key::key_name(key).c_str()); - } - } -} diff --git a/DDDigi/src/DigiPlugins.cpp b/DDDigi/src/DigiPlugins.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2f9199b6316f8a275bf024119f73f757b64c506e --- /dev/null +++ b/DDDigi/src/DigiPlugins.cpp @@ -0,0 +1,43 @@ +//========================================================================== +// AIDA Detector description implementation +//-------------------------------------------------------------------------- +// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN) +// All rights reserved. +// +// For the licensing terms see $DD4hepINSTALL/LICENSE. +// For the list of contributors see $DD4hepINSTALL/doc/CREDITS. +// +// Author : M.Frank +// +//========================================================================== + +// Framework include files +#include <DD4hep/Printout.h> +#include <DD4hep/Primitives.h> +#include <DD4hep/Plugins.h> +#include <DDDigi/DigiKernel.h> +#include <DDDigi/DigiAction.h> +#include <DDDigi/DigiPlugins.h> + +static inline dd4hep::ComponentCast* component(void* p) { return (dd4hep::ComponentCast*)p; } + +void* dd4hep::digi::create_action(const std::string& factory, + const dd4hep::digi::DigiKernel& kernel, + const std::string& arg, void* (*cast)(void*)) { + void* object = PluginService::Create<DigiAction*>(factory, &kernel, arg); + if ( !object ) { + PluginDebug dbg; + object = PluginService::Create<DigiAction*>(factory, &kernel, arg); + if ( !object ) { + except("createPlugin","dd4hep-plugins: Failed to locate plugin %s. \n%s.", + factory.c_str(), dbg.missingFactory(factory).c_str()); + } + } + if ( cast ) { + void* obj = cast(object); + if ( obj ) return obj; + ComponentCast* c = component(object); + invalidHandleAssignmentError(typeid(cast),typeid(*c)); + } + return object; +} diff --git a/DDDigi/src/DigiROOTInput.cpp b/DDDigi/src/DigiROOTInput.cpp index 18a1bea03a87edb7b96a07d0b0ffe64934ee38c9..e3f0cfd9a644e0026725ba38a8012889c48c3bee 100644 --- a/DDDigi/src/DigiROOTInput.cpp +++ b/DDDigi/src/DigiROOTInput.cpp @@ -37,7 +37,7 @@ using namespace dd4hep::digi; */ class DigiROOTInput::internals_t { public: - typedef std::function<std::any(int, const char*, void*)> func_t; + typedef std::function<void(DataSegment&, int, const char*, void*)> func_t; class converter_t { public: @@ -48,6 +48,8 @@ public: /// Mutex to allow re-use of a single source for multiple input streams std::mutex m_lock { }; + + /// Branches present in the current file std::map<unsigned long, converter_t> branches; /// Reference to the current ROOT file to be read TFile* file { }; @@ -127,7 +129,7 @@ void DigiROOTInput::open_new_file() const { TClass* cls = gROOT->GetClass( b->GetClassName(), kTRUE ); /// If there are no required branches, we convert everything if ( this->m_containers.empty() ) { - Key key(this->m_mask, b->GetName()); + Key key(b->GetName(), this->m_mask); b->SetAutoDelete( kFALSE ); imp->branches[key.key] = {b, cls, imp->input_converter(cls)}; continue; @@ -135,7 +137,7 @@ void DigiROOTInput::open_new_file() const { /// Otherwise only the entities asked for for( const auto& bname : this->m_containers ) { if ( bname == b->GetName() ) { - Key key(this->m_mask, b->GetName()); + Key key(b->GetName(), this->m_mask); b->SetAutoDelete( kFALSE ); imp->branches[key.key] = {b, cls, imp->input_converter(cls)}; break; @@ -201,8 +203,7 @@ void DigiROOTInput::execute(DigiContext& context) const { input_len += nb; const auto& func = *br.second.call; void** addr = (void**)b->GetAddress(); - auto data = func(this->m_mask, b->GetName(), *addr); - segment.emplace(br.first, std::move(data)); + func(segment, this->m_mask, b->GetName(), *addr); } info("%s+++ Read event %6ld [%ld bytes] from tree %s file: %s", event->id(), imp->entry, input_len, imp->tree->GetName(), imp->file->GetName()); diff --git a/DDDigi/src/DigiSegmentProcessor.cpp b/DDDigi/src/DigiSegmentProcessor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..07064d0cb6d64207fe2fe691278670d6d4116ba0 --- /dev/null +++ b/DDDigi/src/DigiSegmentProcessor.cpp @@ -0,0 +1,96 @@ +//========================================================================== +// AIDA Detector description implementation +//-------------------------------------------------------------------------- +// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN) +// All rights reserved. +// +// For the licensing terms see $DD4hepINSTALL/LICENSE. +// For the list of contributors see $DD4hepINSTALL/doc/CREDITS. +// +// Author : M.Frank +// +//========================================================================== + +// Framework include files +#include <DD4hep/InstanceCount.h> +#include <DDDigi/DigiKernel.h> +#include <DDDigi/DigiSegmentProcessor.h> + +using namespace dd4hep::digi; + +void DigiSegmentProcessor::work_t::merge_output(DepositVector&& data) { + std::lock_guard<std::mutex> lock(output_lock); +#if 0 + if ( !output.get() ) { + output.reset(new DepositVector(std::move(data))); + } + else { + output->merge(std::move(data)); + } +#endif +} + +void DigiSegmentProcessor::work_t::emplace_output(CellID cell, EnergyDeposit&& data) { + std::lock_guard<std::mutex> lock(output_lock); +#if 0 + if ( !output.get() ) { + output.reset(new DepositVector()); + } + output->emplace(cell, std::move(data)); +#endif +} + +/// Standard constructor +DigiSegmentProcessor::DigiSegmentProcessor(const DigiKernel& krnl, const std::string& nam) + : DigiContainerProcessor(krnl, nam) +{ + InstanceCount::increment(this); +} + +/// Default destructor +DigiSegmentProcessor::~DigiSegmentProcessor() { + InstanceCount::decrement(this); +} + +/// Main functional callback if specific work is known +void DigiSegmentProcessor::handle_segment(DigiContext& /* context */, work_t& /* args */) const { +} + +template <> void DigiParallelWorker<DigiSegmentProcessor, + DigiSegmentSequence::work_t, + dd4hep::VolumeID>::execute(void* args) const { + calldata_t* work = reinterpret_cast<calldata_t*>(args); + action->handle_segment(work->context, *work); +} + +/// Standard constructor +DigiSegmentSequence::DigiSegmentSequence(const DigiKernel& krnl, const std::string& nam) + : DigiSegmentProcessor(krnl, nam) +{ + InstanceCount::increment(this); +} + +/// Default destructor +DigiSegmentSequence::~DigiSegmentSequence() { + InstanceCount::decrement(this); +} + +/// Adopt new parallel worker +void DigiSegmentSequence::adopt_processor(DigiContainerProcessor* action) { + if ( !action ) { + except("+++ FAILED: attempt to add invalid processor!"); + } + auto* proc = dynamic_cast<DigiSegmentProcessor*>(action); + if ( !proc ) { + error("+++ FAILED: Attempt to add processor %s of type %s", + action->c_name(), typeName(typeid(*action)).c_str()); + except("+++ DigiSegmentSplitter do ONLY accept processors of type DigiSegmentProcessor!"); + } + proc->segment = segment; + m_workers.insert(new worker_t(proc, proc->segment.id)); +} + +/// Main functional callback +void DigiSegmentSequence::handle_segment(DigiContext& /* context */, work_t& work) const { + m_kernel.submit(m_workers.get_group(), m_workers.size(), &work, m_parallel); +} diff --git a/DDDigi/src/DigiSegmentSplitter.cpp b/DDDigi/src/DigiSegmentSplitter.cpp index d6578d6a9d7fec19ddfbe1e6762c42b1a99404a0..7fbb9a5c332b2ea41be81f6eb84f205003c56fd4 100644 --- a/DDDigi/src/DigiSegmentSplitter.cpp +++ b/DDDigi/src/DigiSegmentSplitter.cpp @@ -14,125 +14,105 @@ // Framework include files #include <DD4hep/Plugins.h> #include <DD4hep/InstanceCount.h> - #include <DDDigi/DigiKernel.h> #include <DDDigi/DigiContext.h> +#include <DDDigi/DigiPlugins.h> #include <DDDigi/DigiSegmentSplitter.h> using namespace dd4hep::digi; -class DigiSegmentSplitter::internals_t { -public: - /// Reference to master - DigiSegmentSplitter* split { nullptr }; - /// Flag to check the initialization - bool inited { false }; - /// Default constructor - internals_t(DigiSegmentSplitter* s) : split(s) {} - /// Initializing function: compute values which depend on properties - void initialize(DigiContext& context) { - if ( !this->inited ) { - std::lock_guard<std::mutex> lock(context.initializer_lock()); - if ( !this->inited ) { - this->split->initialize(); - this->inited = true; - } - } - } -}; - -template <> void DigiParallelWorker<DigiSegmentAction, - DigiSegmentSplitter::CallData, - int>::execute(void* data) const { - calldata_t* args = reinterpret_cast<calldata_t*>(data); - auto res = action->handleSegment(args->context, args->input); - if ( args->output && !res.empty() ) { - args->parent->register_output(*args->output, std::move(res)); - } -} - /// Standard constructor DigiSegmentSplitter::DigiSegmentSplitter(const DigiKernel& kernel, const std::string& nam) - : DigiEventAction(kernel, nam), + : DigiContainerSequence(kernel, nam), m_split_tool(kernel.detectorDescription()) { - this->internals = std::make_unique<internals_t>(this); declareProperty("detector", m_detector_name); declareProperty("split_by", m_split_by); declareProperty("processor_type", m_processor_type); declareProperty("share_processor", m_share_processor = false); - - declareProperty("input_segment", m_input_id = "deposits"); - declareProperty("input_mask", m_input_mask); - declareProperty("output_segment", m_output_id); - declareProperty("output_mask", m_output_mask); + m_kernel.register_initialize(Callback(this).make(&DigiSegmentSplitter::initialize)); InstanceCount::increment(this); } /// Default destructor DigiSegmentSplitter::~DigiSegmentSplitter() { - for(auto* w : m_workers ) detail::deletePtr(w); - m_workers.clear(); InstanceCount::decrement(this); } - /// Initialization function void DigiSegmentSplitter::initialize() { char text[256]; std::size_t count = 0; m_split_tool.set_detector(m_detector_name); + m_keys = m_split_tool.collection_keys(); m_split_context = m_split_tool.split_context(m_split_by); - m_data_keys = m_split_tool.collection_keys(m_input_mask); - m_splits = m_split_tool.split_segmentation(m_split_by); + m_splits = m_split_tool.split_segmentation(m_split_by); - /// Create the processors: + /// 1) Check if the workers were pre-configured + if ( !m_workers.empty() ) { + bool bad = false; + const auto& workers = m_workers.get(); + /// Create the processors: + for( auto& p : m_splits ) { + auto split_id = p.second.second; + bool ok = false; + for( const auto* w : workers ) { + if ( w->options == split_id ) { ok = true; break; } + } + if ( !ok ) { + error("+++ Missing processor for plit ID: %08ld", split_id); + bad = true; + } + } + if ( bad ) { + except("+++ If you add processors by hand, do it properly! " + "Otherwise use the property 'processor_type'. " + "This setup is invalid."); + } + return; + } + /// IF NOT: + /// 2) Create the processors using the 'processor_type' option for( auto& p : m_splits ) { ::snprintf(text, sizeof(text), "_%05X", m_split_context.split_id(p.first)); std::string nam = this->name() + text; - auto* proc = PluginService::Create<DigiSegmentAction*>(m_processor_type, &m_kernel, nam); + auto* proc = createAction<DigiSegmentProcessor>(m_processor_type, m_kernel, nam); if ( !proc ) { except("+++ Failed to create split worker: %s/%s", m_processor_type.c_str(), nam.c_str()); } proc->segment = m_split_context; proc->segment.detector = p.second.first; proc->segment.id = p.second.second; - m_workers.emplace_back(new Worker(proc, 0)); + m_workers.insert(new worker_t(proc, proc->segment.id)); ++count; } info("+++ Detector splitter is now fully initialized!"); } -/// Main functional callback -void DigiSegmentSplitter::execute(DigiContext& context) const { - auto& input = context.event->get_segment(m_input_id); - this->internals->initialize(context); - for( auto k : m_data_keys ) { - auto* hits = input.pointer<DepositMapping>(k); - if ( hits ) { - /// prepare processors for execution - info("+++ Got hit collection %04X %08X. Prepare processors.", Key::mask(k), Key::item(k)); - /// Now submit them - if ( m_output_id.empty() ) { - CallData data { context, *hits, nullptr, this }; - m_kernel.submit(m_workers, &data); - } - else { - DepositMapping result (m_name+"."+hits->name, m_output_mask); - CallData data { context, *hits, &result, this }; - m_kernel.submit(m_workers, &data); - auto& output = context.event->get_segment(m_output_id); - output.emplace(result.key, std::move(result)); - } - } +/// Adopt new parallel worker +void DigiSegmentSplitter::adopt_processor(DigiContainerProcessor* action) { + if ( !action ) { + except("+++ FAILED: attempt to add invalid processor!"); + } + auto* proc = dynamic_cast<DigiSegmentProcessor*>(action); + if ( !proc ) { + error("+++ FAILED: Attempt to add processor %s of type %s", + action->c_name(), typeName(typeid(*action)).c_str()); + except("+++ DigiSegmentSplitter do ONLY accept processors of type DigiSegmentProcessor!"); } + m_workers.insert(new worker_t(proc, m_workers.size())); } -/// Handle result from segment callbacks -void DigiSegmentSplitter::register_output(DepositMapping& result, - DepositVector&& output) const { - std::lock_guard<std::mutex> lock(m_output_lock); - result.merge(std::move(output)); +/// Main functional callback +void DigiSegmentSplitter::execute(DigiContext& /* context */, work_t& work) const { + Key unmasked_key(work.key.item()); + if ( std::find(m_keys.begin(), m_keys.end(), unmasked_key) != m_keys.end() ) { + if ( work.input.has_value() ) { + Key key = work.key; + info("+++ Got hit collection %04X %08X. Prepare processors for %sparallel execution.", + key.mask(), key.item(), m_parallel ? "" : "NON-"); + m_kernel.submit(m_workers.get_group(), m_workers.size(), &work, m_parallel); + } + } } - diff --git a/DDDigi/src/DigiSegmentationTool.cpp b/DDDigi/src/DigiSegmentationTool.cpp index e2aea1bab5089a2b8f3c0507c99530e8af18e908..37026cfffad3f36f0b7f70378605dbdabcf5ec5b 100644 --- a/DDDigi/src/DigiSegmentationTool.cpp +++ b/DDDigi/src/DigiSegmentationTool.cpp @@ -89,10 +89,10 @@ vector<Key> DigiSegmentationTool::collection_keys(Key::mask_type mask) const vector<Key> keys; if ( this->sensitive.isValid() ) { Readout rd = this->sensitive.readout(); - auto colls = rd.collectionNames(); - if ( colls.empty() ) colls.emplace_back(rd.name()); - for( const auto& c : colls ) - keys.emplace_back(Key(mask, c)); + auto collection_names = rd.collectionNames(); + if ( collection_names.empty() ) collection_names.emplace_back(rd.name()); + for( const auto& collection : collection_names ) + keys.emplace_back(Key(collection, mask)); return keys; } except("DigiSegmentationTool", diff --git a/DDDigi/src/DigiSegmentAction.cpp b/DDDigi/src/DigiSemaphore.cpp similarity index 51% rename from DDDigi/src/DigiSegmentAction.cpp rename to DDDigi/src/DigiSemaphore.cpp index 66e1b723094237c9e10acbe0f2658ca9a19a3472..5da4a444fbfa544e933877bc9fa682c687a9a846 100644 --- a/DDDigi/src/DigiSegmentAction.cpp +++ b/DDDigi/src/DigiSemaphore.cpp @@ -12,26 +12,25 @@ //========================================================================== // Framework include files -#include <DD4hep/InstanceCount.h> -#include <DDDigi/DigiSegmentAction.h> +#include <DDDigi/DigiSemaphore.h> using namespace dd4hep::digi; -/// Standard constructor -DigiSegmentAction::DigiSegmentAction(const DigiKernel& krnl, const std::string& nam) - : DigiAction(krnl, nam) -{ - InstanceCount::increment(this); +/// Wait until reference count is NULL +std::unique_lock<std::mutex> DigiSemaphore::wait_null() { + std::unique_lock<std::mutex> protect(this->lock); + this->reference_count_is_null.wait(protect, [this] { return this->reference_count == 0; } ); + return protect; } -/// Default destructor -DigiSegmentAction::~DigiSegmentAction() { - InstanceCount::decrement(this); +/// Aquire semaphore count +void DigiSemaphore::aquire() { + std::lock_guard guard(this->lock); + ++this->reference_count; } -/// Main functional callback -DepositVector -DigiSegmentAction::handleSegment(DigiContext& /* context */, - const DepositMapping& /* depos */) const { - return {}; +/// Release semaphore count +void DigiSemaphore::release() { + if ( --this->reference_count == 0 ) + this->reference_count_is_null.notify_one(); } diff --git a/DDDigi/src/DigiStoreDump.cpp b/DDDigi/src/DigiStoreDump.cpp index b93ed8a26f2464a26c9f3909002d7ee834d9c934..168cc9002232492b1939731bc6e39a3e41521579 100644 --- a/DDDigi/src/DigiStoreDump.cpp +++ b/DDDigi/src/DigiStoreDump.cpp @@ -52,9 +52,10 @@ void dd4hep::digi::DigiStoreDump::dump(const std::string& tag, const std::any& data = e.second; std::string nam = Key::key_name(key); std::string typ = typeName(data.type()); - std::size_t idx = typ.find(", std::less<long long>, std::allocator<std::pair"); + std::size_t idx = typ.find(", std::allocator<std::"); if ( idx != std::string::npos ) typ = str_replace(typ, typ.substr(idx), ">"); - typ = str_replace(str_replace(typ,"std::",""),"dd4hep::digi::",""); + typ = str_replace(str_replace(typ,"std::",""),"dd4hep::",""); + typ = str_replace(str_replace(typ,"sim::",""),"digi::",""); if ( const auto* mapping = std::any_cast<DepositMapping>(&data) ) { str = this->format("%s|---- %4X %08X %-32s: %6ld hits [%s]", event.id(), key.values.mask, key.values.item, diff --git a/DDDigi/src/DigiSynchronize.cpp b/DDDigi/src/DigiSynchronize.cpp index bf01a5283f457ec5e8c91cf83fc8a27a1889b09f..536e0941489d1296f7d97479be4450eba55a9d33 100644 --- a/DDDigi/src/DigiSynchronize.cpp +++ b/DDDigi/src/DigiSynchronize.cpp @@ -39,18 +39,15 @@ DigiSynchronize::DigiSynchronize(const DigiKernel& kernel, const string& nam) /// Default destructor DigiSynchronize::~DigiSynchronize() { - for(auto* w : m_actors ) detail::deletePtr(w); - m_actors.clear(); InstanceCount::decrement(this); } /// Pre-track action callback void DigiSynchronize::execute(DigiContext& context) const { auto start = chrono::high_resolution_clock::now(); - if ( m_parallel ) - m_kernel.submit(m_actors, &context); - else - m_kernel.execute(m_actors, &context); + if ( !m_actors.empty() ) { + m_kernel.submit(m_actors.get_group(), m_actors.size(), &context, m_parallel); + } chrono::duration<double> secs = chrono::high_resolution_clock::now() - start; debug("+++ Event: %8d (DigiSynchronize) Parallel: %-4s %3ld actions [%8.3g sec]", context.event->eventNumber, yes_no(m_parallel), m_actors.size(), @@ -60,7 +57,7 @@ void DigiSynchronize::execute(DigiContext& context) const { /// Add an actor responding to all callbacks. Sequence takes ownership. void DigiSynchronize::adopt(DigiEventAction* action) { if (action) { - m_actors.emplace_back(new Worker(action, 0)); + m_actors.insert(new Worker(action, 0)); return; } except("DigiSynchronize","++ Attempt to add invalid actor!"); diff --git a/DDDigi/src/noise/DigiSignalProcessorSequence.cpp b/DDDigi/src/noise/DigiSignalProcessorSequence.cpp index 25aec3071d13c336034e933295c933119c7f833e..f5d54c266ca8045aa204cf585f97ef3bf52a3f56 100644 --- a/DDDigi/src/noise/DigiSignalProcessorSequence.cpp +++ b/DDDigi/src/noise/DigiSignalProcessorSequence.cpp @@ -13,6 +13,7 @@ // Framework include files #include <DD4hep/InstanceCount.h> +#include <DDDigi/DigiKernel.h> #include <DDDigi/DigiSegmentation.h> #include <DDDigi/noise/DigiSignalProcessorSequence.h> @@ -21,6 +22,14 @@ using namespace dd4hep::digi; +template <> void +DigiParallelWorker<DigiSignalProcessor, + DigiSignalProcessorSequence::CallData, + int>::execute(void* data) const { + calldata_t* args = reinterpret_cast<calldata_t*>(data); + args->value += (*action)(args->context); +} + /// Standard constructor DigiSignalProcessorSequence::DigiSignalProcessorSequence(const DigiKernel& kernel, const std::string& nam) : DigiSignalProcessor(kernel, nam) @@ -35,9 +44,8 @@ DigiSignalProcessorSequence::~DigiSignalProcessorSequence() { /// Adopt a new action as part of the sequence. Sequence takes ownership. void DigiSignalProcessorSequence::adopt(DigiSignalProcessor* action) { - if ( action ) { - action->addRef(); - m_actors.add(action); + if (action) { + m_actors.insert(new Worker(action, 0)); return; } except("DigiSignalProcessorSequence","++ Attempt to add invalid actor!"); @@ -45,8 +53,12 @@ void DigiSignalProcessorSequence::adopt(DigiSignalProcessor* action) { /// Pre-track action callback double DigiSignalProcessorSequence::operator()(DigiCellContext& context) const { + CallData args { context, 0e0 }; double result = context.data.signal; - for ( const auto* p : m_actors ) - result += p->operator()(context); + for ( const auto* p : m_actors.get() ) { + args.value = 0e0; + p->execute(&args); + result += args.value; + } return context.data.kill ? 0e0 : result; } diff --git a/examples/DDDigi/scripts/TestMultiInteractions.py b/examples/DDDigi/scripts/TestMultiInteractions.py index 223e18e673d85fba4f6ff69240d317e5cf9216ba..35f5152e3877bc7212aee1f6e2dada2640653259 100644 --- a/examples/DDDigi/scripts/TestMultiInteractions.py +++ b/examples/DDDigi/scripts/TestMultiInteractions.py @@ -42,7 +42,11 @@ def run(): digi.info('Created input.overlay75') # ======================================================================================================== event = digi.event_action('DigiSequentialActionSequence/EventAction') - combine = event.adopt_action('DigiContainerCombine/Combine', input_masks=[0x0, 0x1, 0x2, 0x3], deposit_mask=0xFEED) + combine = event.adopt_action('DigiContainerCombine/Combine', + parallel=True, + input_masks=[0x0, 0x1, 0x2, 0x3], + deposit_mask=0xFEED, + erase_combined=False) combine.erase_combined = True # Not thread-safe! only do in SequentialActionSequence dump = event.adopt_action('DigiStoreDump/StoreDump') digi.check_creation([combine, dump]) diff --git a/examples/DDDigi/scripts/TestSegmentationSplit.py b/examples/DDDigi/scripts/TestSegmentationSplit.py index bbe09bc19f01eaf78cb009db768f50cca962efda..5283350c200cb38b4f706d11718ade56e55e22d0 100644 --- a/examples/DDDigi/scripts/TestSegmentationSplit.py +++ b/examples/DDDigi/scripts/TestSegmentationSplit.py @@ -24,15 +24,17 @@ def run(): event = digi.event_action('DigiSequentialActionSequence/EventAction') combine = event.adopt_action('DigiContainerCombine/Combine', input_masks=[0x0], deposit_mask=0xFEED) combine.erase_combined = True # Not thread-safe! only do in SequentialActionSequence - splitter = event.adopt_action('DigiSegmentSplitter/Splitter', - input_segment='deposits', - input_mask=0xFEED, - output_segment='', - output_mask=0xBABE, - detector='SiTrackerBarrel', + split_action = event.adopt_action('DigiContainerSequenceAction/SplitSequence', + parallel=True, + input_segment='deposits', + mask=0xFEED) + splitter = digi.create_action('DigiSegmentSplitter/Splitter', + parallel=True, split_by='layer', + detector='SiTrackerBarrel', processor_type='DigiSegmentDepositPrint') - splitter.parallel = True + split_action.adopt_container_processor(splitter, 'SiTrackerBarrelHits') + dump = event.adopt_action('DigiStoreDump/StoreDump') digi.check_creation([combine, dump, splitter]) digi.info('Created event.dump') diff --git a/examples/DDDigi/src/DigiTestAction.cpp b/examples/DDDigi/src/DigiTestAction.cpp index b798cf74ef7286d991d9587229e42177efee8984..d35cae8d5a6e86189b6d4c97b693345f4af954da 100644 --- a/examples/DDDigi/src/DigiTestAction.cpp +++ b/examples/DDDigi/src/DigiTestAction.cpp @@ -85,7 +85,7 @@ static void noop(int) {} using namespace std; using namespace dd4hep::digi; -DECLARE_DIGIEVENTACTION_NS(dd4hep::digi,DigiTestAction) +DECLARE_DIGIACTION_NS(dd4hep::digi,DigiTestAction) /// Standard constructor DigiTestAction::DigiTestAction(const DigiKernel& kernel, const string& nam)