Loading [MathJax]/extensions/tex2jax.js
The Gaudi Framework  master (d98a2936)
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
HiveDataBroker.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 #include "GraphDumper.h"
12 
13 #include <Gaudi/Algorithm.h>
17 #include <GaudiKernel/Service.h>
18 #include <GaudiKernel/System.h>
19 #include <algorithm>
20 #include <boost/lexical_cast.hpp>
21 #include <boost/tokenizer.hpp>
22 #include <iomanip>
23 #include <ranges>
24 #include <stdexcept>
25 
26 class HiveDataBrokerSvc final : public extends<Service, IDataBroker> {
27 public:
28  using extends::extends;
29 
30  std::vector<Gaudi::Algorithm*> algorithmsRequiredFor( const DataObjIDColl& requested,
31  const std::vector<std::string>& stoppers = {} ) const override;
32  std::vector<Gaudi::Algorithm*> algorithmsRequiredFor( const Gaudi::Utils::TypeNameString& alg,
33  const std::vector<std::string>& stoppers = {} ) const override;
34 
35  StatusCode initialize() override;
36  StatusCode start() override;
37  StatusCode stop() override;
38  StatusCode finalize() override;
39 
40 private:
41  Gaudi::Property<std::string> m_dataLoader{ this, "DataLoader", "",
42  "Attribute any unmet input dependencies to this Algorithm" };
44  this, "DataProducers", {}, "List of algorithms to be used to resolve data dependencies" };
45 
47  this, "DataDepsGraphFile", "",
48  "Name of the output file (.dot or .md extensions allowed) containing the data dependency graph. If empty, no "
49  "graph is dumped" };
50 
51  struct AlgEntry {
52  size_t index;
55  std::set<AlgEntry const*> dependsOn;
56 
57  friend bool operator<( AlgEntry const& lhs, AlgEntry const& rhs ) { return lhs.index < rhs.index; }
58 
59  friend bool operator==( AlgEntry const& lhs, AlgEntry const& rhs ) { return lhs.index == rhs.index; }
60 
61  AlgEntry( size_t i, SmartIF<IAlgorithm>&& p )
62  : index{ i }, ialg{ std::move( p ) }, alg{ dynamic_cast<Gaudi::Algorithm*>( ialg.get() ) } {
63  if ( !alg ) throw std::runtime_error( "algorithm pointer == nullptr???" );
64  }
65  };
66 
67  std::map<std::string, AlgEntry>
68  instantiateAndInitializeAlgorithms( const std::vector<std::string>& names ) const; // algorithms must be fully
69  // initialized first, as
70  // doing so may create
71  // additional data
72  // dependencies...
73 
74  std::map<std::string, AlgEntry> m_algorithms;
75 
76  std::map<DataObjID, AlgEntry const*> mapProducers( std::map<std::string, AlgEntry>& algorithms ) const;
77 
78  std::map<DataObjID, AlgEntry const*> m_dependencies;
79 
80  void visit( AlgEntry const& alg, std::vector<std::string> const& stoppers, std::vector<Gaudi::Algorithm*>& sorted,
81  std::vector<bool>& visited, std::vector<bool>& visiting ) const;
82 
83  void dumpGraphFile() const;
84 };
85 
87 
88 namespace {
89  struct AlgorithmRepr {
90  const Gaudi::Algorithm& parent;
91 
92  friend std::ostream& operator<<( std::ostream& s, const AlgorithmRepr& a ) {
93  std::string typ = System::typeinfoName( typeid( a.parent ) );
94  s << typ;
95  if ( a.parent.name() != typ ) s << "/" << a.parent.name();
96  return s;
97  }
98  };
99 
100  // Sort a DataObjIDColl in a well-defined, reproducible manner.
101  // Used for making debugging dumps.
102  std::vector<const DataObjID*> sorted_( const DataObjIDColl& coll ) {
103  std::vector<const DataObjID*> v;
104  v.reserve( coll.size() );
105  for ( const DataObjID& id : coll ) v.push_back( &id );
106  std::sort( v.begin(), v.end(),
107  []( const DataObjID* a, const DataObjID* b ) { return a->fullKey() < b->fullKey(); } );
108  return v;
109  }
110 
111  template <typename T>
112  std::vector<const T*> sorted_( const std::set<T*>& s ) {
113  std::vector<const T*> v{ s.begin(), s.end() };
114  std::sort( v.begin(), v.end(), []( const auto* lhs, const auto* rhs ) { return *lhs < *rhs; } );
115  return v;
116  }
117 
118  SmartIF<IAlgorithm> createAlgorithm( IAlgManager& am, const std::string& type, const std::string& name ) {
119  // Maybe modify the AppMgr interface to return Algorithm* ??
120  IAlgorithm* tmp = nullptr;
121  StatusCode sc = am.createAlgorithm( type, name, tmp );
122  return sc.isSuccess() ? dynamic_cast<Gaudi::Algorithm*>( tmp ) : nullptr;
123  }
124 } // namespace
125 
127  return Service::initialize().andThen( [&] {
128  // populate m_algorithms
130 
131  // warn about non-reentrant algorithms
133  std::ranges::views::transform( []( const auto& entry ) { return entry.second.alg; } ) |
134  std::ranges::views::filter( []( const auto* alg ) { return alg->cardinality() > 0; } ),
135  [&]( const Gaudi::Algorithm* alg ) {
136  this->warning() << "non-reentrant algorithm: " << AlgorithmRepr{ *alg } << endmsg;
137  } );
138  //== Print the list of the created algorithms
139  if ( msgLevel( MSG::DEBUG ) ) {
140  MsgStream& msg = debug();
141  msg << "Available DataProducers: ";
143  msg, m_algorithms, ", ", []( auto& os, const std::pair<std::string, AlgEntry>& e ) -> decltype( auto ) {
144  return os << AlgorithmRepr{ *e.second.alg };
145  } );
146  msg << endmsg;
147  }
148 
149  // populate m_dependencies and set AlgEntry::dependsOn
151  } );
152 }
153 
155 
156  StatusCode ss = Service::start();
157  if ( !ss.isSuccess() ) return ss;
158 
159  // sysStart for m_algorithms
160  for ( auto& [name, algEntry] : m_algorithms ) {
161  ss = algEntry.alg->sysStart();
162  if ( ss.isFailure() ) {
163  error() << "Unable to start Algorithm: " << name << endmsg;
164  return ss;
165  }
166  }
167  return ss;
168 }
169 
171  StatusCode ss = Service::stop();
172  if ( !ss.isSuccess() ) return ss;
173 
174  // sysStart for m_algorithms
175  for ( auto& [name, algEntry] : m_algorithms ) {
176  ss = algEntry.alg->sysStop();
177  if ( ss.isFailure() ) {
178  error() << "Unable to stop Algorithm: " << name << endmsg;
179  return ss;
180  }
181  }
182  return ss;
183 }
184 
186  for ( auto& [name, algEntry] : m_algorithms ) {
187  algEntry.alg->sysFinalize().ignore( /* AUTOMATICALLY ADDED FOR gaudi/Gaudi!763 */ );
188  }
189  m_algorithms.clear();
190  return Service::finalize();
191 }
192 
193 std::map<std::string, HiveDataBrokerSvc::AlgEntry>
194 HiveDataBrokerSvc::instantiateAndInitializeAlgorithms( const std::vector<std::string>& names ) const {
195  std::map<std::string, AlgEntry> algorithms;
196 
197  //= Get the Application manager, to see if algorithm exist
198  auto appMgr = service<IAlgManager>( "ApplicationMgr" );
199  size_t index = 0;
200  for ( const std::string& item : names ) {
201  const Gaudi::Utils::TypeNameString tn( item );
202 
203  //== Check wether the specified algorithm already exists. If not, create it
204  SmartIF<IAlgorithm> myIAlg = appMgr->algorithm( item, false ); // do not create it now
205  if ( !myIAlg ) {
206  myIAlg = createAlgorithm( *appMgr, tn.type(), tn.name() );
207  } else {
208  // when the algorithm is not created, the ref count is short by one, so we
209  // have to fix it.
210  myIAlg->addRef();
211  }
212 
213  if ( !myIAlg ) {
214  throw GaudiException{ "Failed to create " + boost::lexical_cast<std::string>( item ), __func__,
216  }
217 
218  // propagate the sub-algorithm into own state.
219  StatusCode sc = myIAlg->sysInitialize();
220  if ( sc.isFailure() ) {
221  throw GaudiException{ "Failed to initialize " + boost::lexical_cast<std::string>( item ), __func__,
223  }
224 
225  algorithms.emplace( tn.name(), AlgEntry{ index++, std::move( myIAlg ) } );
226  }
227 
228  return algorithms;
229 }
230 
231 std::map<DataObjID, HiveDataBrokerSvc::AlgEntry const*>
232 HiveDataBrokerSvc::mapProducers( std::map<std::string, AlgEntry>& algorithms ) const {
233  if ( msgLevel( MSG::DEBUG ) ) {
234  debug() << "Data Dependencies for Algorithms:";
235  for ( const auto& [name, entry] : m_algorithms ) {
236  debug() << "\n " << name << " :";
237  for ( const auto* id : sorted_( entry.alg->inputDataObjs() ) ) { debug() << "\n o INPUT " << id->key(); }
238  for ( const auto* id : sorted_( entry.alg->outputDataObjs() ) ) { debug() << "\n o OUTPUT " << id->key(); }
239  }
240  debug() << endmsg;
241  }
242 
243  // If requested, dump a graph of the data dependencies in a .dot or .md file
244  if ( not m_dataDepsGraphFile.empty() ) { dumpGraphFile(); }
245 
246  // figure out all outputs
247  std::map<DataObjID, const AlgEntry*> producers;
248  for ( auto& [name, alg] : algorithms ) {
249  const auto& output = alg.alg->outputDataObjs();
250  if ( output.empty() ) { continue; }
251  for ( auto id : output ) {
252  auto r = producers.emplace( id, &alg );
253  if ( !r.second ) {
254  throw GaudiException( "multiple algorithms declare " + id.key() + " as output (" + name + " and " +
255  producers[id]->alg->name() + " at least). This is not allowed",
256  __func__, StatusCode::FAILURE );
257  }
258  }
259  }
260 
261  // resolve dependencies
262  for ( auto& [name, algEntry] : algorithms ) {
263  auto input = sorted_( algEntry.alg->inputDataObjs() );
264  for ( const DataObjID* idp : input ) {
265  DataObjID id = *idp;
266  auto iproducer = producers.find( id );
267  if ( iproducer != producers.end() ) {
268  algEntry.dependsOn.insert( iproducer->second );
269  } else {
270  std::ostringstream error_message;
271  error_message << "\nUnknown requested input by " << AlgorithmRepr{ *( algEntry.alg ) } << " : "
272  << std::quoted( id.key(), '\'' ) << ".\n";
273  error_message << "You can set the OutputLevel of HiveDataBrokerSvc to DEBUG to get a list of inputs and "
274  "outputs of every registered algorithm.\n";
275  throw GaudiException( error_message.str(), __func__, StatusCode::FAILURE );
276  // TODO: assign to dataloader!
277  // algEntry.dependsOn.insert(dataloader.alg);
278  // dataloader.data.emplace( id ); // TODO: we may ask to much of the
279  // dataloader this way...
280  }
281  }
282  }
283  return producers;
284 }
285 
287 void HiveDataBrokerSvc::visit( AlgEntry const& alg, std::vector<std::string> const& stoppers,
288  std::vector<Gaudi::Algorithm*>& sorted, std::vector<bool>& visited,
289  std::vector<bool>& visiting ) const {
290  assert( visited.size() == m_algorithms.size() );
291  assert( visiting.size() == m_algorithms.size() );
292  if ( visited[alg.index] ) { return; }
293  if ( visiting[alg.index] ) { throw GaudiException( "Cycle detected ", __func__, StatusCode::FAILURE ); }
294 
295  if ( std::none_of( std::begin( stoppers ), std::end( stoppers ),
296  [alg]( auto& stopper ) { return alg.alg->name() == stopper; } ) ) {
297  visiting[alg.index] = true;
298  for ( auto* dep : sorted_( alg.dependsOn ) ) { visit( *dep, stoppers, sorted, visited, visiting ); }
299  visiting[alg.index] = false;
300  }
301 
302  visited[alg.index] = true;
303  sorted.push_back( alg.alg );
304 }
305 
306 std::vector<Gaudi::Algorithm*>
308  const std::vector<std::string>& stoppers ) const {
309  std::vector<Gaudi::Algorithm*> result;
310 
311  std::vector<const AlgEntry*> deps;
312  deps.reserve( requested.size() );
313 
314  // start with seeding from the initial request
315  for ( const auto& id : requested ) {
316  auto i = m_dependencies.find( id );
317  if ( i == m_dependencies.end() )
318  throw GaudiException( "unknown requested input: " + id.key(), __func__, StatusCode::FAILURE );
319  deps.push_back( i->second );
320  }
321  // producers may be responsible for multiple requested DataObjID -- make sure they are only mentioned once
322  std::sort( deps.begin(), deps.end(), []( auto const* lhs, auto const* rhs ) { return *lhs < *rhs; } );
323  deps.erase( std::unique( deps.begin(), deps.end(), []( auto const& lhs, auto const& rhs ) { return *lhs == *rhs; } ),
324  deps.end() );
325 
326  std::vector<bool> visited( m_algorithms.size() );
327  std::vector<bool> visiting( m_algorithms.size() );
328  for ( auto* alg : deps ) { visit( *alg, stoppers, result, visited, visiting ); }
329  return result;
330 }
331 
332 std::vector<Gaudi::Algorithm*>
334  const std::vector<std::string>& stoppers ) const {
335  std::vector<Gaudi::Algorithm*> result;
336 
337  auto it = m_algorithms.find( requested.name() );
338  if ( it == end( m_algorithms ) ) {
339  throw GaudiException{ "No algorithm with name " + requested.name() + " in DataProducers. Type is " +
340  ( requested.haveType() ? requested.type() : "not specified" ),
341  __func__, StatusCode::FAILURE };
342  }
343  auto const& alg = it->second;
344  if ( requested.haveType() && alg.alg->type() != requested.type() ) {
345  error() << "requested " << requested << " but have matching name with different type: " << alg.alg->type()
346  << endmsg;
347  }
348  assert( alg.alg != nullptr );
349 
350  std::vector<bool> visited( m_algorithms.size() );
351  std::vector<bool> visiting( m_algorithms.size() );
352  visit( alg, stoppers, result, visited, visiting );
353 
354  if ( msgLevel( MSG::DEBUG ) ) {
355  debug() << std::endl << "requested " << requested << " returning " << std::endl << " ";
357  debug(), result, ",\n ",
358  []( auto& os, const Gaudi::Algorithm* a ) -> decltype( auto ) { return os << AlgorithmRepr{ *a }; } );
359  debug() << std::endl << endmsg;
360  }
361  return result;
362 }
363 
366  info() << "Dumping data dependencies graph to file: " << g.fileName() << endmsg;
367 
368  // define algs and objects
369  std::set<std::size_t> definedObjects;
370 
371  // loop over all algorithms to create nodes
372  for ( const auto& [name, entry] : m_algorithms ) { g.addNode( entry.alg->name(), std::to_string( entry.index ) ); }
373 
374  // loop over all algorithms to create list of outputs with corresponding alg indexes
375  std::unordered_map<std::string, size_t> output2Idx;
376  for ( const auto& [name, entry] : m_algorithms ) {
377  for ( const auto* id : sorted_( entry.alg->outputDataObjs() ) ) { output2Idx[id->key()] = entry.index; }
378  }
379 
380  // loop over all algorithms to create edges
381  for ( const auto& [name, entry] : m_algorithms ) {
382  for ( const auto* id : sorted_( entry.alg->inputDataObjs() ) ) {
383  g.addEdge( entry.alg->name(), std::to_string( entry.index ), id->key(), std::to_string( output2Idx[id->key()] ),
384  id->key() );
385  }
386  }
387 }
MSG::DEBUG
@ DEBUG
Definition: IMessageSvc.h:22
Histograms_with_global.algorithms
algorithms
Definition: Histograms_with_global.py:19
HiveDataBrokerSvc::initialize
StatusCode initialize() override
Definition: HiveDataBroker.cpp:126
GraphDumper.h
IAlgManager.h
Service::initialize
StatusCode initialize() override
Definition: Service.cpp:118
HiveDataBrokerSvc::m_producers
Gaudi::Property< std::vector< std::string > > m_producers
Definition: HiveDataBroker.cpp:43
Gaudi::Utils::TypeNameString::name
const std::string & name() const
Definition: TypeNameString.h:48
HiveDataBrokerSvc::AlgEntry::index
size_t index
Definition: HiveDataBroker.cpp:52
StatusCode::andThen
StatusCode andThen(F &&f, ARGS &&... args) const
Chain code blocks making the execution conditional a success result.
Definition: StatusCode.h:163
StatusCode::isSuccess
bool isSuccess() const
Definition: StatusCode.h:314
Service::start
StatusCode start() override
Definition: Service.cpp:187
System.h
GaudiException.h
HiveDataBrokerSvc::dumpGraphFile
void dumpGraphFile() const
Definition: HiveDataBroker.cpp:364
gaudirun.s
string s
Definition: gaudirun.py:346
GaudiException
Definition: GaudiException.h:29
HiveDataBrokerSvc::AlgEntry::dependsOn
std::set< AlgEntry const * > dependsOn
Definition: HiveDataBroker.cpp:55
GaudiMP.FdsRegistry.msg
msg
Definition: FdsRegistry.py:19
HiveDataBrokerSvc::AlgEntry::operator==
friend bool operator==(AlgEntry const &lhs, AlgEntry const &rhs)
Definition: HiveDataBroker.cpp:59
HiveDataBrokerSvc::mapProducers
std::map< DataObjID, AlgEntry const * > mapProducers(std::map< std::string, AlgEntry > &algorithms) const
Definition: HiveDataBroker.cpp:232
HiveDataBrokerSvc::AlgEntry::AlgEntry
AlgEntry(size_t i, SmartIF< IAlgorithm > &&p)
Definition: HiveDataBroker.cpp:61
Gaudi::Hive::Graph
utilities to dump graphs in different formats
Definition: GraphDumper.h:30
System::typeinfoName
GAUDI_API const std::string typeinfoName(const std::type_info &)
Get platform independent information about the class type.
Definition: System.cpp:260
gaudirun.output
output
Definition: gaudirun.py:521
GaudiPartProp.tests.id
id
Definition: tests.py:111
HiveDataBrokerSvc::stop
StatusCode stop() override
Definition: HiveDataBroker.cpp:170
CommonMessaging< implements< IService, IProperty, IStateful > >::msgLevel
MSG::Level msgLevel() const
get the cached level (originally extracted from the embedded MsgStream)
Definition: CommonMessaging.h:147
Service::finalize
StatusCode finalize() override
Definition: Service.cpp:223
HiveDataBrokerSvc::m_dataLoader
Gaudi::Property< std::string > m_dataLoader
Definition: HiveDataBroker.cpp:41
ManySmallAlgs.alg
alg
Definition: ManySmallAlgs.py:81
IAlgManager
Definition: IAlgManager.h:34
Gaudi::Utils::begin
AttribStringParser::Iterator begin(const AttribStringParser &parser)
Definition: AttribStringParser.h:135
Gaudi::Utils::TypeNameString
Helper class to parse a string of format "type/name".
Definition: TypeNameString.h:19
Service::name
const std::string & name() const override
Retrieve name of the service
Definition: Service.cpp:333
StatusCode
Definition: StatusCode.h:64
Gaudi::cxx::for_each
void for_each(ContainerOfSynced &c, Fun &&f)
Definition: SynchronizedValue.h:98
IAlgorithm
Definition: IAlgorithm.h:36
gaudirun.g
dictionary g
Definition: gaudirun.py:582
Gaudi::Parsers::operator<<
std::ostream & operator<<(std::ostream &o, const Catalog &c)
printout operator
Definition: Catalog.h:49
HiveDataBrokerSvc::start
StatusCode start() override
Definition: HiveDataBroker.cpp:154
HiveDataBrokerSvc::AlgEntry::operator<
friend bool operator<(AlgEntry const &lhs, AlgEntry const &rhs)
Definition: HiveDataBroker.cpp:57
HiveDataBrokerSvc::m_algorithms
std::map< std::string, AlgEntry > m_algorithms
Definition: HiveDataBroker.cpp:74
HiveDataBrokerSvc::algorithmsRequiredFor
std::vector< Gaudi::Algorithm * > algorithmsRequiredFor(const DataObjIDColl &requested, const std::vector< std::string > &stoppers={}) const override
Definition: HiveDataBroker.cpp:307
Gaudi::Algorithm
Base class from which all concrete algorithm classes should be derived.
Definition: Algorithm.h:87
HiveDataBrokerSvc::instantiateAndInitializeAlgorithms
std::map< std::string, AlgEntry > instantiateAndInitializeAlgorithms(const std::vector< std::string > &names) const
Definition: HiveDataBroker.cpp:194
Gaudi::Property::value
const ValueType & value() const
Definition: Property.h:229
Algorithm.h
SmartIF< IAlgorithm >
HiveDataBrokerSvc::m_dataDepsGraphFile
Gaudi::Property< std::string > m_dataDepsGraphFile
Definition: HiveDataBroker.cpp:46
HiveDataBrokerSvc::m_dependencies
std::map< DataObjID, AlgEntry const * > m_dependencies
Definition: HiveDataBroker.cpp:78
DataObjIDColl
std::unordered_set< DataObjID, DataObjID_Hasher > DataObjIDColl
Definition: DataObjID.h:122
endmsg
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition: MsgStream.h:198
extends
Base class used to extend a class implementing other interfaces.
Definition: extends.h:19
MsgStream
Definition: MsgStream.h:29
Gaudi::Utils::TypeNameString::type
const std::string & type() const
Definition: TypeNameString.h:47
DataObjID
Definition: DataObjID.h:47
IDataBroker.h
StatusCode::ignore
const StatusCode & ignore() const
Allow discarding a StatusCode without warning.
Definition: StatusCode.h:139
Service.h
StatusCode::isFailure
bool isFailure() const
Definition: StatusCode.h:129
gaudirun.type
type
Definition: gaudirun.py:160
ConditionsStallTest.name
name
Definition: ConditionsStallTest.py:77
Service::stop
StatusCode stop() override
Definition: Service.cpp:181
HiveDataBrokerSvc
Definition: HiveDataBroker.cpp:26
SmartIF::get
TYPE * get() const
Get interface pointer.
Definition: SmartIF.h:82
HiveDataBrokerSvc::AlgEntry::ialg
SmartIF< IAlgorithm > ialg
Definition: HiveDataBroker.cpp:53
DECLARE_COMPONENT
#define DECLARE_COMPONENT(type)
Definition: PluginServiceV1.h:45
Gaudi::Utils::TypeNameString::haveType
bool haveType() const
Definition: TypeNameString.h:49
IAlgManager::createAlgorithm
virtual StatusCode createAlgorithm(const std::string &algtype, const std::string &algname, IAlgorithm *&alg, bool managed=false, bool checkIfExists=true)=0
Create an instance of a algorithm type that has been declared beforehand and assigns to it a name.
Properties.v
v
Definition: Properties.py:122
IOTest.end
end
Definition: IOTest.py:125
HiveDataBrokerSvc::AlgEntry
Definition: HiveDataBroker.cpp:51
HiveDataBrokerSvc::AlgEntry::alg
Gaudi::Algorithm * alg
Definition: HiveDataBroker.cpp:54
StatusCode::FAILURE
constexpr static const auto FAILURE
Definition: StatusCode.h:100
HiveDataBrokerSvc::visit
void visit(AlgEntry const &alg, std::vector< std::string > const &stoppers, std::vector< Gaudi::Algorithm * > &sorted, std::vector< bool > &visited, std::vector< bool > &visiting) const
Implements DFS topological sorting.
Definition: HiveDataBroker.cpp:287
HiveDataBrokerSvc::finalize
StatusCode finalize() override
Definition: HiveDataBroker.cpp:185
ProduceConsume.key
key
Definition: ProduceConsume.py:84
IOTest.appMgr
appMgr
Definition: IOTest.py:105
Gaudi::Property< std::string >
Gaudi::ParticleProperties::index
size_t index(const Gaudi::ParticleProperty *property, const Gaudi::Interfaces::IParticlePropertySvc *service)
helper utility for mapping of Gaudi::ParticleProperty object into non-negative integral sequential id...
Definition: IParticlePropertySvc.cpp:39
GaudiUtils::details::ostream_joiner
Stream & ostream_joiner(Stream &os, Iterator first, Iterator last, Separator sep, OutputElement output=OutputElement{})
Definition: SerializeSTL.h:86