ATLAS Offline Software
Loading...
Searching...
No Matches
MixingEventSelector.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
6ATLAS_NO_CHECK_FILE_THREAD_SAFETY; // non-MT EventSelector
7
11#include "EventInfo/EventInfo.h"
12#include "EventInfo/EventID.h"
13#include "EventInfo/EventType.h"
18#include "SGTools/DataProxy.h"
20
21#include "GaudiKernel/GaudiException.h"
22#include "GaudiKernel/TypeNameString.h"
23#include "GaudiKernel/MsgStream.h"
24#include "GaudiKernel/GenericAddress.h"
25#include "CLHEP/Random/RandFlat.h"
27#include <charconv>
28#include <algorithm>
29#include <cassert>
30#include <functional>
31#include <iostream>
32#include <fstream>
33#include <stdexcept>
34#include <sstream>
35#include <string>
36#include <print>
37
38using namespace std;
39using SG::DataProxy;
40
41#ifdef DEBUG_OUTPUT_STATUS
42ofstream outfile2("status.txt");
43#endif
44
45MixingEventSelector::MixingEventSelector(const string& name, ISvcLocator* svc) :
46 base_class(name,svc),
48 m_pEventStore( "StoreGateSvc", name )
49{
50}
51
54
55StatusCode
57 ATH_MSG_INFO ("Initializing {}", name());
58
59// defer this (it triggers a init loop via PPS
60// if (!m_pEventStore.retrieve().isSuccess())
61// return StatusCode::FAILURE;
62
63 //setup random stream
64 CLHEP::HepRandomEngine* collEng(m_atRndmSvc->GetEngine(m_randomStreamName.value()));
65 if(nullptr == collEng ) {
66 ATH_MSG_ERROR ("can not get random stream {}", m_randomStreamName.value());
67 return StatusCode::FAILURE;
68 }
69 //flat distribution in [0,1] range
70 m_chooseRangeRand = std::make_unique<CLHEP::RandFlat>(*(collEng), 0.0, 1.0);
71
72 ATH_CHECK( m_helperTools.retrieve() );
73 for (ToolHandle<IAthenaSelectorTool>& tool : m_helperTools) {
74 ATH_CHECK( tool->postInitialize() );
75 }
76
77 return StatusCode::SUCCESS;
78}
79
80StatusCode
82 ATH_MSG_DEBUG ("Finalizing {}", name());
83
84 for (ToolHandle<IAthenaSelectorTool>& tool : m_helperTools) {
85 tool->preFinalize().ignore();
86 }
87
88 const std::string& fname(m_statusFileName.value());
89 ofstream outfile(fname.c_str());
90 if ( outfile ) {
93 while (i != iEnd) outfile << (*i++).toString();
94 } else if (!fname.empty()) {
95 ATH_MSG_WARNING("unable to open trigger list status file {}", fname);
96 }
97
98 return StatusCode::SUCCESS;
99}
100
101
102void
103MixingEventSelector::setUpTriggerList(Gaudi::Details::PropertyBase&) {
104 using std::placeholders::_1;
106 for_each(m_triggerListProp.value().begin(), m_triggerListProp.value().end(),
107 bind(&MixingEventSelector::decodeTrigger, this, _1));
109}
110
111void
112MixingEventSelector::decodeTrigger(const std::string & triggDescr) {
113 //all this would be much more readable without error reporting...
114 const auto tokens = CxxUtils::tokenize(triggDescr, " :");
115 //we need exactly three tokens: selector name, first and last event 2 B read
116 if (tokens.size() == 3) {
117 auto iToken = tokens.begin();
118 Gaudi::Utils::TypeNameString selTN(*iToken++);
119 //get selector
120 SmartIF<IEvtSelector> pSelector(serviceLocator()->service(selTN));
121 if (pSelector) {
122 //FIXME if (!pSelector.done()) {
123 //try to add to trig list
124 unsigned int firstEvt{};
125 unsigned int lastEvt{};
126 auto string1 = *iToken++;
127 auto string2 = *iToken;
128 auto [ptr1, ec1] = std::from_chars(string1.data(), string1.data() + string1.size(), firstEvt);
129 auto [ptr2, ec2] = std::from_chars(string2.data(), string2.data() + string2.size(), lastEvt);
130 if ( ec1 != std::errc() || ec2 != std::errc() ) {
131 ATH_MSG_ERROR("decodeTrigger: Can't cast [{} {}] to double(frequency). SKIPPING",
132 string1, string2);
133 } else {
134 if (m_trigList.add(Trigger(pSelector, firstEvt, lastEvt))) {
135 if (msgLvl(MSG::DEBUG)) {
136 SmartIF<INamedInterface> pNamed(pSelector);
137 if (pNamed) {
138 msg() << "decodeTrigger: added selector " << pNamed->name()
139 << " first event to be read " << firstEvt
140 << " last event to be read " << lastEvt << endmsg;
141 }
142 }
143 } else {
145 ("decodeTrigger: Selector [{}/{}] not added",
146 selTN.type(), selTN.name());
147 } //can add to range
148 }
149 } else {
151 ("decodeTrigger: Selector [{}/{}] can not be found or created",
152 selTN.type(), selTN.name());
153 } //selector available
154 } else {
156 ("decodeTrigger: Badly formatted descriptor [{}]. SKIPPING",
157 triggDescr);
158
159 } //can parse property string
160}
161
162#ifndef NDEBUG
163#define FORWARD___DEBUG( METHOD )\
164 { ATH_MSG_VERBOSE ("forwarding " << #METHOD << " to service "\
165 << (validTrigger() ? currentTrigger()->name() : "NONE")); }
166#else
167#define FORWARD___DEBUG( METHOD )
168#endif
169
170StatusCode MixingEventSelector::createContext(IEvtSelector::Context*& pctxt) const {
171 pctxt=nullptr;
172 if (!validTrigger()) return StatusCode::FAILURE;
174 StatusCode sc(StatusCode::FAILURE);
175 while (iTr != m_trigList.end() && (sc=(iTr++)->createContext(pctxt)).isSuccess()) ;
176 return sc;
177}
178
179StatusCode
180MixingEventSelector::next(IEvtSelector::Context& /*c*/) const {
181 StatusCode sc(StatusCode::FAILURE);
182 do {
183#ifdef DEBUG_OUTPUT_STATUS
186 while (i != iEnd) outfile2 << (*i++).toString(); //output status
187#endif
189 sc = currentTrigger()->next();
190 if (sc.isFailure()){
192 continue; // we have to add "continue;" after "m_trigList.remove(m_pCurrentTrigger);
193 }
194 } while ((sc.isFailure() || currentTrigger()->done()) && !m_trigList.empty() );
195 // use !m_trigList.empty() to replace validTrigger(), which is not working well
196
197 std::vector<ToolHandle<IAthenaSelectorTool> >::const_iterator
198 i(m_helperTools.begin()), iE(m_helperTools.end());
199 while (i != iE) ((*i++)->preNext()).ignore();
200
201 ++m_eventPos;
203
204 i=m_helperTools.begin(); iE=m_helperTools.end();
205 while (sc.isSuccess() && (i != iE)) {
206 sc =(*i)->postNext();
207 if (sc.isRecoverable())
208 ATH_MSG_INFO("Request skipping event from: {}", (*i)->name());
209 else if (sc.isFailure())
210 ATH_MSG_WARNING("{}:postNext failed", (*i)->name());
211 ++i;
212 }
213 return sc;
214}
215
216
217StatusCode
218MixingEventSelector::createAddress(const IEvtSelector::Context& /*c*/,
219 IOpaqueAddress*& pAddr) const {
220 pAddr=nullptr;
221 if (!validTrigger()) return StatusCode::FAILURE;
222
224 return (currentTrigger()->createAddress(pAddr).isSuccess() &&
225 pAddr != nullptr) ? StatusCode::SUCCESS : StatusCode::FAILURE;
226}
227
228StatusCode
230 IAddressProvider::tadList& /*tads*/ ) {
231 return StatusCode::SUCCESS;
232}
233
234StatusCode
236 IAddressProvider::tadList& /*tads*/ )
237{
238 if (storeID != StoreID::EVENT_STORE && storeID != StoreID::PILEUP_STORE)
239 return StatusCode::SUCCESS;
240
242 if (!m_pEventStore->contains (mclid, m_mergedEventInfoKey)) {
243 // We create the DataProxy here rather than relying on ProxyProvideSvc
244 // to do it because we want to set a non-default dataloader on the proxy.
245 SG::TransientAddress tad (mclid,
247 new GenericAddress (0, mclid),
248 false);
249 auto dp = std::make_unique<SG::DataProxy> (std::move(tad),
250 this,
251 true);
252 ATH_CHECK( m_pEventStore->addToStore (mclid, dp.release()) );
253 }
254 return StatusCode::SUCCESS;
255}
256
257StatusCode
259 const EventContext&) {
260 return StatusCode::FAILURE;
261}
262
263#undef FORWARD___DEBUG
264
265unsigned long MixingEventSelector::getEventNo() const {
266 return ( (m_eventNumbers.value().size() > m_eventPos) ?
267 m_eventNumbers.value()[m_eventPos] :
268 m_eventPos );
269}
270
271//remember that m_pCurrentTrigger and m_trigList are mutable
274 //we look for the first trigger which is not done
275 do {
276 //if called before initialize, choose the last trigger in list
277 unsigned int iTrig = (nullptr != m_chooseRangeRand) ?
278 (unsigned int)(m_chooseRangeRand->fire() * double(m_trigList.todo())) :
279 m_trigList.todo();
280 m_pCurrentTrigger = m_trigList.elementInRange(iTrig);
281 } while (validTrigger() && m_pCurrentTrigger->done() &&
282 m_trigList.remove(m_pCurrentTrigger)); //remove a done trigger
283
284 //printouts
285 if (!validTrigger()) {
286 ATH_MSG_INFO ("setCurrentTrigger: end of input");
287 } else {
288 ATH_MSG_DEBUG ("setCurrentTrigger: now using selector {}",
289 currentTrigger()->name());
290 }
291
292 return m_pCurrentTrigger;
293}
294
299
300bool
302 bool newElem(end() == find(begin(), end() , trig));
303 if (newElem) {
304 m_todo += trig.todo();
305 m_trigs.push_back(trig);
306 m_rangeEnd.push_back(m_todo);
307#ifndef NDEBUG
308 MsgStream log(Athena::getMessageSvc(), "MixingEventSelector::TriggerList");
309 if (log.level() <= MSG::DEBUG) {
310 log << MSG::DEBUG << "add: trigger "
311 << trig.name() << ". New trigger table: \n" << toString() <<endmsg;
312 }
313#endif
314 }
315 return newElem;
316}
317
318bool
320 bool removed(false);
321 unsigned int nElem(m_trigs.size());
322 if (nElem) {
323 unsigned int trigTodo(iTrig->todo());
324 unsigned int trigIndex(iTrig - begin());
325#ifndef NDEBUG
326 string trigName(iTrig->name());
327#endif
328 m_trigs.erase(iTrig);
329 removed = nElem > m_trigs.size();
330 if (removed) {
331 //this means we erased iTrig. Remove its todo count from total
332 m_todo -= trigTodo;
333 //and from each of the subsequent ranges
334 for (unsigned int i=trigIndex+1; i<m_rangeEnd.size(); ++i)
335 m_rangeEnd[i] -= trigTodo;
336 //finally erase the corresponding rangeEnd element
337 m_rangeEnd.erase(m_rangeEnd.begin()+trigIndex);
338#ifndef NDEBUG
339 MsgStream log(Athena::getMessageSvc(), "MixingEventSelector::TriggerList"); //FIXME
340 if (log.level() <= MSG::DEBUG) {
341 log << MSG::DEBUG << "remove: trigger "
342 << trigName
343 << ". New trigger table: \n" << toString() <<endmsg;
344 }
345#endif
346 }
347 }
348 return removed;
349}
350
351string
353 ostringstream os;
354 for (unsigned int i=0; i<m_trigs.size(); ++i) {
355 //cant do os << m_trigs[i].toString();
356 std::println (os, "{}, already read={}, to do={}{} - endRange: {}",
357 m_trigs[i].name(), m_trigs[i].read(), m_trigs[i].todo(),
358 (m_trigs[i].done() ? " done " : " "),
359 m_rangeEnd[i]);
360 }
361 os << endl;
362 return string(os.str());
363}
364
367 iterator iTrig(m_trigs.begin()), eTrig(m_trigs.end());
368 std::vector<unsigned int>::const_iterator iRange(m_rangeEnd.begin());
369 std::vector<unsigned int>::const_iterator eRange(m_rangeEnd.end());
370 while (eRange != iRange && eTrig != iTrig && i > *iRange){
371 ++iRange; ++iTrig;
372 }
373#ifndef NDEBUG
374 MsgStream log(Athena::getMessageSvc(), "MixingEventSelector::TriggerList");
375 if (log.level() <= MSG::VERBOSE) {
376 if (eRange != iRange) log << MSG::VERBOSE
377 << "elementInRange: rangeEnd=" << *iRange
378 << " matches i=" << i << endmsg;
379 }
380#endif
381 return iTrig;
382}
383
385 unsigned int firstEvt,
386 unsigned int lastEvt):
387 m_pSelector(pSel), m_firstEvent(firstEvt),
388 m_toRead(lastEvt+1), m_todo(m_toRead-firstEvt), m_reads(0),
389 m_current(nullptr)
390 { }
391
392IEvtSelector::Context& MixingEventSelector::Trigger::currentContext() const {
393 //make sure we have a context!
394 if (nullptr == m_current) {
395 IEvtSelector::Context* pTmp(nullptr);
396 if ((createContext(pTmp)).isFailure())
397 throw GaudiException("MixingEventSelector::Trigger::currentContext(): can't create context",
398 name(),StatusCode::FAILURE);
399 }
400 // cppcheck-suppress nullPointerRedundantCheck; createContext() sets m_current
401 return *m_current;
402}
403
404std::string
406 ostringstream os;
407 std::println (os, "{}, already read={}, to do={}", name(), m_reads, todo());
408 return string(os.str());
409}
410
411StatusCode
413 StatusCode sc(StatusCode::FAILURE);
414 if (!done()) {
415 sc= selector().next(currentContext());
416 while (sc.isSuccess() && (++m_reads < m_firstEvent))
417 sc = selector().next(currentContext());// m_reads, m_current are mutable
418 }
419 return sc;
420}
421
422StatusCode
424 return selector().previous(currentContext());
425}
426
427StatusCode
429 return (done() ?
430 StatusCode::FAILURE :
432}
433
434StatusCode
435MixingEventSelector::Trigger::createContext(IEvtSelector::Context*& pCtxt) const{
436 StatusCode sc(StatusCode::FAILURE);
437 if (!done()) {
438 sc = selector().createContext(pCtxt);
439 m_current = pCtxt;
440 }
441 return sc;
442}
443
444bool
446 return (toRead() <= m_reads);
447}
448
449
450StatusCode MixingEventSelector::last(IEvtSelector::Context&) const {
451 return StatusCode::FAILURE;
452}
453StatusCode MixingEventSelector::next(IEvtSelector::Context&, int) const {
454 return StatusCode::FAILURE;
455}
456StatusCode MixingEventSelector::previous(IEvtSelector::Context&) const {
457 return StatusCode::FAILURE;
458}
459StatusCode MixingEventSelector::previous(IEvtSelector::Context&,int) const {
460 return StatusCode::FAILURE;
461}
462StatusCode MixingEventSelector::rewind(IEvtSelector::Context&) const {
463 return StatusCode::FAILURE;
464}
465StatusCode MixingEventSelector::releaseContext(IEvtSelector::Context*&) const {
466 return StatusCode::FAILURE;
467}
468StatusCode MixingEventSelector::resetCriteria(const std::string&,
469 IEvtSelector::Context&)const {
470 return StatusCode::FAILURE;
471}
472
473
474// IConverter implementation.
476{
477 static const CLID cid = ClassID_traits<EventInfo>::ID(); return cid;
478}
480{
481 return 0;
482}
483
484
496StatusCode MixingEventSelector::createObj(IOpaqueAddress* /*pAddress*/,
497 DataObject*& refpObject)
498{
499 const EventInfo* pEInfo(nullptr);
500 if (!(m_pEventStore->retrieve(pEInfo)).isSuccess()) {
502 ("addMergedEventInfo: event store does not contain "\
503 "an EventInfo object!");
504 return StatusCode::RECOVERABLE;
505 }
506
507 // copy the original event to a new MergedEventInfo
508 auto mei = std::make_unique<MergedEventInfo> (*pEInfo,
510 getEventNo());
511 refpObject = SG::asStorable (std::move (mei));
512
513
514 //finally slam a new EventID in place of the old! HACK!!! FIXME!!
515 (const_cast<EventInfo*>(pEInfo))->setEventID(
517
518 return StatusCode::SUCCESS;
519}
520
521
522// IConverter dummies.
523StatusCode MixingEventSelector::setDataProvider(IDataProviderSvc* /*pService*/)
524{
525 std::abort();
526}
527SmartIF<IDataProviderSvc>& MixingEventSelector::dataProvider() const
528{
529 std::abort();
530}
531StatusCode MixingEventSelector::setConversionSvc(IConversionSvc* /*pService*/)
532{
533 std::abort();
534}
535SmartIF<IConversionSvc>& MixingEventSelector::conversionSvc() const
536{
537 std::abort();
538}
539StatusCode MixingEventSelector::setAddressCreator(IAddressCreator* /*creator*/)
540{
541 std::abort();
542}
543SmartIF<IAddressCreator>& MixingEventSelector::addressCreator() const
544{
545 std::abort();
546}
547StatusCode MixingEventSelector::fillObjRefs(IOpaqueAddress* /*pAddress*/, DataObject* /*pObject*/)
548{
549 std::abort();
550}
551StatusCode MixingEventSelector::updateObj(IOpaqueAddress* /*pAddress*/, DataObject* /*refpObject*/)
552{
553 std::abort();
554}
555StatusCode MixingEventSelector::updateObjRefs(IOpaqueAddress* /*pAddress*/, DataObject* /*pObject*/)
556{
557 std::abort();
558}
559StatusCode MixingEventSelector::createRep(DataObject* /*pObject*/, IOpaqueAddress*& /*refpAddress*/)
560{
561 std::abort();
562}
563StatusCode MixingEventSelector::fillRepRefs(IOpaqueAddress* /*pAddress*/, DataObject* /*pObject*/)
564{
565 std::abort();
566}
567StatusCode MixingEventSelector::updateRep(IOpaqueAddress* /*pAddress*/, DataObject* /*pObject*/)
568{
569 std::abort();
570}
571StatusCode MixingEventSelector::updateRepRefs(IOpaqueAddress* /*pAddress*/, DataObject* /*pObject*/)
572{
573 std::abort();
574}
#define endmsg
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_DEBUG(x,...)
#define ATH_MSG_ERROR(x,...)
#define ATH_MSG_WARNING(x,...)
#define ATH_MSG_INFO(x,...)
a traits class that associates a CLID to a type T It also detects whether T inherits from Gaudi DataO...
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.
static Double_t sc
This class provides general information about an event.
#define FORWARD___DEBUG(METHOD)
a stream of events read from different selectors.
std::string toString(const float number)
Pipe a number to a string.
convert to and from a SG storable
This class contains trigger related information.
Define macros for attributes used to control the static checker.
#define ATLAS_NO_CHECK_FILE_THREAD_SAFETY
This class provides a unique identification for each event, in terms of run/event number and/or a tim...
Definition EventID.h:34
This class provides general information about an event.
std::list< SG::TransientAddress * > tadList
the list of available selectors with their frequency range
std::vector< Trigger >::iterator iterator
std::vector< unsigned int > m_rangeEnd
std::vector< Trigger >::const_iterator const_iterator
a selector with an associated frequency
StatusCode createContext(IEvtSelector::Context *&pCtxt) const
Trigger(IEvtSelector *pSel, unsigned int firstEvt, unsigned int lastEvt)
const std::string & name() const
StatusCode createAddress(IOpaqueAddress *&) const
IEvtSelector & selector() const
IEvtSelector::Context * m_current
IEvtSelector::Context & currentContext() const
Gaudi::Property< std::string > m_mergedEventInfoKey
virtual StatusCode setConversionSvc(IConversionSvc *pService) override
TriggerList::iterator currentTrigger() const
"intelligent" accessor to the above
Gaudi::Property< std::string > m_statusFileName
virtual StatusCode createContext(IEvtSelector::Context *&refpCtxt) const override
virtual StatusCode initialize() override
TriggerList::iterator setCurrentTrigger() const
choose current trigger at random. Actually modifies state (use mutables)
virtual StatusCode next(IEvtSelector::Context &refCtxt) const override
virtual SmartIF< IDataProviderSvc > & dataProvider() const override
virtual StatusCode createAddress(const IEvtSelector::Context &refCtxt, IOpaqueAddress *&) const override
virtual StatusCode rewind(IEvtSelector::Context &refCtxt) const override
Gaudi::Property< int > m_outputRunNumber
virtual StatusCode previous(IEvtSelector::Context &) const override
Gaudi::Property< std::vector< unsigned long > > m_eventNumbers
unsigned long getEventNo() const
setup and lookup m_evtsNotUsedSoFar. Returns next event no
virtual StatusCode updateObj(IOpaqueAddress *pAddress, DataObject *refpObject) override
virtual StatusCode last(IEvtSelector::Context &) const override
MixingEventSelector(const std::string &name, ISvcLocator *svc)
void decodeTrigger(const std::string &triggDescr)
functor that creates a Trigger object and adds it to m_trigList
Gaudi::Property< std::string > m_randomStreamName
virtual StatusCode createRep(DataObject *pObject, IOpaqueAddress *&refpAddress) override
Gaudi::Property< std::vector< std::string > > m_triggerListProp
virtual StatusCode setAddressCreator(IAddressCreator *creator) override
virtual StatusCode updateObjRefs(IOpaqueAddress *pAddress, DataObject *pObject) override
virtual StatusCode updateAddress(StoreID::type storeID, SG::TransientAddress *tad, const EventContext &ctx) override
virtual StatusCode releaseContext(IEvtSelector::Context *&refCtxt) const override
virtual const CLID & objType() const override
TriggerList m_trigList
the ingredients
virtual StatusCode updateRepRefs(IOpaqueAddress *pAddress, DataObject *pObject) override
virtual StatusCode fillRepRefs(IOpaqueAddress *pAddress, DataObject *pObject) override
virtual StatusCode fillObjRefs(IOpaqueAddress *pAddress, DataObject *pObject) override
virtual StatusCode finalize() override
virtual StatusCode loadAddresses(StoreID::type storeID, IAddressProvider::tadList &tads) override
virtual StatusCode updateRep(IOpaqueAddress *pAddress, DataObject *pObject) override
virtual SmartIF< IAddressCreator > & addressCreator() const override
virtual StatusCode preLoadAddresses(StoreID::type storeID, IAddressProvider::tadList &tads) override
TriggerList::iterator m_pCurrentTrigger
the current trigger
ServiceHandle< StoreGateSvc > m_pEventStore
virtual StatusCode setDataProvider(IDataProviderSvc *pService) override
ServiceHandle< IAtRndmGenSvc > m_atRndmSvc
virtual long repSvcType() const override
unsigned long m_eventPos
the internal event number
void setUpTriggerList(Gaudi::Details::PropertyBase &trigList)
TriggerList property call-back.
std::unique_ptr< CLHEP::RandFlat > m_chooseRangeRand
ToolHandleArray< IAthenaSelectorTool > m_helperTools
virtual StatusCode createObj(IOpaqueAddress *pAddress, DataObject *&refpObject) override
Create the transient representation of an object.
virtual SmartIF< IConversionSvc > & conversionSvc() const override
virtual StatusCode resetCriteria(const std::string &cr, IEvtSelector::Context &c) const override
@ EVENT_STORE
Definition StoreID.h:26
@ PILEUP_STORE
Definition StoreID.h:31
singleton-like access to IMessageSvc via open function and helper
std::string find(const std::string &s)
return a remapped string
Definition hcg.cxx:140
IMessageSvc * getMessageSvc(bool quiet=false)
std::vector< std::string > tokenize(std::string_view the_str, std::string_view delimiters)
Splits the string into smaller substrings.
DataObject * asStorable(SG::DataObjectSharedPtr< T > pObject)
STL namespace.
IovVectorMap_t read(const Folder &theFolder, const SelectionCriterion &choice, const unsigned int limit=10)
MsgStream & msg
Definition testRead.cxx:32