Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:14:05

0001 //==========================================================================
0002 //  AIDA Detector description implementation 
0003 //--------------------------------------------------------------------------
0004 // Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
0005 // All rights reserved.
0006 //
0007 // For the licensing terms see $DD4hepINSTALL/LICENSE.
0008 // For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
0009 //
0010 // Author     : M.Frank
0011 //
0012 //==========================================================================
0013 #ifndef DIGI_DIGI2ROOT_H
0014 #define DIGI_DIGI2ROOT_H
0015 
0016 // Framework include files
0017 #include <DDDigi/DigiOutputAction.h>
0018 #include <DDDigi/DigiData.h>
0019 
0020 /// Namespace for the AIDA detector description toolkit
0021 namespace dd4hep {
0022 
0023   /// Namespace for the Digitization part of the AIDA detector description toolkit
0024   namespace digi {
0025 
0026     /// Event action to support edm4hep output format from DDDigi
0027     /**
0028      *  Supported output containers types are:
0029      *  - MCParticles aka "MCParticles"
0030      *  - EnergyDeposits
0031      *
0032      *  \author  M.Frank
0033      *  \version 1.0
0034      *  \ingroup DD4HEP_DIGITIZATION
0035      */
0036     class Digi2ROOTWriter : public  DigiOutputAction  {
0037     public:
0038       class internals_t;
0039 
0040     protected:
0041       /// Reference to internals
0042       std::shared_ptr<internals_t> internals;
0043 
0044     protected:
0045       /// Define standard assignments and constructors
0046       DDDIGI_DEFINE_ACTION_CONSTRUCTORS(Digi2ROOTWriter);
0047       /// Default destructor
0048       virtual ~Digi2ROOTWriter();
0049 
0050     public:
0051       /// Standard constructor
0052       Digi2ROOTWriter(const kernel_t& kernel, const std::string& nam);
0053       /// Initialization callback
0054       virtual void initialize()  override;
0055       /// Check for valid output stream
0056       virtual bool have_output()  const  override final;
0057       /// Open new output stream
0058       virtual void open_output() const  override final;
0059       /// Close possible open stream
0060       virtual void close_output()  const  override final;
0061       /// Commit event data to output stream
0062       virtual void commit_output() const  override final;
0063     };
0064 
0065     /// Actor to save individual data containers to edm4hep
0066     /** Actor to save individual data containers to edm4hep
0067      *
0068      *  This is a typical worker action of the Digi2ROOTWriter
0069      *
0070      *  \author  M.Frank
0071      *  \version 1.0
0072      *  \ingroup DD4HEP_DIGITIZATION
0073      */
0074     class Digi2ROOTProcessor : public DigiContainerProcessor   {
0075       friend class Digi2ROOTWriter;
0076     protected:
0077       /// Reference to the edm4hep engine
0078       std::shared_ptr<Digi2ROOTWriter::internals_t> internals;
0079 
0080     public:
0081       /// Standard constructor
0082       Digi2ROOTProcessor(const DigiKernel& krnl, const std::string& nam);
0083       /// Standard destructor
0084       virtual ~Digi2ROOTProcessor() = default;
0085 
0086       void convert_particles(DigiContext& context, ParticleMapping& cont)  const;
0087       void convert_deposits(DigiContext& context, DepositVector& cont, const predicate_t& predicate)  const;
0088       void convert_deposits(DigiContext& context, DepositMapping& cont, const predicate_t& predicate)  const;
0089       void convert_history(DigiContext& context, DepositsHistory& cont, work_t& work, const predicate_t& predicate)  const;
0090 
0091       /// Main functional callback
0092       virtual void execute(DigiContext& context, work_t& work, const predicate_t& predicate)  const override final;
0093     };
0094   }    // End namespace digi
0095 }      // End namespace dd4hep
0096 #endif // DIGI_DIGI2ROOT_H
0097 
0098 //==========================================================================
0099 //  AIDA Detector description implementation 
0100 //--------------------------------------------------------------------------
0101 // Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
0102 // All rights reserved.
0103 //
0104 // For the licensing terms see $DD4hepINSTALL/LICENSE.
0105 // For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
0106 //
0107 // Author     : M.Frank
0108 //
0109 //==========================================================================
0110 
0111 /// Framework include files
0112 #include <DD4hep/InstanceCount.h>
0113 #include <DDDigi/DigiContext.h>
0114 #include <DDDigi/DigiPlugins.h>
0115 #include <DDDigi/DigiKernel.h>
0116 #include "DigiIO.h"
0117 
0118 /// ROOT include files
0119 #include <TFile.h>
0120 #include <TTree.h>
0121 #include <TROOT.h>
0122 #include <TClass.h>
0123 #include <TBranch.h>
0124 
0125 #include <vector>
0126 
0127 /// Namespace for the AIDA detector description toolkit
0128 namespace dd4hep {
0129 
0130   /// Namespace for the Digitization part of the AIDA detector description toolkit
0131   namespace digi {
0132 
0133     using persistent_particles_t = std::vector<std::pair<Key::key_type, Particle*> >;
0134     using persistent_deposits_t  = std::vector<std::pair<CellID, EnergyDeposit*> >;
0135 
0136     /// Helper class to create output in edm4hep format
0137     /** Helper class to create output in edm4hep format
0138      *
0139      *  \author  M.Frank
0140      *  \version 1.0
0141      *  \ingroup DD4HEP_DIGITIZATION
0142      */
0143     class Digi2ROOTWriter::internals_t  final {
0144     public:
0145       struct BranchWrapper   {
0146     TClass*  clazz = nullptr;
0147     TBranch* branch = nullptr;
0148     void*    address = nullptr;
0149     void (*fcn_clear)(void* addr) = 0;
0150     void (*fcn_del)(void* addr) = 0;
0151     void clear()                    { this->fcn_clear(this->address); }
0152     void del()                      { this->fcn_del(this->address);   }
0153     template <typename T> T* get()  { return (T*)this->address;       }
0154     template <typename T> void set(T* ptr);
0155       };
0156       template <typename O> struct _wrapper_handler  {
0157     static void clear(void* ptr)  {  O* c = (O*)ptr; c->clear();  }
0158     static void del(void* ptr)    {  O* c = (O*)ptr; delete c;    }
0159       };
0160       typedef std::map<std::string, BranchWrapper> Collections;
0161 
0162       /// Reference to the parent
0163       Digi2ROOTWriter*         m_parent       { nullptr };
0164       /// Collections in the event tree
0165       Collections              m_collections  { };
0166       /// Reference to the ROOT file to open
0167       std::unique_ptr<TFile>   m_file         { };
0168       /// Reference to the event data tree
0169       TTree*                   m_tree         { nullptr };
0170 
0171       /// Property: name of the event tree
0172       std::string              m_section      { "EVENT" };
0173 
0174       /// Default basket size
0175       Int_t                    m_basket_size  { 32000 };
0176       /// Default split level
0177       Int_t                    m_split_level  {    99 };
0178 
0179     private:
0180       /// Helper to register single collection
0181       template <typename T> T* register_collection(const std::string& name, T* collection);
0182 
0183     public:
0184       /// Default constructor
0185       internals_t(Digi2ROOTWriter* parent);
0186       /// Default destructor
0187       ~internals_t();
0188 
0189       /// Open output file
0190       void open();
0191       /// Commit data to disk and close output stream
0192       void close();
0193       /// Commit data at end of filling procedure
0194       void commit();
0195 
0196       /// Create all collections according to the parent setup (locked)
0197       void create_collections();
0198       /// Clear collection content: Store is still owner!
0199       void clearCollections();
0200       /// Access named collection: throws exception ifd the collection is not present (unlocked!)
0201       template <typename T> BranchWrapper& get_collection(const T&);
0202     };
0203 
0204     template <typename T> void Digi2ROOTWriter::internals_t::BranchWrapper::set(T* ptr)   {
0205       clazz     = gROOT->GetClass(typeid(*ptr), kTRUE);
0206       branch    = nullptr;
0207       address   = ptr;
0208       fcn_clear = _wrapper_handler<T>::clear;
0209       fcn_del   = _wrapper_handler<T>::del;
0210     }
0211 
0212     /// Default constructor
0213     Digi2ROOTWriter::internals_t::internals_t(Digi2ROOTWriter* parent) : m_parent(parent)
0214     {
0215     }
0216 
0217     /// Default destructor
0218     Digi2ROOTWriter::internals_t::~internals_t()    {
0219       m_parent->info("Releasing allocated resources.");
0220       if ( m_file ) close();
0221       for( auto& coll : m_collections )   {
0222     coll.second.clear();
0223     coll.second.del();
0224       }
0225       m_collections.clear();
0226     }
0227 
0228     template <typename T> T* Digi2ROOTWriter::internals_t::register_collection(const std::string& nam, T* coll)   {
0229       BranchWrapper bw;
0230       bw.set(coll);
0231       m_collections.emplace(nam, bw);
0232       m_parent->debug("+++ created collection %s <%s>", nam.c_str(), typeName(typeid(T)).c_str());
0233       return coll;
0234     }
0235 
0236     /// Create all collections according to the parent setup
0237     void Digi2ROOTWriter::internals_t::create_collections()    {
0238       if ( m_collections.empty() )   {
0239         for( auto& cont : m_parent->m_containers )   {
0240           const std::string& nam = cont.first;
0241           const std::string& typ = cont.second;
0242           if ( typ == "MCParticles" )   {
0243             register_collection(nam, new persistent_particles_t());
0244       }
0245           else   {
0246             register_collection(nam, new persistent_deposits_t());
0247       }
0248         }
0249       }
0250     }
0251 
0252     /// Access named collection: throws exception ifd the collection is not present
0253     template <typename T> 
0254     Digi2ROOTWriter::internals_t::BranchWrapper& Digi2ROOTWriter::internals_t::get_collection(const T& cont)  {
0255       auto iter = m_collections.find(cont.name);
0256       if ( iter == m_collections.end() )    {
0257         m_parent->except("Error");
0258       }
0259       return iter->second;
0260     }
0261 
0262     /// Clear collection content: Store is still owner!
0263     void Digi2ROOTWriter::internals_t::clearCollections()   {
0264       for( auto& coll : m_collections )
0265     coll.second.clear();
0266     }
0267 
0268     /// Open output file
0269     void Digi2ROOTWriter::internals_t::open()   {
0270       if ( m_file )   {
0271     close();
0272       }
0273       std::string fname = m_parent->next_stream_name();
0274       m_file.reset(TFile::Open(fname.c_str(), "RECREATE", "DDDigi data"));
0275       m_tree = new TTree(m_section.c_str(), "DDDigi data", m_split_level, m_file.get());
0276       m_parent->info("+++ Opened ROOT output file %s", m_file->GetName());
0277       for( auto& coll : m_collections )    {
0278     auto& dsc = coll.second;
0279     dsc.branch = m_tree->Branch(coll.first.c_str(),
0280                     dsc.clazz->GetName(),
0281                     &dsc.address,
0282                     m_basket_size,
0283                     m_split_level);
0284     dsc.branch->SetAutoDelete(kFALSE);
0285       }
0286       m_parent->info("+++ Will save %ld events to %s",
0287              m_parent->num_events, m_parent->m_output.c_str());
0288     }
0289 
0290     /// Commit data to disk and close output stream
0291     void Digi2ROOTWriter::internals_t::close()   {
0292       if ( m_file )    {
0293     TDirectory::TContext ctxt(m_file.get());
0294     m_parent->info("+++ Closing ROOT output file %s after %ld events and %ld bytes",
0295                m_file->GetName(), m_tree->GetEntries(), m_file->GetBytesWritten());
0296     for( auto& coll : m_collections )   {
0297       coll.second.branch->ResetAddress();
0298       coll.second.branch = nullptr;
0299     }
0300     m_tree->Write();
0301     m_file->Close();
0302     m_tree = nullptr;
0303       }
0304       m_file.reset();
0305     }
0306 
0307     /// Commit data at end of filling procedure
0308     void Digi2ROOTWriter::internals_t::commit()   {
0309       if ( m_tree )   {
0310     m_tree->Fill();
0311         clearCollections();
0312     ++m_parent->event_count;
0313     if ( m_parent->m_sequence_streams )  {
0314       if ( 0 == (m_parent->event_count%m_parent->num_events) )  {
0315         close();
0316       }
0317     }
0318         return;
0319       }
0320       m_parent->except("+++ Failed to write output file. [Stream is not open]");
0321     }
0322 
0323     /// Standard constructor
0324     Digi2ROOTWriter::Digi2ROOTWriter(const DigiKernel& krnl, const std::string& nam)
0325       : DigiOutputAction(krnl, nam)
0326     {
0327       internals = std::make_shared<internals_t>(this);
0328       m_processor_type = "Digi2ROOTProcessor";
0329       declareProperty("basket_size",    internals->m_basket_size);
0330       declareProperty("split_level",    internals->m_split_level);
0331       InstanceCount::increment(this);
0332     }
0333 
0334     /// Default destructor
0335     Digi2ROOTWriter::~Digi2ROOTWriter()   {
0336       internals.reset();
0337       InstanceCount::decrement(this);
0338     }
0339 
0340     /// Initialization callback
0341     void Digi2ROOTWriter::initialize()   {
0342       this->DigiOutputAction::initialize();
0343       for ( auto& c : m_registered_processors )   {
0344         auto* act = dynamic_cast<Digi2ROOTProcessor*>(c.second);
0345         if ( act )   { // This is not nice! Need to think about something better.
0346           act->internals = this->internals;
0347       continue;
0348         }
0349     except("Error: Invalid processor type for ROOT output: %s", c.second->c_name());
0350       }
0351       m_parallel = false;
0352       internals->create_collections();
0353     }
0354 
0355     /// Check for valid output stream
0356     bool Digi2ROOTWriter::have_output()  const  {
0357       return internals->m_file.get() != nullptr;
0358     }
0359 
0360     /// Open new output stream
0361     void Digi2ROOTWriter::open_output() const   {
0362       internals->open();
0363     }
0364 
0365     /// Close possible open stream
0366     void Digi2ROOTWriter::close_output()  const  {
0367       internals->close();
0368     }
0369 
0370     /// Commit event data to output stream
0371     void Digi2ROOTWriter::commit_output() const  {
0372       internals->commit();
0373     }
0374 
0375     /// Standard constructor
0376     Digi2ROOTProcessor::Digi2ROOTProcessor(const DigiKernel& krnl, const std::string& nam)
0377       : DigiContainerProcessor(krnl, nam)
0378     {
0379     }
0380 
0381     void Digi2ROOTProcessor::convert_particles(DigiContext&     ctxt,
0382                            ParticleMapping& cont)  const
0383     {
0384       auto& coll = internals->get_collection(cont);
0385       auto* vec = coll.get<persistent_particles_t>();
0386       vec->clear();
0387       vec->reserve(cont.size());
0388       for( auto& p : cont )   {
0389     vec->emplace_back(std::make_pair(p.first, &p.second));
0390       }
0391       info("%s+++ %-24s added %6ld entries from mask: %04X",
0392            ctxt.event->id(), cont.name.c_str(), vec->size(), cont.key.mask());
0393     }
0394 
0395     void Digi2ROOTProcessor::convert_deposits(DigiContext&       ctxt,
0396                           DepositMapping&    cont,
0397                           const predicate_t& predicate)  const
0398     {
0399       auto& coll = internals->get_collection(cont);
0400       auto* vec  = coll.get<persistent_deposits_t>();
0401       vec->clear();
0402       vec->reserve(cont.size());
0403       for ( auto& depo : cont )   {
0404     if ( predicate(depo) )   {
0405       vec->emplace_back(std::make_pair(depo.first, &depo.second));
0406     }
0407       }
0408       info("%s+++ %-24s added %6ld entries from mask: %04X",
0409            ctxt.event->id(), cont.name.c_str(), vec->size(), cont.key.mask());
0410     }
0411 
0412     void Digi2ROOTProcessor::convert_deposits(DigiContext&       ctxt,
0413                           DepositVector&     cont,
0414                           const predicate_t& predicate)  const
0415     {
0416       auto& coll = internals->get_collection(cont);
0417       auto* vec  = coll.get<persistent_deposits_t>();
0418       vec->clear();
0419       vec->reserve(cont.size());
0420       for ( auto& depo : cont )   {
0421     if ( predicate(depo) )   {
0422       vec->emplace_back(std::make_pair(depo.first, &depo.second));
0423     }
0424       }
0425       info("%s+++ %-24s added %6ld entries from mask: %04X",
0426            ctxt.event->id(), cont.name.c_str(), vec->size(), cont.key.mask());
0427     }
0428 
0429     void Digi2ROOTProcessor::convert_history(DigiContext&       ctxt,
0430                          DepositsHistory&   cont,
0431                          work_t&            work,
0432                          const predicate_t& predicate)  const
0433     {
0434       info("%s+++ %-32s Segment: %d Predicate:%s Conversion to edm4hep not implemented!",
0435            ctxt.event->id(), cont.name.c_str(), int(work.input.segment->id),
0436            typeName(typeid(predicate)).c_str());
0437     }
0438 
0439     /// Main functional callback
0440     void Digi2ROOTProcessor::execute(DigiContext& ctxt, work_t& work, const predicate_t& predicate)  const  {
0441       if ( auto* p = work.get_input<ParticleMapping>() )
0442         convert_particles(ctxt, *p);
0443       else if ( auto* m = work.get_input<DepositMapping>() )
0444         convert_deposits(ctxt, *m, predicate);
0445       else if ( auto* v = work.get_input<DepositVector>() )
0446         convert_deposits(ctxt, *v, predicate);
0447       else if ( auto* h = work.get_input<DepositsHistory>() )
0448         convert_history(ctxt, *h, work, predicate);
0449       else
0450         except("Request to handle unknown data type: %s", work.input_type_name().c_str());
0451     }
0452 
0453   }    // End namespace digi
0454 }      // End namespace dd4hep
0455 
0456 /// Factory instantiation:
0457 #include <DDDigi/DigiFactories.h>
0458 DECLARE_DIGIACTION_NS(dd4hep::digi,Digi2ROOTWriter)
0459 DECLARE_DIGIACTION_NS(dd4hep::digi,Digi2ROOTProcessor)