File indexing completed on 2025-01-18 09:14:05
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #ifndef DIGI_DIGI2ROOT_H
0014 #define DIGI_DIGI2ROOT_H
0015
0016
0017 #include <DDDigi/DigiOutputAction.h>
0018 #include <DDDigi/DigiData.h>
0019
0020
0021 namespace dd4hep {
0022
0023
0024 namespace digi {
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036 class Digi2ROOTWriter : public DigiOutputAction {
0037 public:
0038 class internals_t;
0039
0040 protected:
0041
0042 std::shared_ptr<internals_t> internals;
0043
0044 protected:
0045
0046 DDDIGI_DEFINE_ACTION_CONSTRUCTORS(Digi2ROOTWriter);
0047
0048 virtual ~Digi2ROOTWriter();
0049
0050 public:
0051
0052 Digi2ROOTWriter(const kernel_t& kernel, const std::string& nam);
0053
0054 virtual void initialize() override;
0055
0056 virtual bool have_output() const override final;
0057
0058 virtual void open_output() const override final;
0059
0060 virtual void close_output() const override final;
0061
0062 virtual void commit_output() const override final;
0063 };
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074 class Digi2ROOTProcessor : public DigiContainerProcessor {
0075 friend class Digi2ROOTWriter;
0076 protected:
0077
0078 std::shared_ptr<Digi2ROOTWriter::internals_t> internals;
0079
0080 public:
0081
0082 Digi2ROOTProcessor(const DigiKernel& krnl, const std::string& nam);
0083
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
0092 virtual void execute(DigiContext& context, work_t& work, const predicate_t& predicate) const override final;
0093 };
0094 }
0095 }
0096 #endif
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
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
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
0128 namespace dd4hep {
0129
0130
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
0137
0138
0139
0140
0141
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
0163 Digi2ROOTWriter* m_parent { nullptr };
0164
0165 Collections m_collections { };
0166
0167 std::unique_ptr<TFile> m_file { };
0168
0169 TTree* m_tree { nullptr };
0170
0171
0172 std::string m_section { "EVENT" };
0173
0174
0175 Int_t m_basket_size { 32000 };
0176
0177 Int_t m_split_level { 99 };
0178
0179 private:
0180
0181 template <typename T> T* register_collection(const std::string& name, T* collection);
0182
0183 public:
0184
0185 internals_t(Digi2ROOTWriter* parent);
0186
0187 ~internals_t();
0188
0189
0190 void open();
0191
0192 void close();
0193
0194 void commit();
0195
0196
0197 void create_collections();
0198
0199 void clearCollections();
0200
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
0213 Digi2ROOTWriter::internals_t::internals_t(Digi2ROOTWriter* parent) : m_parent(parent)
0214 {
0215 }
0216
0217
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
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
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
0263 void Digi2ROOTWriter::internals_t::clearCollections() {
0264 for( auto& coll : m_collections )
0265 coll.second.clear();
0266 }
0267
0268
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
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
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
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
0335 Digi2ROOTWriter::~Digi2ROOTWriter() {
0336 internals.reset();
0337 InstanceCount::decrement(this);
0338 }
0339
0340
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 ) {
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
0356 bool Digi2ROOTWriter::have_output() const {
0357 return internals->m_file.get() != nullptr;
0358 }
0359
0360
0361 void Digi2ROOTWriter::open_output() const {
0362 internals->open();
0363 }
0364
0365
0366 void Digi2ROOTWriter::close_output() const {
0367 internals->close();
0368 }
0369
0370
0371 void Digi2ROOTWriter::commit_output() const {
0372 internals->commit();
0373 }
0374
0375
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
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 }
0454 }
0455
0456
0457 #include <DDDigi/DigiFactories.h>
0458 DECLARE_DIGIACTION_NS(dd4hep::digi,Digi2ROOTWriter)
0459 DECLARE_DIGIACTION_NS(dd4hep::digi,Digi2ROOTProcessor)