ATLAS Offline Software
Control/AthenaExamples/AthExStoreGateExample/src/WriteData.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
3 */
4 
5 #undef NDEBUG
6 #include "WriteData.h"
7 
8 #include <list>
9 #include <vector>
10 
12 #include "MyContObj.h"
13 #include "MapStringFloat.h"
15 
17 #include "StoreGate/StoreGateSvc.h"
18 #include "AthLinks/DataLink.h"
19 #include "AthLinks/ElementLink.h"
20 
23 
25 
26 WriteData::WriteData(const std::string& name, ISvcLocator* pSvcLocator) :
27  AthAlgorithm(name, pSvcLocator)
28 {
29 }
30 
31 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
32 
34  ATH_MSG_INFO ("in initialize()");
35  //locate the StoreGateSvc and initialize our local ptr
36  StatusCode sc = evtStore().retrieve();
37  if (!sc.isSuccess()) ATH_MSG_ERROR ("Could not find StoreGateSvc");
38  return sc;
39 }
40 
41 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
42 
44  //this example illustrates how to record objects into the StoreGate(SG)
45  //with and without providing a key
46  //It then covers the new DataLink class and its usage as a persistable
47  //reference among objects in the SG
48  //Finally it shows how to use symlinks to record an object using its
49  //concrete type and its base class(es).
50 
51  ATH_MSG_INFO ("in execute()");
52 
53  // For algorithms that produce new data objects like this one
54  // the SG works like a bulletin board: the algorithm posts the
55  // new object to the SG (optionally providing a "name" for it).
56  // The SG assigns a unique identifier to the object and puts it on display
57  // alongside others of the same type.
58  // At preset intervals all objects are removed from the board to make room
59  // for new ones and filed.
60 
61  // Part 1: Recording objects to the SG
62  // We create a MyDataObj on the heap (using "new")
63  // (so that later we can pass ownership to SG)
64  //
65  MyDataObj *dobj = new MyDataObj;
66  dobj->val(1);
67 
68  // now we record dobj. SG will identify dobj as the first obj
69  // of type MyDataObj
70  StatusCode sc = evtStore()->record(dobj, SG::DEFAULTKEY, false);
71  // Remember NEVER delete an object recorded in the SG:
72  // SG owns the object after it has been recorded
73  if ( sc.isFailure() ) {
74  ATH_MSG_ERROR (" could not register dobj");
75  return( onError() );
76  }
77 
78  //now we create a second MyDataObj instance...
79  MyDataObj *dobj2 = new MyDataObj;
80  dobj2->val(2);
81 
82  //...try to record it as we did for the first. Since dobj2 is also a
83  //MyDataObj we expect to see an error printed
84  ATH_MSG_WARNING ("we expect an error message here");
85  sc = evtStore()->record(dobj2, SG::DEFAULTKEY, false);
86  ATH_MSG_WARNING ("end of error message");
87  if ( !sc.isFailure() ) {
89  (" allowed to register two default objects for type MyDataObj");
90  return( onError() );
91  }
92  // The error handling will have deleted dobj2.
93 
94  //here we go again...
95  MyDataObj *dobj3 = new MyDataObj;
96  dobj3->val(3);
97 
98  //... but this time we register the dobj3 using this algo name as key
99  //sc = evtStore()->record(dobj3, name(), true);
100  sc = evtStore()->record(dobj3, name());
101  //the last argument of record, which for now defaults to true, is "allowMods"
102  //by setting it to true we allow downstream algorithms to modify dobj3
103  if ( sc.isFailure() ) {
104  ATH_MSG_ERROR (" could not register Data Object");
105  return( onError() );
106  }
107  //now dobj3 is known both as the default MyDataObj and the MyDataObj
108  //with key "WriteData"
109  //Notice that while in this case we used a std::string as key, this
110  //need not be the case. Any type satisfying the constraints specified
111  //in StoreGate/constraints/KeyConcept.h is a valid key
112  //Currently (release 1.3.5) KeyConcept requires a key to be convertible
113  //to and from a std::string (hence a string is a valid key)
114  //From release 2.0.0 (or 1.3.6) the only requirement on the key type
115  //will be to be sortable, i.e. to provide a "less than" operator <
116 
117 
119 
120  // Part 2: storing collections in the SG
121 
122  //first we create two instances on MyContObj
123  //(they can be created on the stack as std::vector copies them anyway
124 
125  MyContObj* mco1 = new MyContObj;
126  MyContObj* mco2 = new MyContObj;
127  mco1->set(11.3, 132);
128  mco2->set(41.7, 291);
129 
131  cobj->reserve(10);
132  cobj->push_back(mco1);
133  cobj->push_back(mco2); // if I push back this, it core dumps in map record
134 
135  //finally we record the list itself. As before we don't need to specify
136  //a key. This make sense for collections, as in many applications (Atlfast)
137  //there is only one instance of each collection in the whole app
138  sc = evtStore()->record(cobj, SG::DEFAULTKEY, false);
139  if ( sc.isFailure() ) {
140  ATH_MSG_ERROR (" could not register list<MyContObj>");
141  return( onError() );
142  }
143 
144  //
145  // as above with a vector of integers
146  //
147 
148  //again notice how the vector is created on the heap
149  std::vector<float> *vFloat = new std::vector<float>;
150  vFloat->push_back(1.0);
151  vFloat->push_back(2.0);
152  vFloat->push_back(3.0);
153 
154  sc = evtStore()->record(vFloat, SG::DEFAULTKEY, false);
155  if ( sc.isFailure() ) {
156  ATH_MSG_ERROR (" could not register vector<float>");
157  return( onError() );
158  }
159 
160  //
161  // now we record a map
162  //
163 
165  (*m)["uno"]=1.0;
166  (*m)["due"]=2.0;
167 
168  sc = evtStore()->record(m, SG::DEFAULTKEY, false);
169  if ( sc.isFailure() ) {
170  ATH_MSG_ERROR (" could not register MapStringFloat");
171  return( onError() );
172  }
173 
175  //
176  // Part 3: Data Links
177  //
178  // Data links are persistable references. Typically they will replace
179  // pointers from one object in the event to another, hence they have
180  // the usual "pointer" syntax (op *, op ->, op !, ...)
181  // (to be pedantic they have the moniker syntax as they don't define ++, --)
182  // For example in Atlfast::Cell
183  // class Cell {
184  // ...
185  // private:
186  // std::vector<const HepMC::Particle*> m_particles;
187  // };
188  // m_particles would become
189  // std::vector<HepMCLink<Particle>::type > m_particles;
190  //
191  // To understand data links it is important to observe that the SG
192  // is not able to identify every single object in the event.
193  // In particular individual elements of a container (the MyContObj
194  // in the vector above or the Particles in McEventCollection) are not
195  // recorded individually into SG, only their owner (the container) is.
196  // For this reason data links are supported by two class templates:
197  // DataLink<DATAOBJ> is a link to a data object i.e. an object
198  // identified by SG
199  // ElementLink<CONTAINER> is a link to an element of a container (which
200  // in turn is a SG data object)
201  // To make a DataLink persistable we need to provide its SG identifier
202  // (its type and key).
203  // To make an ElementLink persistable we need two pieces of information:
204  // i) the SG identifier (type/key) of the data object owning the element
205  // ii) the identifier of the contained object within the owner
206  // For example when we write out a link to the third element of
207  // our vector<float> we want to write the SG id of the vector
208  // and the index (2) of the element in the vector
209  //
210  // Since the indexing mechanism of a container depends on the container
211  // type we need to specialize ElementLink for different containers
212  // Elements of STL sequences (lists, vectors, deques but also DataVector
213  // and DataList) are dealt with automatically.
214  // For other STL or STL-like containers, the data object designer (or the
215  // client must "help" ElementLink identifying the type of container
216  // Three macros in the header StoreGate/DeclareIndexingPolicy.h
217  // are provided to this end:
218  // for sequences use CONTAINER_IS_SEQUENCE( MySequence )
219  // for sets use CONTAINER_IS_SET( MySet )
220  // for maps and related containers use CONTAINER_IS_MAP( MyMap )
221  //
222  // It is also possible to define custom specializations of ElementLink
223  // for custom containers (e.g. GenParticleLink for McEventCollection).
224  //
225  //Enough! Let's now create our first DataLink. It refers to the first
226  // MyDataObj we recorded. DataLink constructors use references
227  // as input arguments
228  //
229  // DataLink referring to a storable object
230  //
231  DataLink<MyDataObj> dobjLink(*dobj);
232  //since dobj is identifiable in the SG a reference to it is all we need
233 
234  dobj2 = new MyDataObj;
235  dobj2->val(2);
236  CHECK( evtStore()->record(dobj2, "dobj2") );
237 
238  //Otherwise one could first create an empty link
239  DataLink<MyDataObj> dobjLink2;
240  //and later on set it to refer to its target
241  dobjLink2.toStorableObject(*dobj2);
242 
243 
244  // Added Aug 30, 2001 HMA
245  // DataLink made from a key. This should work for either an object
246  // already registered in the store, or an object that has a
247  // persistency for it. we use dobj3, which is an object registered with
248  // a key.
249 
250  DataLink<MyDataObj> dobjLink3(name());
251  // now access it. DataLink will do a retrieve to get it from the store.
252  dobjLink3->val();
253 
254  //
255  // ElementLinks referring to contained objects
256  //
257  typedef ElementLink<std::vector<float> > VecElemLink;
258 
259 
260  VecElemLink thirdElementLink(*vFloat, 2); //THIS CRASHES SUN CC
261 
262  //sometimes we would not know the index of the element we want to refer to
263 
264  //reference to an element of the vector
265  float& anElement = vFloat->operator[](0);
266 
267  //starting from an empty link
268  VecElemLink aLink;
269  //we can refer it to its target without knowing its index
270  aLink.toContainedElement(*vFloat, anElement);
271  //it is better though to remember that toContainedElement for an
272  //ElementLink performs a linear search of "anElement" into "vFloat".
273  // If vFloat has a million elements think twice before using
274  // toContainedElement!
275 
276 
277  //Now let's put all this VecElemLink in a list
278  std::list<VecElemLink> *pLinkList = new std::list<VecElemLink>;
279  pLinkList->push_back(aLink);
280  pLinkList->push_back(thirdElementLink);
281 
282  //and finally let's record the list of links into SG
283  sc = evtStore()->record(pLinkList, name(), false);
284  if ( sc.isFailure() ) {
285  ATH_MSG_ERROR (" could not register the list of DataLinks");
286  return( onError() );
287  }
288  //
289  // Part 3b: create a vector of links to the elements of the map above
290  //
291  typedef ElementLink<MapStringFloat> MapElemLink;
292  std::vector<MapElemLink>* linkVector = new std::vector<MapElemLink>;
293 
294  linkVector->push_back(MapElemLink(*m, "uno"));
295  MapElemLink mLink;
296  mLink.toContainedElement(*m, (*m)["due"]);
297  linkVector->push_back(mLink);
298 
299  sc = evtStore()->record(linkVector, SG::DEFAULTKEY, false);
300  if ( sc.isFailure() ) {
301  ATH_MSG_ERROR (" could not register the vector of DataLinks");
302  return( onError() );
303  }
304 
305  // Part 4
306  // make a link to dobj as its base class after it has been registered
307  // this allows later to retrieve different concrete types as a common ABC
308 
309  const BaseClass * pDO = 0;
310  if ( (evtStore()->symLink(dobj, pDO)).isFailure() ) {
311  ATH_MSG_ERROR (" could not make link to BaseClass");
312  return( onError() );
313  }
314 
315  // make a link as its base class, with the same name
316  if ( ( evtStore()->symLink(dobj3, pDO)).isFailure() ) {
317  ATH_MSG_ERROR (" could not make link to BaseClass");
318  return( onError() );
319  }
320 
321  // Part 5
322  // finally dump the sturcture of the StoreGate before returning
323  ATH_MSG_INFO (" registered all data objects");
324  ATH_MSG_INFO (" StoreGate structure before returning from execute \n"
325  << evtStore()->dump());
326 
327  return StatusCode::SUCCESS;
328 }
329 
330 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
331 
333 
334  ATH_MSG_INFO ("in finalize()");
335  return StatusCode::SUCCESS;
336 }
337 
338 
340 
341  ATH_MSG_ERROR ("Dumping StoreGate after error occurred\n"
342  << evtStore()->dump());
343  return StatusCode::FAILURE;
344 }
345 
DataVector::reserve
void reserve(size_type n)
Attempt to preallocate enough memory for a specified number of elements.
StoreGateExample_ClassDEF.h
python.SystemOfUnits.m
int m
Definition: SystemOfUnits.py:91
ATH_MSG_INFO
#define ATH_MSG_INFO(x)
Definition: AthMsgStreamMacros.h:31
MyContObj.h
WriteData::initialize
StatusCode initialize()
Definition: Control/AthenaExamples/AthExStoreGateExample/src/WriteData.cxx:33
MyDataObj::val
void val(int i)
Definition: AthExStoreGateExample/MyDataObj.h:24
WriteData::onError
StatusCode onError()
Definition: Control/AthenaExamples/AthExStoreGateExample/src/WriteData.cxx:339
AthenaPoolTestRead.sc
sc
Definition: AthenaPoolTestRead.py:27
WriteData::WriteData
WriteData(const std::string &name, ISvcLocator *pSvcLocator)
Definition: Control/AthenaExamples/AthExStoreGateExample/src/WriteData.cxx:26
AthCommonDataStore< AthCommonMsg< Algorithm > >::evtStore
ServiceHandle< StoreGateSvc > & evtStore()
The standard StoreGateSvc (event store) Returns (kind of) a pointer to the StoreGateSvc.
Definition: AthCommonDataStore.h:85
MyContObj::set
void set(float t, int i)
Definition: MyContObj.h:18
MapStringFloat.h
ATH_MSG_ERROR
#define ATH_MSG_ERROR(x)
Definition: AthMsgStreamMacros.h:33
WriteData::execute
StatusCode execute()
Definition: Control/AthenaExamples/AthExStoreGateExample/src/WriteData.cxx:43
MyContObj
Definition: MyContObj.h:11
MyDataObj
Definition: AthExStoreGateExample/MyDataObj.h:16
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
BaseClass
Definition: HiveDataObj.h:12
CHECK
#define CHECK(...)
Evaluate an expression and check for errors.
Definition: Control/AthenaKernel/AthenaKernel/errorcheck.h:422
SG::DEFAULTKEY
const std::string DEFAULTKEY
Definition: DefaultKey.h:12
python.ChapPy.dump
def dump(buf, stdout=sys.stdout)
Definition: ChapPy.py:25
DataVector
Derived DataVector<T>.
Definition: DataVector.h:581
AthAlgorithm
Definition: AthAlgorithm.h:47
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:192
errorcheck.h
Helpers for checking error return status codes and reporting errors.
MyDataObj.h
DataVector::push_back
value_type push_back(value_type pElem)
Add an element to the end of the collection.
DataVector.h
An STL vector of pointers that by default owns its pointed-to elements.
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
WriteData::finalize
StatusCode finalize()
Definition: Control/AthenaExamples/AthExStoreGateExample/src/WriteData.cxx:332
DefaultKey.h
StoreGateSvc.h
MapStringFloat
std::map< std::string, float > MapStringFloat
Definition: MapStringFloat.h:21
WriteData.h
This file contains the class definition for the WriteData class.