The Gaudi Framework  v31r0 (aeb156f0)
RCWNTupleCnv.cpp
Go to the documentation of this file.
1 #define ROOTHISTCNV_RCWNTUPLECNV_CPP
2 
3 // Include files
6 #include "GaudiKernel/NTuple.h"
7 
8 // Compiler include files
9 #include <cstdio>
10 #include <cstring>
11 #include <list>
12 #include <utility>
13 #include <vector>
14 
15 #include "RCWNTupleCnv.h"
16 
17 #include "TLeafD.h"
18 #include "TLeafF.h"
19 #include "TLeafI.h"
20 #include "TTree.h"
21 
22 namespace {
23  template <typename T>
24  size_t saveItem( char* target, const NTuple::_Data<T>& src ) {
25  static_assert( std::is_trivially_copyable<T>::value, "T must be trivally copyable" );
26  std::memcpy( target, src.buffer(), sizeof( T ) * src.length() );
27  return sizeof( T ) * src.length();
28  }
29 
30  template <typename T>
31  size_t loadItem( const char* src, NTuple::_Data<T>& target ) {
32  static_assert( std::is_trivially_copyable<T>::value, "T must be trivally copyable" );
33  std::memcpy( const_cast<void*>( target.buffer() ), src, sizeof( T ) * target.length() );
34  return sizeof( T ) * target.length();
35  }
36 
37  template <typename POD>
38  decltype( auto ) downcast_item( const INTupleItem& i ) {
39  return dynamic_cast<const NTuple::_Data<POD>&>( i );
40  }
41  template <typename POD>
42  decltype( auto ) downcast_item( INTupleItem& i ) {
43  return dynamic_cast<NTuple::_Data<POD>&>( i );
44  }
45  template <typename POD, typename T>
46  void downcast_item( T&& ) = delete;
47 
48  template <typename Item, typename F>
49  decltype( auto ) visit( Item& i, F&& f ) {
50  switch ( i.type() ) {
51  case DataTypeInfo::INT:
52  return f( downcast_item<int>( i ) );
53  case DataTypeInfo::CHAR:
54  return f( downcast_item<char>( i ) );
56  return f( downcast_item<short>( i ) );
57  case DataTypeInfo::LONG:
58  return f( downcast_item<long>( i ) );
60  return f( downcast_item<long long>( i ) );
62  return f( downcast_item<unsigned char>( i ) );
64  return f( downcast_item<unsigned short>( i ) );
65  case DataTypeInfo::UINT:
66  return f( downcast_item<unsigned int>( i ) );
68  return f( downcast_item<unsigned long>( i ) );
70  return f( downcast_item<unsigned long long>( i ) );
72  return f( downcast_item<double>( i ) );
74  return f( downcast_item<float>( i ) );
75  case DataTypeInfo::BOOL:
76  return f( downcast_item<bool>( i ) );
77  }
78  throw std::runtime_error( "RCWNTupleCnv::visit: unknown INTupleItem::type()" );
79  }
80 
81  //-----------------------------------------------------------------------------
82  template <class T>
83  void analyzeItem( std::string typ, const NTuple::_Data<T>* it, std::string& desc, std::string& block_name,
84  std::string& var_name, long& lowerRange, long& upperRange, long& size )
85  //-----------------------------------------------------------------------------
86  {
87 
88  RootHistCnv::parseName( it->name(), block_name, var_name );
89 
90  // long item_size = (sizeof(T) < 4) ? 4 : sizeof(T);
91  long item_size = sizeof( T );
92  long dimension = it->length();
93  long ndim = it->ndim() - 1;
94  desc += var_name;
95  if ( it->hasIndex() || it->length() > 1 ) { desc += '['; }
96  if ( it->hasIndex() ) {
97  std::string ind_blk, ind_var;
98  RootHistCnv::parseName( it->index(), ind_blk, ind_var );
99  if ( ind_blk != block_name ) {
100  std::cerr << "ERROR: Index for CWNT variable " << ind_var << " is in a different block: " << ind_blk
101  << std::endl;
102  }
103  desc += ind_var;
104  } else if ( it->dim( ndim ) > 1 ) {
105  desc += std::to_string( it->dim( ndim ) );
106  }
107 
108  for ( int i = ndim - 1; i >= 0; i-- ) {
109  desc += "][";
110  desc += std::to_string( it->dim( i ) );
111  }
112  if ( it->hasIndex() || it->length() > 1 ) { desc += ']'; }
113 
114  if ( it->range().lower() != it->range().min() && it->range().upper() != it->range().max() ) {
115  lowerRange = it->range().lower();
116  upperRange = it->range().upper();
117  } else {
118  lowerRange = 0;
119  upperRange = -1;
120  }
121  desc += typ;
122  size += item_size * dimension;
123  }
124 } // namespace
125 
126 //-----------------------------------------------------------------------------
128 //-----------------------------------------------------------------------------
129 {
130  MsgStream log( msgSvc(), "RCWNTupleCnv" );
131  rtree = new TTree( desc.c_str(), nt->title().c_str() );
132  log << MSG::VERBOSE << "created tree id: " << rtree->GetName() << " title: " << nt->title() << " desc: " << desc
133  << endmsg;
134 
135  // Loop over the items
136 
137  std::string block_name, var_name;
138  long lowerRange, upperRange;
139  long size = 0;
140  long cursize, oldsize = 0;
141  std::vector<std::string> item_fullname;
142  // std::vector<long> item_size,item_size2;
143  std::vector<long> item_buf_pos, item_buf_len, item_buf_end;
144  std::vector<long> item_range_lower, item_range_upper;
146 
147  for ( const auto& i : nt->items() ) {
148  std::string item;
149 
150  visit( *i, [&]( const auto& data ) {
151  analyzeItem( this->rootVarType( data.type() ), &data, item, block_name, var_name, lowerRange, upperRange, size );
152  } );
153 
154  item_name.emplace_back( block_name, item );
155  cursize = size - oldsize;
156 
157  log << MSG::VERBOSE << "item: " << item << " type " << i->type() << " blk: " << block_name << " var: " << var_name
158  << " rng: " << lowerRange << " " << upperRange << " sz: " << size << " " << cursize
159  << " buf_pos: " << size - cursize << endmsg;
160 
161  item_fullname.push_back( var_name );
162  item_buf_pos.push_back( size - cursize );
163  item_buf_len.push_back( cursize );
164  item_buf_end.push_back( size );
165  item_range_lower.push_back( lowerRange );
166  item_range_upper.push_back( upperRange );
167 
168  oldsize = size;
169  }
170 
171  // Make a new buffer, and tell the ntuple where it is
172  char* buff = nt->setBuffer( new char[size] );
173 
174  log << MSG::VERBOSE << "Created buffer size: " << size << " at " << (void*)buff << endmsg;
175 
176  // Zero out the buffer to make ROOT happy
177  std::fill_n( buff, size, 0 );
178 
179  char* buf_pos = buff;
180 
181  auto end = item_name.cend();
182 
183  // Loop over items, creating a new branch for each one;
184  unsigned int i_item = 0;
185  for ( auto itr = item_name.cbegin(); itr != end; ++itr, ++i_item ) {
186 
187  buf_pos = buff + item_buf_pos[i_item];
188 
189  // log << MSG::WARNING << "adding TBranch " << i_item << " "
190  // << item_fullname[i_item]
191  // << " format: " << itr->second.c_str() << " at "
192  // << (void*) buf_pos << " (" << (void*) buff << "+"
193  // << (void*)item_buf_pos[i_item] << ")"
194  // << endmsg;
195 
196 #if ROOT_VERSION_CODE >= ROOT_VERSION( 5, 15, 0 )
197  auto br = new TBranch( rtree,
198 #else
199  TBranch* br = new TBranch(
200 #endif
201  item_fullname[i_item].c_str(), buf_pos, itr->second.c_str() );
202 
203  if ( itr->first != "AUTO_BLK" ) {
204  std::string title = itr->first;
205  title = itr->first + "::" + br->GetTitle();
206  br->SetTitle( title.c_str() );
207  }
208 
209  log << MSG::DEBUG << "adding TBranch " << br->GetTitle() << " at " << (void*)buf_pos << endmsg;
210 
211  // for index items with a limited range. Must be a TLeafI!
212  if ( item_range_lower[i_item] < item_range_upper[i_item] ) {
213  // log << MSG::VERBOSE << "\"" << item_fullname[i_item]
214  // << "\" is range limited " << item_range_lower[i_item] << " "
215  // << item_range_upper[i_item] << endmsg;
216  TLeafI* index = nullptr;
217  TObject* tobj = br->GetListOfLeaves()->FindObject( item_fullname[i_item].c_str() );
218  if ( tobj->IsA()->InheritsFrom( "TLeafI" ) ) {
219  index = dynamic_cast<TLeafI*>( tobj );
220 
221  if ( index ) {
222  index->SetMaximum( item_range_upper[i_item] );
223  // FIXME -- add for next version of ROOT
224  // index->SetMinimum( item_range_lower[i_item] );
225  } else {
226  log << MSG::ERROR << "Could dynamic cast to TLeafI: " << item_fullname[i_item] << endmsg;
227  }
228  }
229  }
230 
231  rtree->GetListOfBranches()->Add( br );
232  }
233 
234  log << MSG::INFO << "Booked TTree with ID: " << desc << " \"" << nt->title() << "\" in directory " << getDirectory()
235  << endmsg;
236 
237  return StatusCode::SUCCESS;
238 }
239 
240 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
241 
242 //-----------------------------------------------------------------------------
244 //-----------------------------------------------------------------------------
245 {
246  // Fill the tree;
247  const auto& items = nt->items();
248  std::accumulate( begin( items ), end( items ), nt->buffer(), []( char* dest, const INTupleItem* i ) {
249  return dest + visit( *i, [dest]( const auto& item ) { return saveItem( dest, item ); } );
250  } );
251 
252  rtree->Fill();
253  nt->reset();
254  return StatusCode::SUCCESS;
255 }
256 
257 //-----------------------------------------------------------------------------
258 StatusCode RootHistCnv::RCWNTupleCnv::readData( TTree* rtree, INTuple* ntup, long ievt )
259 //-----------------------------------------------------------------------------
260 {
261  if ( ievt >= rtree->GetEntries() ) {
262  MsgStream log( msgSvc(), "RCWNTupleCnv::readData" );
263  log << MSG::ERROR << "no more entries in tree to read. max: " << rtree->GetEntries() << " current: " << ievt
264  << endmsg;
265  return StatusCode::FAILURE;
266  }
267 
268  rtree->GetEvent( ievt );
269  ievt++;
270 
271  // copy data from ntup->buffer() to ntup->items()->buffer()
272  auto& items = ntup->items();
273  std::accumulate( begin( items ), end( items ), const_cast<const char*>( ntup->buffer() ),
274  []( const char* src, INTupleItem* i ) {
275  return src + visit( *i, [src]( auto& item ) { return loadItem( src, item ); } );
276  } );
277 
278  return StatusCode::SUCCESS;
279 }
280 
281 //-----------------------------------------------------------------------------
283 //-----------------------------------------------------------------------------
284 {
285  MsgStream log( msgSvc(), "RCWNTupleCnv::load" );
286 
287  StatusCode status;
288 
289  NTuple::Tuple* pObj = nullptr;
290 
291  std::string title = tree->GetTitle();
292  log << MSG::VERBOSE << "loading CWNT " << title << " at: " << tree << endmsg;
293 
294  status = m_ntupleSvc->create( CLID_ColumnWiseTuple, title, pObj );
295  INTuple* ntup = dynamic_cast<INTuple*>( pObj );
296 
297  INTupleItem* item = nullptr;
298 
299  std::string itemName, indexName, item_type, itemTitle, blockName;
300  // long numEnt, numVar;
301  long size, totsize = 0;
303 
304  // numEnt = (int)tree->GetEntries();
305  // numVar = tree->GetNbranches();
306 
307  // loop over all branches (==leaves)
308  TObjArray* lbr = tree->GetListOfBranches();
309  TIter bitr( lbr );
310  while ( TObject* tobjb = bitr() ) {
311 
312  TBranch* br = (TBranch*)tobjb;
313  itemTitle = br->GetTitle();
314 
315  int ipos = itemTitle.find( "::" );
316  if ( ipos >= 0 ) {
317  blockName = itemTitle.substr( 0, ipos );
318  } else {
319  blockName = "";
320  }
321 
322  TObjArray* lf = br->GetListOfLeaves();
323 
324  TIter litr( lf );
325  while ( TObject* tobj = litr() ) {
326 
327  bool hasRange = false;
328  int indexRange = 0;
329  int itemSize;
330  item = nullptr;
331 
332  // TLeaf* tl = (TLeaf*)tobj;
333  TLeaf* tl = dynamic_cast<TLeaf*>( tobj );
334  itemName = tl->GetName();
335 
336  // char* buf_pos = (char*)tl->GetValuePointer();
337  // cout << " " << itemName << " " << blockName << " "
338  // << (void*)buf_pos;
339 
340  if ( blockName != "" ) {
341  log << MSG::DEBUG << "loading NTuple item " << blockName << "/" << itemName;
342  } else {
343  log << MSG::DEBUG << "loading NTuple item " << itemName;
344  }
345 
346  int arraySize;
347  TLeaf* indexLeaf = tl->GetLeafCounter( arraySize );
348 
349  if ( arraySize == 0 ) { log << MSG::ERROR << "TLeaf counter size = 0. This should not happen!" << endmsg; }
350 
351  if ( indexLeaf ) {
352  // index Arrays and Matrices
353 
354  indexName = indexLeaf->GetName();
355  // indexRange = tl->GetNdata();
356  indexRange = indexLeaf->GetMaximum();
357  itemSize = indexRange * tl->GetLenType() * arraySize;
358 
359  log << "[" << indexName;
360 
361  // Just for Matrices
362  if ( arraySize != 1 ) { log << "][" << arraySize; }
363  log << "]";
364 
365  } else {
366  itemSize = tl->GetLenType() * arraySize;
367 
368  indexName = "";
369 
370  if ( arraySize == 1 ) {
371  // Simple items
372  } else {
373  // Arrays of constant size
374  log << "[" << arraySize << "]";
375  }
376  }
377 
378  log << endmsg;
379 
380  // cout << " index: " << indexName << endl;
381 
382  // size = tl->GetNdata() * tl->GetLenType();
383  size = itemSize;
384  totsize += size;
385 
386  hasRange = tl->IsRange();
387 
388  itemList.emplace_back( tl, itemSize );
389 
390  // Integer
391  if ( tobj->IsA()->InheritsFrom( "TLeafI" ) ) {
392 
393  TLeafI* tli = dynamic_cast<TLeafI*>( tobj );
394  if ( tli->IsUnsigned() ) {
395  unsigned long min = 0, max = 0;
396  if ( hasRange ) {
397  min = tli->GetMinimum();
398  max = tli->GetMaximum();
399  }
400 
401  item = createNTupleItem( itemName, blockName, indexName, indexRange, arraySize, min, max, ntup );
402  } else {
403  long min = 0, max = 0;
404  if ( hasRange ) {
405  min = tli->GetMinimum();
406  max = tli->GetMaximum();
407  }
408 
409  item = createNTupleItem( itemName, blockName, indexName, indexRange, arraySize, min, max, ntup );
410  }
411 
412  // Float
413  } else if ( tobj->IsA()->InheritsFrom( "TLeafF" ) ) {
414  float min = 0., max = 0.;
415 
416  TLeafF* tlf = dynamic_cast<TLeafF*>( tobj );
417  if ( hasRange ) {
418  min = float( tlf->GetMinimum() );
419  max = float( tlf->GetMaximum() );
420  }
421 
422  item = createNTupleItem( itemName, blockName, indexName, indexRange, arraySize, min, max, ntup );
423 
424  // Double
425  } else if ( tobj->IsA()->InheritsFrom( "TLeafD" ) ) {
426  double min = 0., max = 0.;
427 
428  TLeafD* tld = dynamic_cast<TLeafD*>( tobj );
429  if ( hasRange ) {
430  min = tld->GetMinimum();
431  max = tld->GetMaximum();
432  }
433 
434  item = createNTupleItem( itemName, blockName, indexName, indexRange, arraySize, min, max, ntup );
435 
436  } else {
437  log << MSG::ERROR << "Uknown data type" << endmsg;
438  }
439 
440  if ( item ) {
441  ntup->add( item );
442  } else {
443  log << MSG::ERROR << "Unable to create ntuple item \"" << itemName << "\"" << endmsg;
444  }
445 
446  } // end litr
447  } // end bitr
448 
449  log << MSG::DEBUG << "Total buffer size of NTuple: " << totsize << " Bytes." << endmsg;
450 
451  char* buf = ntup->setBuffer( new char[totsize] );
452  char* bufpos = buf;
453 
454  int ts = 0;
455  for ( const auto& iitr : itemList ) {
456  TLeaf* leaf = iitr.first;
457  int isize = iitr.second;
458 
459  log << MSG::VERBOSE << "setting TBranch " << leaf->GetBranch()->GetName() << " buffer at " << (void*)bufpos
460  << endmsg;
461 
462  leaf->GetBranch()->SetAddress( (void*)bufpos );
463 
464  // //testing
465  // if (leaf->IsA()->InheritsFrom("TLeafI")) {
466  // for (int ievt=0; ievt<5; ievt++) {
467  // leaf->GetBranch()->GetEvent(ievt);
468  // int *idat = (int*)bufpos;
469  // log << MSG::WARNING << leaf->GetName() << ": " << ievt << " "
470  // << *idat << endmsg;
471 
472  // }
473  // }
474 
475  ts += isize;
476 
477  bufpos += isize;
478  }
479 
480  if ( totsize != ts ) { log << MSG::ERROR << "buffer size mismatch: " << ts << " " << totsize << endmsg; }
481 
482  refpObject = ntup;
483 
484  return StatusCode::SUCCESS;
485 }
486 
487 // Instantiation of a static factory class used by clients to create
488 // instances of this service
std::string getDirectory()
Definition: RConverter.cpp:148
virtual const std::string & name() const =0
Access _Item name.
Definition of the MsgStream class used to transmit messages.
Definition: MsgStream.h:24
virtual const ItemRange & range() const =0
Access the range if specified.
bool parseName(const std::string &full, std::string &blk, std::string &var)
Definition: RNTupleCnv.cpp:236
EventIDBase min(const EventIDBase &lhs, const EventIDBase &rhs)
Definition: EventIDBase.h:202
T to_string(T...args)
virtual StatusCode add(INTupleItem *item)=0
Add an item row to the N tuple.
T endl(T...args)
constexpr static const auto SUCCESS
Definition: StatusCode.h:85
SmartIF< IMessageSvc > & msgSvc() const
Retrieve pointer to message service.
Definition: Converter.cpp:95
#define DECLARE_CONVERTER(x)
Definition: Converter.h:150
T cend(T...args)
Converter of Column-wise NTuple into ROOT format.
Definition: RCWNTupleCnv.h:20
StatusCode book(const std::string &desc, INTuple *pObject, TTree *&tree) override
Book the N tuple.
EventIDBase max(const EventIDBase &lhs, const EventIDBase &rhs)
Definition: EventIDBase.h:215
constexpr auto size(const C &c) noexcept(noexcept(c.size())) -> decltype(c.size())
STL class.
NTuple interface class definition.
Definition: INTuple.h:81
virtual void reset()=0
Reset all entries to their default values.
T push_back(T...args)
virtual long ndim() const =0
Dimension.
NTuple interface class definition.
Definition: INTuple.h:27
T memcpy(T...args)
virtual long length() const =0
Access the buffer length.
virtual const char * buffer() const =0
Access data buffer (CONST)
virtual StatusCode create(const CLID &typ, const std::string &title, NTuple::Tuple *&refpTuple)=0
Create requested N tuple (Hide constructor)
This class is used for returning status codes from appropriate routines.
Definition: StatusCode.h:50
StatusCode load(TTree *tree, INTuple *&refpObject) override
Create the transient representation of an object.
Abstract class describing basic data in an Ntuple.
Definition: NTuple.h:38
Abstract base class which allows the user to interact with the actual N tuple implementation.
Definition: NTuple.h:375
StatusCode readData(TTree *rtree, INTuple *pObject, long ievt) override
Read N tuple data.
virtual const void * buffer() const =0
Access data buffer (CONST)
T find(T...args)
T cbegin(T...args)
virtual char * setBuffer(char *buff)=0
Attach data buffer.
virtual const std::string & index() const =0
Access the index _Item.
T c_str(T...args)
T fill_n(T...args)
constexpr static const auto FAILURE
Definition: StatusCode.h:86
T substr(T...args)
virtual long dim(long i) const =0
Access individual dimensions.
INTupleItem * createNTupleItem(std::string itemName, std::string blockName, std::string indexName, int indexRange, int arraySize, TYP min, TYP max, INTuple *ntup)
Add an item of a given type to the N tuple.
Definition: RNTupleCnv.cpp:261
virtual ItemContainer & items()=0
Access item container.
AttribStringParser::Iterator begin(const AttribStringParser &parser)
virtual bool hasIndex() const =0
Is the tuple have an index item?
T accumulate(T...args)
SmartIF< INTupleSvc > m_ntupleSvc
Reference to N tuple service.
Definition: RNTupleCnv.h:54
virtual const std::string & title() const =0
Object title.
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition: MsgStream.h:192
virtual std::string rootVarType(int)
Return ROOT type info:
Definition: RNTupleCnv.cpp:200
StatusCode writeData(TTree *rtree, INTuple *pObject) override
Write N tuple data.
T emplace_back(T...args)