diff --git a/DDDigi/ddg4/DigiDDG4Input.cpp b/DDDigi/ddg4/DigiDDG4Input.cpp index f887b0a4183ed30d5c63513420bd4d8a6c25aac0..6efa7a77dff450c6d4bc12573711db26737dd396 100644 --- a/DDDigi/ddg4/DigiDDG4Input.cpp +++ b/DDDigi/ddg4/DigiDDG4Input.cpp @@ -50,6 +50,7 @@ namespace { if ( ptr ) { Key history_key; input_data<T> data(ptr); + history_key.set_segment(segment.id); history_key.set_mask(Key::mask_type(mask)); for(size_t i=0; i < data.items->size(); ++i) { auto* p = (*data.items)[i]; @@ -57,11 +58,10 @@ namespace { 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); + dep.history.hits.emplace_back(history_key, 1.0); history_key.set_item(p->g4ID); - dep.particle_history.emplace_back(history_key, 1.0); + dep.history.particles.emplace_back(history_key, 1.0); out.emplace(p->cellID, std::move(dep)); particles.emplace_back(wrap_t(p)); } @@ -97,18 +97,17 @@ static void* convert_sim_geant4particles() { using wrap_t = std::shared_ptr<sim::Geant4Particle>; auto* items = (std::vector<sim::Geant4Particle*>*)ptr; for( auto* p : *items ) { - Key key(0); + Key key; Particle part; - key.set_mask(mask); - key.set_item(out->size()); - p->mask = mask; + key.set_mask(mask).set_item(out->size()).set_segment(segment.id); + p->mask = mask; 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)); + out->push(key, std::move(part)); } items->clear(); } diff --git a/DDDigi/include/DDDigi/DigiContainerDrop.h b/DDDigi/include/DDDigi/DigiContainerDrop.h new file mode 100644 index 0000000000000000000000000000000000000000..5f4305bde067b2b3248bfbbbd10f52a03369bf14 --- /dev/null +++ b/DDDigi/include/DDDigi/DigiContainerDrop.h @@ -0,0 +1,79 @@ +//========================================================================== +// 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_DIGICONTAINERDROP_H +#define DDDIGI_DIGICONTAINERDROP_H + +/// Framework include files +#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 DigiContainerDrop : public DigiEventAction { + public: + class work_definition_t; + using self_t = DigiContainerDrop; + using Worker = DigiParallelWorker<self_t,work_definition_t>; + using Workers = DigiParallelWorkers<Worker>; + + protected: + /// Property: Container names to be loaded + std::vector<std::string> m_containers { }; + /// Property: Input data segment name + std::string m_input; + /// Property: event masks to be handled + std::vector<int> m_input_masks { }; + /// 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 { }; + + /// Worker objects to be submitted to TBB each performing part of the job + Workers m_workers; + + protected: + /// Define standard assignments and constructors + DDDIGI_DEFINE_ACTION_CONSTRUCTORS(DigiContainerDrop); + + /// Default destructor + virtual ~DigiContainerDrop(); + + /// Initializing function: compute values which depend on properties + void initialize(); + + /// Decide if a continer is to merged based on the properties + virtual bool use_key(Key key) const; + + public: + /// Standard constructor + DigiContainerDrop(const DigiKernel& kernel, const std::string& name); + + /// Main functional callback + virtual void execute(DigiContext& context) const; + }; + } // End namespace digi +} // End namespace dd4hep +#endif // DDDIGI_DIGICONTAINERDROP_H diff --git a/DDDigi/include/DDDigi/DigiContainerProcessor.h b/DDDigi/include/DDDigi/DigiContainerProcessor.h index c615e70fee9ea1a3abec44add3deeaefae2e40c1..a414ebbe7768182b8190d235caf84cb5112e5987 100644 --- a/DDDigi/include/DDDigi/DigiContainerProcessor.h +++ b/DDDigi/include/DDDigi/DigiContainerProcessor.h @@ -171,8 +171,8 @@ namespace dd4hep { }; using worker_t = DigiParallelWorker<processor_t, work_t>; using workers_t = DigiParallelWorkers<worker_t>; - using reg_workers_t = std::map<Key::itemkey_type, worker_t*>; - using reg_processors_t = std::map<Key::itemkey_type, processor_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 @@ -255,12 +255,18 @@ namespace dd4hep { /// Property: event mask for output data int m_output_mask { 0x0 }; + /// Set of container names to be used by this processor + std::map<std::string, std::vector<processor_t*> > m_processors; + std::map<Key::itemkey_type, std::vector<worker_t*> > m_worker_map; + /// Set of work items to be processed and passed to clients - std::set<Key> m_work_items; + std::set<Key> m_work_items; /// Set of keys required by each worker - worker_keys_t m_worker_keys; + worker_keys_t m_worker_keys; + /// Ordered list of actions registered + std::vector<processor_t*> m_actions; /// Lock for output merging - mutable std::mutex m_output_lock; + mutable std::mutex m_output_lock; /// Array of sub-workers workers_t m_workers; @@ -270,6 +276,8 @@ namespace dd4hep { DDDIGI_DEFINE_ACTION_CONSTRUCTORS(DigiMultiContainerProcessor); /// Default destructor virtual ~DigiMultiContainerProcessor(); + /// Initialize action object + void initialize(); public: /// Standard constructor diff --git a/DDDigi/include/DDDigi/DigiData.h b/DDDigi/include/DDDigi/DigiData.h index 17ae58f52a281a70dcd771587960296101f562f9..936028d79c6c33b364633214823e51255bca1bd9 100644 --- a/DDDigi/include/DDDigi/DigiData.h +++ b/DDDigi/include/DDDigi/DigiData.h @@ -53,7 +53,10 @@ namespace dd4hep { typedef std::uint64_t key_type; typedef std::uint32_t itemkey_type; typedef std::uint16_t mask_type; - + typedef std::uint8_t segment_type; + typedef std::uint8_t submask_type; + + private: /// First union entry used for fast initialization key_type key; /// Second union entry to use for discrimination @@ -61,11 +64,12 @@ namespace dd4hep { // Ordering is important here: // We want to group the containers by item ie. by container name // and not by mask - itemkey_type item; + segment_type segment; + submask_type submask; mask_type mask; - mask_type spare; + itemkey_type item; } values; - + public: /// Default constructor Key(); /// Move constructor @@ -73,11 +77,13 @@ namespace dd4hep { /// Copy constructor Key(const Key&); /// Initializaing constructor (fast) - Key(key_type full_mask); + Key(key_type full_mask) = delete; /// Initializing constructor with key generation using hash algorithm - Key(const char* item, mask_type mask); + explicit Key(const char* item, mask_type mask); /// Initializing constructor with key generation using hash algorithm - Key(const std::string& item, mask_type mask); + explicit Key(const std::string& item, mask_type mask); + /// Assignment operator + Key& operator = (const Key::key_type) = delete; /// Assignment operator Key& operator = (const Key&); /// Move assignment operator @@ -92,48 +98,52 @@ namespace dd4hep { /// Generate key using hash algorithm void set(const std::string& name, int mask); - /// Conversion to uint64 - key_type toLong() const { - return key; + /// Set key mask + Key& set_mask(mask_type m) { + this->values.mask = m; + return *this; } - - /// Project the item part of the key - mask_type mask() const { - return this->values.mask; + /// Set key submask + Key& set_submask(submask_type m) { + this->values.submask = m; + return *this; } - /// Set key mask - void set_mask(Key k) { - this->values.mask = k.values.mask; + /// Set key submask + Key& set_submask(const char* opt_tag); + /// Set key item identifier + Key& set_item(itemkey_type i) { + this->values.item = i; + return *this; } /// Set key mask - void set_mask(mask_type m) { - this->values.mask = m; - } - /// Project the item part of the key - static mask_type mask(key_type k) { - return Key(k).values.mask; + Key& set_segment(segment_type seg) { + this->values.segment = seg; + return *this; } /// Project the item part of the key - static mask_type mask(Key k) { - return k.values.mask; + mask_type mask() const { + return this->values.mask; } - /// Project the mask part of the key itemkey_type item() const { return this->values.item; } - /// Set key item identifier - void set_item(itemkey_type i) { - this->values.item = i; + /// Project the segment part of the key + segment_type segment() const { + return this->values.segment; } - /// Project the mask part of the key - static itemkey_type item(key_type k) { - return Key(k).values.item; + /// Access key as long integer + key_type value() const { + return this->key; } /// Project the mask part of the key static itemkey_type item(Key k) { return k.values.item; } + /// Project the item part of the key + static mask_type mask(Key k) { + return k.values.mask; + } /// Access key name (if registered properly) static std::string key_name(const Key& key); }; @@ -152,12 +162,6 @@ namespace dd4hep { inline Key::Key(const Key& copy) { this->key = copy.key; } - - /// Initializaing constructor (fast) - inline Key::Key(key_type full_mask) { - this->key = full_mask; - } - /// Initializaing constructor with key generation using hash algorithm inline Key::Key(const char* item, mask_type mask) { this->set(item, mask); @@ -198,7 +202,7 @@ namespace dd4hep { class SegmentEntry { public: std::string name { }; - Key key { 0x0 }; + Key key { }; public: /// Initializing constructor SegmentEntry(const std::string& name, Key::mask_type mask); @@ -238,7 +242,7 @@ namespace dd4hep { double mass { 0e0 }; char charge { 0 }; /// Source contributing - std::any history; + std::any history; public: /// Initializing constructor @@ -264,18 +268,18 @@ namespace dd4hep { } /// Particle mapping definition for digitization - /** Particle mapping definition for digitization + /** * * \author M.Frank * \version 1.0 * \ingroup DD4HEP_DIGITIZATION */ 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 container_t = std::map<Key, 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; @@ -301,6 +305,11 @@ namespace dd4hep { /// Add new entry to the particle mapping (not thread safe!) void push(Key key, Particle&& particle); + /// Merge new deposit map onto existing map (not thread safe!) (CONST) + std::size_t insert(const ParticleMapping& updates); + /// Add new entry to the particle mapping (not thread safe!) (CONST) + void insert(Key key, const Particle& particle); + /// Access container size std::size_t size() const { return this->data.size(); } /// Check container if empty @@ -326,8 +335,56 @@ namespace dd4hep { { } + /// Class to hold the processing history of the detector response + /** + * + * \author M.Frank + * \version 1.0 + * \ingroup DD4HEP_DIGITIZATION + */ + class History { + public: + struct hist_entry_t { + Key source { }; + double weight { 0e0 }; + hist_entry_t(Key s, double w); + hist_entry_t() = default; + hist_entry_t(hist_entry_t&& copy) = default; + hist_entry_t(const hist_entry_t& copy) = default; + hist_entry_t& operator=(hist_entry_t&& copy) = default; + hist_entry_t& operator=(const hist_entry_t& copy) = default; + ~hist_entry_t() = default; + }; + /// Sources contributing to the deposit indexed by the cell identifier + std::vector<hist_entry_t> hits; + std::vector<hist_entry_t> particles; + + public: + /// Default constructor + History() = default; + /// Disable move constructor + History(History&& copy) = default; + /// Disable copy constructor + History(const History& copy) = default; + /// Default destructor + virtual ~History() = default; + /// Disable move assignment + History& operator=(History&& copy) = default; + /// Disable copy assignment + History& operator=(const History& copy) = default; + + /// Update history + void update(const History& upda); + /// Drop history information + std::pair<std::size_t,std::size_t> drop(); + }; + + inline History::hist_entry_t::hist_entry_t(Key s, double w) + : source(s), weight(w) { + } + /// Energy deposit definition for digitization - /** Energy deposit definition for digitization + /** * * \author M.Frank * \version 1.0 @@ -349,8 +406,7 @@ namespace dd4hep { Key::mask_type mask { 0 }; /// Sources contributing to this deposit - std::vector<std::pair<Key, double> > hit_history; - std::vector<std::pair<Key, double> > particle_history; + History history; public: /// Default constructor @@ -373,7 +429,7 @@ namespace dd4hep { /// Energy deposit vector definition for digitization - /** Energy deposit vector definition for digitization + /** * * \author M.Frank * \version 1.0 @@ -404,8 +460,12 @@ namespace dd4hep { DepositVector& operator=(const DepositVector& copy) = default; /// Merge new deposit map onto existing vector (destroys inputs. not thread safe!) std::size_t merge(DepositVector&& updates); + /// Merge new deposit map onto existing vector (destroys inputs. not thread safe!) + std::size_t merge(const DepositVector& updates); /// Merge new deposit map onto existing map (destroys inputs. not thread safe!) std::size_t merge(DepositMapping&& updates); + /// Merge new deposit map onto existing map (destroys inputs. not thread safe!) + std::size_t merge(const DepositMapping& updates); /// Merge new deposit map onto existing vector (keep inputs. not thread safe!) std::size_t insert(const DepositVector& updates); /// Merge new deposit map onto existing map (keep inputs. not thread safe!) @@ -441,7 +501,7 @@ namespace dd4hep { } /// Energy deposit mapping definition for digitization - /** Energy deposit mapping definition for digitization + /** * * \author M.Frank * \version 1.0 @@ -470,12 +530,14 @@ namespace dd4hep { DepositMapping& operator=(DepositMapping&& copy) = default; /// Disable copy assignment DepositMapping& operator=(const DepositMapping& copy) = default; + /// Merge new deposit map onto existing map (not thread safe!) 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 merge(DepositVector&& updates); /// Merge new deposit map onto existing map (not thread safe!) std::size_t insert(const DepositVector& updates); @@ -510,8 +572,8 @@ namespace dd4hep { address_t address; }; - /// Energy deposit vector definition for digitization - /** Energy deposit vector definition for digitization + /// Detector response vector definition for digitization + /** * * \author M.Frank * \version 1.0 @@ -540,6 +602,11 @@ namespace dd4hep { DetectorResponse& operator=(DetectorResponse&& copy) = default; /// Disable copy assignment DetectorResponse& operator=(const DetectorResponse& copy) = default; + + /// Merge new deposit map onto existing map (not thread safe!) + std::size_t merge(DetectorResponse&& updates); + /// Merge new deposit map onto existing map (not thread safe!) + std::size_t insert(const DetectorResponse& updates); /// Emplace entry void emplace(CellID cell, ADCValue&& value); @@ -571,6 +638,80 @@ namespace dd4hep { this->data.emplace_back(cell, std::move(value)); } + /// Detector history vector definition for digitization + /** + * + * \author M.Frank + * \version 1.0 + * \ingroup DD4HEP_DIGITIZATION + */ + class DetectorHistory : public SegmentEntry { + public: + using container_t = std::vector<std::pair<CellID, History> >; + using iterator = container_t::iterator; + using const_iterator = container_t::const_iterator; + + container_t data { }; + + public: + /// Initializing constructor + DetectorHistory(const std::string& name, Key::mask_type mask); + /// Default constructor + DetectorHistory() = default; + /// Disable move constructor + DetectorHistory(DetectorHistory&& copy) = default; + /// Disable copy constructor + DetectorHistory(const DetectorHistory& copy) = default; + /// Default destructor + virtual ~DetectorHistory() = default; + /// Disable move assignment + DetectorHistory& operator=(DetectorHistory&& copy) = default; + /// Disable copy assignment + DetectorHistory& operator=(const DetectorHistory& copy) = default; + + /// Merge new deposit map onto existing map (not thread safe!) + std::size_t merge(DetectorHistory&& updates); + /// Merge new deposit map onto existing map (not thread safe!) + std::size_t insert(const DetectorHistory& updates); + + /// Insert new entry + void insert(CellID cell, const History& value); + /// Emplace new entry + void emplace(CellID cell, History&& value); + + /// 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 DetectorHistory::DetectorHistory(const std::string& nam, Key::mask_type msk) + : SegmentEntry(nam, msk) + { + } + + /// Emplace new entry + inline void DetectorHistory::emplace(CellID cell, History&& value) { + this->data.emplace_back(cell, std::move(value)); + } + + /// Insert new entry + inline void DetectorHistory::insert(CellID cell, const History& value) { + this->data.emplace_back(cell, value); + } + + /// Data segment definition (locked map) /** * @@ -580,7 +721,8 @@ namespace dd4hep { */ class DataSegment { public: - using container_map_t = std::map<Key::key_type, std::any>; + using key_t = Key::key_type; + using container_map_t = std::map<Key, std::any>; using iterator = container_map_t::iterator; using const_iterator = container_map_t::const_iterator; @@ -598,10 +740,10 @@ namespace dd4hep { public: container_map_t data; std::mutex& lock; - + uint32_t id { 0 }; public: /// Initializing constructor - DataSegment(std::mutex& lock); + DataSegment(std::mutex& lock, int id); /// Default constructor DataSegment() = delete; /// Disable move constructor @@ -652,13 +794,13 @@ namespace dd4hep { /// End iteration iterator end() { return this->data.end(); } /// Find entry by key - iterator find(Key key) { return this->data.find(key.key); } + iterator find(Key key) { return this->data.find(key); } /// Begin iteration (CONST) const_iterator begin() const { return this->data.begin(); } /// End iteration (CONST) const_iterator end() const { return this->data.end(); } /// Find entry by key - const_iterator find(Key key) const { return this->data.find(key.key); } + const_iterator find(Key key) const { return this->data.find(key); } }; /// Access data as reference by key. If not existing, an exception is thrown @@ -713,7 +855,7 @@ namespace dd4hep { segment_t m_deposits; /// Helper: Save access with segment creation if it does not exist - DataSegment& access_segment(segment_t& seg); + DataSegment& access_segment(segment_t& seg, uint32_t id); public: /// Current event number diff --git a/DDDigi/include/DDDigi/DigiInputAction.h b/DDDigi/include/DDDigi/DigiInputAction.h index ca3690b12550fbd401242e3c569ed1203f9c0fd4..87fc6496692b75dfaad23fd5b16cb50c53833311 100644 --- a/DDDigi/include/DDDigi/DigiInputAction.h +++ b/DDDigi/include/DDDigi/DigiInputAction.h @@ -16,9 +16,6 @@ /// Framework include files #include <DDDigi/DigiEventAction.h> -/// C/C++ include files -#include <limits> - /// Namespace for the AIDA detector description toolkit namespace dd4hep { @@ -26,7 +23,6 @@ namespace dd4hep { namespace digi { // Forward declarations - class DigiAction; class DigiInputAction; /// Base class for input actions to the digitization @@ -60,7 +56,6 @@ namespace dd4hep { /// Callback to read event input virtual void execute(DigiContext& context) const override; }; - } // End namespace digi } // End namespace dd4hep #endif // DDDIGI_DIGIINPUTACTION_H diff --git a/DDDigi/include/DDDigi/DigiOutputAction.h b/DDDigi/include/DDDigi/DigiOutputAction.h new file mode 100644 index 0000000000000000000000000000000000000000..17314301fb723d082170999315fdfa5e5d058474 --- /dev/null +++ b/DDDigi/include/DDDigi/DigiOutputAction.h @@ -0,0 +1,64 @@ +//========================================================================== +// 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_DIGIOUTPUTACTION_H +#define DDDIGI_DIGIOUTPUTACTION_H + +/// Framework include files +#include <DDDigi/DigiEventAction.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 DigiOutputAction; + + /// Base class for output actions to the digitization + /** + * + * \author M.Frank + * \version 1.0 + * \ingroup DD4HEP_DIGITIZATION + */ + class DigiOutputAction : public DigiEventAction { + public: + enum { OUTPUT_START = -1 }; + enum { NO_MASK = 0x0 }; + + protected: + /// Array of data containers to be saved + std::vector<std::string> m_containers { }; + /// Property: Output data specification + std::string m_output { }; + /// Property: Mask to flag output source items + int m_mask { NO_MASK }; + + protected: + /// Define standard assignments and constructors + DDDIGI_DEFINE_ACTION_CONSTRUCTORS(DigiOutputAction); + + public: + /// Standard constructor + DigiOutputAction(const DigiKernel& kernel, const std::string& nam); + /// Default destructor + virtual ~DigiOutputAction(); + + /// Callback to read event output + virtual void execute(DigiContext& context) const override; + }; + + } // End namespace digi +} // End namespace dd4hep +#endif // DDDIGI_DIGIOUTPUTACTION_H diff --git a/DDDigi/include/DDDigi/DigiParallelWorkers.h b/DDDigi/include/DDDigi/DigiParallelWorkers.h index 33f9c8fcb629dbd9f60ebf67b6ac736fa2050ecf..a078abe4cdc3fa7d67bb89015e4a6c86d56c04a6 100644 --- a/DDDigi/include/DDDigi/DigiParallelWorkers.h +++ b/DDDigi/include/DDDigi/DigiParallelWorkers.h @@ -73,6 +73,7 @@ namespace dd4hep { std::size_t size() const; bool empty() const; bool insert(worker_t* entry) const; + void clear(); }; template <typename T> inline @@ -105,6 +106,13 @@ namespace dd4hep { bool DigiParallelWorkers<T>::empty() const { return actors.empty(); } + + template <typename T> inline + void DigiParallelWorkers<T>::clear() { + auto group = get_group(); // Lock worker array until no clients present + actors.clear(); + } + template <typename T> inline typename DigiParallelWorkers<T>::group_t DigiParallelWorkers<T>::get_group() const { return group_t(*this); diff --git a/DDDigi/include/DDDigi/DigiROOTInput.h b/DDDigi/include/DDDigi/DigiROOTInput.h index 46d9425ffd7bd670bf6806422a1c06fe4a945026..f52f7f7cdd4302d7b24dfd59e6fcb18b9ef42817 100644 --- a/DDDigi/include/DDDigi/DigiROOTInput.h +++ b/DDDigi/include/DDDigi/DigiROOTInput.h @@ -18,10 +18,6 @@ // C/C++ include files #include <memory> -#include <mutex> - -// Forward declarations -class TClass; /// Namespace for the AIDA detector description toolkit namespace dd4hep { diff --git a/DDDigi/include/DDDigi/DigiROOTOutput.h b/DDDigi/include/DDDigi/DigiROOTOutput.h new file mode 100644 index 0000000000000000000000000000000000000000..2f6575a286da6badd5c41d31c4f6f23bd15789d4 --- /dev/null +++ b/DDDigi/include/DDDigi/DigiROOTOutput.h @@ -0,0 +1,79 @@ +//========================================================================== +// AIDA Detector description implementation +//-------------------------------------------------------------------------- +// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN) +// All rights reserved. +// +// For the licensing terms see $DD4hepINSTALL/LICENSE. +// For the list of contributors see $DD4hepINSTALL/doc/CREDITS. +// +// Author : M.Frank +// +//========================================================================== +#ifndef DDDIGI_DIGIROOTOUTPUT_H +#define DDDIGI_DIGIROOTOUTPUT_H + +/// Framework include files +#include <DDDigi/DigiOutputAction.h> + +/// C/C++ include files +#include <memory> + +/// Forward declarations +class TFile; +class TTree; +class TBranch; + + +/// Namespace for the AIDA detector description toolkit +namespace dd4hep { + + /// Namespace for the Digitization part of the AIDA detector description toolkit + namespace digi { + + // Forward declarations + class DigiROOTOutput; + + /// Base class for output actions to the digitization + /** + * + * \author M.Frank + * \version 1.0 + * \ingroup DD4HEP_DIGITIZATION + */ + class DigiROOTOutput : public DigiOutputAction { + + protected: + /// Helper classes + class internals_t; + /// Property: Name of the tree to connect to + std::string m_tree_name { }; + /// Property: Segment name to place output data default: outputs + std::string m_location { }; + /// Property: name of the event tree + std::string m_section { }; + /// Property: File size limit + std::size_t m_max_file_size { std::numeric_limits<std::size_t>::max() }; + /// Property: vector with disabled collections + std::vector<std::string> m_disabledCollections { }; + /// Property: vector with disabled collections + bool m_disableParticles { false }; + + /// Connection parameters to the "current" output source + std::unique_ptr<internals_t> imp { }; + + protected: + /// Define standard assignments and constructors + DDDIGI_DEFINE_ACTION_CONSTRUCTORS(DigiROOTOutput); + + public: + /// Standard constructor + DigiROOTOutput(const DigiKernel& kernel, const std::string& nam); + /// Default destructor + virtual ~DigiROOTOutput(); + /// Callback to read event output + virtual void execute(DigiContext& context) const override; + }; + } // End namespace digi +} // End namespace dd4hep +#endif // DDDIGI_DIGIROOTOUTPUT_H diff --git a/DDDigi/plugins/Components.cpp b/DDDigi/plugins/Components.cpp index abfe7880fc80658e1fc2a4a419a6817650d9fc98..b9ef72ec906249a0c1a86537b408798849161761 100644 --- a/DDDigi/plugins/Components.cpp +++ b/DDDigi/plugins/Components.cpp @@ -27,6 +27,12 @@ DECLARE_DIGIACTION_NS(dd4hep::digi,DigiInputAction) #include <DDDigi/DigiROOTInput.h> DECLARE_DIGIACTION_NS(dd4hep::digi,DigiROOTInput) +#include <DDDigi/DigiOutputAction.h> +DECLARE_DIGIACTION_NS(dd4hep::digi,DigiOutputAction) + +#include <DDDigi/DigiROOTOutput.h> +DECLARE_DIGIACTION_NS(dd4hep::digi,DigiROOTOutput) + #include <DDDigi/DigiSynchronize.h> DECLARE_DIGIACTION_NS(dd4hep::digi,DigiSynchronize) @@ -54,6 +60,9 @@ DECLARE_DIGIACTION_NS(dd4hep::digi,DigiAttenuatorSequence) #include <DDDigi/DigiContainerCombine.h> DECLARE_DIGIACTION_NS(dd4hep::digi,DigiContainerCombine) +#include <DDDigi/DigiContainerDrop.h> +DECLARE_DIGIACTION_NS(dd4hep::digi,DigiContainerDrop) + #include <DDDigi/DigiSegmentProcessor.h> DECLARE_DIGIACTION_NS(dd4hep::digi,DigiSegmentProcessor) DECLARE_DIGIACTION_NS(dd4hep::digi,DigiSegmentSequence) diff --git a/DDDigi/plugins/DigiDepositSmearing.cpp b/DDDigi/plugins/DigiDepositSmearing.cpp new file mode 100644 index 0000000000000000000000000000000000000000..da28a26234e2de48b53edd7a0a39627ff6ae3a79 --- /dev/null +++ b/DDDigi/plugins/DigiDepositSmearing.cpp @@ -0,0 +1,87 @@ +//========================================================================== +// 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/DigiContainerProcessor.h> + +/// C/C++ include files +#include <limits> + +/// Namespace for the AIDA detector description toolkit +namespace dd4hep { + /// Namespace for the Digitization part of the AIDA detector description toolkit + namespace digi { + + /// Actor to smear geographically energy deposits + /** + * + * \author M.Frank + * \version 1.0 + * \ingroup DD4HEP_DIGITIZATION + */ + class DigiDepositSmearing : public DigiContainerProcessor { + protected: + /// Property: Energy cutoff. No hits will be merged with a deposit smaller + double m_cutoff { std::numeric_limits<double>::epsilon() }; + /// Property: register empty containers + bool m_register_empty_containers { true }; + + public: + /// Standard constructor + DigiDepositSmearing(const DigiKernel& krnl, const std::string& nam) + : DigiContainerProcessor(krnl, nam) + { + declareProperty("deposit_cutoff", m_cutoff); + declareProperty("m_register_empty_containers", m_register_empty_containers); + } + + /// Create deposit mapping with updates on same cellIDs + template <typename T> void create_deposits(const T& cont, work_t& work) const { + Key key(cont.name, work.output.mask); + DepositMapping m(cont.name, work.output.mask); + std::size_t dropped = 0UL, updated = 0UL, added = 0UL; + for( const auto& dep : cont ) { + const EnergyDeposit& depo = dep.second; + if ( depo.deposit >= m_cutoff ) { + CellID cell = dep.first; + auto iter = m.data.find(cell); + if ( iter == m.data.end() ) + m.data.emplace(dep.first, depo), ++added; + else + iter->second.update_deposit_weighted(depo), ++updated; + continue; + } + ++dropped; + } + if ( m_register_empty_containers ) { + work.output.data.put(m.key, std::move(m)); + } + info("+++ %-32s added %6ld updated %6ld dropped %6ld entries (now: %6ld) from mask: %04X to mask: %04X", + cont.name.c_str(), added, updated, dropped, m.size(), cont.key.mask(), m.key.mask()); + } + + /// Main functional callback + virtual void execute(DigiContext&, work_t& work) const override final { + if ( const auto* v = work.get_input<DepositVector>() ) + create_deposits(*v, work); + else if ( const auto* m = work.get_input<DepositMapping>() ) + create_deposits(*m, work); + else + except("Request to handle unknown data type: %s", work.input_type_name().c_str()); + } + }; + } // End namespace digi +} // End namespace dd4hep + +#include <DDDigi/DigiFactories.h> +DECLARE_DIGIACTION_NS(dd4hep::digi,DigiDepositSmearing) diff --git a/DDDigi/plugins/DigiDepositWeightedPosition.cpp b/DDDigi/plugins/DigiDepositWeightedPosition.cpp index 8a5ae36d48ee6f23c4fe65240a55e60f28109bfa..80ef0b495e8787be9789b99fd7d950c0142f3f94 100644 --- a/DDDigi/plugins/DigiDepositWeightedPosition.cpp +++ b/DDDigi/plugins/DigiDepositWeightedPosition.cpp @@ -22,9 +22,8 @@ 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 - * + /// Actor to merge energy deposits weighted with their energy deposit + /** * The selected deposits are placed in the output container * supplied by the arguments. Multiple CellIDs will be merged to one single * deposit, where the merge computes the resulting position and diff --git a/DDDigi/plugins/DigiHitHistoryDrop.cpp b/DDDigi/plugins/DigiHitHistoryDrop.cpp index b4da3d172a1ce476cd96a860d4494e0fcdfcf923..652129098a2027e16a894e715e2e93f485154d64 100644 --- a/DDDigi/plugins/DigiHitHistoryDrop.cpp +++ b/DDDigi/plugins/DigiHitHistoryDrop.cpp @@ -59,6 +59,18 @@ namespace dd4hep { InstanceCount::increment(this); } + template <typename T> + std::pair<std::size_t, std::size_t> drop_history(T& cont) const { + std::size_t num_drop_hit = 0; + std::size_t num_drop_particle = 0; + for( auto& c : cont ) { + auto ret = c.second.history.drop(); + num_drop_hit += ret.first; + num_drop_particle += ret.second; + } + return std::make_pair(num_drop_hit,num_drop_particle); + } + /// Main functional callback virtual void execute(DigiContext& context) const final { auto& inputs = context.event->get_segment(m_input); @@ -69,20 +81,14 @@ namespace dd4hep { auto im = std::find(m_masks.begin(), m_masks.end(), key.mask()); if ( im != m_masks.end() ) { if ( DepositMapping* m = std::any_cast<DepositMapping>(&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(); - } + auto ret = drop_history(*m); + num_drop_hit += ret.first; + num_drop_particle += ret.second; } 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(); - } + auto ret = drop_history(*m); + num_drop_hit += ret.first; + num_drop_particle += ret.second; } } } diff --git a/DDDigi/plugins/DigiSegmentDepositExtractor.cpp b/DDDigi/plugins/DigiSegmentDepositExtractor.cpp index bb6a5ebc2529fd32304e1625cd4b492493f06ff5..7ee93ee136647773d4148e5f562467c22e7a1d29 100644 --- a/DDDigi/plugins/DigiSegmentDepositExtractor.cpp +++ b/DDDigi/plugins/DigiSegmentDepositExtractor.cpp @@ -47,7 +47,7 @@ namespace dd4hep { } /// Main functional callback virtual void execute(DigiContext&, work_t& work) const override final { - if ( segment.matches(work.input.key.key) ) { + if ( segment.matches(work.input.key.value()) ) { if ( const auto* m = work.get_input<DepositMapping>() ) copy_deposits(*m, work); else if ( const auto* v = work.get_input<DepositVector>() ) diff --git a/DDDigi/plugins/DigiSegmentDepositPrint.cpp b/DDDigi/plugins/DigiSegmentDepositPrint.cpp index a8fa3b1a388275d83e3fd8fea5bdaad063d7e25a..a76fa9f06c81d482ee60dcda043e13469300d509 100644 --- a/DDDigi/plugins/DigiSegmentDepositPrint.cpp +++ b/DDDigi/plugins/DigiSegmentDepositPrint.cpp @@ -35,8 +35,8 @@ namespace dd4hep { 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.history.hits.size(), + depo.history.particles.size(), depo.deposit); } /// Main functional callback @@ -54,7 +54,7 @@ namespace dd4hep { else if ( const auto* v = work.get_input<DepositVector>() ) std::for_each(v->begin(), v->end(), call); else - error("+++ Request to dump an invalid container %s", Key::key_name(work.input.key.item()).c_str()); + error("+++ Request to dump an invalid container %s", Key::key_name(work.input.key).c_str()); } }; } // End namespace digi diff --git a/DDDigi/plugins/DigiSimpleADCResponse.cpp b/DDDigi/plugins/DigiSimpleADCResponse.cpp index 029f4ebc808c9644b8a0d24d3b77f9c9cc20ade9..b540f1d9a0c7479c713341e99f60840fc9b2b969 100644 --- a/DDDigi/plugins/DigiSimpleADCResponse.cpp +++ b/DDDigi/plugins/DigiSimpleADCResponse.cpp @@ -24,7 +24,8 @@ namespace dd4hep { namespace digi { class DigiSimpleADCResponse : public DigiSegmentProcessor { - std::string m_name_postfix { ".adc" }; + std::string m_response_postfix { ".adc" }; + std::string m_history_postfix { ".hist" }; double m_use_segmentation { false }; double m_signal_cutoff { std::numeric_limits<double>::epsilon() }; double m_signal_saturation { std::numeric_limits<double>::max() }; @@ -35,29 +36,34 @@ namespace dd4hep { DigiSimpleADCResponse(const DigiKernel& krnl, const std::string& nam) : DigiSegmentProcessor(krnl, nam) { - declareProperty("cutoff", m_signal_cutoff); - declareProperty("saturation", m_signal_saturation); - declareProperty("adc_resolution", m_adc_resolution); - declareProperty("name_postfix", m_name_postfix); + declareProperty("cutoff", m_signal_cutoff); + declareProperty("saturation", m_signal_saturation); + declareProperty("adc_resolution", m_adc_resolution); + declareProperty("response_postfix", m_response_postfix); + declareProperty("history_postfix", m_history_postfix); } /// Create container with ADC counts and register it to the output segment template <typename T, typename P> void create_adc_counts(const char* tag, const T& input, work_t& work, const P& predicate) const { std::string postfix = m_use_segmentation ? "."+segment.identifier() : std::string(); - std::string outname = input.name + postfix + m_name_postfix; - DetectorResponse response(outname, work.output.mask); + std::string response_name = input.name + postfix + m_response_postfix; + std::string history_name = input.name + postfix + m_history_postfix; + DetectorResponse response(response_name, work.output.mask); + DetectorHistory history (history_name, work.output.mask); for( const auto& dep : input ) { if ( predicate(dep) ) { CellID cell = dep.first; const auto& depo = dep.second; ADCValue::value_t adc_count = std::round((depo.deposit * m_adc_resolution) / m_signal_saturation); response.emplace(cell, {adc_count, ADCValue::address_t(cell)}); + history.insert(cell, depo.history); } } info("%s+++ %-32s %6ld ADC values. Input: %-32s %6ld deposits", tag, - outname.c_str(), response.size(), input.name.c_str(), input.size()); + response_name.c_str(), response.size(), input.name.c_str(), input.size()); work.output.data.put(response.key, std::move(response)); + work.output.data.put(history.key, std::move(history)); } /// Create container with ADC counts and register it to the output segment template <typename P> @@ -75,7 +81,7 @@ namespace dd4hep { virtual void execute(DigiContext& context, work_t& work) const override final { if ( !m_use_segmentation ) create_adc_counts(context, work, accept_all_t()); - else if ( segment.matches(work.input.key.key) ) + else if ( segment.matches(work.input.key.value()) ) create_adc_counts(context, work, accept_segment_t(segment)); } }; diff --git a/DDDigi/python/dddigi.py b/DDDigi/python/dddigi.py index e36dffcdb2521f8528e8fa5f468b064b9e21703b..40e4d1bf73670bdacdcdf7d1e5b2510c40042944 100644 --- a/DDDigi/python/dddigi.py +++ b/DDDigi/python/dddigi.py @@ -159,11 +159,27 @@ def _setKernelProperty(self, name, value): # --------------------------------------------------------------------------- +def TestAction(kernel, nam, sleep=0): + obj = Interface.createAction(kernel, str('DigiTestAction/' + nam)) + if sleep != 0: + obj.sleep = sleep + return obj +# --------------------------------------------------------------------------- + + +def Action(kernel, nam, **options): + action = Interface.createAction(kernel, str(nam)) + for option in options.items(): + setattr(action, option[0], option[1]) + return action +# --------------------------------------------------------------------------- + + def _get_action(self): return Interface.toAction(self) - #if hasattr(self, 'I_am_a_ROOT_interface_handle'): - # return Interface.toAction(self.get()) - #return self + # if hasattr(self, 'I_am_a_ROOT_interface_handle'): + # return Interface.toAction(self.get()) + # return self # --------------------------------------------------------------------------- @@ -214,13 +230,6 @@ Kernel.terminate = _kernel_terminate # --------------------------------------------------------------------------- -def _get_container_processor(self): - if hasattr(self, 'I_am_a_ROOT_interface_handle'): - return Interface.toContainerProcessor(self.get()) - return self -# --------------------------------------------------------------------------- - - def _default_adopt(self, action): getattr(self, '__adopt')(action.get()) # --------------------------------------------------------------------------- @@ -228,22 +237,23 @@ def _default_adopt(self, action): def _adopt_event_action(self, action): " Helper to convert DigiActions objects to DigiEventAction " - getattr(self, '__adopt')(Interface.toEventAction(action.get())) + proc = Interface.toEventAction(_get_action(action)) + attr = getattr(self, '__adopt') + attr(proc) # --------------------------------------------------------------------------- -def _adopt_processor_action(self, action, container): +def _adopt_container_processor(self, action, container): " Helper to convert DigiActions objects to DigiEventAction " - attr = getattr(self, 'adopt_processor') - proc = _get_container_processor(action) + attr = getattr(_get_action(self), 'adopt_processor') + proc = Interface.toContainerProcessor(_get_action(action)) attr(proc, container) - # print('ContainerProcessor succesfully adopted') # --------------------------------------------------------------------------- def _adopt_sequence_action(self, name, **options): " Helper to adopt DigiAction objects for DigiSynchronize " - kernel = Interface.createKernel(Interface.toAction(self)) + kernel = Interface.createKernel(_get_action(self)) action = Action(kernel, name) for option in options.items(): setattr(action, option[0], option[1]) @@ -253,16 +263,8 @@ def _adopt_sequence_action(self, name, **options): def _adopt_processor(self, action, containers): - getattr(self, '__adopt_processor')(action.get(), containers) -# --------------------------------------------------------------------------- - - -def _setup(obj, call='adopt', py_call=_default_adopt): - _import_class('digi', obj) - cls = getattr(current, obj) - setattr(cls, '__' + call, getattr(cls, call)) - setattr(cls, call, py_call) - return cls + proc = Interface.toContainerProcessor(_get_action(action)) + attr = getattr(_get_action(self), '__adopt_processor')(proc, containers) # --------------------------------------------------------------------------- @@ -283,12 +285,12 @@ def _get(self, name): def _set(self, name, value): """This function is called when properties are passed to the c++ objects.""" import dd4hep as dd4hep - a = Interface.toAction(self) + action = _get_action(self) name = dd4hep.unicode_2_string(name) value = dd4hep.unicode_2_string(value) - if Interface.setProperty(a, name, value): + if Interface.setProperty(action, name, value): return - msg = 'DigiAction::SetProperty [Unhandled]: Cannot set ' + a.name() + '.' + name + ' = ' + value + msg = 'DigiAction::SetProperty [Unhandled]: Cannot set ' + action.name() + '.' + name + ' = ' + value raise KeyError(msg) # --------------------------------------------------------------------------- @@ -297,37 +299,25 @@ def _props(obj, **extensions): _import_class('digi', obj) cls = getattr(current, obj) for extension in extensions.items(): - setattr(cls, extension[0], extension[1]) + call = extension[0] + if hasattr(cls, call): + setattr(cls, '__' + call, getattr(cls, call)) + setattr(cls, call, extension[1]) cls.__getattr__ = _get cls.__setattr__ = _set return cls # --------------------------------------------------------------------------- -def TestAction(kernel, nam, sleep=0): - obj = Interface.createAction(kernel, str('DigiTestAction/' + nam)) - if sleep != 0: - obj.sleep = sleep - return obj -# --------------------------------------------------------------------------- - - -def Action(kernel, nam, **options): - action = Interface.createAction(kernel, str(nam)) - for option in options.items(): - setattr(action, option[0], option[1]) - return action -# --------------------------------------------------------------------------- - - -_setup('DigiSynchronize', call='adopt', py_call=_adopt_event_action) -_setup('DigiActionSequence', call='adopt', py_call=_adopt_event_action) - +# +# Import unmodified classes from C++ _import_class('digi', 'DigiKernel') _import_class('digi', 'DigiContext') _import_class('digi', 'DigiAction') _import_class('digi', 'DigiEventAction') _import_class('digi', 'DigiInputAction') +# +# Import classes with specialized python extensions _props('ActionHandle', adopt_property=_adopt_property, add_property=_add_property, @@ -336,15 +326,13 @@ _props('ActionHandle', add_list_property=_add_list_property, add_vector_property=_add_vector_property, add_mapped_property=_add_mapped_property) -_props('DigiSynchronize', adopt_action=_adopt_sequence_action) -_props('DigiActionSequence', adopt_action=_adopt_sequence_action) +_props('DigiSynchronize', adopt=_adopt_event_action, adopt_action=_adopt_sequence_action) +_props('DigiActionSequence', adopt=_adopt_event_action, 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) - - +_props('DigiContainerSequenceAction', adopt_container_processor=_adopt_container_processor) +_props('DigiMultiContainerProcessor', adopt_processor=_adopt_processor) +# # Need to import digitize late, since it cross includes dddigi Digitize = None try: diff --git a/DDDigi/src/DigiAttenuator.cpp b/DDDigi/src/DigiAttenuator.cpp index 3eb43cde4887b27a65f7898672ce6ae6dbfc05ba..42f4746f38983b00a914d8e0d5dbdb44bbecbfe1 100644 --- a/DDDigi/src/DigiAttenuator.cpp +++ b/DDDigi/src/DigiAttenuator.cpp @@ -44,8 +44,12 @@ DigiAttenuator::~DigiAttenuator() { /// Attenuator callback for single container template <typename T> std::size_t DigiAttenuator::attenuate(T& cont) const { - for( auto& c : cont ) - c.second.deposit *= m_factor; + for( auto& c : cont ) { + auto& depo = c.second; + depo.deposit *= m_factor; + for( auto& h : depo.history.hits ) h.weight *= m_factor; + for( auto& h : depo.history.particles ) h.weight *= m_factor; + } return cont.size(); } diff --git a/DDDigi/src/DigiContainerCombine.cpp b/DDDigi/src/DigiContainerCombine.cpp index 2fa76e7eeb614528e74ff62d91e523e0a5a01df8..8f144b346522d6d95fa08e17ab5ef66d367cc64b 100644 --- a/DDDigi/src/DigiContainerCombine.cpp +++ b/DDDigi/src/DigiContainerCombine.cpp @@ -47,7 +47,7 @@ public: keys.reserve(inputs.size()); work.reserve(inputs.size()); for( auto& i : inputs ) { - Key key = i.first; + Key key(i.first); if ( combine->use_key(key) ) { keys.emplace_back(key); work.emplace_back(&i.second); @@ -60,29 +60,57 @@ public: format[sizeof(format)-1] = 0; } - template<typename T> void merge_depos(DepositVector& output, T& input, int thr) { + template<typename OUT, typename IN> void merge_depos(OUT& output, IN& 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->debug(this->format, thr, input.name.c_str(), input.key.values.mask, cnt, "deposits"); + combine->debug(this->format, thr, input.name.c_str(), input.key.mask(), cnt, "deposits"); this->cnt_depos += cnt; this->cnt_conts++; } - void merge(const std::string& nam, size_t start, int thr) { + void merge_hist(const std::string& nam, size_t start, int thr) { + std::size_t cnt; Key key = keys[start]; - DepositVector out(nam, combine->m_deposit_mask); - for( std::size_t j = start; j < keys.size(); ++j ) { + DetectorHistory 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(); + DetectorHistory* next = std::any_cast<DetectorHistory>(work[j]); + if ( combine->m_erase_combined ) { + cnt = out.merge(std::move(*next)); + work[j]->reset(); + } + else { + cnt = out.insert(*next); + } + combine->debug(format, thr, next->name.c_str(), keys[j].mask(), cnt, "histories"); + cnt_parts += cnt; + cnt_conts++; + } + } + key.set_mask(combine->m_deposit_mask); + outputs.emplace(key, std::move(out)); + } + + void merge_response(const std::string& nam, size_t start, int thr) { + std::size_t cnt; + Key key = keys[start]; + DetectorResponse out(nam, combine->m_deposit_mask); + for( std::size_t j=start; j < keys.size(); ++j ) { + if ( keys[j].item() == key.item() ) { + DetectorResponse* next = std::any_cast<DetectorResponse>(work[j]); + if ( combine->m_erase_combined ) { + cnt = out.merge(std::move(*next)); + work[j]->reset(); + } + else { + cnt = out.insert(*next); + } + combine->debug(format, thr, next->name.c_str(), keys[j].mask(), cnt, "histories"); + cnt_parts += cnt; + cnt_conts++; } } key.set_mask(combine->m_deposit_mask); @@ -90,16 +118,42 @@ public: } void merge_parts(const std::string& nam, size_t start, int thr) { + std::size_t cnt; 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)); + if ( combine->m_erase_combined ) { + cnt = out.merge(std::move(*next)); + work[j]->reset(); + } + else { + cnt = out.insert(*next); + } combine->debug(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(const std::string& nam, size_t start, int thr) { + Key key = keys[start]; + DepositVector 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 + break; + if ( combine->m_erase_combined ) + this->work[j]->reset(); + break; } } key.set_mask(combine->m_deposit_mask); @@ -109,23 +163,29 @@ public: 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 ) + if ( keys[i].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 detector response + else if ( DetectorResponse* resp = std::any_cast<DetectorResponse>(work[i]) ) { + merge_response(resp->name+opt, i, thr); + } + /// Merge response history + else if ( DetectorHistory* hist = std::any_cast<DetectorHistory>(work[i]) ) { + merge_hist(hist->name+opt, i, thr); } /// Merge particle container else if ( ParticleMapping* parts = std::any_cast<ParticleMapping>(work[i]) ) { merge_parts(parts->name+opt, i, thr); - break; } + break; } } @@ -173,14 +233,14 @@ DigiContainerCombine::~DigiContainerCombine() { void DigiContainerCombine::initialize() { for ( const auto& cont : m_containers ) { Key key(cont, 0x0); - m_cont_keys.emplace(key.key); + m_cont_keys.emplace(key.item()); if ( m_input_masks.empty() ) { - m_keys.emplace(key.key); + m_keys.emplace(key.value()); continue; } for ( int m : m_input_masks ) { - key.values.mask = m; - m_keys.emplace(key.key); + key.set_mask(m); + m_keys.emplace(key.value()); } } if ( !m_output_name_flag.empty() ) @@ -201,8 +261,10 @@ 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(); + if ( !m_cont_keys.empty() ) { + key.set_mask(0); + return m_cont_keys.find(key.value()) != m_cont_keys.end(); + } return std::find(m.begin(), m.end(), key.mask()) != m.end(); } return true; diff --git a/DDDigi/src/DigiContainerDrop.cpp b/DDDigi/src/DigiContainerDrop.cpp new file mode 100644 index 0000000000000000000000000000000000000000..75a69639d05d2fc992d83a586b7123a7b0ca7419 --- /dev/null +++ b/DDDigi/src/DigiContainerDrop.cpp @@ -0,0 +1,158 @@ +//========================================================================== +// 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/DigiContainerDrop.h> + +/// C/C++ include files +#include <set> + +using namespace dd4hep::digi; + +class DigiContainerDrop::work_definition_t { +public: + const DigiContainerDrop* drop; + std::vector<Key> keys; + std::vector<std::any*> work; + std::set<Key::itemkey_type> items; + + DigiEvent& event; + DataSegment& inputs; + + /// Initializing constructor + work_definition_t(const DigiContainerDrop* c, DigiEvent& ev, DataSegment& in) + : drop(c), event(ev), inputs(in) + { + keys.reserve(inputs.size()); + work.reserve(inputs.size()); + for( auto& i : inputs ) { + Key key(i.first); + if ( drop->use_key(key) ) { + keys.emplace_back(key); + work.emplace_back(&i.second); + items.insert(key.item()); + } + } + } + + void drop_one(Key::itemkey_type itm) { + for( std::size_t i=0; i < keys.size(); ++i ) { + if ( keys[i].item() != itm ) + continue; + /// Drop deposit mapping + if ( std::any_cast<DepositMapping>(work[i]) ) + work[i]->reset(); + /// Drop deposit vector + else if ( std::any_cast<DepositVector>(work[i]) ) + work[i]->reset(); + /// Drop particle container + else if ( std::any_cast<ParticleMapping>(work[i]) ) + work[i]->reset(); + /// Drop deposit history + else if ( std::any_cast<DetectorHistory>(work[i]) ) + work[i]->reset(); + /// Drop detector response + else if ( std::any_cast<DetectorResponse>(work[i]) ) + work[i]->reset(); + break; + } + } + + void drop_all() { + for( auto itm : items ) + drop_one(itm); + } +}; + +template <> void DigiParallelWorker<DigiContainerDrop, + DigiContainerDrop::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->drop_one(itm); + return; + } + ++cnt; + } +} + +/// Standard constructor +DigiContainerDrop::DigiContainerDrop(const DigiKernel& krnl, const std::string& nam) + : DigiEventAction(krnl, nam) +{ + declareProperty("containers", m_containers); + declareProperty("input_masks", m_input_masks); + declareProperty("input_segment", m_input = "inputs"); + m_kernel.register_initialize(Callback(this).make(&DigiContainerDrop::initialize)); + InstanceCount::increment(this); +} + +/// Default destructor +DigiContainerDrop::~DigiContainerDrop() { + InstanceCount::decrement(this); +} + +/// Initializing function: compute values which depend on properties +void DigiContainerDrop::initialize() { + for ( const auto& cont : m_containers ) { + Key key(cont, 0x0); + m_cont_keys.emplace(key.value()); + if ( m_input_masks.empty() ) { + m_keys.emplace(key.value()); + continue; + } + for ( int m : m_input_masks ) { + key.set_mask(m); + m_keys.emplace(key.value()); + } + } +} + +/// Decide if a continer is to dropd based on the properties +bool DigiContainerDrop::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; +} + +/// Main functional callback +void DigiContainerDrop::execute(DigiContext& context) const { + auto& event = *context.event; + auto& inputs = event.get_segment(m_input); + work_definition_t def(this, event, inputs); + if ( m_parallel ) { + size_t count = def.items.size(); + if ( m_workers.size() < count ) { + auto group = m_workers.get_group(); // Lock worker group + for(size_t i=m_workers.size(); i <= count; ++i) + m_workers.insert(new Worker(nullptr, i)); + } + m_kernel.submit(context, m_workers.get_group(), def.items.size(), &def); + } + else { + def.drop_all(); + } + inputs.erase(def.keys); +} + diff --git a/DDDigi/src/DigiContainerProcessor.cpp b/DDDigi/src/DigiContainerProcessor.cpp index 87adb9f3932d4a437e2873ebe83dcbfdacee8efd..758f75162a8246d43572294c78d691488810ac60 100644 --- a/DDDigi/src/DigiContainerProcessor.cpp +++ b/DDDigi/src/DigiContainerProcessor.cpp @@ -98,7 +98,7 @@ void DigiContainerProcessor::execute(DigiContext& context, work_t& work) const /// 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()); + context.event->id(), (void*)this, key.value(), key.mask(), key.item(), Key::key_name(key).c_str()); } /// Standard constructor @@ -156,9 +156,8 @@ DigiContainerSequenceAction::~DigiContainerSequenceAction() { /// Initialization callback void dd4hep::digi::DigiContainerSequenceAction::initialize() { for( auto& ent : m_registered_processors ) { - Key key = ent.first; worker_t* w = new worker_t(ent.second, m_registered_workers.size()); - m_registered_workers.emplace(key.item(), w); + m_registered_workers.emplace(ent.first, w); m_workers.insert(w); } } @@ -168,7 +167,7 @@ void DigiContainerSequenceAction::adopt_processor(DigiContainerProcessor* action const std::string& container) { Key key(container, 0x0); - auto it = m_registered_processors.find(key.item()); + auto it = m_registered_processors.find(key); if ( it != m_registered_processors.end() ) { if ( action != it->second ) { except("+++ The action %s was already registered to mask:%04X container:%s!", @@ -181,7 +180,7 @@ void DigiContainerSequenceAction::adopt_processor(DigiContainerProcessor* action return; } action->addRef(); - m_registered_processors.emplace(key.item(), action); + m_registered_processors.emplace(key, action); info("+++ Adding processor: %s for container: [%08X] %s", action->c_name(), key.item(), container.c_str()); } @@ -199,9 +198,8 @@ void DigiContainerSequenceAction::adopt_processor(DigiContainerProcessor* action /// Get hold of the registered processor for a given container DigiContainerSequenceAction::worker_t* DigiContainerSequenceAction::need_registered_worker(Key item_key, bool exc) const { - Key key; - key.set_item(item_key.item()); - auto it = m_registered_workers.find(item_key.item()); + item_key.set_mask(0); + auto it = m_registered_workers.find(item_key); if ( it != m_registered_workers.end() ) { return it->second; } @@ -218,9 +216,9 @@ void DigiContainerSequenceAction::execute(DigiContext& context) const { auto& outputs = event.get_segment(m_output_segment); std::vector<ParallelWorker*> event_workers; output_t output { m_output_mask, outputs }; - work_t args { context, {}, output, m_properties, *this }; + work_t args { context, { }, output, m_properties, *this }; - args.input_items.resize(m_workers.size(), {0, nullptr}); + args.input_items.resize(m_workers.size(), { { }, nullptr }); event_workers.reserve(inputs.size()); for( auto& i : inputs ) { Key key(i.first); @@ -254,6 +252,7 @@ DigiMultiContainerProcessor::DigiMultiContainerProcessor(const DigiKernel& krnl, this->declareProperty("input_segment", m_input_segment); this->declareProperty("output_mask", m_output_mask); this->declareProperty("output_segment", m_output_segment); + m_kernel.register_initialize(Callback(this).make(&DigiMultiContainerProcessor::initialize)); InstanceCount::increment(this); } @@ -262,6 +261,58 @@ DigiMultiContainerProcessor::~DigiMultiContainerProcessor() { InstanceCount::decrement(this); } +/// Initialize action object +void DigiMultiContainerProcessor::initialize() { + std::map<processor_t*,worker_t*> action_workers; + std::map<processor_t*,std::vector<Key> > keys; + std::map<processor_t*,std::vector<std::string> > action_containers; + + m_worker_keys.clear(); + m_worker_map.clear(); + m_work_items.clear(); + m_workers.clear(); + for( auto& proc : m_processors ) { + Key key(proc.first, 0x0); + m_work_items.insert(key); + for ( auto* action : proc.second ) { + keys[action].push_back(key); + action_containers[action].push_back(proc.first); + } + } + /// We need to preserve the order the actions were submitted + /// and remove later added duplicates (for different containers) + for( auto* action : m_actions ) { + auto worker_keys = keys[action]; + worker_t* w = nullptr; + auto iw = action_workers.find(action); + if ( iw != action_workers.end() ) { + w = iw->second; + } + else { + w = new worker_t(action, m_workers.size()); + m_worker_keys.emplace_back(worker_keys); + m_workers.insert(w); + action_workers[action] = w; + } + for( auto key : worker_keys ) + m_worker_map[key.item()].push_back(w); + } + /// Add some printout about the configuration + for(auto* action : m_actions ) { + auto conts = action_containers[action]; + std::stringstream str; + str << "[ "; + for( const auto& cont : conts ) + str << cont << " "; + str << "]"; + info("+++ Use processor: %-32s for processing: %s", action->c_name(), str.str().c_str()); + } + /// All done: release reference count aquired in adopt_processor + for(auto* action : m_actions ) + action->release(); +} + +/// Adopt new parallel worker void DigiMultiContainerProcessor::adopt_processor(DigiContainerProcessor* action, const std::vector<std::string>& containers) { if ( !action ) { except("+++ Attempt to use invalid processor. Request FAILED."); @@ -269,19 +320,13 @@ void DigiMultiContainerProcessor::adopt_processor(DigiContainerProcessor* action 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 << " "; + m_processors[cont].push_back(action); + } + if ( std::find(m_actions.begin(), m_actions.end(), action) == m_actions.end() ) { + m_actions.emplace_back(action); + action->addRef(); } - 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 @@ -293,10 +338,11 @@ void DigiMultiContainerProcessor::execute(DigiContext& context) const { 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(); + Key key(i.first); + key.set_mask(0); + bool use = msk.empty() || std::find(msk.begin(), msk.end(), key.mask()) != msk.end(); if ( use ) { - use = m_work_items.empty() || m_work_items.find(in_key.item()) != m_work_items.end(); + use = m_work_items.empty() || m_work_items.find(key) != m_work_items.end(); if ( use ) { work_items.emplace_back(std::make_pair(i.first, &i.second)); } @@ -319,17 +365,28 @@ template <> void DigiParallelWorker<DigiContainerProcessor, const auto& keys = par.worker_keys(this->options); const auto& masks = par.input_masks(); for( const auto& item : arg->items ) { - Key key = item.first; + Key key(item.first); + key.set_mask(0); + const char* tag = ""; if ( masks.empty() || std::find(masks.begin(), masks.end(), key.mask()) != masks.end() ) { + tag = "mask accepted"; if ( keys.empty() ) { DigiContainerProcessor::work_t work {arg->context, {key, *item.second }, arg->output, arg->properties }; action->execute(work.context, work); + continue; } - else if ( std::find(keys.begin(), keys.end(), Key(key.item())) != keys.end() ) { + else if ( std::find(keys.begin(), keys.end(), key) != keys.end() ) { DigiContainerProcessor::work_t work {arg->context, {key, *item.second }, arg->output, arg->properties }; action->execute(work.context, work); + continue; } + tag = "no keys matching"; } + if ( tag ) {} +#if 0 + par.info("%s+++ Ignore container: %016lX --> %04X %08X %s [%s]", + arg->context.event->id(), key.value(), key.mask(), key.item(), Key::key_name(key).c_str(), tag); +#endif } } diff --git a/DDDigi/src/DigiData.cpp b/DDDigi/src/DigiData.cpp index 7cdf283b01936d589239b7ff539181122a35ca2b..518d6cf5fb9bf06edb8de56b530ab01aca19c501 100644 --- a/DDDigi/src/DigiData.cpp +++ b/DDDigi/src/DigiData.cpp @@ -41,27 +41,48 @@ void Key::set(const std::string& name, int mask) { except("DDDigi::Key", "+++ No key name was specified -- this is illegal!"); } this->key = 0; - this->values.mask = (Key::mask_type)(0xFFFF&mask); - this->values.item = detail::hash32(name); + this->set_mask(Key::mask_type(0xFFFF&mask)); + this->set_item(detail::hash32(name)); std::lock_guard<std::mutex> lock(_k.lock); _k.map[this->key] = name; } +/// Set key submask +Key& Key::set_submask(const char* opt_tag) { + submask_type sm = detail::hash16(opt_tag); + this->values.submask = sm; + return *this; +} + /// Access key name (if registered properly) std::string Key::key_name(const Key& k) { auto& _k = keys(); std::lock_guard<std::mutex> lock(_k.lock); - std::map<unsigned long, std::string>::const_iterator it = _k.map.find(k.key); + std::map<unsigned long, std::string>::const_iterator it = _k.map.find(k.value()); if ( it != _k.map.end() ) return it->second; Key kk; - kk.values.item = ~0x0; + kk.set_item(~0x0); for( const auto& e : _k.map ) { - if ( (e.first & kk.key) == k.values.item ) + if ( (e.first & kk.value()) == k.values.item ) return e.second; } return "UNKNOWN"; } +/// Update history +void History::update(const History& upda) { + hits.insert(hits.end(), upda.hits.begin(), upda.hits.end()); + particles.insert(particles.end(), upda.particles.begin(), upda.particles.end()); +} + +/// Drop history information +std::pair<std::size_t,std::size_t> History::drop() { + std::pair<std::size_t,std::size_t> ret(hits.size(), particles.size()); + hits.clear(); + particles.clear(); + return ret; +} + /// Update the deposit using deposit weighting void EnergyDeposit::update_deposit_weighted(const EnergyDeposit& upda) { double sum = deposit + upda.deposit; @@ -70,8 +91,7 @@ void EnergyDeposit::update_deposit_weighted(const EnergyDeposit& upda) { position = pos; momentum = mom; deposit = sum; - hit_history.insert(hit_history.end(), upda.hit_history.begin(), upda.hit_history.end()); - particle_history.insert(particle_history.end(), upda.particle_history.begin(), upda.particle_history.end()); + history.update(upda.history); } /// Update the deposit using deposit weighting @@ -82,8 +102,7 @@ void EnergyDeposit::update_deposit_weighted(EnergyDeposit&& upda) { position = pos; momentum = mom; deposit = sum; - hit_history.insert(hit_history.end(), upda.hit_history.begin(), upda.hit_history.end()); - particle_history.insert(particle_history.end(), upda.particle_history.begin(), upda.particle_history.end()); + history.update(upda.history); } /// Merge new deposit map onto existing map @@ -174,13 +193,21 @@ std::size_t DepositMapping::insert(const DepositMapping& updates) { return update_size; } +/// Merge new deposit map onto existing map +std::size_t ParticleMapping::insert(const ParticleMapping& updates) { + std::size_t update_size = updates.size(); + for( const ParticleMapping::value_type& c : updates ) + this->insert(Key(c.first), c.second); + return update_size; +} + /// Merge new deposit map onto existing map std::size_t ParticleMapping::merge(ParticleMapping&& updates) { std::size_t update_size = updates.size(); #if defined(__GNUC__) && (__GNUC__ >= 10) for( ParticleMapping::value_type& c : updates ) { Particle part(std::move(c.second)); - this->push(c.first, std::move(part)); + this->push(Key(c.first), std::move(part)); } #endif return update_size; @@ -191,7 +218,7 @@ void ParticleMapping::push(Key particle_key, Particle&& particle_data) { /// Lower compiler version have a bad implementation of std::any bool ret = false; #else - bool ret = data.emplace(particle_key.key, std::move(particle_data)).second; + bool ret = data.emplace(particle_key, std::move(particle_data)).second; #endif if ( !ret ) { except("ParticleMapping","Error in particle map. Duplicate ID: mask:%04X Number:%d History:%s", @@ -199,17 +226,53 @@ void ParticleMapping::push(Key particle_key, Particle&& particle_data) { } } +void ParticleMapping::insert(Key particle_key, const Particle& particle_data) { + bool ret = data.emplace(particle_key, particle_data).second; + if ( !ret ) { + except("ParticleMapping","Error in particle map. Duplicate ID: mask:%04X Number:%d History:%s", + 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; + data.emplace(particle_key, std::move(particle_data)).second; #endif } +/// Merge new deposit map onto existing map (not thread safe!) +std::size_t DetectorResponse::merge(DetectorResponse&& updates) { + std::size_t len = updates.size(); + data.insert(data.end(), updates.data.begin(), updates.data.end()); + return len; +} + +/// Merge new deposit map onto existing map (not thread safe!) +std::size_t DetectorResponse::insert(const DetectorResponse& updates) { + std::size_t len = updates.size(); + data.insert(data.end(), updates.data.begin(), updates.data.end()); + return len; +} + +/// Merge new deposit map onto existing map (not thread safe!) +std::size_t DetectorHistory::merge(DetectorHistory&& updates) { + std::size_t len = updates.size(); + data.insert(data.end(), updates.data.begin(), updates.data.end()); + return len; +} + +/// Merge new deposit map onto existing map (not thread safe!) +std::size_t DetectorHistory::insert(const DetectorHistory& updates) { + std::size_t len = updates.size(); + data.insert(data.end(), updates.data.begin(), updates.data.end()); + return len; +} + /// Initializing constructor -DataSegment::DataSegment(std::mutex& l) : lock(l) +DataSegment::DataSegment(std::mutex& l, int i) : lock(l), id(i) { } @@ -220,12 +283,12 @@ bool DataSegment::emplace(Key key, std::any&& item) { /// Lower compiler version have a bad implementation of std::any bool ret = false; #else - bool ret = data.emplace(key.key, std::move(item)).second; + bool ret = data.emplace(key, std::move(item)).second; #endif if ( !ret ) { Key k(key); except("DataSegment","Error in DataSegment map. Duplicate ID: mask:%04X Number:%d Value:%s", - k.values.mask, k.values.item, yes_no(item.has_value())); + k.mask(), k.item(), yes_no(item.has_value())); } return ret; } @@ -239,12 +302,13 @@ template <typename DATA> bool DataSegment::put(Key key, DATA&& value) { template bool DataSegment::put(Key key, DepositVector&& data); template bool DataSegment::put(Key key, DepositMapping&& data); template bool DataSegment::put(Key key, ParticleMapping&& data); +template bool DataSegment::put(Key key, DetectorHistory&& data); template bool DataSegment::put(Key key, DetectorResponse&& data); /// Remove data item from segment bool DataSegment::erase(Key key) { std::lock_guard<std::mutex> l(lock); - auto iter = data.find(key.key); + auto iter = data.find(key); if ( iter != data.end() ) { data.erase(iter); return true; @@ -257,7 +321,7 @@ std::size_t DataSegment::erase(const std::vector<Key>& keys) { std::size_t count = 0; std::lock_guard<std::mutex> l(lock); for(auto key : keys) { - auto iter = data.find(key.key); + auto iter = data.find(key); if ( iter != data.end() ) { data.erase(iter); ++count; @@ -272,7 +336,7 @@ void DataSegment::print_keys() const { for( const auto& e : this->data ) { Key k(e.first); printout(INFO, "DataSegment", "Key No.%4: %16lX <> %16lX -> %04X %10ld", - count, e.first, k.key, k.values.mask, k.values.item, + count, e.first, k.value(), k.mask(), k.item(), typeName(e.second.type()).c_str()); ++count; } @@ -281,17 +345,17 @@ void DataSegment::print_keys() const { /// Call on failed any-casts during data requests std::string DataSegment::invalid_cast(Key key, const std::type_info& type) const { return dd4hep::format(0, "Invalid segment data cast. Key:%ld type:%s", - key.key, typeName(type).c_str()); + key.value(), typeName(type).c_str()); } /// Call on failed data requests during data requests std::string DataSegment::invalid_request(Key key) const { - return dd4hep::format(0, "Invalid segment data requested. Key:%ld",key.key); + return dd4hep::format(0, "Invalid segment data requested. Key:%ld",key.value()); } /// Access data item by key std::any* DataSegment::get_item(Key key, bool exc) { - auto it = this->data.find(key.key); + auto it = this->data.find(key); if (it != this->data.end()) return &it->second; if ( exc ) throw std::runtime_error(invalid_request(key)); return nullptr; @@ -299,7 +363,7 @@ std::any* DataSegment::get_item(Key key, bool exc) { /// Access data item by key (CONST) const std::any* DataSegment::get_item(Key key, bool exc) const { - auto it = this->data.find(key.key); + auto it = this->data.find(key); if (it != this->data.end()) return &it->second; if ( exc ) throw std::runtime_error(invalid_request(key)); return nullptr; @@ -326,14 +390,14 @@ DigiEvent::~DigiEvent() InstanceCount::decrement(this); } -DataSegment& DigiEvent::access_segment(std::unique_ptr<DataSegment>& segment) { +DataSegment& DigiEvent::access_segment(std::unique_ptr<DataSegment>& segment, uint32_t id) { if ( segment ) { return *segment; } std::lock_guard<std::mutex> guard(m_lock); /// Check again after holding the lock: if ( !segment ) { - segment = std::make_unique<DataSegment>(this->m_lock); + segment = std::make_unique<DataSegment>(this->m_lock, id); } return *segment; } @@ -342,19 +406,19 @@ DataSegment& DigiEvent::access_segment(std::unique_ptr<DataSegment>& segment) DataSegment& DigiEvent::get_segment(const std::string& name) { switch(::toupper(name[0])) { case 'I': - return access_segment(m_inputs); + return access_segment(m_inputs,1); case 'C': - return access_segment(m_counts); + return access_segment(m_counts,2); case 'D': switch(::toupper(name[1])) { case 'E': - return access_segment(m_deposits); + return access_segment(m_deposits,3); default: - return access_segment(m_data); + return access_segment(m_data,0xFEED); } break; case 'O': - return access_segment(m_outputs); + return access_segment(m_outputs,4); default: break; } diff --git a/DDDigi/src/DigiOutputAction.cpp b/DDDigi/src/DigiOutputAction.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ad23ac4b6df3abd809160c1dcf4366ebbb494c12 --- /dev/null +++ b/DDDigi/src/DigiOutputAction.cpp @@ -0,0 +1,44 @@ +//========================================================================== +// 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/DigiOutputAction.h> + +// C/C++ include files +#include <stdexcept> +#include <unistd.h> + +using namespace std; +using namespace dd4hep::digi; + +/// Standard constructor +DigiOutputAction::DigiOutputAction(const DigiKernel& kernel, const string& nam) + : DigiEventAction(kernel, nam) +{ + declareProperty("containers", m_containers); + declareProperty("output", m_output); + declareProperty("mask", m_mask); + InstanceCount::increment(this); +} + +/// Default destructor +DigiOutputAction::~DigiOutputAction() { + InstanceCount::decrement(this); +} + +/// Pre-track action callback +void DigiOutputAction::execute(DigiContext& /* context */) const { + info("+++ Virtual method execute() --- Should not be called"); + ::sleep(1); +} diff --git a/DDDigi/src/DigiROOTInput.cpp b/DDDigi/src/DigiROOTInput.cpp index e3f0cfd9a644e0026725ba38a8012889c48c3bee..8d353559422ea3ed73516656de0584625f58ff7c 100644 --- a/DDDigi/src/DigiROOTInput.cpp +++ b/DDDigi/src/DigiROOTInput.cpp @@ -131,7 +131,7 @@ void DigiROOTInput::open_new_file() const { if ( this->m_containers.empty() ) { Key key(b->GetName(), this->m_mask); b->SetAutoDelete( kFALSE ); - imp->branches[key.key] = {b, cls, imp->input_converter(cls)}; + imp->branches[key.value()] = {b, cls, imp->input_converter(cls)}; continue; } /// Otherwise only the entities asked for @@ -139,7 +139,7 @@ void DigiROOTInput::open_new_file() const { if ( bname == b->GetName() ) { Key key(b->GetName(), this->m_mask); b->SetAutoDelete( kFALSE ); - imp->branches[key.key] = {b, cls, imp->input_converter(cls)}; + imp->branches[key.value()] = {b, cls, imp->input_converter(cls)}; break; } } diff --git a/DDDigi/src/DigiROOTOutput.cpp b/DDDigi/src/DigiROOTOutput.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3929794e72888167caacd64ea2e8ee2f34f68297 --- /dev/null +++ b/DDDigi/src/DigiROOTOutput.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/DigiROOTOutput.h> + +/// ROOT include files +#include <TFile.h> +#include <TTree.h> +#include <TBranch.h> + +/// C/C++ include files +#include <stdexcept> +#include <unistd.h> + +using namespace std; +using namespace dd4hep::digi; + +class DigiROOTOutput::internals_t { +public: + typedef std::map<std::string, TBranch*> Branches; + typedef std::map<std::string, TTree*> Sections; + /// Reference to the ROOT file to open + TFile* m_file { nullptr }; + /// Reference to the event data tree + TTree* m_tree { nullptr }; + /// Known file sections + Sections m_sections; + /// Branches in the event tree + Branches m_branches; + DigiROOTOutput* output { nullptr }; + +public: + internals_t(DigiROOTOutput* o) + : output(o) + { + } + ~internals_t() { + if (m_file) { + TDirectory::TContext ctxt(m_file); + m_tree->Write(); + m_file->Close(); + m_tree = 0; + detail::deletePtr (m_file); + } + } + /// Create/access tree by name for non collection user data + TTree* section(const std::string& nam) { + auto i = m_sections.find(nam); + if ( i == m_sections.end() ) { + TDirectory::TContext ctxt(m_file); + TTree* t = new TTree(nam.c_str(), ("Digitization " + nam + " information").c_str()); + m_sections.emplace(nam, t); + return t; + } + return i->second; + } + /// Commit data at end of filling procedure + void commit() { + if ( m_file ) { + TObjArray* a = m_tree->GetListOfBranches(); + Long64_t evt = m_tree->GetEntries() + 1; + Int_t nb = a->GetEntriesFast(); + /// Fill NULL pointers to all branches, which have less entries than the Event branch + for (Int_t i = 0; i < nb; ++i) { + TBranch* br_ptr = (TBranch*) a->UncheckedAt(i); + Long64_t br_evt = br_ptr->GetEntries(); + if (br_evt < evt) { + Long64_t num = evt - br_evt; + br_ptr->SetAddress(0); + while (num > 0) { + br_ptr->Fill(); + --num; + } + } + } + m_tree->SetEntries(evt); + } + } + /// Fill single EVENT branch entry (Geant4 collection data) + int fill(const string& nam, const std::type_info& type, void* ptr) { + if (m_file) { + TBranch* b = 0; + auto i = m_branches.find(nam); + if (i == m_branches.end()) { + TClass* cl = TBuffer::GetClass(type); + if (cl) { + b = m_tree->Branch(nam.c_str(), cl->GetName(), (void*) 0); + b->SetAutoDelete(false); + m_branches.emplace(nam, b); + } + else { + throw runtime_error("No ROOT TClass object availible for object type:" + typeName(type)); + } + } + else { + b = (*i).second; + } + Long64_t evt = b->GetEntries(), nevt = b->GetTree()->GetEntries(), num = nevt - evt; + if (nevt > evt) { + b->SetAddress(0); + while (num > 0) { + b->Fill(); + --num; + } + } + b->SetAddress(&ptr); + int nbytes = b->Fill(); + if (nbytes < 0) { + throw runtime_error("Failed to write ROOT collection:" + nam + "!"); + } + return nbytes; + } + return 0; + } + /// Callback to store the Geant4 event + void saveEvent(DigiContext& /* ctxt */) { + if ( !output->m_disableParticles ) { +#if 0 + Geant4ParticleMap* parts = context()->event().extension<Geant4ParticleMap>(); + if ( parts ) { + typedef Geant4HitWrapper::HitManipulator Manip; + typedef Geant4ParticleMap::ParticleMap ParticleMap; + Manip* manipulator = Geant4HitWrapper::manipulator<Geant4Particle>(); + const ParticleMap& pm = parts->particles(); + vector<void*> particles; + particles.reserve(pm.size()); + for ( const auto& i : pm ) { + particles.emplace_back((ParticleMap::mapped_type*)i.second); + } + fill("MCParticles",manipulator->vec_type,&particles); + } +#endif + } + } +}; + +/// Standard constructor +DigiROOTOutput::DigiROOTOutput(const DigiKernel& kernel, const std::string& nam) + : DigiOutputAction(kernel, nam) +{ + imp = std::make_unique<internals_t>(this); + declareProperty("section", m_section = "EVENT"); + declareProperty("max_file_size", m_max_file_size); + declareProperty("disabled_collections", m_disabledCollections); + declareProperty("disable_particles", m_disableParticles); + InstanceCount::increment(this); +} + +/// Default destructor +DigiROOTOutput::~DigiROOTOutput() { + imp.reset(); + InstanceCount::decrement(this); +} + +/// Pre-track action callback +void DigiROOTOutput::execute(DigiContext& context) const { + imp->saveEvent(context); +#if 0 + for (int i = 0; i < nCol; ++i) { + G4VHitsCollection* hc = hce->GetHC(i); + saveCollection(ctxt, hc); + } +#endif +} + +#if 0 +/// Callback to store the Geant4 run information +void DigiROOTOutput::beginRun(const G4Run* run) { + if (!m_file && !m_output.empty()) { + TDirectory::TContext ctxt(TDirectory::CurrentDirectory()); + m_file = TFile::Open(m_output.c_str(), "RECREATE", "DD4hep digitization data"); + if (m_file->IsZombie()) { + detail::deletePtr (m_file); + except("+++ Failed to open ROOT output file:'" + m_output + "'"); + } + m_tree = section("EVENT"); + } + Geant4OutputAction::beginRun(run); +} + + + +/// Callback to store each Geant4 hit collection +void DigiROOTOutput::saveCollection(DigiContext& /* ctxt */, G4VHitsCollection* collection) { + Geant4HitCollection* coll = dynamic_cast<Geant4HitCollection*>(collection); + string hc_nam = collection->GetName(); + for(const auto& n : m_disabledCollections) { + if ( n == hc_nam ) { + return; + } + } + if (coll) { + vector<void*> hits; + coll->getHitsUnchecked(hits); + size_t nhits = coll->GetSize(); + if ( m_handleMCTruth && m_truth && nhits > 0 ) { + hits.reserve(nhits); + try { + for(size_t i=0; i<nhits; ++i) { + Geant4HitData* h = coll->hit(i); + Geant4Tracker::Hit* trk_hit = dynamic_cast<Geant4Tracker::Hit*>(h); + if ( 0 != trk_hit ) { + Geant4HitData::Contribution& t = trk_hit->truth; + int trackID = t.trackID; + t.trackID = m_truth->particleID(trackID); + } + Geant4Calorimeter::Hit* cal_hit = dynamic_cast<Geant4Calorimeter::Hit*>(h); + if ( 0 != cal_hit ) { + Geant4HitData::Contributions& c = cal_hit->truth; + for(Geant4HitData::Contributions::iterator j=c.begin(); j!=c.end(); ++j) { + Geant4HitData::Contribution& t = *j; + int trackID = t.trackID; + t.trackID = m_truth->particleID(trackID); + } + } + } + } + catch(...) { + printout(ERROR,name(),"+++ Exception while saving collection %s.",hc_nam.c_str()); + } + } + fill(hc_nam, coll->vector_type(), &hits); + } +} +#endif diff --git a/DDDigi/src/DigiSegmentSplitter.cpp b/DDDigi/src/DigiSegmentSplitter.cpp index b4236d508e26e70f38b9e40e7057fee53572047e..8b22c28c7db107a843b2cead53b125e34c36aa81 100644 --- a/DDDigi/src/DigiSegmentSplitter.cpp +++ b/DDDigi/src/DigiSegmentSplitter.cpp @@ -120,7 +120,8 @@ void DigiSegmentSplitter::adopt_processor(DigiContainerProcessor* action) { /// Main functional callback void DigiSegmentSplitter::execute(DigiContext& context, work_t& work) const { Key key = work.input_key(); - Key unmasked_key(key.item()); + Key unmasked_key; + unmasked_key.set_item(key.item()); if ( std::find(m_keys.begin(), m_keys.end(), unmasked_key) != m_keys.end() ) { if ( work.has_input() ) { info("+++ Got hit collection %04X %08X. Prepare processors for %sparallel execution.", diff --git a/DDDigi/src/DigiStoreDump.cpp b/DDDigi/src/DigiStoreDump.cpp index 09c66b52c89ac2cf793dffeb6e957dcdf3d69c21..7f17ad0caa314dff265a233221b74decc5344b1c 100644 --- a/DDDigi/src/DigiStoreDump.cpp +++ b/DDDigi/src/DigiStoreDump.cpp @@ -59,28 +59,33 @@ void dd4hep::digi::DigiStoreDump::dump(const std::string& tag, 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 deposits [%s]", - event.id(), key.values.mask, key.values.item, + str = this->format("%s|---- %04X %08X %-32s: %6ld deposits [%s]", + event.id(), key.mask(), key.item(), nam.c_str(), mapping->size(), typ.c_str()); } else if ( const auto* vector = std::any_cast<DepositVector>(&data) ) { - str = this->format("%s|---- %4X %08X %-32s: %6ld deposits [%s]", - event.id(), key.values.mask, key.values.item, + str = this->format("%s|---- %04X %08X %-32s: %6ld deposits [%s]", + event.id(), key.mask(), key.item(), nam.c_str(), vector->size(), typ.c_str()); } else if ( const auto* parts = std::any_cast<ParticleMapping>(&data) ) { - str = this->format("%s|---- %4X %08X %-32s: %6ld particles [%s]", - event.id(), key.values.mask, key.values.item, + str = this->format("%s|---- %04X %08X %-32s: %6ld particles [%s]", + event.id(), key.mask(), key.item(), nam.c_str(), parts->size(), typ.c_str()); } else if ( const auto* adcs = std::any_cast<DetectorResponse>(&data) ) { - str = this->format("%s|---- %4X %08X %-32s: %6ld ADC values [%s]", - event.id(), key.values.mask, key.values.item, + str = this->format("%s|---- %04X %08X %-32s: %6ld ADC values [%s]", + event.id(), key.mask(), key.item(), nam.c_str(), adcs->size(), typ.c_str()); } + else if ( const auto* hist = std::any_cast<DetectorHistory>(&data) ) { + str = this->format("%s|---- %04X %08X %-32s: %6ld histories [%s]", + event.id(), key.mask(), key.item(), + nam.c_str(), hist->size(), typ.c_str()); + } else { - str = this->format("%s|---- %4X %08X %-32s: %s", - event.id(), key.values.mask, key.values.item, + str = this->format("%s|---- %04X %08X %-32s: %s", + event.id(), key.mask(), key.item(), nam.c_str(), typ.c_str()); } records.push_back(str); diff --git a/examples/DDDigi/scripts/DigiTest.py b/examples/DDDigi/scripts/DigiTest.py index f0cfb73a3c7333d633d26973c56c983995319308..31a1836bcf5178a370d6ef9392c026881cec1796 100644 --- a/examples/DDDigi/scripts/DigiTest.py +++ b/examples/DDDigi/scripts/DigiTest.py @@ -112,6 +112,7 @@ class Test(dddigi.Digitize): self.used_inputs = [] next = self.inputs[len(self.used_inputs)] self.used_inputs.append(next) + self.info('Prepariing next input file: ' + str(next)) return next def run_checked(self, num_events=5, num_threads=5, parallel=3): diff --git a/examples/DDDigi/scripts/TestHitProcessing.py b/examples/DDDigi/scripts/TestHitProcessing.py index b21d9faf4523710265aa749fd4f8b87293399da5..e8e3d9192af3897597788bea93330936a8850c29 100644 --- a/examples/DDDigi/scripts/TestHitProcessing.py +++ b/examples/DDDigi/scripts/TestHitProcessing.py @@ -18,50 +18,37 @@ def run(): input = digi.input_action('DigiParallelActionSequence/READER') # ======================================================================================================== digi.info('Created SIGNAL input') - signal = input.adopt_action('DigiROOTInput/SignalReader', mask=0x0, input=[digi.next_input()]) - digi.check_creation([signal]) + input.adopt_action('DigiROOTInput/SignalReader', mask=0x0, input=[digi.next_input()]) # ======================================================================================================== digi.info('Creating collision overlays....') # ======================================================================================================== overlay = input.adopt_action('DigiSequentialActionSequence/Overlay-1') - evtreader = overlay.adopt_action('DigiROOTInput/Read-1', mask=0x1, input=[digi.next_input()]) - digi.check_creation([overlay, evtreader]) + overlay.adopt_action('DigiROOTInput/Read-1', mask=0x1, input=[digi.next_input()]) digi.info('Created input.overlay-1') # ======================================================================================================== overlay = input.adopt_action('DigiSequentialActionSequence/Overlay-2') - evtreader = overlay.adopt_action('DigiROOTInput/Read-2', mask=0x2, input=[digi.next_input()]) - digi.check_creation([overlay, evtreader]) + overlay.adopt_action('DigiROOTInput/Read-2', mask=0x2, input=[digi.next_input()]) digi.info('Created input.overlay-2') # ======================================================================================================== event = digi.event_action('DigiSequentialActionSequence/EventAction') combine = event.adopt_action('DigiContainerCombine/Combine', parallel=True, - input_masks=[0x0, 0x1, 0x2, 0x3], - output_mask=0xFEED, - output_segment='deposits', - erase_combined=False) + input_masks=[0x0, 0x1, 0x2], + output_mask=0xAAA0, + output_segment='inputs') combine.erase_combined = True - proc = event.adopt_action('DigiContainerSequenceAction/HitP1', - parallel=True, - input_mask=0xFEED, - input_segment='deposits') - count = digi.create_action('DigiCellMultiplicityCounter/CellCounter') - proc.adopt_container_processor(count, digi.containers()) proc = event.adopt_action('DigiContainerSequenceAction/HitP2', parallel=True, - input_mask=0xFEED, - input_segment='deposits', - output_mask=0x0, - output_segment='output') + input_mask=0xAAA0, + input_segment='inputs', + output_mask=0xAAA1, + output_segment='inputs') count = digi.create_action('DigiDepositWeightedPosition/CellCreator') proc.adopt_container_processor(count, digi.containers()) - dump = event.adopt_action('DigiStoreDump/StoreDump') - - digi.check_creation([combine, dump, proc]) - digi.info('Created event.dump') - + event.adopt_action('DigiStoreDump/StoreDump') # ======================================================================================================== - digi.run_checked(num_events=5, num_threads=5, parallel=3) + digi.info('Starting digitization core') + digi.run_checked(num_events=3, num_threads=25, parallel=5) if __name__ == '__main__': diff --git a/examples/DDDigi/scripts/TestMultiContainerParallel.py b/examples/DDDigi/scripts/TestMultiContainerParallel.py index 8934b1fb39a4e7089ee043f293a76f1fd7a78b43..72fff4e167862e2b79091dccf0cb697068f73783 100644 --- a/examples/DDDigi/scripts/TestMultiContainerParallel.py +++ b/examples/DDDigi/scripts/TestMultiContainerParallel.py @@ -24,7 +24,7 @@ def run(): # ======================================================================== event = digi.event_action('DigiSequentialActionSequence/EventAction') proc = event.adopt_action('DigiMultiContainerProcessor/ContainerProc', - input_masks=[0x0, 0x1, 0x2, 0x3, 0xFEED]) + parallel=True, input_masks=[0x0, 0x1, 0x2, 0x3, 0xFEED]) conts = digi.containers(2) for i in range(len(conts)): merge = dddigi.Action(digi.kernel(), 'DigiContainerProcessor/SegmentPrint_%03d' % (i,)) diff --git a/examples/DDDigi/scripts/TestSimpleADCResponse.py b/examples/DDDigi/scripts/TestSimpleADCResponse.py index 6bb327b960bdef0443df205ea5ad730905582f8a..fb1529cc5817a86da00d612b7f43d11db3dac400 100644 --- a/examples/DDDigi/scripts/TestSimpleADCResponse.py +++ b/examples/DDDigi/scripts/TestSimpleADCResponse.py @@ -16,16 +16,19 @@ def run(): digi = DigiTest.Test(geometry=None) # ======================================================================================================== - input = digi.input_action('DigiParallelActionSequence/READER') + input = digi.input_action('DigiSequentialActionSequence/READER') input.adopt_action('DigiROOTInput/SignalReader', mask=0x0, input=[digi.next_input()]) # ======================================================================================================== event = digi.event_action('DigiSequentialActionSequence/EventAction') + event.adopt_action('DigiStoreDump/DumpInput') proc = event.adopt_action('DigiContainerCombine/Combine', parallel=True, - input_masks=[0x0, 0x1, 0x2, 0x3], + input_masks=[0x0], + input_segment='inputs', output_mask=0xFEED, output_segment='deposits', - erase_combined=True) + erase_combined=False) + event.adopt_action('DigiStoreDump/DumpCombine') proc = event.adopt_action('DigiContainerSequenceAction/ADCsequence', parallel=True, input_mask=0xFEED, @@ -34,12 +37,15 @@ def run(): output_segment='output') count = digi.create_action('DigiSimpleADCResponse/ADCCreate') proc.adopt_container_processor(count, digi.containers()) - - event.adopt_action('DigiStoreDump/StoreDump') + event.adopt_action('DigiContainerDrop/DropCombine', + parallel=True, + input_masks=[0xFEED], + input_segment='deposits') + event.adopt_action('DigiStoreDump/DumpOutput') digi.info('Created event.dump') # ======================================================================================================== - digi.run_checked(num_events=5, num_threads=5, parallel=3) + digi.run_checked(num_events=5, num_threads=1, parallel=3) if __name__ == '__main__': diff --git a/examples/DDDigi/scripts/TestSpillover.py b/examples/DDDigi/scripts/TestSpillover.py index 6745adb40ce62ee76148881cd480b1580fa9cf45..e62e21c4bddda182b4addc7071dde87d0e7940f9 100644 --- a/examples/DDDigi/scripts/TestSpillover.py +++ b/examples/DDDigi/scripts/TestSpillover.py @@ -19,8 +19,7 @@ def run(): input = digi.input_action('DigiParallelActionSequence/READER') # ======================================================================================================== - signal = input.adopt_action('DigiROOTInput/SignalReader', mask=0x0, input=[digi.next_input()]) - digi.check_creation([signal]) + input.adopt_action('DigiROOTInput/SignalReader', mask=0x0, input=[digi.next_input()]) digi.info('Created input.signal') # ======================================================================================================== digi.info('Creating spillover sequence for EARLIER bunch crossings.....') diff --git a/examples/DDG4/CMakeLists.txt b/examples/DDG4/CMakeLists.txt index f2c00182bd2655a8d3aa2a251f69438c2b2b1994..4634ff08eeef2f2d75de239bd38f85be3b9b2280 100644 --- a/examples/DDG4/CMakeLists.txt +++ b/examples/DDG4/CMakeLists.txt @@ -87,4 +87,12 @@ if (DD4HEP_USE_GEANT4) REGEX_PASS "Created specialize logical volume \\[G4LogicalCrystalVolume\\]: ChannelingDevice_vol" REGEX_FAIL " ERROR ;EXCEPTION;Exception" ) + # + # Test G4 stacking action + dd4hep_add_test_reg( DDG4_TestStackingAction + COMMAND "${CMAKE_INSTALL_PREFIX}/bin/run_test_DDG4.sh" + EXEC_ARGS ${Python_EXECUTABLE} ${DDG4examples_INSTALL}/scripts/TestStacking.py -batch -events 3 + REGEX_PASS " \\[2\\] Calling classifyNewTrack. StackManager" + REGEX_FAIL " ERROR ;EXCEPTION;Exception" + ) endif()