GSI Object Oriented Online Offline (Go4)  GO4-6.3.0
TGo4HDF5Adapter.cxx
Go to the documentation of this file.
1 // $Id$
2 //-----------------------------------------------------------------------
3 // The GSI Online Offline Object Oriented (Go4) Project
4 // Experiment Data Processing at EE department, GSI
5 //-----------------------------------------------------------------------
6 // Copyright (C) 2000- GSI Helmholtzzentrum fuer Schwerionenforschung GmbH
7 // Planckstr. 1, 64291 Darmstadt, Germany
8 // Contact: http://go4.gsi.de
9 //-----------------------------------------------------------------------
10 // This software can be used under the license agreements as stated
11 // in Go4License.txt file which is part of the distribution.
12 //-----------------------------------------------------------------------
13 
14 
15 #include "TGo4HDF5Adapter.h"
16 
17 #include "TList.h"
18 #include "TDataMember.h"
19 #include "TVirtualCollectionProxy.h"
20 #include "TBaseClass.h"
21 
22 #include "TGo4Log.h"
23 #include "TGo4EventElement.h"
24 #include "TGo4CompositeEvent.h"
25 
26 const char *TGo4HDF5Adapter::fgcFILESUF = ".h5";
27 
28 
30 {
31  if(fxFile) {
32  delete fxFile;
33  fxFile = nullptr;
34  }
35 }
36 
37 
39 {
40  if(fbDataSetExists)
41  delete fxHandle;
42  fbDataSetExists = kFALSE;
43  fxHandle = nullptr;
44 }
45 
47 {
48  if (!event)
49  return 0;
50  TClass *evclass = event->Class();
51  TClass *actualclass = evclass->GetActualClass(event);
52  size_t rev = actualclass->Size();
53  go4hdfdbg("TGo4HDF5Adapter: ScanEventSize for class %s with object size %ld\n", actualclass->GetName(), rev);
54  return rev;
55 }
56 
57 void TGo4HDF5Adapter::AddSubHandle(TGo4HDF5DataHandle *handle, const char *name, const char *type, size_t size,
58  size_t memberoffset, const char *membername, const char *classname,
59  TClass *valueclass)
60 {
61  TGo4HDF5DataHandle *subhandle = handle->AddSubMember(name, size, type);
62  subhandle->SetParentOffset(memberoffset);
63  subhandle->SetMemberName(membername);
64  subhandle->SetMemberClass(classname);
65  TGo4HDF5SubVectorDataHandle *subvector = dynamic_cast<TGo4HDF5SubVectorDataHandle *>(subhandle);
66  if (subvector) {
67  TString containerclass = "TGo4HDF5VectorProxy";
68  FillTypeInfo(subhandle, name, containerclass.Data());
69 
70  } else {
71  if (valueclass)
72  FillTypeInfo(subhandle, valueclass, name);
73  else
74  FillTypeInfo(subhandle, name, classname);
75  }
76 }
77 
78 void TGo4HDF5Adapter::FillTypeInfo(TGo4HDF5DataHandle *handle, TClass *rootclass, const char *basename)
79 {
80  if (!handle || !rootclass)
81  return;
82  go4hdfdbg("TGo4HDF5Adapter::FillTypeInfo CCCC - for class %s \n", rootclass->GetName());
83  // first check here baseclass members:
84  // otherwise will not store complete object
85  // and we have the problem of the bounce buffer with offset when reading back (first implementation!)
86  TIter baseiter(rootclass->GetListOfBases());
87  while (auto obj = baseiter()) {
88  // printf("TGo4HDF5Adapter::FillTypeInfo - baseiter object 0x%x of name %s, class:%s\n", obj, (obj ?
89  // obj->GetName() : "No base class"), (obj ? obj->IsA()->GetName() : "No type"));
90  TBaseClass *base = dynamic_cast<TBaseClass *>(obj);
91  go4hdfdbg("TGo4HDF5Adapter::FillTypeInfo - base class 0x%lx %s \n", (unsigned long)base,
92  (base ? base->GetName() : "No base class"));
93  if (!base)
94  continue;
95  TClass *bclass = base->GetClassPointer();
96  if (!bclass)
97  continue;
98  FillTypeInfo(handle, bclass, basename);
99  }
100 
101  // skip base class members not necessary for our dataset:G
102  if (strcmp(rootclass->GetName(), "TObject") == 0)
103  return;
104  if (strcmp(rootclass->GetName(), "TNamed") == 0)
105  return;
106  if (strcmp(rootclass->GetName(), "TGo4EventElement") == 0)
107  return;
108 
109  if (strcmp(rootclass->GetName(), "TGo4CompositeEvent") == 0) {
110  go4hdfdbg("TGo4HDF5Adapter::FillTypeInfo COMP detects go4 composite event. Assign fMaxIndex member...\n");
111  TDataMember *member = rootclass->GetDataMember("fMaxIndex");
112  if (!member)
113  return;
114  size_t memberoffset = member->GetOffset();
115  const char *memtypename = member->GetFullTypeName();
116  TString fullname =
117  (basename ? TString::Format("%s_%s", basename, member->GetName()) : TString(member->GetName()));
118  const char *membername = fullname.Data();
119  Int_t arraydim = member->GetArrayDim();
120  FillTypeInfo(handle, membername, memtypename, memberoffset, arraydim, member);
121  return;
122  // avoid that reading back the event will overwrite our objectarray pointers, since it is inside the fiReadOffset
123  // range! for composite events without own members, however, need the fMaxIndex as dummy to produce a hdf5 dataset
124  }
125 
126  // follows the members of our class
127  TIter iter(rootclass->GetListOfDataMembers());
128 
129  while (auto obj = iter()) {
130  TDataMember *member = dynamic_cast<TDataMember *>(obj);
131  if (!member)
132  continue;
133  const char *memtypename = member->GetFullTypeName();
134  TString fullname =
135  (basename ? TString::Format("%s_%s", basename, member->GetName()) : TString(member->GetName()));
136  const char *membername = fullname.Data();
137  size_t memberoffset = member->GetOffset();
138  Int_t arraydim = member->GetArrayDim();
139  go4hdfdbg("TGo4HDF5Adapter::FillTypeInfo *** sees member %s of type %s, offset=%ld, arraydim=%d\n", membername,
140  memtypename, memberoffset, arraydim);
141  // continue; // DEBUG IT
142 
143  if (arraydim > 2)
144  continue;
145  // hsize_t maxindex1 = 1, maxindex2 = 1;
146  // H5::DataType theType;
147  // do not edit IsA info
148  if (strstr(memtypename, "TClass")) // handles TClass * and atomic_TClass_ptr of ROOT6
149  continue;
150  if (strstr(membername, "fgIsA")) // paranoidly redundant, never come here
151  continue;
152 
153  if (member->Property() & kIsStatic) {
154  go4hdfdbg("TGo4HDF5Adapter::FillTypeInfo ignored static member.\n");
155  continue;
156  }
157 
158  // first check if we have a collection member.
159  TClass *innerclass = TClass::GetClass(memtypename);
160  TVirtualCollectionProxy *cprox = innerclass ? innerclass->GetCollectionProxy() : nullptr;
161  if (cprox) {
162  TClass *collectionclass = cprox->GetCollectionClass();
163  TClass *valueclass = cprox->GetValueClass();
164  EDataType valuetype = cprox->GetType();
165  // Int_t colltype=cprox->GetCollectionType();
166  go4hdfdbg("TGo4HDF5Adapter::FillTypeInfo *** has collection proxy, type:%d, valueclass=0x%lx, valuetype=%d\n",
167  cprox->GetCollectionType(), (unsigned long)valueclass, valuetype);
168  size_t innersize = 0;
169  size_t collsize = 0;
170  TString typenm;
171  TString colltypnm;
172 
173  // continue; // JAM DEBUG - leave out collections to test composite event io first! OK, this works
174 
175  if (valueclass) {
176  collsize = collectionclass->Size();
177  innersize = valueclass->Size();
178  typenm = valueclass->GetName();
179  colltypnm = collectionclass->GetName();
180  go4hdfdbg("TGo4HDF5Adapter::FillTypeInfo has collection proxy for type %d, collectionclass %s, class %s, "
181  "size:%ld, collsize:%ld\n",
182  collectionclass->GetCollectionType(), colltypnm.Data(), typenm.Data(), innersize,
183  collsize); //, cprox->Size() needs real collection object set to proxy);
184 
185  } else if (valuetype) {
186  TDataType *datatype = TDataType::GetDataType(valuetype);
187  typenm = datatype->GetTypeName();
188  innersize = datatype->Size();
189 
190  // will not work, since basic type do not have class object in ROOT!
191  // valueclass=TClass::GetClass(typenm.Data());
192  // go4hdfdbg("TGo4HDF5Adapter::FillTypeInfo sees valueclass %s\n",(valueclass? valueclass->GetName() :"NO
193  // CLASS"));
194 
195  colltypnm = memtypename; // get the vector<double> here!
196  collectionclass = TClass::GetClass(memtypename);
197  if (collectionclass)
198  collsize = collectionclass->Size();
199  else
200  go4hdfdbg("TGo4HDF5Adapter::FillTypeInfo could not get class for collection %s \n", memtypename);
201  go4hdfdbg(
202  "TGo4HDF5Adapter::FillTypeInfo has collection proxy for value %d, type %s, size:%ld, collsize:%ld\n",
203  collectionclass->GetCollectionType(), typenm.Data(), innersize, collsize);
204  } else {
205  continue;
206  }
207 
209 
210  // now evaluate the subhandles depending on the array dimension:
211  // here treat special case of array of vectors (poland example)
212  Int_t maxindex1 = 0, maxindex2 = 0;
213  switch (arraydim) {
214 
215  default:
216  // plain collection that is not part of another array:
217  AddSubHandle(handle, membername, colltypnm.Data(), innersize, memberoffset, member->GetName(),
218  typenm.Data(), valueclass);
219  break;
220 
221  case 1:
222  maxindex1 = member->GetMaxIndex(0);
223  for (int x = 0; x < maxindex1; ++x) {
224  TString arraymember =
225  TString::Format("%s[%d]", membername, x); // contains supermembers as prefix for full name
226  TString memberhandle =
227  TString::Format("%s[%d]", member->GetName(), x); // only local member for pointer handle
228  AddSubHandle(handle, arraymember.Data(), colltypnm.Data(), innersize, memberoffset, memberhandle.Data(),
229  typenm.Data(), valueclass);
230  memberoffset += collsize;
231  }
232  break;
233 
234  case 2:
235  maxindex1 = member->GetMaxIndex(0);
236  maxindex2 = member->GetMaxIndex(1);
237  for (int x = 0; x < maxindex1; ++x)
238  for (int y = 0; y < maxindex2; ++y) {
239  TString arraymember =
240  TString::Format("%s[%d][%d]", membername, x, y); // contains supermembers as prefix for full name
241  TString memberhandle =
242  TString::Format("%s[%d][%d]", member->GetName(), x, y); // only local member for pointer handle
243  AddSubHandle(handle, arraymember.Data(), colltypnm.Data(), innersize, memberoffset,
244  memberhandle.Data(), typenm.Data(), valueclass);
245  memberoffset += collsize;
246  }
247  break;
248 
249  }; // switch(arraydim)
250  continue;
251  }
252 
253  FillTypeInfo(handle, membername, memtypename, memberoffset, arraydim, member);
254 
255  }
256 }
257 
259  const char *membername, const char *memtypename, size_t memberoffset,
260  Int_t arraydim, TDataMember *member)
261  {
262  H5::DataType theType;
263  hsize_t maxindex1 = 1, maxindex2 = 1;
264 
265  go4hdfdbg("TGo4HDF5Adapter::FillTypeInfo begins for type %s ...\n",memtypename);
266 
267  if ((strcmp(memtypename, "Char_t") == 0) || (strcmp(memtypename, "char") == 0))
268  theType = H5::PredType::NATIVE_CHAR;
269  else if ((strcmp(memtypename, "UChar_t") == 0) || (strcmp(memtypename, "unsigned char") == 0))
270  theType = H5::PredType::NATIVE_UCHAR;
271  else if ((strcmp(memtypename, "Short_t") == 0) || (strcmp(memtypename, "short") == 0))
272  theType = H5::PredType::NATIVE_SHORT;
273  else if ((strcmp(memtypename, "UShort_t") == 0) || (strcmp(memtypename, "unsigned short") == 0))
274  theType = H5::PredType::NATIVE_USHORT;
275  else if ((strcmp(memtypename, "Int_t") == 0) || (strcmp(memtypename, "int") == 0))
276  theType = H5::PredType::NATIVE_INT;
277  else if ((strcmp(memtypename, "UInt_t") == 0) || (strcmp(memtypename, "unsigned int") == 0))
278  theType = H5::PredType::NATIVE_UINT;
279  else if ((strcmp(memtypename, "ULong_t") == 0) || (strcmp(memtypename, "unsigned long") == 0))
280  theType = H5::PredType::NATIVE_ULONG;
281  else if ((strcmp(memtypename, "Double_t") == 0) || (strcmp(memtypename, "double") == 0))
282  theType = H5::PredType::NATIVE_DOUBLE;
283  else if ((strcmp(memtypename, "Float_t") == 0) || (strcmp(memtypename, "float") == 0))
284  theType = H5::PredType::NATIVE_FLOAT;
285  else if ((strcmp(memtypename, "Bool_t") == 0) || (strcmp(memtypename, "bool") == 0))
286  theType = H5::PredType::NATIVE_HBOOL;
287  else if ((strcmp(memtypename, "TString") == 0) || strstr(memtypename, "string")) {
288  return; // skip for the moment names and text information TODO!
289  }
290 
291  else if (strcmp(memtypename, "TGo4HDF5VectorProxy") == 0) {
292  // this is dummy class to represent vector of vector entry, handle it manually without root
293  go4hdfdbg("TGo4HDF5Adapter::FillTypeInfo handles explicitly vector entry %s\n", memtypename);
294 
295  TString innermemname;
296  TGo4HDF5DataHandle innercomp(memtypename, sizeof(TGo4HDF5VectorProxy));
297  innermemname = TString::Format("%s_fx_Begin_ptr", membername);
298  innercomp.InsertTypeMember(innermemname.Data(), HOFFSET(TGo4HDF5VectorProxy, fx_Begin_ptr),
299  H5::PredType::NATIVE_ULONG);
300  innermemname = TString::Format("%s_fx_End_ptr", membername);
301  innercomp.InsertTypeMember(innermemname.Data(), HOFFSET(TGo4HDF5VectorProxy, fx_End_ptr),
302  H5::PredType::NATIVE_ULONG);
303  innermemname = TString::Format("%s_fx_Cap_ptr", membername);
304  innercomp.InsertTypeMember(innermemname.Data(), HOFFSET(TGo4HDF5VectorProxy, fx_Cap_ptr),
305  H5::PredType::NATIVE_ULONG);
306  theType = *(innercomp.GetType());
307  }
308 
309  else {
310  // evaluate structure components here
311  TClass *innerclass = TClass::GetClass(memtypename);
312 
313  if (!innerclass)
314  return;
315  go4hdfdbg("TGo4HDF5Adapter::FillTypeInfo finds root class info for type %s\n", memtypename);
316 
317  size_t innersize = innerclass->Size();
318  // temporary datahandle just to extract the type components
319  TGo4HDF5DataHandle innercomp(memtypename, innersize);
320  FillTypeInfo(&innercomp, innerclass, membername);
321  theType = *(innercomp.GetType());
322  }
323 
324  const H5std_string theMEMBER(membername);
325 
326  switch (arraydim) {
327  case 1: {
328  maxindex1 = member->GetMaxIndex(0);
329  hsize_t dims[1] = {maxindex1};
330  H5::ArrayType theArray(theType, arraydim, dims);
331  go4hdfdbg(
332  "TGo4HDF5Adapter::FillTypeInfo inserts array member %s, type %s dimension %d, maxindex:%lld, offset:%ld\n",
333  membername, memtypename, arraydim, maxindex1, memberoffset);
334  handle->InsertTypeMember(theMEMBER, memberoffset, theArray);
335  break;
336  }
337  case 2: {
338  maxindex1 = member->GetMaxIndex(0);
339  maxindex2 = member->GetMaxIndex(1);
340  hsize_t dims[2] = {maxindex1, maxindex2};
341  H5::ArrayType theArray(theType, arraydim, dims);
342  go4hdfdbg(
343  "TGo4HDF5Adapter::FillTypeInfo inserts array member %s, type %s dimension %d, maxindex:%lld, offset:%ld\n",
344  membername, memtypename, arraydim, maxindex1, memberoffset);
345 
346  handle->InsertTypeMember(theMEMBER, memberoffset, theArray);
347  break;
348  }
349 
350  default:
351  go4hdfdbg(
352  "TGo4HDF5Adapter::FillTypeInfo inserts simple member %s, type %s dimension %d, maxindex:%lld, offset:%ld\n",
353  membername, memtypename, arraydim, maxindex1, memberoffset);
354 
355  handle->InsertTypeMember(theMEMBER, memberoffset, theType);
356  break;
357 
358  } // switch()
359  }
360 
362 {
363  TClass *evclass = event->Class();
364  if (!evclass) {
365  TGo4Log::Error("TGo4HDF5Adapter::BuildDataType can not find an event class\n");
366  return;
367  }
368  TClass *actualclass = evclass->GetActualClass(event);
369  TString actualclassname= actualclass->GetName();
370  size_t eventsize=ScanEventSize(event);
371  TGo4HDF5DataHandle* theHandle = nullptr;
372  go4hdfdbg("TGo4HDF5Adapter::BuildDataType for class %s\n",
373  actualclassname.Data());
374  if(!parent)
375  {
376  // top level event, components are scanned recursively:
377  fxHandle=new TGo4HDF5BasicDataHandle(actualclassname.Data(), eventsize);
378  fxHandle->SetObjectPointer(event);
379  FillTypeInfo(fxHandle, actualclass, actualclassname.Data());
380  theHandle=fxHandle;
381  fxHandle->SetTopEvent(event);
382  fxHandle->SetTopEventClass(actualclassname.Data());
383 
384  }
385  else
386  {
387  // component of a composite event: belongs to the parent handle
388  TString compname=TString::Format("%s_%s(%d)",parent->GetTypeName(), actualclassname.Data(), index);
389  TString comptype="Go4CompEv"; // do we need to tag the subhandles here?
390  theHandle=parent->AddSubMember(compname.Data(), eventsize, comptype.Data());
391  void *super=parent->Data(); // everything is relative to immediate mother element
392  size_t delta = (char *) event - (char *) super;
393  go4hdfdbg("TGo4HDF5Adapter::BuildDataType sets parent offset %ld (event:0x%lx, super:0x%lx)\n",
394  delta, (unsigned long) event, (unsigned long) super);
395  theHandle->SetParentOffset(delta);
396  theHandle->SetObjectPointer(super);
397  // prepend here the parent name to our subhandle:
398  FillTypeInfo(theHandle, actualclass, theHandle->GetTypeName());
399 
400  // for reading back component data, each composite subevent has to override the top level parent event:
401  theHandle->SetTopEvent(event);
402  theHandle->SetTopEventClass(actualclassname.Data());
403 
404  }
405 
406  // need to scan components of composite event here:
407  TGo4CompositeEvent *comp = dynamic_cast<TGo4CompositeEvent *>(event);
408  if(comp)
409  {
410  go4hdfdbg("TGo4HDF5Adapter::BuildDataType evaluates members of Go4 composite event %s\n",
411  comp->GetName());
412  Short_t numSubEvents=comp->getNElements();
413  for (int i = 0; i < numSubEvents; ++i) {
414  TGo4EventElement *sub = comp->getEventElement(i);
415  if (!sub)
416  continue;
417  BuildDataType(sub, theHandle, i);
418  }
419  }
420 
421  // finally, set reference pointers for all evaluated subcomponents:
422  if(!parent)
423  {
424  theHandle->SetObjectPointer(event); // set it here, because parentoffsets of subcomponents may have changed at recursive evaluation
425  }
426 }
427 
428 
429 
431 {
432  UInt_t h5flags = 0;
433 
434  switch (flags) {
435  case GO4_H5F_ACC_NONE:
436  case GO4_H5F_ACC_TRUNC: h5flags = H5F_ACC_TRUNC; break;
437  case GO4_H5F_ACC_EXCL: h5flags = H5F_ACC_EXCL; break;
438  case GO4_H5F_ACC_RDONLY: h5flags = H5F_ACC_RDONLY; break;
439  case GO4_H5F_ACC_RDWR: h5flags = H5F_ACC_RDWR; break;
440  default: h5flags = H5F_ACC_TRUNC; break;
441  }
442  return h5flags;
443 }
H5::CompType * GetType() const
static void FillTypeInfo(TGo4HDF5DataHandle *handle, TClass *rootclass, const char *basename=nullptr)
static const char * fgcFILESUF
void InsertTypeMember(const H5std_string &name, size_t offset, const H5::DataType &new_member)
H5::H5File * fxFile
UInt_t ConvertFileMode(Go4_H5_File_Flags flags)
#define go4hdfdbg(args...)
Definition: Go4HDF5.h:26
size_t ScanEventSize(TGo4EventElement *event)
static void AddSubHandle(TGo4HDF5DataHandle *handle, const char *name, const char *type, size_t size, size_t memberoffset, const char *membername, const char *classname, TClass *valueclass)
virtual void DeleteDataSet()
void SetTopEventClass(const char *classname)
Go4_H5_File_Flags
Definition: Go4HDF5.h:41
void SetTopEvent(TGo4EventElement *eve)
TGo4EventElement * getEventElement(Int_t idx)
static void Error(const char *text,...) GO4_PRINTF_ARGS
Definition: TGo4Log.cxx:320
void BuildDataType(TGo4EventElement *event, TGo4HDF5DataHandle *parent=nullptr, Int_t index=0)
virtual void SetObjectPointer(void *memptr)
void SetParentOffset(size_t off)
const char * GetTypeName() const
Short_t getNElements() const
TGo4HDF5DataHandle * AddSubMember(const char *name, size_t datasize, const char *collectiontype=nullptr)
virtual void CloseFile()
void SetMemberName(const char *name)
TGo4HDF5DataHandle * fxHandle
void SetMemberClass(const char *clname)