|
//____________________________________________________________________
//
// BrEventNode is a BRAHMS data class providing storage and access
// function for event data information. The data is stored in
// BrDataObject objects that are kept inside a THashList (currently a
// TObjArray).
//
// This allows modification of the BrEvent content by the user, with
// the BrDataObject providing a standard interface for information
// retrieval, bookkeeping and I/O selection.
//
// Note that the node own its contained objects. That is, when the
// node is deleted via a operator delete, the objects contained in the
// class is deleted too, and you can no longer refence that memory.
// See also BrEventNode::~BrEventNode and chapter 8 in [1].
//
// A consideration on owner ship (Christian Holm):
// -----------------------------------------------
// Since the node owns it's refenerenced (or contained) objects, it's
// impossible for a BrModule to have a cache of memory to be reused
// in the event loop. This is a rather unfortunate sideeffect.
//
// What we'd like to allow for modules to do, is to create a
// TClonesArray and use that as a memory pool:
//
// In BrModule::Init:
//
// fPool = new TClonesArray("BrSomeDataClass");
//
// This pool will then be used in the event loop, and references into
// that pool will be put in the node:
//
// In BrModule::Event(inNode, outNode):
//
// fPool->Clear();
// ...
// BrSomeDataClass* data =
// new((*fPool)[fNData++]) BrSomeDataClass();
// outNode->AddObject(data);
//
// If a module does not want to pool the memory (?), then it must
// explicitly set the kCanDelete bit:
//
// In BrModule::Event(inNode, outNode):
//
// BrSomeDataClass* data = new BrSomeDataClass();
// data->SetBit(kCanDelete, kTRUE);
// outNode->AddObject(data);
//
// Ofcourse the data class could per default set that bit.
//
// This strategy could significantly speed up the BRAT code, since the
// ::operator new and ::operator delete messages are very expensive
// indeed, which can be circumvented by using a pool of data.
//
// The strategy outlined of course requires that BrSomeDataClass is of
// fixed size, that is does not allocate memory, and pointers should
// be non-persistant (requirement of TClonesArray).
//
// Since using this strategy has far reaching effects on the code, it
// will not be implmented at this time (Mon Aug 20 16:15:13 2001), but
// _must_ await a consensues decision.
//
// Side note:
// ----------
// Note the use ofHashTables. This will be most efficient to access
// data by name. This should be chekced out carefully, and performence
// measured. Note this is in fact not the case simple TObjArrays are
// used.
//
//
/*
References:
[1] ROOT Users
Guide
*/
//
//____________________________________________________________________
//
// $Id: BrEventNode.cxx,v 1.3 2001/08/21 16:16:36 cholm Exp $
// $Author: cholm $
// $Date: 2001/08/21 16:16:36 $
//
#include "BrEventNode.h"
#include "BrDataTable.h"
//
// Root classes
//
#include "TBuffer.h"
#include "TClass.h"
#if ROOT_VERSION_CODE >= ROOT_VERSION(2,25,3)
#include "TROOT.h"
#endif
#include <iostream.h>
// Change:
// January 6, 1999 FV
// Added method
// BrRemoveDataObject(object) to enable an easy way of removing
// datatables and simpler dataobjects from a node e.g to make a
// reduced size output file. Example (without check for existence of
// nodes...)
//
// BrEventNode* fs_node = (BrEventNode*)digitized_node->GetObject("FFS");
// BrDataTable* t1b = digitized_node->GetDataTable("TPCSequence T1B");
// fs_node->RemoveDataObject(t1b);
// t1b->Delete();
//
// May 17, 2000 FV
// Removed entries list in ListObjects-- DataObject do NOT have an entries
// method unless they are tables.
//
// September 19, 2000, Christian Holm
// Preprocessor conditional code for ROO 2.25/03
// (IndentLevel => gROOT->IndentLevel etc.)
//
//____________________________________________________________
ClassImp(BrEventNode);
//____________________________________________________________
BrEventNode::BrEventNode()
{
// Constructor. Set counter and list data members to zero.
// Don't use this constructor unless you have to and know
// what you are doing
// Use BrEventNode(Char_t Name) instead
fObjectList = 0;
fVerbose = 0;
}
//____________________________________________________________
BrEventNode::BrEventNode(const Char_t* Name, const Char_t *Title )
: BrDataObject(Name,Title)
{
// Constructor. Create the hash table
// for storing the data objects for this event. Set the
// eventnode name
fObjectList = 0;
fVerbose = 0;
}
//_______________________________________________________________________
BrEventNode::BrEventNode(const BrEventNode &node)
{
// Copy constructor. This is done in a simple way for now.
// and this will NOT work as defined!!!!
//
Int_t len = sizeof(BrEventNode);
memcpy(this, &node, len);
}
//_______________________________________________________________________
BrEventNode::~BrEventNode()
{
// Destructor. Delete BrEventNode and all the data objects currently
// owned by BrEventNode. It is assumed but not checked that all
// member in the lower nodes are also deleted.
//
// It's controversial wether we should actually call
// TObjArray::Delete here. Maybe a TObjArray::Clear would be
// better.
if(fObjectList) {
fObjectList->Delete();
delete fObjectList;
fObjectList = 0;
}
}
//_______________________________________________________________________
void BrEventNode::CheckList()
{
// Check if list exist. If not, create it.
if (!fObjectList) fObjectList = new TObjArray();
}
//_______________________________________________________________________
Int_t BrEventNode::AddObject(BrDataObject *object)
{
// Add a BrDataObejct to the EventNode. The object can be simple,
// or an EventNode..
//
CheckList();
fObjectList->Add(object);
if(fVerbose)
cout << "<BrEventNode::AddObject>: Add data Object "
<< object->GetName() << ", total of "
<< fObjectList->GetSize() << " objects" << endl;
return fObjectList->GetSize();
}
//_____________________________________________________________________
BrEventNode* BrEventNode::GetEventNode(const Char_t *name) const
{
// Return the node named name
if(!fObjectList)
return 0; //If no list, means nothing in it to get
TString n(name);
TIter next(fObjectList);
BrDataObject *object;
while ((object = (BrDataObject*)next())){
// First check if the object really is a BrEventNode (for type
// safe returns), and then compare the name.
if (object->IsA()->InheritsFrom(BrEventNode::Class())
&& !n.CompareTo(object->GetName()))
return (BrEventNode*)object;
// If the next object is a node, then we search that. In this way,
// we recursively search the tree.
if(object->IsNode()) {
object = ((BrEventNode*)object)->GetEventNode(name);
// If the object is found in a sub node, then we return
// immediatly.
if(object)
return (BrEventNode*)object;
}
}
return 0;
}
//_____________________________________________________________________
BrDataTable* BrEventNode::GetDataTable(const Char_t *name) const
{
// Get a pointer to a BrDataObject with the given Name in the node
// or lower in the tree. Only the first occurence of an object with
// a specified name is returned. Recursive calls are made if
// EventNodes are part of the list.
//
if(!fObjectList)
return 0; //If no list, means nothing in it to get
TString n(name);
TIter next(fObjectList);
BrDataObject *object;
while ((object = (BrDataObject*)next())){
// First check if the object really is a BrDataTable (for type
// safe returns), and then compare the name.
if (object->IsA()->InheritsFrom(BrDataTable::Class())
&& !n.CompareTo(object->GetName()))
return (BrDataTable*)object;
// If the next object is a node, then we search that. In this way,
// we recursively search the tree.
if(object->IsNode()) {
object = ((BrEventNode*)object)->GetDataTable(name);
// If the object is found in a sub node, then we return
// immediatly.
if(object)
return (BrDataTable*)object;
}
}
return 0;
}
//_______________________________________________________________________
BrDataObject* BrEventNode::GetObject(const Char_t *name) const
{
// Get a pointer to a BrDataObject with the given Name in the node
// or lower in the tree. Only the first occurence of an object with
// a specified name is returned. Recursive calls are made if
// EventNodes are part of the list.
if(!fObjectList)
return 0; //If no list, means nothing in it to get
TString n(name);
TIter next(fObjectList);
BrDataObject *object;
while ((object = (BrDataObject*)next())){
// Since any object we can add to the node is derived from
// BrDataObject, we really don't need to make a type check here.
if (!n.CompareTo(object->GetName()))
return (BrDataObject*)object;
if(object->IsNode()){
object = ((BrEventNode*)object)->GetObject(name);
// If the object is found in a sub node, then we return
// immediatly.
if(object)
return object;
}
}
return 0;
}
//______________________________________________________
void BrEventNode::Clear(Option_t* option)
{
// Clear internal TObjArray object. That is, remove pointers to
// actual objects. The objects are only deleted (memory freed) if
// the TObjArray::SetOwner(kTRUE) message has been sent, or the
// kCanDelete bit is set (see also the class description).
if(fObjectList)
fObjectList->Clear(option);
}
//______________________________________________________
void BrEventNode::ListObjects() const
{
// List on standard out a summary of BrDataObjects in the
// EventNode. The listing is recursive. All levels are scanned.
// Depreciated. Use Print instead.
if(!fObjectList)
return; //no need to print if no object list yet
BrDataObject *object;
Int_t num = 0;
TIter NextObject(fObjectList);
while((object = (BrDataObject*)NextObject())) {
#if ROOT_VERSION_CODE >= ROOT_VERSION(2,25,3)
gROOT->IndentLevel();
#else
IndentLevel();
#endif
cout << num << " - " << object << " - "
<< object->GetName() << " - "
<< object->GetTitle() << endl;
if(object->IsNode()){
#if ROOT_VERSION_CODE >= ROOT_VERSION(2,25,3)
gROOT->IncreaseDirLevel();
#else
IncreaseDirLevel();
#endif
((BrEventNode*) object)->ListObjects();
#if ROOT_VERSION_CODE >= ROOT_VERSION(2,25,3)
gROOT->DecreaseDirLevel();
#else
DecreaseDirLevel();
#endif
}
num++;
}
}
//______________________________________________________
void BrEventNode::Copy(BrEventNode &eventnode)
{
//Copy contents from this into eventnode
BrDataObject::Copy(eventnode);
eventnode.fVerbose = fVerbose;
if(!fObjectList)
return;
TIter next(fObjectList);
BrDataObject* dataObj;
while((dataObj = (BrDataObject*)next()))
eventnode.AddObject(dataObj);
}
//________________________________________________________________
void BrEventNode::RemoveDataObject(BrDataObject* object)
{
// Remove Dataobject from Table, but do not delete obejct.
//
if(fObjectList)
fObjectList->Remove(object);
}
//________________________________________________________________
BrEventNode& BrEventNode::operator +=(const BrEventNode& node)
{
// This operator takes matching elements of nodes and adds them
// together. The cases when one node has elements that the other
// does not is not yet taken into account.
// objlist1 is local object list
// objlist2 is object list of node we are adding to.
// nument1 is number of entries of local object list
// nument2 is number of entries of node we are adding to
// object1 is object found in local list
// object2 is object found in node we are adding to
TObjArray *objlist1;
TObjArray *objlist2;
objlist1 = GetObjectList();
if (!objlist1)
return *this;
Int_t nument1 = objlist1->GetEntries();
objlist2 = node.GetObjectList();
if (!objlist2)
return *this;
Int_t nument2 = objlist2->GetEntries();
TObject *object1 = 0;
TObject *object2 = 0;
for(Int_t i1 = 0; i1 < nument1; i1++) {
object1 = objlist1->At(i1);
for(Int_t i2 = 0; i2 < nument2; i2++) {
object2 = objlist2->At(i2);
if(!strcmp(object1->GetName(),object2->GetName())) {
// We have found two objects with the same name. Add them
// together
if (object1->IsA() == BrEventNode::Class())
*(BrEventNode*)object1 += *(BrEventNode*)object2;
else if (object1->IsA() == BrDataTable::Class())
*(BrDataTable*)object1 += *(BrDataTable*)object2;
#if 0
// I took out this instance, since it seems rediculus to
// have a special case for it.
else if(object1->IsA() == BrGeantHeader::Class())
// It is not clear to me what to do about BrGeantHeaders
// when mixing events. It should be discussed if this
// facility is really used. For the moment, I just add
// them to the list. How we get them both out will be
// another story.
this->AddObject((BrDataObject*)object2);
#endif
else {
#ifdef USE_NODE_FULL_CONCAT
this->AddObject((BrDataObject*)object2);
#else
cout << "Object found in EventNode "
<< node.GetName () << " is off class "
<< object1->IsA()->Class_Name() << "." << endl
<< "There is no support for it yet, "
<< "please see your BRAT manager" << endl;
#endif
}
// Break out of this loop, cause we found machting objects.
// Zero the thing, so that we know if the object was found of
// not.
object2 = 0;
break;
}
}
}
return *this;
}
//________________________________________________________________
void BrEventNode::Browse(TBrowser* b)
{
if(!fObjectList) return;
TIter next(fObjectList);
TObject* obj;
while((obj = next()))
b->Add(obj);
}
//________________________________________________________________
void BrEventNode::Print(Option_t* option) const
{
// Print all contained objects, passing the option along.
// Options:
// R Recursive print [Default]
// See also BrDataObject::Print
BrDataObject::Print(option);
if(!fObjectList)
return; //no need to go further if no object list.
TString opt(option);
opt.ToLower();
if (opt.Contains("r")) {
gROOT->IncreaseDirLevel();
TIter next(fObjectList);
TObject *obj = 0;
while((obj = next())) {
gROOT->IndentLevel();
obj->Print(option);
}
gROOT->DecreaseDirLevel();
}
}
//________________________________________________________________
BrEventNode& operator+(const BrEventNode& node1, const BrEventNode& node2)
{
// This operator takes matching elements of nodes and adds them
// together. The cases when one node has elements that the other
// does not is not yet taken into account.
TObjArray *objlist1,*objlist2;
objlist1 = node1.GetObjectList();
Int_t nument1 = objlist1->GetEntries();
objlist2 = node2.GetObjectList();
Int_t nument2 = objlist2->GetEntries();
BrEventNode *tmp = new BrEventNode(node1.GetName());
if(objlist1) {
for(Int_t i1=0;i1<nument1;i1++) {
TObject *object1 = objlist1->At(i1);
for(Int_t i2=0;i2<nument2;i2++) {
TObject *object2 = objlist2->At(i2);
if(!strcmp(object1->GetName(),object2->GetName())) {
// We have found two objects with the same name. Add them
// to the output event
if(!strcmp(object1->IsA()->GetName(),"BrEventNode")) {
BrEventNode *tmpnode =
new BrEventNode(*(BrEventNode*)object1
+ *(BrEventNode*)object2);
tmp->AddEventNode(tmpnode);
}
else if(!strcmp(object1->IsA()->GetName(),"BrDataTable")) {
BrDataTable *tmptable =
new BrDataTable(*(BrDataTable*)object1
+ *(BrDataTable*)object2);
tmp->AddDataTable(tmptable);
}
else if(!strcmp(object1->IsA()->GetName(),"BrGeantHeader")) {
// It is not clear to me what to do about BrGeantHeaders
// when mixing events. It should be discussed if this
// facility is really used. For the moment, I just add
// them to the list. How we get them both out will be
// another story.
tmp->AddObject((BrDataObject*)object1);
tmp->AddObject((BrDataObject*)object2);
}
else {
cout<< "Object found in EventNode " << node1.GetName()
<< " is " <<object1->IsA()->GetName() << "." <<endl;
cout<<"There is no support for it yet, "
"please see your BRAT manager"<<endl;
}
}
}
}
}
return *tmp;
}
//____________________________________________________________________
BrEventNode& BrEventNode::operator=(const BrEventNode &rhs)
{
// BrEventNode assignment operator.
// This is done with a simple memcpy for the moment.
if (this != &rhs) {
Int_t len = sizeof(BrEventNode);
memcpy(this,&rhs,len);
}
return *this;
}
//____________________________________________________________
BrEventNode & BrEventNode::operator=(const BrEvent &rhs)
{
// BrEvent to BrEventNode assignment operator.
cout<< "Inside assignment of BrEvent to BrEventNode. "
<< "Should we be here? see BRAT manager" << endl;
return *this;
}
/*
//______________________________________________________________________________
void BrEventNode::Streamer(TBuffer &R__b)
{
// Stream an object of class BrEvent.
if (R__b.IsReading()) {
Version_t R__v = R__b.ReadVersion();
BrDataObject::Streamer(R__b);
R__b >> fVerbose;
R__b >> fObjectList;
} else {
R__b.WriteVersion(BrEventNode::IsA());
BrDataObject::Streamer(R__b);
R__b << fVerbose;
// make a temporary hashtable for the objects marked
// as persistent and store only those in the output
// buffer. Since this is a node iterative calls should probably be
// implemented. What has to be done for BrEvent that is a derived
// Class ?
//
TObkArray *temp = new TObjArray();
TIter NextObject(fObjectList);
TObject *obj;
while(obj = NextObject())
{
temp->Add(obj);
}
R__b << temp;
temp->Clear();
delete temp;
}
}
*/
// $Log: BrEventNode.cxx,v $
// Revision 1.3 2001/08/21 16:16:36 cholm
// Added method CheckLis for on-demand allocation.
// Added some more documentation.
// Added type-safety to GetDataTable, GetEventNode methods.
//
// Revision 1.2 2001/08/08 21:52:08 hagel
// Eliminate memory leak by creating on demand fObjectList and fEventHeader
//
// Revision 1.1.1.1 2001/06/21 14:54:58 hagel
// Initial revision of brat2
//
// Revision 1.25 2001/06/01 15:46:54 cholm
// Fixed creation id class to be more clean. Now sets the user name
// (if avaliable) has a Print method.
// PRint method in BrDataObject.
// Print method in BrDataTable
// Print method in BrEvent
// Print method in BrEventNode
//
// Revision 1.24 2000/10/03 19:29:59 cholm
// Made IsFolder() const (since it is in TObject) which was needed for the
// objects to be browsable. Aslo, as of ROOT version 2.25.02 there's a list
// of special objects, which BrEventIO now is added to. Some doc to
// BrEventNode::Clear() added! Added method BrEventNode::SetOwner().
// Christian Holm
//
// Revision 1.23 2000/09/19 11:34:17 cholm
// Since TObject::IndentLevel() is moved to TROOT::IndentLevel(), and similar
// for TObject::IncreaseDirLevel(), and TObject::DecreaseDirLevel() as of
// ROOT 2.25.03, I've made these corrections, conditional on the ROOT version
// of course.
//
// Revision 1.22 2000/06/15 14:17:04 alv
// Made more of the Get-methods const member functions
//
// Revision 1.21 2000/06/03 18:20:48 videbaek
// Maded BrEbentIO derice from BrModule and related changes.
//
// Revision 1.20 2000/05/18 20:25:40 videbaek
// Removed flawed usage of Brdataobject->GetEntries() in listobjects.
//
// Revision 1.19 2000/05/17 10:36:23 ouerdane
// see top of file
//
// Revision 1.18 2000/04/13 00:02:29 cholm
// Added methods for browsing BrEvents, either directly or via
// a BrEventIO. Also added method GetROOTFile to BrEventIO.
//
// Revision 1.17 2000/01/07 01:29:44 videbaek
// Added RemoveDataObject.1
//
// Revision 1.16 2000/01/06 16:03:03 videbaek
// Added method RemoveDataObject(object)
//
// Revision 1.15 1999/12/30 19:43:09 videbaek
// imple cleanup of code
//
// Revision 1.14 1999/09/13 21:06:51 videbaek
// Modify constructor to deal properly with Title param
//
// Revision 1.13 1999/06/01 20:38:31 hagel
// Added GetEventNode(...)
//
// Revision 1.12 1999/05/12 16:22:21 hagel
// Implemented + , =+ and = operators for BrEventNode. These will be useful
// for adding events together. Has been tested for single pion events and seems
// to work. In the course of implementing this, several conflicts with const were
// identified. These were cleaned up by adding appropriate const's where needed.
// It was checked that it did not break other things.
//
// Revision 1.11 1999/03/07 00:00:42 hagel
//
// Revision 1.10 1998/08/27 21:31:39 hagel
// Change Copy to copy from this to object
//
// Revision 1.9 1998/08/20 14:28:18 hagel
// Add Copy method + cleanup
//
// Revision 1.8 1998/08/14 21:26:25 videbaek
// Some cleanup mods
//
// Revision 1.7 1998/08/05 15:40:29 hagel
// Add Clear to BrEventNode
//
// Revision 1.6 1998/07/03 16:01:53 hagel
// Clean up g++ warnings
//
// Revision 1.5 1998/04/30 17:12:18 videbaek
// Added functionality to BrIOModule
//
// Revision 1.3 1998/03/09 20:53:50 videbaek
// Ensure that pointers are non-NULL before deleting
//
// Revision 1.2 1998/03/06 22:09:59 videbaek
// Working update
//
// Revision 1.1.1.1 1998/03/04 21:32:48 brahmlib
// Brat base
|