Juggler
Juggling algorithms and event processing using gaudi framework
DataHandle.h
Go to the documentation of this file.
1 // SPDX-License-Identifier: LGPL-3.0-or-later
2 // Copyright (C) 2022 Whitney Armstrong
3 
4 #ifndef JUGBASE_DATAHANDLE_H
5 #define JUGBASE_DATAHANDLE_H
6 
7 #include "JugBase/DataWrapper.h"
8 #include "JugBase/PodioDataSvc.h"
9 
10 #include <GaudiKernel/AlgTool.h>
11 #include <GaudiKernel/Algorithm.h>
12 #include <GaudiKernel/DataObjectHandle.h>
13 #include <GaudiKernel/GaudiException.h>
14 #include <Gaudi/Property.h>
15 #include <GaudiKernel/ServiceLocatorHelper.h>
16 
17 #include <TTree.h>
18 
19 #include <type_traits>
20 
21 namespace Jug {
22 using VecULong = std::vector<unsigned long>;
23 using VecVecULong = std::vector<std::vector<unsigned long>>;
24 }
25 
26 
27 /** Specialisation of the Gaudi DataHandle
28  * for use with podio collections.
29  *
30  * \ingroup base
31  */
32 template <typename T>
33 class DataHandle : public DataObjectHandle<DataWrapper<T>> {
34 
35 public:
36  friend class Algorithm;
37  friend class AlgTool;
38 
39 public:
42 
43  /// Initialises mother class
44  DataHandle(DataObjID& descriptor, Gaudi::DataHandle::Mode a, IDataHandleHolder* fatherAlg);
45 
46  DataHandle(const std::string& k, Gaudi::DataHandle::Mode a, IDataHandleHolder* fatherAlg);
47 
48  ///Retrieve object from transient data store
49  const T* get();
50 
51  /**
52  * Register object in transient store
53  */
54  void put(T* object);
55 
56  /**
57  * Create and register object in transient store
58  */
60 
61 private:
62  ServiceHandle<IDataProviderSvc> m_eds;
63  bool m_isGoodType{false};
64  bool m_isCollection{false};
65  T* m_dataPtr;
66 };
67 
68 template <typename T>
70  // release memory allocated for primitive types (see comments in ctor)
71  if constexpr (std::is_integral_v<T> || std::is_floating_point_v<T>) {
72  delete m_dataPtr;
73  }
74 }
75 
76 //---------------------------------------------------------------------------
77 template <typename T>
78 DataHandle<T>::DataHandle(DataObjID& descriptor, Gaudi::DataHandle::Mode a, IDataHandleHolder* fatherAlg)
79  : DataObjectHandle<DataWrapper<T>>(descriptor, a, fatherAlg), m_eds("EventDataSvc", "DataHandle") {
80 
81 }
82 /// The DataHandle::Writer constructor is used to create the corresponding branch in the output file
83 template <typename T>
84 DataHandle<T>::DataHandle(const std::string& descriptor, Gaudi::DataHandle::Mode a, IDataHandleHolder* fatherAlg)
85  : DataObjectHandle<DataWrapper<T>>(descriptor, a, fatherAlg), m_eds("EventDataSvc", "DataHandle") {
86 
87  if (a == Gaudi::DataHandle::Writer) {
88  auto ret = m_eds.retrieve();
89  // FIXME deal with errors
90  PodioDataSvc* pds;
91  pds = dynamic_cast<PodioDataSvc*>( m_eds.get());
92  m_dataPtr = nullptr;
93  if (nullptr != pds) {
94  if (std::is_convertible<T*,podio::CollectionBase*>::value) {
95  // case 1: T is a podio collection
96  // for this case creation of branches is still handled in PodioOutput
97  // (but could be moved here in the future)
98  } else if constexpr (std::is_integral_v<T>) {
99  // case 2: T is some integer type
100  // the call signature for TTree Branch is different for primitive types
101  // in particular, we pass the pointer, not the adress of the pointer
102  // and have to append a char indicating type (see TTree documentation)
103  // therefore space needs to be allocated for the integer
104  m_dataPtr = new T();
105  TTree* tree = pds->eventDataTree();
106  tree->Branch(descriptor.c_str(), m_dataPtr, (descriptor + "/I").c_str());
107  } else if constexpr (std::is_floating_point_v<T>) {
108  // case 3: T is some floating point type
109  // similar case 2, distinguish floats and doubles by size
110  m_dataPtr = new T();
111  TTree* tree = pds->eventDataTree();
112  if (sizeof(T) > 4) {
113  tree->Branch(descriptor.c_str(), m_dataPtr, (descriptor + "/D").c_str());
114  } else {
115  tree->Branch(descriptor.c_str(), m_dataPtr, (descriptor + "/F").c_str());
116  }
117  } else {
118  // case 4: T is any other type (for which exists a root dictionary,
119  // otherwise i/o will fail)
120  // this includes std::vectors of ints, floats
121  TTree* tree = pds->eventDataTree();
122  tree->Branch(descriptor.c_str(), &m_dataPtr);
123  }
124  }
125  }
126 }
127 
128 /**
129  * Try to retrieve from the transient store. If the retrieval succeded and
130  * this is the first time we retrieve, perform a dynamic cast to the desired
131  * object. Then finally set the handle as Read.
132  * If this is not the first time we cast and the cast worked, just use the
133  * static cast: we do not need the checks of the dynamic cast for every access!
134  */
135 template <typename T>
136 const T* DataHandle<T>::get() {
137  DataObject* dataObjectp = nullptr;
138  auto sc = m_eds->retrieveObject(DataObjectHandle<DataWrapper<T>>::fullKey().key(), dataObjectp);
139 
140  if (LIKELY(sc.isSuccess())) {
141  if (UNLIKELY(!m_isGoodType && !m_isCollection)) {
142  // only do this once (if both are false after this, we throw exception)
143  m_isGoodType = nullptr != dynamic_cast<DataWrapper<T>*>(dataObjectp);
144  if (!m_isGoodType) {
145  auto tmp = dynamic_cast<DataWrapper<podio::CollectionBase>*>(dataObjectp);
146  if (tmp != nullptr) {
147  m_isCollection = nullptr != dynamic_cast<T*>(tmp->collectionBase());
148  }
149  }
150  }
151  if (LIKELY(m_isGoodType)) {
152  return static_cast<DataWrapper<T>*>(dataObjectp)->getData();
153  } else if (m_isCollection) {
154  // The reader does not know the specific type of the collection. So we need a reinterpret_cast if the handle was
155  // created by the reader.
157  return reinterpret_cast<const T*>(tmp->collectionBase());
158  } else {
159  std::string errorMsg("The type provided for " + DataObjectHandle<DataWrapper<T>>::pythonRepr() +
160  " is different from the one of the object in the store.");
161  throw GaudiException(errorMsg, "wrong product type", StatusCode::FAILURE);
162  }
163  }
164  std::string msg("Could not retrieve product " + DataObjectHandle<DataWrapper<T>>::pythonRepr());
165  throw GaudiException(msg, "wrong product name", StatusCode::FAILURE);
166 }
167 
168 //---------------------------------------------------------------------------
169 template <typename T>
170 void DataHandle<T>::put(T* objectp) {
171  std::unique_ptr<DataWrapper<T>> dw = std::make_unique<DataWrapper<T>>();
172  // in case T is of primitive type, we must not change the pointer address
173  // (see comments in ctor) instead copy the value of T into allocated memory
174  if constexpr (std::is_integral_v<T> || std::is_floating_point_v<T>) {
175  *m_dataPtr = *objectp;
176  } else {
177  m_dataPtr = objectp;
178  }
179  dw->setData(objectp);
180  DataObjectHandle<DataWrapper<T>>::put(std::move(dw));
181 
182 }
183 //---------------------------------------------------------------------------
184 /**
185  * Create the collection, put it in the DataObjectHandle and return the
186  * pointer to the data. Call this function if you create a collection and
187  * want to save it.
188  */
189 template <typename T>
191  T* objectp = new T();
192  this->put(objectp);
193  return objectp;
194 }
195 
196 // temporary to allow property declaration
197 namespace Gaudi {
198 template <class T>
199 class Property<::DataHandle<T>&> : public ::DataHandleProperty {
200 public:
201  Property(const std::string& name, ::DataHandle<T>& value) : ::DataHandleProperty(name, value) {}
202 
203  /// virtual Destructor
204  virtual ~Property() {}
205 };
206 }
207 
208 #endif
DataHandle::DataHandle
DataHandle()
DataWrapper
Definition: DataWrapper.h:30
PodioDataSvc
Definition: PodioDataSvc.h:26
DataHandle::put
void put(T *object)
Definition: DataHandle.h:170
example_calodigi.key
key
Definition: example_calodigi.py:28
Jug::VecULong
std::vector< unsigned long > VecULong
Definition: DataHandle.h:22
Jug
Definition: DD4hepBField.h:22
DataWrapper.h
DataWrapper::collectionBase
virtual podio::CollectionBase * collectionBase()
try to cast to collectionBase; may return nullptr;
Definition: DataWrapper.h:50
Gaudi
Definition: DataHandle.h:197
Gaudi::Property<::DataHandle< T > & >::Property
Property(const std::string &name, ::DataHandle< T > &value)
Definition: DataHandle.h:201
DataHandle::AlgTool
friend class AlgTool
Definition: DataHandle.h:37
DataHandle::createAndPut
T * createAndPut()
Definition: DataHandle.h:190
DataHandle::DataHandle
DataHandle(const std::string &k, Gaudi::DataHandle::Mode a, IDataHandleHolder *fatherAlg)
The DataHandle::Writer constructor is used to create the corresponding branch in the output file.
Definition: DataHandle.h:84
DataHandle::get
const T * get()
Retrieve object from transient data store.
Definition: DataHandle.h:136
DataHandle::Algorithm
friend class Algorithm
Definition: DataHandle.h:36
Gaudi::Property<::DataHandle< T > & >::~Property
virtual ~Property()
virtual Destructor
Definition: DataHandle.h:204
PodioDataSvc::eventDataTree
TTree * eventDataTree()
Definition: PodioDataSvc.h:66
PodioDataSvc.h
DataHandle::~DataHandle
~DataHandle()
Definition: DataHandle.h:69
DataHandle::DataHandle
DataHandle(DataObjID &descriptor, Gaudi::DataHandle::Mode a, IDataHandleHolder *fatherAlg)
Initialises mother class.
Definition: DataHandle.h:78
DataHandle
Definition: DataHandle.h:33
Jug::VecVecULong
std::vector< std::vector< unsigned long > > VecVecULong
Definition: DataHandle.h:23