ATLAS Offline Software
Loading...
Searching...
No Matches
xAODEventSelector.cxx
Go to the documentation of this file.
1
2
3/*
4 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
5*/
6
7// xAODEventSelector.cxx
8// Implementation file for class xAODEventSelector
9// Author: Johannes Elmsheuser, Will Buttinger
11
12// STL includes
13#include <sstream>
14#include <string>
15#include <algorithm>
16#include <vector>
17#include <stdint.h>
18
19// ROOT includes
20#include "TROOT.h"
22#include "TClass.h"
23#include "TFile.h"
24#include "TKey.h"
25#include "TLeaf.h"
26
27#include "Gaudi/Property.h"
28
29// Framework includes
30#include "GaudiKernel/FileIncident.h"
31#include "GaudiKernel/IIoComponentMgr.h"
32#include "GaudiKernel/ISvcLocator.h"
33#include "GaudiKernel/ITHistSvc.h"
34#include "GaudiKernel/MsgStream.h"
35#include "GaudiKernel/StatusCode.h"
36#include "GaudiKernel/System.h"
37#include "GaudiKernel/IClassIDSvc.h"
42
43// StoreGate includes
44
45#include "SGTools/BuiltinsClids.h" // to make sure we have their clids
46#include "SGTools/StlMapClids.h" // to make sure we have their clids
47#include "SGTools/StlVectorClids.h" // to make sure we have their clids
50
51// EventInfo includes
52#include "EventInfo/EventInfo.h"
53#include "EventInfo/EventType.h"
54#include "EventInfo/EventID.h"
56
57// Package includes
58#include "xAODEventSelector.h"
59#include "xAODBranchAddress.h"
60#include "RootGlobalsRestore.h"
61
62// xAOD include(s):
63#include "xAODRootAccess/Init.h"
64
65#include "GaudiKernel/ServiceHandle.h"
67#include <map>
68
69
73
74namespace Athena {
75
79class xAODEventContext : public ::IEvtSelector::Context
80{
81public:
85 virtual ~xAODEventContext() {}
87 virtual void* identifier() const override {
88 void* id ATLAS_THREAD_SAFE = const_cast<xAODEventSelector*>(m_evtsel);
89 return id;
90 }
91
92 const std::vector<std::string>& files() const { return m_evtsel->m_inputCollectionsName.value(); }
94 const TFile* file() const { return m_evtsel->m_tfile; }
96 StatusCode setFile ATLAS_NOT_THREAD_SAFE (const std::string& fname) {
97 return const_cast<xAODEventSelector*>(m_evtsel)->setFile(fname);
98 }
99
100 std::size_t fileIndex() const { return m_evtsel->m_collIdx; }
102 int64_t entry() const { return m_evtsel->m_curEvt; }
103
104private:
107};
108
110 ISvcLocator* svcLoc ) :
111 base_class ( name, svcLoc ),
112 m_dataStore( "StoreGateSvc/StoreGateSvc", name ),
113 m_imetaStore( "StoreGateSvc/InputMetaDataStore", name ),
114 m_ometaStore( "StoreGateSvc/MetaDataStore", name ),
115 m_clidsvc ( "ClassIDSvc", name ),
116 m_dictsvc ( "AthDictLoaderSvc", name ),
117 m_incsvc ( "IncidentSvc", name ),
118 m_poolSvc ( "PoolSvc" , name ),
119 m_ppSvc ( "ProxyProviderSvc" , name ),
120 m_nbrEvts ( 0 ),
121 m_curEvt ( 0 ),
122 m_collIdx ( 0 ),
123 m_collEvts ( ),
124 m_needReload (true),
126 m_tevent(NULL),
127 m_tfile(NULL),
129{
130//Properties important to end user:
131 declareProperty( "InputCollections", m_inputCollectionsName,"List of input (ROOT) file names" );
132 declareProperty( "SkipEvents",m_skipEvts = 0,"Number of events to skip at the beginning" );
133 declareProperty( "AccessMode", m_accessMode = -1, "-1 = use TEvent Default; 0 = BranchAccess; 1 = ClassAccess; 2 = AthenaAccess" );
134
135 declareProperty( "FillEventInfo", m_fillEventInfo=false,"If True, will fill old EDM EventInfo with xAOD::EventInfo content, necessary for database reading (IOVDbSvc)");
136
137 declareProperty( "PrintPerfStats", m_printPerfStats=false,"If True, at end of job will print the xAOD perf stats");
138
139//Expert Properties:
140 declareProperty( "EvtStore", m_dataStore, "Store where to publish data");
141 declareProperty( "ProxyProviderSvc" , m_ppSvc , "The ProxyProviderSvc that we should register ourself in and connect the EvtStore to");
142 declareProperty( "InputMetaStore",m_imetaStore, "Store where to publish (input) metadata");
143 declareProperty( "MetaStore",m_ometaStore, "Store where to publish (output) metadata");
144 declareProperty( "TreeName",m_tupleName = "CollectionTree","Name of the TTree to load/read from input file(s)" );
145 declareProperty( "MetaDataTreeName", m_metadataName = "MetaData","Name of the TTree to load/read metadata from input file(s)" );
146
147 declareProperty( "ReadMetaDataWithPool", m_readMetadataWithPool=false, "If true, using POOL to read metadata, will ensure input file is registered with catalog");
148 declareProperty( "printEventProxyWarnings", m_printEventProxyWarnings);
149
150#ifndef XAOD_ANALYSIS
151 declareProperty( "CollectionType", m_collectionType="", "Compability flag for RecExCommon");
152#endif
153
154}
155
156// Destructor
160
162{
163 ATH_MSG_VERBOSE ("Enter xAODEventSelector initialization...");
164
165 CHECK( m_clidsvc.retrieve() );
166 CHECK( m_dictsvc.retrieve() );
167
168 if ( m_tupleName.value().empty() ) {
169 ATH_MSG_ERROR("You have to give a TTree name to read from the ROOT files !");
170 return StatusCode::FAILURE;
171 }
172
173 const std::size_t nbrInputFiles = m_inputCollectionsName.value().size();
174 if ( nbrInputFiles < 1 ) {
175 ATH_MSG_ERROR("You need to give at least 1 input file !!" << endmsg
176 << "(Got [" << nbrInputFiles << "] file instead !)");
177 return StatusCode::FAILURE;
178 } else {
179 ATH_MSG_INFO("Selector configured to read [" << nbrInputFiles << "] file(s)...");
180 }
181
182 ATH_MSG_DEBUG("Calling xAOD::Init...");
183 int old_level = gErrorIgnoreLevel;
184 gErrorIgnoreLevel = kWarning;
185 xAOD::Init().ignore();
186 gErrorIgnoreLevel = old_level;
187 //if using the AthROOTErrorHandlerSvc, need to initialize it once again to give back error handling control to svc
188 if(serviceLocator()->existsService("AthROOTErrorHandlerSvc")) {
189 ServiceHandle<IService> ehSvc("AthROOTErrorHandlerSvc",name());
190 CHECK( ehSvc.retrieve() );
191 CHECK( ehSvc->initialize() ); //gives back control to svc
192 CHECK( ehSvc.release() );
193 }
194 switch(m_accessMode) {
195 case -1: ATH_MSG_INFO("Using DEFAULT xAOD access mode (usually same as CLASS mode)"); break;
196 case 0: ATH_MSG_INFO("Using BRANCH xAOD access mode"); break;
197 case 1: ATH_MSG_INFO("Using CLASS xAOD access mode"); break;
198 case 2: ATH_MSG_INFO("Using ATHENA xAOD access mode"); break;
199 }
200 if(m_accessMode != -1) {
201 m_tevent = new xAOD::xAODTEvent(xAOD::TEvent::EAuxMode(m_accessMode)); //our special class inheriting from xAOD::TEvent
202 } else {
203 m_tevent = new xAOD::xAODTEvent(); //our special class inheriting from xAOD::TEvent
204 }
205 m_tevent->printProxyWarnings(m_printEventProxyWarnings);
206
207 //use the first file to decide if reading metadata with POOL is ok
209 std::unique_ptr<TFile> f( TFile::Open( m_inputCollectionsName.value()[0].c_str() ) );
210 if(!f) {
211 ATH_MSG_ERROR("Failed to open first input file: " << m_inputCollectionsName.value()[0]);
212 return StatusCode::FAILURE;
213 }
214 if(!f->Get("##Shapes")) {
215 ATH_MSG_INFO("First file is not POOL file (e.g. is CxAOD), so reading metadata with xAOD::TEvent instead");
217 }
218 f->Close();
219 }
220
221
222 {
223 // register this service for 'I/O' events
224 ServiceHandle<IIoComponentMgr> iomgr("IoComponentMgr", name());
225 if (!iomgr.retrieve().isSuccess()) {
226 ATH_MSG_FATAL("Could not retrieve IoComponentMgr !");
227 return StatusCode::FAILURE;
228 }
229 if (!iomgr->io_register(this).isSuccess()) {
230 ATH_MSG_FATAL("Could not register myself with the IoComponentMgr !");
231 return StatusCode::FAILURE;
232 }
233 // register input file's names with the I/O manager
234 const std::vector<std::string>& incol = m_inputCollectionsName.value();
235 bool allGood = true;
236 for (std::size_t icol = 0, imax = incol.size(); icol < imax; icol++) {
237 if (!iomgr->io_register(this,
238 IIoComponentMgr::IoMode::READ,
239 incol[icol]).isSuccess()) {
240 ATH_MSG_FATAL("could not register [" << incol[icol] << "] for output !");
241 allGood = false;
242 } else {
243 ATH_MSG_VERBOSE("io_register[" << this->name() << "](" << incol[icol] << ") [ok]");
244 }
245 }
246 if (!allGood) {
247 return StatusCode::FAILURE;
248 }
249 }
250
251 if (!do_init_io().isSuccess()) {
252 return StatusCode::FAILURE;
253 }
254
255 // retrieve event stores
256 // this needs to happen *after* having initialized the i/o
257 // as our branches (which need a valid m_ntuple pointer)
258 // may be asked to be registered as we are a ProxyProvider.
259 // retrieving the event store will poke the ProxyProviderSvc...
260/*
261 if ( !m_dataStore.retrieve().isSuccess() ) {
262 ATH_MSG_ERROR("Could not retrieve [" << m_dataStore.typeAndName() << "] !!");
263 return StatusCode::FAILURE;
264 }
265
266 // ditto for (input) meta data store
267 if (!m_imetaStore.retrieve().isSuccess()) {
268 ATH_MSG_ERROR("Could not retrieve [" << m_imetaStore.typeAndName() << "] !!");
269 return StatusCode::FAILURE;
270 }
271
272 // ditto for (output) meta data store
273 if (!m_ometaStore.retrieve().isSuccess()) {
274 ATH_MSG_ERROR
275 ("Could not retrieve [" << m_ometaStore.typeAndName() << "] !!");
276 return StatusCode::FAILURE;
277 }
278*/
279
280 //ensure the xAODCnvSvc is listed in the EventPersistencySvc
281 ServiceHandle<IProperty> epSvc("EventPersistencySvc",name());
282
283
284 std::vector<std::string> propVal;
285 CHECK( Gaudi::Parsers::parse( propVal , epSvc->getProperty("CnvServices").toString() ) );
286 bool foundSvc(false); bool foundPoolSvc(false);
287 for(const std::string& s : propVal) {
288 if(s=="Athena::xAODCnvSvc") { foundSvc=true; }
289 if(s=="AthenaPoolCnvSvc") { foundPoolSvc=true; } //only need this if in hybrid mode
290 }
291 if(!foundSvc) propVal.push_back("Athena::xAODCnvSvc");
292 if(!foundPoolSvc && m_readMetadataWithPool) propVal.push_back("AthenaPoolCnvSvc");
293
294 if(!foundSvc || (!foundPoolSvc && m_readMetadataWithPool)) {
295 CHECK( epSvc->setProperty("CnvServices", Gaudi::Utils::toString( propVal ) ));
296 }
297
298
299 //we should also add ourself as a proxy provider
300 CHECK( m_ppSvc.retrieve() );
301
302 //ensure the MetaDataSvc is added as a provider first, if we are in hybrid mode
304 std::vector<std::string> propVal;
305 IProperty* prop = dynamic_cast<IProperty*>(&*m_ppSvc);
306 if (!prop) {
307 return StatusCode::FAILURE;
308 }
309 CHECK( Gaudi::Parsers::parse( propVal , prop->getProperty("ProviderNames").toString() ) );
310 bool foundSvc(false);
311 for(const std::string& s : propVal) {
312 if(s=="MetaDataSvc") { foundSvc=true; break; }
313 }
314 if(!foundSvc) {
315 propVal.push_back("MetaDataSvc");
316 IProperty* prop = dynamic_cast<IProperty*>(&*m_ppSvc);
317 if (!prop) {
318 return StatusCode::FAILURE;
319 }
320 CHECK( prop->setProperty("ProviderNames", Gaudi::Utils::toString( propVal ) ));
321 }
322 }
323
324 //now we add ourself as a provider
325 m_ppSvc->addProvider( this );
326 //trigger a reload of proxies in the storegate, which will poke the proxyprovidersvc
327 //not actually needed
328 //CHECK( m_dataStore->loadEventProxies() );
329
330
331 //finally ensure the storegate has our proxy set in it
332 //FIXME: this doesnt seem to allow multi storegates on the fly ???
333 //m_dataStore->setProxyProviderSvc( &*m_ppSvc );
334
335 CHECK( m_ppSvc.release() );
336
337
338 //load the first file .. this is so metadata can be read even if no events present
339 //checked above that there's at least one file
340 CHECK( setFile(m_inputCollectionsName.value()[0]) );
341
342 //first FirstInputFile incident so that input metadata store is populated by MetaDataSvc
343 m_incsvc->fireIncident(FileIncident(name(), "FirstInputFile", m_inputCollectionsName.value()[0]));
344
346
347
348 return StatusCode::SUCCESS;
349}
350
352{
353 ATH_MSG_VERBOSE ("Finalize...");
354 // FIXME: this should be tweaked/updated if/when a selection function
355 // or filtering predicate is applied (one day?)
356 ATH_MSG_INFO ("Total events read: " << (m_nbrEvts - m_skipEvts));
357
358 if(m_printPerfStats) {
361 }
362
363
364 return StatusCode::SUCCESS;
365}
366
368// Const methods:
370
371StatusCode
372xAODEventSelector::next( IEvtSelector::Context& ctx ) const
373{
374 // std::cout << "::next(fidx=" << m_collIdx << ", eidx=" << m_curEvt << ")"
375 // << std::endl;
376 ATH_MSG_DEBUG ("next() : iEvt " << m_curEvt);
377
378 // get evt context
379 xAODEventContext* rctx = dynamic_cast<xAODEventContext*>(&ctx);
380 if ( 0 == rctx ) {
381 ATH_MSG_ERROR ("Could not dyn-cast to xAODEventContext !!");
382 throw GaudiException("xAODEventSelector::next() - Unable to get xAODEventContext","xAODEventSelector",StatusCode::FAILURE);
383 }
384
385
386 const TFile *file = rctx->file();
387 if(file && m_nbrEvts==0) {
388 //fire the BeginInputFile incident for the first file
389 m_incsvc->fireIncident(FileIncident(name(), "BeginInputFile", file->GetName()));
390 }
391
392 if (!file) { //must be starting another file ...
393 auto& fnames = rctx->files();
394 //std::size_t fidx = rctx->fileIndex();
395 if( rctx->setFile("").isFailure() ) {
396 throw GaudiException("xAODEventSelector::next() - Fatal error when trying to setFile('')","xAODEventSelector",StatusCode::FAILURE);
397 }
398
399 while( m_tevent_entries == 0 ) { //iterate through files until we have one with entries
400 if (m_collIdx < int(rctx->files().size())) {
401 const std::string& fname = fnames[m_collIdx];
402 if( rctx->setFile( fname ).isFailure() ) {
403 throw GaudiException("xAODEventSelector::next() - Fatal error when trying to setFile('" + fname + "')","xAODEventSelector",StatusCode::FAILURE);
404 }
405 ATH_MSG_DEBUG("TEvent entries = " << m_tevent_entries);
406 //fire incident for this file ..
407 m_incsvc->fireIncident(FileIncident(name(), "BeginInputFile", rctx->file()->GetName()));
408 } else {
409 // end of collections
410 return StatusCode::FAILURE; //this is a valid failure ... athena will interpret as 'finished looping'
411 }
412 if( m_tevent_entries==0) m_collIdx++;
413
414
415 } //end of while loop
416
417 }
418
419
420 ATH_MSG_DEBUG("m_curEvt=" << m_curEvt);
421
422 //Infer the local entry (entry of current file) from the global entry
423
424 int64_t global_entry = rctx->entry(); //the actual event counter
425 int64_t entry = global_entry;
426 if (m_collEvts[m_collIdx].min_entries < 0) {
427 // need to trigger collmetadata...
428 const_cast<xAODEventSelector*>(this)->find_coll_idx(entry);
429 }
430 // rctx::entry is the *global* entry number.
431 // we need the local one...
432 entry = global_entry - m_collEvts[m_collIdx].min_entries; //actual entry in the current file
433
434
435
436 if ( m_tevent_entries > entry ) {
437
438 // Load the event:
439 if( m_tevent->getEntry( entry ) < 0 ) {
440 ATH_MSG_ERROR( "Failed to load entry " << static_cast< int >( entry ) );
441 throw GaudiException("xAODEventSelector::next() - xAOD::TEvent::getEntry returned less than 0 bytes","xAODEventSelector",StatusCode::FAILURE);
442 }
443
444 ++m_nbrEvts;
445 m_curEvt = global_entry + 1;
446
447 // std::cout << "--event-info--" << std::endl;
448 // event info
449
450 // EventInfo is required, otherwise Athena will crash
451 const xAOD::EventInfo* xaodEventInfo = 0;
452 if(m_fillEventInfo) {
453 if(m_tevent->retrieve( xaodEventInfo , "EventInfo").isFailure()) {
454 ATH_MSG_ERROR("Could not find xAOD::EventInfo");
455 throw GaudiException("xAODEventSelector::next() - Could not find xAOD::EventInfo","xAODEventSelector",StatusCode::FAILURE);
456 }
457 }
458 EventType* evtType = new EventType;
459 //const std::size_t runNbr = (xaodEventInfo) ? xaodEventInfo->runNumber() : 0;
460 EventInfo* evtInfo = new EventInfo(
461 (xaodEventInfo) ? new EventID(xaodEventInfo->runNumber(), xaodEventInfo->eventNumber(), xaodEventInfo->timeStamp(), xaodEventInfo->timeStampNSOffset(), xaodEventInfo->lumiBlock(), xaodEventInfo->bcid()) : new EventID(0, m_curEvt-1,0 ), evtType);
462 if ( !m_dataStore->record( evtInfo, "EventInfo" ).isSuccess() ) {
463 ATH_MSG_ERROR ("Could not record EventInfo !");
464 delete evtInfo; evtInfo = 0;
465 throw GaudiException("xAODEventSelector::next() - Could not record EventInfo","xAODEventSelector",StatusCode::FAILURE);
466 }
467
468 return StatusCode::SUCCESS;
469
470 } else {
471 // file is depleted
472 auto& fnames = rctx->files();
473 std::size_t fidx = rctx->fileIndex();
474 m_incsvc->fireIncident(FileIncident(name(), "EndInputFile", fnames[fidx]));
475
476 // prepare for next file, if any...
477 // std::cout << "=========================================================="
478 // << std::endl;
479 // std::cerr << "::switch to next file...\n";
480
481 // iterate over our "cached" transient addresses,
482 // marking them as garbage and dropping the RootBranchAddress (as a side effect of
483 // ::setAddress(NULL).
484 // this way, the next time we hit ::createRootBranchAddress or ::updateAddress
485 // all internal states are kosher.
486
487 /*
488 * Problem for rel22 --
489 * The proxyProviderSvc 'moves' the transient addresses created in this class
490 * and thus invalidates them.
491 * The sequence is proxyProviderSvc will call "loadAddresses" method below but
492 * when it puts them into a DataProxy it will move the addresses so they are now invalid
493 *
494 * Shortest route to fixing this is just to clear the addresses and not touch them again
495 */
496 self()->m_rootAddresses.clear();
497
498 for (auto& iaddr : self()->m_rootAddresses) {
499 iaddr.second = false; // mark as invalid
500 SG::TransientAddress* taddr = iaddr.first;
501 taddr->setAddress(NULL);
502 }
503 const bool forceRemove = false;
504 CHECK( m_dataStore->clearStore(forceRemove) ); //must clear the storegate so that any tampering user did in EndInputFile incident is cleared
505 m_needReload = true;
506
507 m_collIdx += 1;
508 CHECK( rctx->setFile("") );
509 return next(*rctx);
510 }
511
512 // NOT REACHED
513 // std::cout << "***end of collections***" << std::endl;
514 // end of collections
515 //return StatusCode::FAILURE;
516}
517
518StatusCode xAODEventSelector::next( Context& ctx, int jump ) const
519{
520 ATH_MSG_DEBUG ("next(" << jump << ") : iEvt " << m_curEvt);
521
522 if (self()->seek(ctx, m_curEvt + jump).isSuccess()) {
523 return StatusCode::FAILURE;
524 }
525 return next(ctx);
526}
527
528StatusCode
529xAODEventSelector::previous( IEvtSelector::Context& ctx ) const
530{
531 return next( ctx, -1 );
532}
533
534StatusCode
535xAODEventSelector::previous( Context& ctx, int jump ) const
536{
537 return next( ctx, -jump );
538}
539
540StatusCode
541xAODEventSelector::last( Context& /*ctxt*/ ) const
542{
543 ATH_MSG_ERROR ("............. Last Event Not Implemented .............");
544 return StatusCode::FAILURE;
545}
546
547
548StatusCode
549xAODEventSelector::rewind( Context& ctxt ) const
550{
551 return self()->seek(ctxt, 0);
552}
553
554StatusCode
555xAODEventSelector::createContext( Context*& refCtx ) const
556{
557 xAODEventContext *ctx = new xAODEventContext(this);
558 refCtx = ctx;
559 return StatusCode::SUCCESS;
560}
561
562StatusCode
563xAODEventSelector::createAddress( const Context& /*refCtx*/,
564 IOpaqueAddress*& /*addr*/ ) const
565{
566 //std::cerr << "::TTES::createAddress()...\n";
567 return StatusCode::SUCCESS;
568}
569
570StatusCode
571xAODEventSelector::releaseContext( Context*& refCtxt ) const
572{
573 if(refCtxt==0) return StatusCode::SUCCESS; //added to avoid warning from MetaDataSvc, which passes an empty context
574 xAODEventContext *ctx = dynamic_cast<xAODEventContext*>(refCtxt);
575 if ( ctx ) {
576 delete ctx; ctx = 0;
577 return StatusCode::SUCCESS;
578 }
579
580 return StatusCode::FAILURE;
581}
582
583StatusCode
584xAODEventSelector::resetCriteria( const std::string&, Context& ) const
585{
586 ATH_MSG_ERROR ("............. resetCriteria Not Implemented .............");
587 return StatusCode::FAILURE;
588}
589
591// Non-const methods:
593
598StatusCode
599xAODEventSelector::seek (Context& refCtxt, int evtnum) const
600{
601 // std::cout << "::seek - evtnum=" << evtnum
602 // << " curevt=" << m_curEvt
603 // << " curcol=" << m_collIdx
604 // << std::endl;
605 long coll_idx = find_coll_idx(evtnum);
606 // std::cout << "::seek - evtnum=" << evtnum
607 // << " curevt=" << m_curEvt
608 // << " curcol=" << m_collIdx
609 // << " colidx=" << coll_idx
610 // << std::endl;
611 if (coll_idx == -1 && evtnum < m_curEvt) {
612 coll_idx = m_collIdx;
613 }
614
615 if (coll_idx == -1) {
616 ATH_MSG_INFO("seek: reached end of input.");
617 return StatusCode::RECOVERABLE;
618 }
619
620 if (coll_idx != m_collIdx) {
621 // tell everyone we switched files...
622 xAODEventContext* rctx = dynamic_cast<xAODEventContext*>(&refCtxt);
623 if (!rctx) {
624 return StatusCode::FAILURE;
625 }
626 ATH_CHECK(rctx->setFile(""));
627 }
628
629 m_collIdx = coll_idx;
630 m_curEvt = evtnum;
631
632 return StatusCode::SUCCESS;
633}
634
639int
640xAODEventSelector::curEvent (const Context& /*refCtxt*/) const
641{
642 return m_curEvt;
643}
644
647StatusCode
649{
650 ATH_MSG_VERBOSE("I/O reinitialization...");
651
652 ServiceHandle<IIoComponentMgr> iomgr("IoComponentMgr", name());
653 if (!iomgr.retrieve().isSuccess()) {
654 ATH_MSG_FATAL("Could not retrieve IoComponentMgr !");
655 return StatusCode::FAILURE;
656 }
657 if (!iomgr->io_hasitem(this)) {
658 ATH_MSG_FATAL("IoComponentMgr does not know about myself !");
659 return StatusCode::FAILURE;
660 }
661 std::vector<std::string> inputCollections = m_inputCollectionsName.value();
662
663 for (std::size_t
664 i = 0,
665 imax = m_inputCollectionsName.value().size();
666 i < imax;
667 ++i) {
668 std::string &fname = inputCollections[i];
669 // std::cout << "--retrieve new name for [" << fname << "]...\n";
670 if (!iomgr->io_contains(this, fname)) {
671 ATH_MSG_ERROR("IoComponentMgr does not know about [" << fname << "] !");
672 return StatusCode::FAILURE;
673 }
674 if (!iomgr->io_retrieve(this, fname).isSuccess()) {
675 ATH_MSG_FATAL("Could not retrieve new value for [" << fname << "] !");
676 return StatusCode::FAILURE;
677 }
678 // std::cout << "--> [" << fname << "]\n" << std::flush;
679 }
680 // all good... copy over.
681 m_inputCollectionsName = inputCollections;
682
683 // remove our EventInfo if any...
684 // {
685 // const bool force_remove = true;
686 // if (!m_dataStore->clearStore(force_remove).isSuccess()) {
687 // ATH_MSG_ERROR("could not clear event store!");
688 // return StatusCode::FAILURE;
689 // } else {
690 // ATH_MSG_INFO("sgdump: \n" << m_dataStore->dump());
691 // }
692 // }
693
694 // std::cout << "--> do_init_io...\n" << std::flush;
695 if (!do_init_io().isSuccess()) {
696 return StatusCode::FAILURE;
697 }
698
699 ATH_MSG_INFO("I/O reinitialization... [done]");
700 return StatusCode::SUCCESS;
701}
702
703
707StatusCode
709 tadList& /*tads*/)
710{
711 // std::cerr << "TTES::preLoadAddresses(" << int(storeID)
712 // << "," << tads.size()
713 // << ")...\n";
714 return StatusCode::SUCCESS;
715}
716
718StatusCode
720{
721 if (m_needReload || m_rootAddresses.empty()) {
722 //CHECK(createMetaDataRootBranchAddresses());
723 return createRootBranchAddresses(storeID, tads);
724 }
725
726 return StatusCode::SUCCESS;
727}
728
730StatusCode
732 const EventContext& /*ctx*/)
733{
734 // check if this tad is known to us.
735 if (tad) {
736 auto itr = m_rootAddresses.find(tad);
737 if ( itr != m_rootAddresses.end() && itr->second ) {
738 return StatusCode::SUCCESS;
739 }
740 ATH_MSG_DEBUG("updateAddress: address [" << tad->clID() << "#"
741 << tad->name() << ") NOT known to us.");
742 return StatusCode::FAILURE;
743 }
744
745 // do nothing.
746 return StatusCode::SUCCESS;
747}
748
749
751// Protected methods:
753
754
755
756
757StatusCode
759 tadList &tads)
760{
761 if (storeID != StoreID::EVENT_STORE) {
762 ATH_MSG_INFO("-- not the event-store --");
763 return(StatusCode::SUCCESS);
764 }
765
766 if (0 == m_tfile) {
767 ATH_MSG_ERROR("null pointer to n-tuple !");
768 return StatusCode::FAILURE;
769 }
770
771 TTree* inputTree = dynamic_cast<TTree*>(m_tfile->Get(m_tupleName.value().c_str()));
772
773 if(inputTree!=0) {
774
775
776 ATH_MSG_DEBUG("Reading xAOD::EventFormat");
777
778 // m_tevent->dump();
779
780 const void* value_ptr = m_tevent; //passed as 'parameter' to the address object
781
782 std::set<std::string> missingAux;
783
784 for( auto itr = m_tevent->inputEventFormat()->begin(); itr!=m_tevent->inputEventFormat()->end();++itr) {
785 if(inputTree->GetBranch(itr->second.branchName().c_str())==0) continue; //skip branches that are not available in the input collection
786 ATH_MSG_VERBOSE("EFE:" << itr->first << " branchName = " << itr->second.branchName() << " className=" << itr->second.className());
787 CLID id = 0;
788 if( m_clidsvc->getIDOfTypeInfoName(itr->second.className(), id).isFailure() &&
789 m_clidsvc->getIDOfTypeName(itr->second.className(), id).isFailure()) {
790 //if this is an AuxStore (infer if key ends in Aux.), its possible we schema-evolved away from the version in the input file, but that this evolution is actually 'ok' in some cases. So don't print an error if the CLID is missing for an Aux, but we will print a warning at the end for these aux stores
791 if(itr->second.branchName().compare(itr->second.branchName().length()-4,4,"Aux.")==0) {
792 missingAux.insert( itr->second.className() );continue;
793 } else {
794 //vectors can be missing their std:: prefix, so add that and retry before failing
795 TString className = itr->second.className();
797 //ALT solution to this is do what RootNtupleEventSelector does: uses TClass:GetClass
798 //and GetTypeInfo() method to get the proper type info
799 TClass *cls = TClass::GetClass(className);
800 if(cls) {
801 const std::type_info *ti = cls->GetTypeInfo();
802 if(ti) className = System::typeinfoName(*ti);
803 }
804
805 if( m_clidsvc->getIDOfTypeInfoName(className.Data(), id).isFailure() &&
806 m_clidsvc->getIDOfTypeName(className.Data(), id).isFailure()) {
807 ATH_MSG_WARNING("No CLID for class " << itr->second.className() << " , cannot read " << itr->second.branchName());
808 continue;
809 }
810 }
811 }
812
813 const std::string br_name = itr->second.branchName();
814
816 (POOL_ROOTTREE_StorageType, id,
817 m_tupleName.value(),
818 br_name,
819 (unsigned long)(value_ptr),
820 (unsigned long)(0)); //IMPORTANT THIS IS 0: signals to xAODBranchAddress to read event-level info (see setTEventAddress)
821 // recycle old rootaddress, if any.
822 SG::TransientAddress* taddr = NULL;
823 // FIXME: should we only iterate over m_rootAddresses which have been marked
824 // as invalid ? (ie: iaddr->second == false)
825 // probably not worth it... (but depends on the "occupancy")
826 for (auto
827 iaddr = m_rootAddresses.begin(),
828 iaddre= m_rootAddresses.end();
829 iaddr != iaddre;
830 ++iaddr) {
831 SG::TransientAddress *old = iaddr->first;
832 if (old->clID() == id &&
833 old->name() == br_name) {
834 // found a "cached" transient address which corresponds to this clid+key
835 // bind it to our new RootBranchAddress...
836 old->setAddress(addr);
837 taddr = old;
838 iaddr->second = true; // mark as valid
839 break;
840 }
841 }
842 if (taddr == NULL) {
843 taddr = new SG::TransientAddress(id, br_name, addr);
844 taddr->setProvider(this, storeID);
845 taddr->clearAddress(false);
846 // only add the *new* TransientAddress to the input list as the *old* ones
847 // are already tracked by the datastore (via the sticky proxies)
848 tads.push_back(taddr);
849 // note: we can store this taddr *b/c* we don't clearAddress it
850 // ie: b/c we just called clearAddress(false) so it will be recycled
851 // over the events.
852 m_rootAddresses.insert(std::make_pair(taddr, true));
853 }
854 // }
855 }
856
857
858 if(missingAux.size()) {
859 std::string allAux; for(auto& s : missingAux) allAux += s + ", ";
860 ATH_MSG_WARNING("The following AuxStore types are not directly accessible (missing CLID, possibly from schema evolution): " << allAux);
861 }
862 } //end if block of requiring input tree to exist
863 else {
864 ATH_MSG_DEBUG("No input collection " << m_tupleName.value() << " found in input file " << m_tfile->GetTitle() );
865 }
866
867 m_needReload = false;
868 // remember that we need to fire a BeginInputFile incident.
869 // we can't fire it just now as some client may need the tree and its
870 // content loaded in the evtstore when their ::handle method is
871 // called.
872 // so we do it later.
873 //MOVED TO handle method - which is fired on BeginEvent after StoreGateSvc
874 //m_fireBIF = true;
875
876 ATH_MSG_DEBUG("In xAODEventSelector::createRootBranchAddresses end ...");
877
878 return StatusCode::SUCCESS;
879}
880
881StatusCode
883{
884
885 ATH_MSG_DEBUG("In xAODEventSelector::createMetaDataRootBranchAddresses start ...");
886
887 if ( 0 == m_tfile ) {
888 ATH_MSG_ERROR ("Could not get m_tfile !!");
889 throw "xAODEventSelector: Unable to get m_tfile";
890 }
891
892 //FIXME JE
893 ATH_MSG_DEBUG("m_metadataName.value().c_str() = " << m_metadataName.value().c_str() );
894 TTree* tree = dynamic_cast<TTree*>(m_tfile->Get(m_metadataName.value().c_str()));
895 ATH_MSG_DEBUG("m_tfile = " << m_tfile );
896 ATH_MSG_DEBUG("tree = " << tree );
897 if (!tree) std::abort();
898 TObjArray *leaves = tree->GetListOfLeaves();
899 if (!leaves) {
900 ATH_MSG_INFO("no leaves!!");
901 return StatusCode::SUCCESS;
902 }
903
904 // loop over leaves
905 for (Int_t i = 0; i < leaves->GetEntries(); ++i) {
906 TLeaf *leaf = (TLeaf *)leaves->At(i);
907 TBranch *branch = leaf->GetBranch();
908 if (branch) {
909
910 CLID id = 0;
911 const void* value_ptr = m_tevent;
912 const std::string type_name = leaf->GetTypeName();
913 const std::string br_name = branch->GetName();
914 // Skip if type_name does contain xAOD, ie. is not an xAOD container
915 const std::string toCheck = "xAOD::";
916 if (type_name.find(toCheck) == std::string::npos) {
917 ATH_MSG_DEBUG("** Skip type-name = " << type_name << ", br_name = " << br_name );
918 continue;
919 }
920 const std::string sg_key = br_name;//m_tupleName.value()+"/"+br_name;
921 TClass *cls = TClass::GetClass(type_name.c_str());
922 const std::type_info *ti = 0;
923
924 // Skip the EventFormat branch. That must not be disturbed by the
925 // generic metadata handling.
926 if( br_name == "EventFormat" ) continue;
927
928 if (cls) {
929 ti = cls->GetTypeInfo();
930 // first, try to load a dict for that class...
931 if (ti) {
932 m_dictsvc->load_type(*ti);
933 }
934 if (!ti) {
935 ATH_MSG_DEBUG("could not find a type-info for [" <<
936 type_name << "]");
937 continue;
938 }
939
940 // Find the clid for the typeInfo
942
943 if (id == 0) {
944 ATH_MSG_DEBUG("** could not find a CLID for type-name ["
945 << type_name << "]");
946 continue;
947 }
948
949
950
951 ATH_MSG_DEBUG("id = " << id << ", m_metadataName.value() = " << m_metadataName.value() << ", br_name = " << br_name << ", value_ptr = " << value_ptr);
954 (POOL_ROOTTREE_StorageType, id,
955 m_metadataName.value(),
956 br_name,
957 (unsigned long)(value_ptr),
958 (unsigned long)(1))); //IMPORTANT THIS IS 1: signals to BranchAddress to read metadata
959 if (!m_imetaStore->recordAddress(br_name, std::move(addr), true).isSuccess()) {
960 ATH_MSG_ERROR("could not record address at [" << br_name << "] in store ["
961 << m_imetaStore->name() << "]");
962 }
963 // SG::TransientAddress* taddr = new SG::TransientAddress
964 // (id, sg_key, addr);
965 // taddr->setProvider(this);
966 // taddr->clearAddress(true);
967 // tads.push_back(taddr);
968 }
969 }
970 }
971
972 ATH_MSG_DEBUG("In xAODEventSelector::createMetaDataRootBranchAddresses end ...");
973
974 return StatusCode::SUCCESS;
975}
976
977
978TFile*
979xAODEventSelector::fetchNtupleFile(const std::string& fname) const
980{
981 TFile* file = NULL;
982 if(fname.empty()) return file; //if blank, return 0
984 //see if file already open
985 file = (TFile*)gROOT->GetListOfFiles()->FindObject(fname.c_str());
986 if (!file) {
987 //open the file
988 file = TFile::Open(fname.c_str(), "READ");
989 if (file) file->SetName(fname.c_str());
990 }
991 //check file is ok before returning
992 if (!file || file->IsZombie()) {
993 ATH_MSG_ERROR("could not open next file in input collection ["
994 << fname << "]");
995 if (file) {
996 file->Close();
997 }
998 return 0;
999 }
1000 return file;
1001}
1002
1003//move onto given file
1004StatusCode xAODEventSelector::setFile(const std::string& fname) {
1005
1006 TFile* newFile = fetchNtupleFile(fname);
1007 if(!newFile && !fname.empty()) {
1008 ATH_MSG_FATAL( "xAODEventSelector: Unable to fetch Ntuple: " << fname);
1009 return StatusCode::FAILURE; //failed to load file
1010 }
1011
1012 if(m_tfile && m_tfile != newFile) {
1013 const std::string currFile = m_tfile->GetName();
1014 //disconnect pool if necessary ... always fire this, hopefully it is safe even if not needed
1015 m_poolSvc->disconnectDb("PFN:"+currFile).ignore();
1016 //close existing file
1017 m_tfile->Close();
1018 //we should also cleanup after pool, in case it has left open files dangling
1019 }
1020 m_tfile = newFile;
1021 m_tevent_entries = 0; //will set in a moment
1022
1023 if(!m_tfile) return StatusCode::SUCCESS; //must have been setting to blank file
1024
1025 if(m_tevent->readFrom( m_tfile ).isFailure()) {
1026 ATH_MSG_FATAL( "xAODEventSelector: TEvent cannot read " << fname);
1027 return StatusCode::FAILURE;
1028 }
1029
1030 m_tevent_entries = m_tevent->getEntries();
1031
1032 //need to load metadata for file
1033 if (!m_imetaStore->clearStore().isSuccess()) {
1034 ATH_MSG_INFO("could not clear store [" << m_imetaStore.typeAndName() << "]");
1035 return StatusCode::FAILURE;
1036 }
1037
1038
1040 //ensure input file collection created
1041 ATH_MSG_DEBUG("Creating poolsvc collection for " << fname);
1042 m_poolSvc->createCollection( "ImplicitCollection" , "PFN:"+fname , fname ); //FIXME: this throws exceptions which get in the way of debugging with gdb :-(
1043
1044 //metadata will be read by MetaDataSvc, triggered by the BeginInputFile call
1045 } else {
1046 if (!createMetaDataRootBranchAddresses().isSuccess()) {
1047 ATH_MSG_ERROR("Could not load metadata");
1048 }
1049 }
1050
1051
1052
1053 return StatusCode::SUCCESS;
1054
1055}
1056
1057
1058StatusCode
1060{
1061 // std::cout << "::fetchNtuple..." << std::endl;
1062
1063 // initialize some helper structures and data
1064 {
1066 zero.min_entries = -1;
1067 zero.max_entries = -1;
1068 m_collEvts.resize(m_inputCollectionsName.value().size(), zero);
1069 m_collIdx = 0;
1070 }
1071
1072
1073
1074 //CHECK( setFile( m_inputCollectionsName.value()[m_collIdx] ) );
1075
1076
1077 // std::cout << "::clear-root-addresses..." << std::endl;
1078 // reset the list of branches
1079 //m_rootAddresses.clear();
1080 m_needReload = true;
1081
1082 // skip events we are asked to skip
1084 m_nbrEvts = 0;
1085
1086 // std::cout << "::fetchNtuple...[done]" << std::endl;
1087 return StatusCode::SUCCESS;
1088}
1089
1093int
1095{
1096 // std::cout << "--find_coll_idx(" << evtidx << ")..." << std::endl
1097 // << "--collsize: " << m_collEvts.size() << std::endl;
1098 for (std::size_t i = 0, imax = m_collEvts.size();
1099 i < imax;
1100 ++i) {
1101 // std::cout << "--[" << i << "]...\n";
1102 CollMetaData &itr = m_collEvts[i];
1103 if (itr.min_entries == -1) {
1104 TFile *file = fetchNtupleFile(m_inputCollectionsName.value()[i]);
1105 if (file) {
1106 long offset = 0;
1107 if (i > 0) {
1108 CollMetaData &jtr = m_collEvts[i-1];
1109 offset += jtr.max_entries;
1110 }
1111 itr.min_entries = offset;
1112 TTree* tree = dynamic_cast<TTree*>(file->Get(m_tupleName.value().c_str()));
1113 itr.max_entries = offset + ( (tree) ? tree->GetEntriesFast() : 0);
1114 } else {
1115 throw "xAODEventSelector: Unable to fetch ntuple";
1116 }
1117 }
1118 // std::cout << "--[" << i << "] => [" << itr.min_entries << ", "
1119 // << itr.max_entries << ") evtidx=[" << evtidx << "]"
1120 // << std::endl;
1121 if (itr.min_entries <= evtidx && evtidx < itr.max_entries) {
1122 return i;
1123 }
1124 }
1125 return -1;
1126}
1127
1128
1129int xAODEventSelector::size (Context& /*refCtxt*/) const {
1130 //use find_coll_idx to trigger a population of the m_collEvts ... dummy call with -1 to trigger all colls loaded
1131 find_coll_idx(-1);
1132 return m_collEvts.back().max_entries;
1133}
1134
1135//not used for anything
1136void xAODEventSelector::handle(const Incident& /*incident*/) {
1137
1138}
1139
1140} //> namespace Athena
#define endmsg
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_FATAL(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
a static registry of CLID->typeName entries.
macros to associate a CLID to a type
#define CHECK(...)
Evaluate an expression and check for errors.
This class provides a unique identification for each event, in terms of run/event number and/or a tim...
This class provides general information about an event.
uint32_t CLID
The Class ID type.
Include TBranchElement.h, suppressing clang warnings.
int imax(int i, int j)
Define macros for attributes used to control the static checker.
#define ATLAS_THREAD_SAFE
state of a few global resources from ROOT and restores their initial value upon d-tor call.
A simple class to do the retrieve from TEvent.
event selector context ... just holds reference back to the selector
int64_t entry() const
access to the current event entry number
StatusCode setFile ATLAS_NOT_THREAD_SAFE(const std::string &fname)
call to setFile on evtSel
std::size_t fileIndex() const
access to the file iterator
virtual void * identifier() const override
identifier method required by IEvtSelector::Context
const std::vector< std::string > & files() const
access to the container of files
xAODEventContext(const xAODEventSelector *sel)
standard c-tor with initialization
const xAODEventSelector * m_evtsel
reference to the hosting event selector instance
const TFile * file() const
access to the current file
virtual ~xAODEventContext()
standard d-tor
Class implementing the GAUDI IEvtSelector interface using ROOT TTree as a backend.
ServiceHandle< StoreGateSvc > m_ometaStore
Pointer to the StoreGateSvc output metadata store.
virtual StatusCode updateAddress(StoreID::type storeID, SG::TransientAddress *tad, const EventContext &ctx) override
update a transient Address
virtual int size(Context &refCtxt) const override
ICollectionSize interface
StringProperty m_tupleName
Name of TTree to load from collection of input files.
virtual StatusCode next(Context &refCtxt) const override
xAODEventSelector(const std::string &name, ISvcLocator *svcLoc)
Constructor with parameters:
long m_nbrEvts
Number of Events read so far.
ServiceHandle< IDictLoaderSvc > m_dictsvc
Pointer to the IDictLoaderSvc.
TFile * m_tfile
current TFile being read
virtual StatusCode resetCriteria(const std::string &cr, Context &ctx) const override
StringArrayProperty m_inputCollectionsName
List of input files containing TTree.
StatusCode createRootBranchAddresses(StoreID::type storeID, tadList &tads)
helper method to create proxies
int find_coll_idx(int evtidx) const
helper method to get the collection index (into m_inputCollectionsName) for a given event index evtid...
StatusCode createMetaDataRootBranchAddresses() const
helper method to create proxies for the metadata store
virtual StatusCode releaseContext(Context *&refCtxt) const override
friend class Athena::xAODEventContext
StringProperty m_metadataName
Name of TTree to load from metadata of input files.
xAOD::xAODTEvent * m_tevent
current TEvent being read
xAODEventSelector * self() const
non-const access to self (b/c next() is const)
std::vector< CollMetaData > m_collEvts
cache of the number of entries for each collection
StatusCode do_init_io()
helper method to init the i/o components
virtual StatusCode initialize() override
virtual StatusCode io_reinit() override
Callback method to reinitialize the internal state of the component for I/O purposes (e....
ServiceHandle< IProxyProviderSvc > m_ppSvc
Handle to the proxy provider svc.
virtual StatusCode loadAddresses(StoreID::type storeID, tadList &list) override
get all new addresses from Provider for this Event.
ServiceHandle< StoreGateSvc > m_dataStore
Pointer to the StoreGateSvc event store.
StatusCode setFile(const std::string &fname)
switch to given file, loading metadata and triggering a beginInputFile incident
virtual StatusCode previous(Context &refCtxt) const override
std::unordered_map< SG::TransientAddress *, bool > m_rootAddresses
virtual int curEvent(const Context &refCtxt) const override
return the current event number.
ServiceHandle< IIncidentSvc > m_incsvc
Handle to the incident service.
virtual StatusCode createAddress(const Context &refCtxt, IOpaqueAddress *&) const override
virtual StatusCode finalize() override
ServiceHandle< IClassIDSvc > m_clidsvc
Pointer to the IClassIDSvc.
virtual StatusCode last(Context &refContext) const override
virtual StatusCode seek(Context &refCtxt, int evtnum) const override
Seek to a given event number.
TFile * fetchNtupleFile(const std::string &fname) const
helper method to retrieve the correct tuple
long m_curEvt
current event index
ServiceHandle< IPoolSvc > m_poolSvc
Handle to the PoolSvc (used in Hybrid mode when user is reading metadata with pool)
virtual StatusCode createContext(Context *&refpCtxt) const override
virtual ~xAODEventSelector()
Destructor:
long m_skipEvts
Number of events to skip at the beginning.
virtual StatusCode rewind(Context &refCtxt) const override
long m_collIdx
current collection index (into m_inputCollectionsName)
virtual void handle(const Incident &incident) override
virtual StatusCode preLoadAddresses(StoreID::type storeID, tadList &list) override
ServiceHandle< StoreGateSvc > m_imetaStore
Pointer to the StoreGateSvc input metadata store.
static CLID typeinfoToCLID(const std::type_info &ti)
Return the CLID corresponding to a type_info.
Simple smart pointer for Gaudi-style refcounted objects.
CLID clID() const
Retrieve string key:
void clearAddress(const bool &flag)
Return the clearAddress flag.
const std::string & name() const
Get the primary (hashed) SG key.
void setAddress(CxxUtils::RefCountedPtr< IOpaqueAddress > pAddress)
Retrieve primary clid.
void setProvider(IAddressProvider *provider, StoreID::type storeID)
@ EVENT_STORE
Definition StoreID.h:26
uint32_t lumiBlock() const
The current event's luminosity block number.
uint32_t bcid() const
The bunch crossing ID of the event.
uint32_t timeStamp() const
POSIX time in seconds from 1970. January 1st.
uint32_t runNumber() const
The current event's run number.
uint32_t timeStampNSOffset() const
Nanosecond time offset wrt. the time stamp.
uint64_t eventNumber() const
The current event's event number.
ReadStats & stats()
Access the object belonging to the current thread.
Definition IOStats.cxx:17
static IOStats & instance()
Singleton object accessor.
Definition IOStats.cxx:11
void stop()
Stop the statistics collection.
void start(bool clear=true)
Start the statistics collection.
static PerfStats & instance()
Function accessing the singleton instance.
void Print(::Option_t *option="") const
Print information about the collected statistics.
void zero(TH2 *h)
zero the contents of a 2d histogram
Some weak symbol referencing magic... These are declared in AthenaKernel/getMessageSvc....
StatusCode parse(std::tuple< Tup... > &tup, const Gaudi::Parsers::InputData &input)
StatusCode Init(const char *appname)
Function initialising ROOT/PyROOT for using the ATLAS EDM.
Definition Init.cxx:31
EventInfo_v1 EventInfo
Definition of the latest event info version.
long max_entries
number of entries after this collection
long min_entries
number of entries up to this collection
TChain * tree
TFile * file