BRAT 2.4.5
Class index
Full class index
brahmlib
BRAHMS
ROOT page
//____________________________________________________________________
// 
// BRAHMS Output Tree Module
//
// The idea for creating this class was the use of BrTrackTree to create
// a usefull output tree. As opposed to BrTrackTree this module does not have 
// limitations on the kinds of objects included in the tree. One can add all
// the kinds of objects that one usually finds in an output BrEvent. After an 
// analysis session one can use the output tree for easy plotting of distributions 
// and correlations, e.g. using the TTreeViewer.
//
// Usage, assuming instance 'mainModule' of BrMainModule is created:
//
//   BrOutputTreeModule* otm = new BrOutputTreeModule("OTM", "Output Tree Module");
//   otm->SetIOMode(BrIOModule::kBrJobFile | BrIOModule::kBrRecreateFile);
//   otm->AddFile("mytree.root");
//   otm->AddElement("BrBbVertex", "BB Vertex");
//   otm->AddElement("BrFFSTrack", "FFSTrack", kTRUE);
//   ...<Adding other elements>...
//   mainModule->AddModule(otm);
//
// The module distinguishes between two kinds of elements added to it. If the 
// element does not represent objects in a BrDataTable in the output BrEvent, 
// a branch for the class given as the first argument in AddElement() is created. 
//
// It the element represents objects found in BrDataTables, e.g. the case for 
// BrFFSTrack above, a TClonesArray for these objects is instantiated and a branch for
// the array is created. This behavior requires the third argument of AddElement()to 
// be true. For each event the instance of TClonesArray is filled with objects from its
// corresponding BrDataTable and the tree is filled.
//
// To allow the user to create several instances of this class, the name of the tree 
// includes a number. Thus the first instance of this class creates a tree named 'T1', 
// the second instance creates a tree named 'T2' and so on.
//
// Since a branch name in a TTree can not contain blanks, eventual blanks in the 
// name of objects (second argument in AddElement()) is substituted with underscores. 
// Thus the element named 'BB Vertex' above will show up in the tree as 'BB_Vertex'.
// 
// Note optional arguments in AddElement() for buffer size and split level. Also note 
// the possiblity to set the auto save parameter for the tree using SetAutoSave().
// Look for more information obout these parameters in the TTree class descrition and 
// and in the ROOT User Guide.

//____________________________________________________________________
//
// $Id: BrOutputTreeModule.cxx,v 1.6 2002/08/15 17:21:35 videbaek Exp $
// $Author: videbaek $
// $Date: 2002/08/15 17:21:35 $
// $Copyright: (C) 2001 BRAHMS Collaboration <brahmlib@rhic.bnl.gov>
//
#ifndef BRAT_BrOutputTreeModule
#include "BrOutputTreeModule.h"
#endif
#ifndef WIN32
#include <iostream>
#include <iomanip>
#else
#include <iostream.h>
#include <iomanip.h>
#endif
#ifndef ROOT_TMethodCall
#include "TMethodCall.h"
#endif
#ifndef ROOT_TROOT
#include "TROOT.h"
#endif

//____________________________________________________________________
ClassImp(BrOutputTreeElement);

//____________________________________________________________________
 BrOutputTreeElement::BrOutputTreeElement(const Char_t* className, 
					 const Char_t* name,
					 const Char_t* branchName,
					 Bool_t isTable, Int_t arrSize,
					 Int_t bufSize, Int_t splitLevel)
  : fClassName(className), fName(name), fBranchName(branchName), fIsTable(isTable)
{
  // Named Constructor
  // If element is data table (isTable == kTRUE), 
  // the name of the table is <name>
  // Otherwise the name of the object is <name>.

  // If data table create an instance of TClonesArray
  // Else set pointer to NULL. If not table no object will be instantiated 
  // and assigned to fStore for this element.
  if (fIsTable)
    // Comment by cholm:  This is dangerous if the class classname can
    // have variable size! 
    fStore = new TClonesArray(className, arrSize);
  else 
    fStore = NULL; 
  
  fBufSize = bufSize;
  fSplitLevel = splitLevel;
  if (fSplitLevel) fBufSize /= 4;
}

//____________________________________________________________________
 BrOutputTreeElement::~BrOutputTreeElement()
{
  // Destructor. Only if this element refers to a data table, and thus an
  // instance of TClonesArray is allocated, this object will be deleted.

  if (fIsTable) delete fStore;
}

//____________________________________________________________________
 void BrOutputTreeElement::Branch(TTree* t)
{
  // Create branch in tree t for this element.

  // Abort if there is no tree
  if (!t) {
    cerr << "<BrOutputTreeElement::Branch>: There is no output tree" << endl;
    return;
  }

  // Replace eventual blanks in branch name with underscores. TTree truncates
  // blanks.
  TString name(fBranchName);
  Ssiz_t pos;
  while ((pos = name.First(" ")) != -1) name.Replace(pos, 1, "_");

  // If data table create a TClonesArray branch
  if (fIsTable)
    fBranch = t->Bronch(name, "TClonesArray", &fStore, fBufSize, fSplitLevel);

  // Otherwise create a branch for the object.
  else {
    // Add . (dot) to name to make subbranches be named according to 
    //<master branch name>.<subbranch name>
    name += ".";

    // Create dummy.
    TMethodCall* call = new TMethodCall(gROOT->GetClass(fClassName), fClassName, ""); 
    Long_t addr;
    call->Execute((void*)0, addr);
    delete call;
    fStore = (TObject*)addr;

    // Branch the tree.
    fBranch = t->Bronch(name, fClassName, &fStore, fBufSize, fSplitLevel);

    // Delete dummy.
    delete fStore;
  }
}

//____________________________________________________________________
 void BrOutputTreeElement::Event(BrEventNode* event)
{
  // Event function. This function is called once per element per
  // event.  If data table the table with name fName is searched for
  // in the event. If found the TClonesArray is filled. Otherwise the
  // data object with name fName is searched for in the event. If
  // found its address is assigned to fStore and the address of the
  // branch is updated.

  // Return if no event
  if (!event) return;

  // If data table, get table and put tracks into the clones array
  if (fIsTable) {
    // Clear the array
    TClonesArray *arr = (TClonesArray*) fStore;
    arr->Clear();

    // Get data table from event
    BrDataTable *table = event->GetDataTable(fName);
    if (!table || !table->GetEntries()) return;

    // Add entries to clones array
    Int_t nEntries = table->GetEntries();
    const Char_t* cn = fClassName.Data();
    Char_t com[512];
    for (Int_t iE = 0; iE < nEntries; iE++) {

      // Perform the following commands for each entry, e.g. for
      // BrTpcTrackCandidate: 
      // gROOT->Reset(); 
      // BrTpcTrackCandidate* obj
      //  = (BrTpcTrackCandidate*)((BrDataTable*)<tableaddress>)->At(iE); 
      // TClonesArray* arrRef =
      //    *((TClonesArray*)<arr address>); new(arrRef[iE])
      // BrTpcTrackCandidate(*obj);

#ifdef INTERPETER
       sprintf(com, 
	      "gROOT->Reset();"
	      "%s* dataTable = (%s*)((BrDataTable*)0x%lx)->At(%d);"
	      "TClonesArray& arrRef = *((TClonesArray*)0x%lx);"
	      "new(arrRef[%d]) %s(*dataTable);", 
	      cn, cn, (Long_t)table, iE,  // arguments of first line
	      (Long_t)arr,                // arguments of second line
	      iE, cn);                    // arguments of third line
       gROOT->ProcessLine(com);
#else
       // Comment by cholm:  You can get a similar effect without
       // using the interpretor (the gROOT->Reset() is a bit dangerous
       // here  btw.) by using a TBuffer and the class streamers: 
       // Fv 8/14/02: I tried to mplement this because creating rawdata
       // digitizaed object is horendously slow with the interpreter method
       // but it seems to fail. Any clues?
       // YES after resetting the buffer when switching mode it is all ok.
       // Since the intepreter is not use it is about afactor 100 faster!
       //
       
       TClass* cl = gROOT->GetClass(fClassName); 
       TObject*o  = arr->New(iE);
       TBuffer b(TBuffer::kWrite);
       TObject * obj = table->At(iE);
       obj->Streamer(b);
       b.SetReadMode();
       b.SetBufferOffset();
       o->Streamer(b);
#endif
    }
  }

  // If not data table, get data object and update address in the branch
  else {
    // Clear fStore. No object created on the heap, and thus no need for deleting.
    fStore = NULL;

    // Get data object.
    fStore = event->GetObject(fName);
    if (!fStore) return;

    // Update the branch address.
    fBranch->SetAddress(&fStore);
  }
}

//____________________________________________________________________
 void BrOutputTreeElement::Print()
{
  // Print the parameters of this element to stdout.
  
  cout << "| " << setw(28) << fClassName
       << " | " << setw(23) << fName
       << " | " << setw(9) << (fIsTable ? "table" : "") 
       << " |" << endl;
}

//____________________________________________________________________
ClassImp(BrOutputTreeModule);

//____________________________________________________________________
BrOutputTreeModule::BrOutputTreeModule()
{
  // Default constructor. DO NOT USE
  SetState(kSetup);

  Setup();
}

//____________________________________________________________________
BrOutputTreeModule::BrOutputTreeModule(const Char_t* name, const Char_t* title)
: BrIOModule(name, title)
{
  // Named Constructor
  SetState(kSetup);

  Setup();
}

//____________________________________________________________________
BrOutputTreeModule::~BrOutputTreeModule()
{
  // Destructor

  // Delete elements in array and array itself. Elements are deleted automatically
  // as the array is owner.
  delete fElements;

  // Delete tree.
  delete fTree;

  // Close file if still open and delete it.
  if (fFile->IsOpen()) fFile->Close();
  delete fFile;
}

//____________________________________________________________________
void BrOutputTreeModule::AddElement(const Char_t* className, 
				    const Char_t* name,
				    const Char_t* branchName,
				    Bool_t isTable, Int_t arrSize,
				    Int_t bufSize, Int_t splitLevel)
{
  // Add element to be included in tree.

  // Create array of elements. Make array owner of its elements so that the elements
  // are deleted when the array is deleted.
  if (!fElements) {
    fElements = new TObjArray;
    fElements->SetOwner();
  }

  // Create element and add to list of elements
  BrOutputTreeElement *el = 
    new BrOutputTreeElement(className, name, branchName,
			    isTable, arrSize, bufSize, splitLevel);
  fElements->Add(el);
}

//____________________________________________________________________
void BrOutputTreeModule::AddElement(const Char_t* className, 
				    const Char_t* name,
				    Bool_t isTable, Int_t arrSize,
				    Int_t bufSize, Int_t splitLevel)
{
  // Add element to be included in tree.
  AddElement(className, name, name, isTable, 
	     arrSize, bufSize, splitLevel);
}

//____________________________________________________________________
Bool_t BrOutputTreeModule::Close()
{
  // Close the file Opened by the object. Return 
  // kFALSE if no file was open.

  // Return kFALSE if no instance of TFile has been created.
  if (!fFile) {
    Failure("Close", "no file opened");
    return kFALSE;
  }
  
  // Return kFALSE if file was not opened.
  if(!fFile->IsOpen()) {
    Failure("Close", "file not opened");
    return kFALSE;
  }
    
  fFile->Write();
  fFile->Flush();
  fFile->Close();

  delete fFile;
  fFile = NULL;
    
  return kTRUE;
}

//____________________________________________________________________
void BrOutputTreeModule::Event(BrEvent* event)
{
  // Per event method.

  Info(10 ,"Event", " Start of Event");

  SetState(kEvent);

  // Save current gDirectory and make the file the current directory.
  TDirectory *saveDir = gDirectory;
  fFile->cd();
    
  // Check if any of the entries in event is an event node. In that case do a
  // nested call of this Event function.
  TIter nextObj(event->GetObjectList());
  BrDataObject *dObj;
  while ((dObj = (BrDataObject*)nextObj()))
    if (dObj->InheritsFrom("BrEventNode")) Event((BrEvent*)dObj);

  // Call the event function for all elements.
  TIter nextEl(fElements);
  BrOutputTreeElement *el;
  while ((el = (BrOutputTreeElement*)nextEl()))
    el->Event(event);

  // Fill the tree
  fNumBytesWritten += fTree->Fill();

  // Return to saved directory
  gDirectory = saveDir;
  gDirectory->cd();

  Info(10 ,"Event", "End of Event");
}

//____________________________________________________________________
Bool_t BrOutputTreeModule::Open(const Char_t* fname, const Option_t* option)
{
  // Open ROOT file. If no options is specified, open in RECREATE mode.

  if (!strcasecmp(option, "read")) {
    Failure("Open", "Cowardly refusing to read histogram files");
    return kFALSE;
  }
 
  // Check to see if the a file already exists and is open.
  if (fFile)
    if (fFile->IsOpen()) {
      Stop("Open","File %s is already opened, " 
	   "please close before trying to open", fname);
      return kFALSE;
    }
  
  // Save directory we were in before coming here.
  TDirectory *saveDir = gDirectory; 
  
  // Save file name.
  fFileName = fname;

  // Get option to open file with.
  TString fileOption;
  if (!option) 
    fileOption = "RECREATE";
  else 
    fileOption = option;		
  
  if(DebugLevel() > 3) 
    cout << "File option is " << fileOption.Data() << endl;
  
  // Create instance of TFile.
  if(!fileOption.CompareTo("RECREATE",TString::kIgnoreCase))
    fFile = new TFile(fFileName,"RECREATE",fFileName,1);

  // Check if instance TFile was created.
  if (!fFile) {
    Failure("Open", "could not open file %s", fFileName.Data()); 
    gDirectory = saveDir;
    gDirectory->cd();
    delete fFile;
    fFile = NULL;
    return kFALSE;
  }

  // Check if file was opened.
  if (!fFile->IsOpen()) {
    Failure("Open", "could definitely not open file %s", fFileName.Data()); 
    gDirectory = saveDir;
    gDirectory->cd();
    delete fFile;
    fFile = NULL;
    return kFALSE;
  }
    
  // Go to the file - which we should be in anyway. 
  fFile->cd();
  
  // Show contents of the toplevel directory .
  if (DebugLevel() > 3)
    fFile->ls();

  // Set the BrIOModule status variables .
  fIOStatus = 1;
  fEof = kFALSE;
  fError = kFALSE;
  fNumBytesWritten = 0;
  fNumBytesRead = 0;
  SetStatus(kOk);

  // Create tree.
  static Int_t treeNum = 1;
  fTree = new TTree(Form("T%d", treeNum++), "BRAHMS Output Tree");
  fTree->SetAutoSave(GetAutoSave()); 

  // Branch the elements.
  TIter next(fElements);
  BrOutputTreeElement *el = NULL;
  while ((el = (BrOutputTreeElement*)next()))
    el->Branch(fTree);
  
  // Go back to old gDirectory.
  gDirectory = saveDir;
  gDirectory->cd();

  return kTRUE;
}

//____________________________________________________________________
void BrOutputTreeModule::Print(Option_t* option) const
{
  // Print module information
  // See BrModule::Print for options.
  // In addition this module defines the Option:
  // <fill in here>

  TString opt(option);
  opt.ToLower(); 
  
  BrIOModule::Print(option); 
  if (opt.Contains("d")) 
   cout << endl 
         << "  Original author: Jens Ivar Jordre" << endl
         << "  Last Modifications: " << endl 
         << "    $Author: videbaek $" << endl  
         << "    $Date: 2002/08/15 17:21:35 $"   << endl 
         << "    $Revision: 1.6 $ " << endl  
         << endl 
         << "-------------------------------------------------" << endl;

  // Return if no elements.
  if (opt.Contains("l") && fElements && fElements->GetEntries()) {
    cout << "+--------------------------------------------------------------------+" << endl
	 << "| BrOutputTreeModule:" 
	 << setw(18) << GetName()
	 << " "
	 << setw(30) << GetTitle() 
	 << "|" << endl
	 << "+--------------------------------------------------------------------+" << endl;
    
    
    // Call the Print function of all elements.
    TIter next(fElements);
    BrOutputTreeElement *el;
    Int_t ind = 0;
    while ((el = (BrOutputTreeElement*)next()))
      el->Print();
    cout << "+--------------------------------------------------------------------+" << endl;
  }
}

//____________________________________________________________________
void BrOutputTreeModule::SetAutoSave(Int_t autos)
{
  // Set tree autosave parameter.

  fAutoSave = autos;
  if (fTree) fTree->SetAutoSave(autos);
}

//____________________________________________________________________
void BrOutputTreeModule::Setup()
{
  // Setup default parameters.

  fFile = NULL;
  fTree = NULL;
  fAutoSave = 10000000;
  fElements = NULL;
}


//____________________________________________________________________
//
// $Log: BrOutputTreeModule.cxx,v $
// Revision 1.6  2002/08/15 17:21:35  videbaek
// Improved dramatically execution time by getting rid of interpreter and
// instead using compiled code.
//
// Revision 1.5  2001/12/14 15:37:50  cholm
// Modified the classes to allow the concept of file set, introduced via
// BrIOModule. Also use new Info method rather than explicit
//   if (Verbose() > 4)
//      cout << "Opening file ladida" << endl;
//
// Revision 1.4  2001/11/21 12:57:07  pchristi
// Added the oppertunity to set the branchname instead of having classname as branchname.
//
// Revision 1.3  2001/10/20 20:40:21  jens
// Some forgotten fixes.
//
// Revision 1.2  2001/10/20 20:37:01  jens
// Small fixes in the description
//
// Revision 1.1  2001/10/20 03:44:44  jens
// New class BrOutputTreeModule
//
//

This page automatically generated by script docBrat by Christian Holm

Copyright ; 2002 BRAHMS Collaboration <brahmlib@rcf.rhic.bnl.gov>
Last Update on by

Validate HTML
Validate CSS