The Gaudi Framework  master (ff829712)
Loading...
Searching...
No Matches
Sequencer.cpp
Go to the documentation of this file.
1/***********************************************************************************\
2* (c) Copyright 1998-2025 CERN for the benefit of the LHCb and ATLAS collaborations *
3* *
4* This software is distributed under the terms of the Apache version 2 licence, *
5* copied verbatim in the file "LICENSE". *
6* *
7* In applying this licence, CERN does not waive the privileges and immunities *
8* granted to it by virtue of its status as an Intergovernmental Organization *
9* or submit itself to any jurisdiction. *
10\***********************************************************************************/
11// Sequencer class
12// Implements:
13// 1) Common functionality of IInterface
14// 2) Default behavior for the IAlgorithm
15#include <Gaudi/Sequencer.h>
16
17#include <GaudiKernel/Chrono.h>
21#include <GaudiKernel/Stat.h>
23
24#define ON_DEBUG if ( msgLevel( MSG::DEBUG ) )
25#define ON_VERBOSE if ( msgLevel( MSG::VERBOSE ) )
26
27namespace Gaudi {
29 auto is_good = decodeMemberNames();
30 if ( !is_good ) {
31 error() << "Unable to configure one or more sequencer members " << endmsg;
32 return is_good;
33 }
34
35 is_good = decodeBranchMemberNames();
36 if ( !is_good ) {
37 error() << "Unable to configure one or more branch members " << endmsg;
38 return is_good;
39 }
40
41 // We have to "decode" members before calling base class initialize
42 is_good = Sequence::initialize();
43 if ( !is_good ) return is_good;
44
45 // Loop over all branches
46 // (Sequence does not know about branches)
47 for ( auto& alg : branchAlgorithms() ) {
48 is_good = alg->sysInitialize();
49 if ( is_good.isFailure() ) {
50 error() << "Unable to initialize Algorithm " << alg->name() << endmsg;
51 return is_good;
52 }
53 }
54
55 return is_good;
56 }
57
59 // Bypass the loop if this sequencer is disabled
60 if ( isEnabled() ) {
61 // Loop over all branch members calling their reinitialize functions
62 // if they are not disabled.
63 for ( auto& alg : branchAlgorithms() ) {
64 if ( alg->isEnabled() ) { alg->reinitialize().ignore(); }
65 }
67 }
69 }
70
73 ON_DEBUG debug() << name() << " Sequencer::execute()" << endmsg;
74
75 auto state = execState( ctx );
76
77 // Bypass the loop if this sequencer is disabled or has already been executed
78 if ( isEnabled() && !( state.state() == AlgExecState::Done ) ) {
79 Gaudi::Algorithm* lastAlgorithm;
80 result = execute( ctx, *subAlgorithms(), m_isInverted, lastAlgorithm );
81 if ( result.isSuccess() ) {
82 const bool passed = state.filterPassed();
83 if ( !passed && m_shortCircuit ) {
84
85 // Filter failed and stop override not set. Execute the
86 // branch if there is one associated with the filter
87 // algorithm that failed. Note that the first member on
88 // the branch is the failing algorithm and so should
89 // be skipped.
90 const auto& theAlgs = branchAlgorithms();
91 if ( !theAlgs.empty() ) {
92 Gaudi::Algorithm* branchAlgorithm = theAlgs[0];
93 if ( lastAlgorithm == branchAlgorithm ) {
94
95 // Branch specified - Loop over branch members
96 result = execute( ctx, branchAlgorithms(), m_isBranchInverted, lastAlgorithm, 1 );
97 if ( result.isSuccess() ) {
98
99 // The final filter passed state will be set true if either
100 // of the main or branches passed, otherwise false.
101
102 // Save the branch filter passed state.
103 setBranchFilterPassed( ctx, state.filterPassed() );
104 }
105 }
106 }
107 }
108 }
109
110 // Prevent multiple executions of this sequencer for the current event
111 state.setState( AlgExecState::Done );
112 }
113 return result;
114 }
115
117 // Loop over all branch members calling their finalize functions
118 // if they are not disabled. Note that the Sequence::finalize
119 // function already does this for the main members.
120 for ( auto& alg : branchAlgorithms() ) {
121 if ( alg->sysFinalize().isFailure() ) { error() << "Unable to finalize Algorithm " << alg->name() << endmsg; }
122 }
123 return Sequence::finalize();
124 }
125
127 auto is_good = Sequence::start();
128 if ( !is_good ) return is_good;
129
130 // Loop over all branches
131 for ( auto& alg : branchAlgorithms() ) {
132 is_good = alg->sysStart();
133 if ( !is_good ) {
134 error() << "Unable to start Algorithm " << alg->name() << endmsg;
135 return is_good;
136 }
137 }
138
139 return is_good;
140 }
141
143 // Loop over all branch members calling their finalize functions
144 // if they are not disabled.
145 for ( auto& alg : branchAlgorithms() ) {
146 if ( alg->sysStop().isFailure() ) { error() << "Unable to stop Algorithm " << alg->name() << endmsg; }
147 }
148 return Sequence::stop();
149 }
150
152 auto lock = std::scoped_lock{ m_branchFilterMutex };
153 return m_branchFilterPassed[ctx.slot()];
154 }
155
156 void Sequencer::setBranchFilterPassed( const EventContext& ctx, bool state ) const {
157 auto lock = std::scoped_lock{ m_branchFilterMutex };
158 m_branchFilterPassed[ctx.slot()] = state;
159 }
160
161 StatusCode Sequencer::append( Gaudi::Algorithm* pAlgorithm ) { return append( pAlgorithm, *subAlgorithms() ); }
162
164 return append( pAlgorithm, branchAlgorithms() );
165 }
166
167 StatusCode Sequencer::createAndAppend( const std::string& type, const std::string& name,
168 Gaudi::Algorithm*& pAlgorithm ) {
169 return createAndAppend( type, name, pAlgorithm, *subAlgorithms() );
170 }
171
172 StatusCode Sequencer::createAndAppendToBranch( const std::string& type, const std::string& name,
173 Gaudi::Algorithm*& pAlgorithm ) {
174 return createAndAppend( type, name, pAlgorithm, branchAlgorithms() );
175 }
176
177 StatusCode Sequencer::remove( Gaudi::Algorithm* pAlgorithm ) { return remove( pAlgorithm->name() ); }
178
179 StatusCode Sequencer::remove( const std::string& algname ) { return remove( algname, *subAlgorithms() ); }
180
182 return removeFromBranch( pAlgorithm->name() );
183 }
184
185 StatusCode Sequencer::removeFromBranch( const std::string& algname ) { return remove( algname, branchAlgorithms() ); }
186
187 const std::vector<Gaudi::Algorithm*>& Sequencer::branchAlgorithms() const { return m_branchAlgs; }
188
189 std::vector<Gaudi::Algorithm*>& Sequencer::branchAlgorithms() { return m_branchAlgs; }
190
192 // Decode the membership list
194 }
195
197 // Decode the branch membership list
199 }
200
204
205 StatusCode Sequencer::append( Gaudi::Algorithm* pAlgorithm, std::vector<Gaudi::Algorithm*>& theAlgs ) {
206 // Check that the specified algorithm doesn't already exist in the membership list
207 if ( std::find( std::begin( theAlgs ), std::end( theAlgs ), pAlgorithm ) != std::end( theAlgs ) ) {
208 return StatusCode::FAILURE;
209 }
210 theAlgs.push_back( pAlgorithm );
211 pAlgorithm->addRef();
212 return StatusCode::SUCCESS;
213 }
214
215 StatusCode Sequencer::createAndAppend( const std::string& type, const std::string& algName,
216 Gaudi::Algorithm*& pAlgorithm, std::vector<Gaudi::Algorithm*>& theAlgs ) {
217 auto theAlgMgr = serviceLocator()->service<IAlgManager>( "ApplicationMgr" );
218 if ( !theAlgMgr ) return StatusCode::FAILURE;
219
220 IAlgorithm* tmp;
221 StatusCode result = theAlgMgr->createAlgorithm( type, algName, tmp );
222 if ( result.isSuccess() ) {
223 try {
224 pAlgorithm = dynamic_cast<Gaudi::Algorithm*>( tmp );
225 theAlgs.push_back( pAlgorithm );
226 } catch ( ... ) {
227 error() << "Unable to create Algorithm " << algName << endmsg;
228 result = StatusCode::FAILURE;
229 }
230 }
231
232 return result;
233 }
234
235 StatusCode Sequencer::decodeNames( Gaudi::Property<std::vector<std::string>>& theNames,
236 std::vector<Gaudi::Algorithm*>& theAlgs, std::vector<bool>& theLogic ) {
237 StatusCode result;
238 auto theAlgMgr = serviceLocator()->service<IAlgManager>( "ApplicationMgr" );
239 if ( theAlgMgr ) {
240 // Clear the existing list of algorithms
241 theAlgs.clear();
242
243 // Build the list of member algorithms from the contents of the
244 // theNames list.
245 for ( const auto& n : theNames.value() ) {
246
247 // Parse the name for a syntax of the form:
248 //
249 // <type>/<name>
250 //
251 // Where <name> is the algorithm instance name, and <type> is the
252 // algorithm class type (being a subclass of Algorithm).
253 const Gaudi::Utils::TypeNameString typeName( n );
254 std::string theName = typeName.name();
255 std::string theType = typeName.type();
256
257 // Parse the name for a syntax of the form:
258 //
259 // <name>:invert
260 //
261 // Where <name> is the algorithm instance name and ":invert"
262 // indicates that the filter passed logic is inverted.
263 bool isInverted = false;
264 std::string::size_type invert = theName.find_first_of( ":" );
265 // Skip all occurrences of "::" (allow namespaces)
266 while ( std::string::npos != invert && invert < ( theName.size() - 1 ) && theName[invert + 1] == ':' )
267 invert = theName.find_first_of( ":", invert + 2 );
268 if ( std::string::npos != invert ) {
269 if ( theName == theType ) {
270 // This means that we got something like "Type:invert",
271 // so we have to strip the ":invert" from the type too.
272 theType = theType.substr( 0, invert );
273 }
274 theName = theName.substr( 0, invert );
275 isInverted = true;
276 }
277 // Check whether the supplied name corresponds to an existing
278 // Algorithm object.
279 SmartIF<IAlgorithm>& theIAlg = theAlgMgr->algorithm( theName, false );
280 Gaudi::Algorithm* theAlgorithm = nullptr;
282 if ( theIAlg ) {
283 try {
284 theAlgorithm = dynamic_cast<Gaudi::Algorithm*>( theIAlg.get() );
285 } catch ( ... ) {
286 warning() << theName << " is not an Algorithm - Failed dynamic cast" << endmsg;
287 theAlgorithm = nullptr; // release
288 }
289 }
290 if ( theAlgorithm ) {
291
292 // The specified Algorithm already exists - just append it to the membership list.
293 status = append( theAlgorithm, theAlgs );
294 if ( status.isSuccess() ) {
295 ON_DEBUG debug() << theName << " already exists - appended to member list" << endmsg;
296 } else {
297 warning() << theName << " already exists - append failed!!!" << endmsg;
298 result = StatusCode::FAILURE;
299 }
300 } else {
301
302 // The specified name doesn't exist - create a new object of the specified type
303 // and append it to the membership list.
304 status = createAndAppend( theType, theName, theAlgorithm, theAlgs );
305 if ( status.isSuccess() ) {
306 ON_DEBUG debug() << theName << " doesn't exist - created and appended to member list" << endmsg;
307 } else {
308 warning() << theName << " doesn't exist - creation failed!!!" << endmsg;
309 result = StatusCode::FAILURE;
310 }
311 }
312 if ( status.isSuccess() ) theLogic.push_back( isInverted );
313 }
314 }
315 // Print membership list
316 if ( result.isSuccess() && theAlgs.size() != 0 ) {
317 info() << "Member list: ";
318 auto ai = theAlgs.begin();
319 auto li = theLogic.begin();
320 for ( ; ai != theAlgs.end(); ++ai, ++li ) {
321
322 if ( ai != theAlgs.begin() ) info() << ", ";
323 auto alg = *ai;
324 if ( alg->name() == System::typeinfoName( typeid( *alg ) ) )
325 info() << alg->name();
326 else
327 info() << System::typeinfoName( typeid( *alg ) ) << "/" << alg->name();
328
329 if ( *li ) info() << ":invert";
330 }
331 info() << endmsg;
332 }
333 return result;
334 }
335
336 StatusCode Sequencer::execute( const EventContext& ctx, const std::vector<Gaudi::Algorithm*>& theAlgs,
337 const std::vector<bool>& theLogic, Gaudi::Algorithm*& lastAlgorithm,
338 std::size_t first ) const {
340
341 auto state = execState( ctx );
342 state.setFilterPassed( !m_modeOR ); // for OR, result will be false, unless (at least) one is true
343 // for AND, result will be true, unless (at least) one is false
344 // also see comment below ....)
345
346 // Reset the branch filter passed flag
347 setBranchFilterPassed( ctx, false );
348
349 auto exists = [&]( const std::string_view loc ) -> bool {
350 DataObject* tmp{ nullptr };
351 return evtSvc()->retrieveObject( loc, tmp ).isSuccess();
352 };
353
354 // Do not execute if one or more of the m_vetoObjs exist in TES
355 if ( const auto it = find_if( begin( m_vetoObjs ), end( m_vetoObjs ), exists ); it != end( m_vetoObjs ) ) {
356 if ( msgLevel( MSG::DEBUG ) ) debug() << *it << " found, skipping event " << endmsg;
357 return result;
358 }
359
360 // Execute if m_requireObjs is empty
361 // or if one or more of the m_requireObjs exist in TES
362 if ( !( m_requireObjs.empty() || any_of( begin( m_requireObjs ), end( m_requireObjs ), exists ) ) ) {
363 return result;
364 }
365
366 // Loop over all algorithms calling their execute functions if they
367 // are (a) not disabled, and (b) aren't already executed. Note that
368 // in the latter case the filter state is still examined. Terminate
369 // the loop if an algorithm indicates that it's filter didn't pass.
370 auto size = theAlgs.size();
371 for ( auto i = first; i < size; i++ ) {
372 lastAlgorithm = theAlgs[i];
373 result = executeMember( lastAlgorithm, ctx );
374 if ( result.isSuccess() ) {
375 if ( !m_ignoreFilter ) {
376 // Take the filter passed status of this algorithm as my own status.
377 // Note that we take into account inverted logic.
378 bool passed = lastAlgorithm->execState( ctx ).filterPassed();
379 bool isInverted = theLogic[i];
380 if ( isInverted ) passed = !passed;
381
382 // in OR mode, we don't care about things
383 // which are false, as they leave our current state alone (provided
384 // we stared as 'false'!), and in AND mode, we keep our current
385 // state until someone returns 'false' (provided we started as 'true')
386 if ( m_modeOR ? passed : !passed ) {
387 state.setFilterPassed( m_modeOR );
388 if ( m_shortCircuit ) { break; }
389 }
390 }
391 } else {
392 break;
393 }
394 }
395 if ( m_invert ) state.setFilterPassed( !state.filterPassed() );
396 return result;
397 }
398
399 StatusCode Sequencer::executeMember( Gaudi::Algorithm* theAlgorithm, const EventContext& context ) const {
401 if ( theAlgorithm->isEnabled() ) {
402 if ( theAlgorithm->execState( context ).state() != AlgExecState::Done ) {
403 result = theAlgorithm->sysExecute( context );
404 }
405 }
406 return result;
407 }
408
409 StatusCode Sequencer::remove( const std::string& algname, std::vector<Gaudi::Algorithm*>& theAlgs ) {
411
412 // Test that the algorithm exists in the member list
413 for ( auto& alg : theAlgs ) {
414 if ( alg->name() == algname ) {
415
416 // Algorithm with specified name exists in the algorithm list - remove it
417 // THIS ISN'T IMPLEMENTED YET!!!!
418 info() << "Sequencer::remove( ) isn't implemented yet!!!!!" << endmsg;
419 result = StatusCode::SUCCESS;
420 break;
421 }
422 }
423 return result;
424 }
425
426 std::ostream& Sequencer::toControlFlowExpression( std::ostream& os ) const {
427 if ( m_invert ) os << '~';
428
429 auto& theAlgs = *subAlgorithms();
430 if ( theAlgs.empty() ) return os << ( ( !m_modeOR ) ? "CFTrue" : "CFFalse" );
431
432 // if we have only one element, we do not need a name
433 if ( theAlgs.size() > 1 ) os << "seq(";
434
435 const auto algs_count = theAlgs.size();
436 const auto op = m_shortCircuit ? ( m_modeOR ? " | " : " & " ) : " >> ";
437 size_t i = 0;
438 while ( i < algs_count ) {
439 if ( i ) os << op;
440 if ( m_isInverted[i] ) os << '~';
441 theAlgs[i]->toControlFlowExpression( os );
442 ++i;
443 }
444 if ( theAlgs.size() > 1 ) os << ')';
445 return os;
446 }
447} // namespace Gaudi
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition MsgStream.h:198
#define ON_DEBUG
State state() const
bool filterPassed() const
MsgStream & error() const
shortcut for the method msgStream(MSG::ERROR)
MsgStream & warning() const
shortcut for the method msgStream(MSG::WARNING)
MsgStream & debug() const
shortcut for the method msgStream(MSG::DEBUG)
MsgStream & info() const
shortcut for the method msgStream(MSG::INFO)
A DataObject is the base class of any identifiable object on any data store.
Definition DataObject.h:37
This class represents an entry point to all the event specific data.
Base class from which all concrete algorithm classes should be derived.
Definition Algorithm.h:87
StatusCode sysExecute(const EventContext &ctx) override
The actions to be performed by the algorithm on an event.
SmartIF< ISvcLocator > & serviceLocator() const override
The standard service locator.
const std::string & name() const override
The identifying name of the algorithm object.
AlgExecStateRef execState(const EventContext &ctx) const override
get the AlgExecStateRef of current algorithm Actually a small wrapper around it, thus the plain objec...
const std::string & type() const override
The type of the algorithm object.
Definition Algorithm.h:162
bool isEnabled() const override
Is this algorithm enabled or disabled?
SmartIF< IDataProviderSvc > & evtSvc() const
shortcut for method eventSvc
Definition Algorithm.h:233
Implementation of property with value of concrete type.
Definition PropertyFwd.h:27
StatusCode finalize() override
System finalization.
Definition Sequence.cpp:40
StatusCode start() override
System start.
Definition Sequence.cpp:56
StatusCode reinitialize() override
Reinitialization method invoked by the framework.
Definition Sequence.cpp:78
const std::vector< Algorithm * > * subAlgorithms() const
List of sub-algorithms. Returns a pointer to a vector of (sub) Algorithms.
Definition Sequence.cpp:105
StatusCode stop() override
System stop.
Definition Sequence.cpp:68
StatusCode initialize() override
Initialization method invoked by the framework.
Definition Sequence.cpp:28
Gaudi::Property< bool > m_modeOR
Definition Sequencer.h:194
std::ostream & toControlFlowExpression(std::ostream &os) const override
Produce string representation of the control flow expression.
void setBranchFilterPassed(const EventContext &ctx, bool state) const
Set the branch filter passed flag for the last event.
Gaudi::Property< std::vector< std::string > > m_branchNames
Definition Sequencer.h:182
StatusCode execute(const EventContext &ctx) const override
The actions to be performed by the sequencer on an event.
Definition Sequencer.cpp:71
StatusCode remove(Gaudi::Algorithm *pAlgorithm)
Remove the specified algorithm from the sequencer.
StatusCode decodeBranchMemberNames()
Decode branch member name list.
Gaudi::Property< std::vector< std::string > > m_names
Definition Sequencer.h:173
Gaudi::Property< bool > m_shortCircuit
Definition Sequencer.h:192
StatusCode finalize() override
Sequencer finalization.
StatusCode createAndAppendToBranch(const std::string &type, const std::string &name, Gaudi::Algorithm *&pAlgorithm)
Create a algorithm and append it to the sequencer branch.
StatusCode start() override
Sequencer finalization.
StatusCode decodeNames(Gaudi::Property< std::vector< std::string > > &theNames, std::vector< Gaudi::Algorithm * > &theAlgs, std::vector< bool > &theLogic)
Decode algorithm names, creating or appending algorithms as appropriate.
std::vector< bool > m_isBranchInverted
Definition Sequencer.h:205
StatusCode createAndAppend(const std::string &type, const std::string &name, Gaudi::Algorithm *&pAlgorithm)
Create a algorithm and append it to the sequencer.
StatusCode reinitialize() override
Sequencer Reinitialization.
Definition Sequencer.cpp:58
Gaudi::Property< bool > m_invert
Definition Sequencer.h:196
std::mutex m_branchFilterMutex
Definition Sequencer.h:207
const std::vector< Gaudi::Algorithm * > & branchAlgorithms() const
List of branch algorithms.
std::map< EventContext::ContextID_t, bool > m_branchFilterPassed
Definition Sequencer.h:208
StatusCode executeMember(Gaudi::Algorithm *theAlgorithm, const EventContext &context) const
Execute member algorithm.
StatusCode initialize() override
Initialization of a sequencer.
Definition Sequencer.cpp:28
std::vector< bool > m_isInverted
Definition Sequencer.h:203
Gaudi::Property< std::vector< std::string > > m_requireObjs
Definition Sequencer.h:200
std::vector< Gaudi::Algorithm * > m_branchAlgs
Definition Sequencer.h:204
StatusCode append(Gaudi::Algorithm *pAlgorithm)
Append an algorithm to the sequencer.
bool branchFilterPassed(const EventContext &ctx) const
Was the branch filter passed for the last event?
StatusCode stop() override
Sequencer stop.
StatusCode decodeMemberNames()
Decode Member Name list.
StatusCode removeFromBranch(Gaudi::Algorithm *pAlgorithm)
Gaudi::Property< bool > m_ignoreFilter
Definition Sequencer.h:195
StatusCode appendToBranch(Gaudi::Algorithm *pAlgorithm)
Append an algorithm to the sequencer branch.
Gaudi::Property< std::vector< std::string > > m_vetoObjs
Definition Sequencer.h:198
Helper class to parse a string of format "type/name".
The IAlgManager is the interface implemented by the Algorithm Factory in the Application Manager to s...
Definition IAlgManager.h:34
The IAlgorithm is the interface implemented by the Algorithm base class.
Definition IAlgorithm.h:36
virtual StatusCode retrieveObject(IRegistry *pDirectory, std::string_view path, DataObject *&pObject)=0
Retrieve object identified by its directory entry.
virtual SmartIF< IService > & service(const Gaudi::Utils::TypeNameString &typeName, const bool createIf=true)=0
Returns a smart pointer to a service.
Small smart pointer class with automatic reference counting for IInterface.
Definition SmartIF.h:28
TYPE * get() const
Get interface pointer.
Definition SmartIF.h:82
This class is used for returning status codes from appropriate routines.
Definition StatusCode.h:64
bool isSuccess() const
Definition StatusCode.h:314
constexpr static const auto SUCCESS
Definition StatusCode.h:99
constexpr static const auto FAILURE
Definition StatusCode.h:100
This file provides a Grammar for the type Gaudi::Accumulators::Axis It allows to use that type from p...
Definition __init__.py:1
@ DEBUG
Definition IMessageSvc.h:22
GAUDI_API const std::string typeinfoName(const std::type_info &)
Get platform independent information about the class type.
Definition System.cpp:260