PHOOL FRAMEWORK


The goal of this page is just to give an idea of the functions of the basic PHOOL instructions that appear in the CAMERA macros.

* The PHOOL framework consists basically in a directory ("node") structure and a set of operations to deal with the objects contained in it.
* One uses PHOOL directory structure and I/O methods to access, handle and process the data of the PRDF and DST PHENIX files.
* Those are the types of nodes implemented in PHOOL:
 
PHNode  An abstract base class for all node classes
PHCompositeNode A node which can hold other nodes
PHDataNode<T> A node which can hold a data object (template).
Methods: getData() or setData()
PHIODataNode A data node which can hold persistent data
PHRawDataNode A node digested by the PHRawOManager

* Initialization:

// Upload PHOOL library
   gSystem->Load("libphool.so");

* Example in PRDF -> DST analysis:

// Setting up the node tree
   PHCompositeNode* topNode = new PHCompositeNode("TOP");
   PHCompositeNode* parNode = new PHCompositeNode("PAR");
   topNode->addNode(parNode);
   PHCompositeNode* emcNode = new PHCompositeNode("EMC");
   topNode->addNode(emcNode);

// "DST" is the output composite node wich will be written on disk
   PHCompositeNode* dstNode = new PHCompositeNode("DST");
   topNode->addNode(dstNode);

* In CINT:

[] topNode->print();
TOP (PHCompositeNode)/
   EMC (PHCompositeNode)/
   DST (PHCompositeNode)/

* Example in DST -> HISTOS analysis:

// Setting up the node tree
   PHCompositeNode* topNode = new PHCompositeNode("TOP");
   PHCompositeNode* dstNode = new PHCompositeNode("DST");
   topNode->addNode(dstNode);

* Any valid node tree must have a composite topNode.
* The topNode is the top level of the directory structure that will (temporarily) contain the data read from the PRDF or from the DST.
* The data nodes can contain various types of data. Usually, they store subsystem tables. Each table is stored in a separate node.

* Those are the classes that handle with nodes:
 
PHNodeIterator.h An iterator to navigate a node tree
PHNodeReset.h  An strategy which calls reset() on a PHNode
PHNodeOperation.h An abstract strategy base class which operates on PHNodes
PHDataNodeIterator.h  A special PHOOL node iterator that simplifies finding and adding data nodes
PHIOManager.h  An abstract base class for file IO
PHNodeIOManager.h A class that manages file IO for PHIODataNodes
PHRawDataNode.h  A node digested by the PHRawOManager
PHRawOManager.h A class that writes a node-tree into a PRDF file

* The PHNodeIterator permits to move around within the directory structure and to find nodes of a specific name and type (containing e.g. data objects).
* The PHNodeReset object will be used to reset (empty) the structure at the end of an event.

* Typical examples of application of such classes are found in :

  1. PRDF -> DST Analysis   : Usually done with camDataIni.C   + camDataPar.C + camDataRun.C
  2. DST  -> HISTOS Analysis: Usually done with camDataCheck.C + emcCheckBook.C or with pdst



(1) PRDF -> DST Analysis

// Making a node iterator to navigate the topNode
   PHNodeIterator mainIter(topNode);
   PHNodeReset reset;

// Setting up the input PRDF file (this is handled by libEvent.so)
   Event *thisEvent = 0;
   mainIter.addNode(new PHDataNode<Event>(thisEvent,"PRDF"));

// Declaration of the Eventiterator that will permit to navigate the PRDF file
   Eventiterator *eventIter = new fileEventiterator("rawData.prdf");

* We attach to the topNode directory the new Event as a DataNode structure.

// Setting up the DST output file in which the dstNode structure will be written
   PHNodeIOManager *dstOut = new PHNodeIOManager("dstData.root",PHWrite);

// Setting up and reading the parameter input file
   PHNodeIOManager *parIn = new PHNodeIOManager("para.root",PHReadOnly);
   parIn->read(parNode);

* The I/O node manager permits to access (write, read) persistent data on disk

// Initializing the data-processing modules (those here need e.g. libemc.so)
   mEmcGeomModule* mEmcGeom = new mEmcGeomModule;
   mEmcCalibTowerModule* mEmcCalibTower = new mEmcCalibTowerModule;
   mEmcClusterNewModule* mEmcClusterNew = new mEmcClusterNewModule(mEmcGeometry);

// Finding a Table of parameters under the topNode and getting their data (we need here libWrappers.so)
   PHIODataNode<PHTable>* dEmcGeaParamsNode = (PHIODataNode<PHTable>*)mainIter->findFirst("PHIODataNode","dEmcGeaParams");
   dEmcGeaParamsWrapper* dEmcGeaParams = (dEmcGeaParamsWrapper*)dEmcGeaParamsNode->getData();

// Initializing a wrapped STAF-table and adding it to the "parNode"
   size_t mr=1;
   dEmcRecoParWrapper* dEmcRecoPar = new dEmcRecoParWrapper("dEmcRecoPar",mr);
   PHIODataNode<PHTable>* dEmcRecoParNode = new PHIODataNode<PHTable>(dEmcRecoPar,"dEmcRecoPar");
   parNode->addNode(dEmcRecoParNode);

// Initializing a wrapped STAF-table and adding it to the "emcNode"
   size_t mr=15000;
   dEmcRawDataWrapper* dEmcRawData = new dEmcRawDataWrapper("dEmcRawData",mr);
   PHIODataNode<PHTable>* dEmcRawDataNode = new PHIODataNode<PHTable>(dEmcRawData,"dEmcRawData");
   emcNode->addNode(dEmcRawDataNode);

// Initializing a wrapped STAF-table and adding it to the dstNode
   size_t mr=10000;
   dEmcCalibTowerWrapper* dEmcCalibTower = new dEmcCalibTowerWrapper("dEmcCalibTower",mr);
   PHIODataNode<PHTable>* dEmcCalibTowerNode = new PHIODataNode<PHTable>(dEmcCalibTower,"dEmcCalibTower");
   dstNode->addNode(dEmcCalibTowerNode);

* Since table dEmcCalibTowerNode is under the node dstNode, it will be written on disk.

// End of camDataIni.C
// Starting with camDataRun.C

// Entering the event loop
   while ((thisEvent = eventIter->getNextEvent()) && eventNumber++ < maxEvents && checkFlag == 1)  {
   mainIter.cd();
   ((PHDataNode<Event>*)(mainIter.findFirst("PHDataNode","PRDF")))->setData(thisEvent);

* The read method of the I/O manager eventIter will retrieve (a pointer to) the next Event object (or 0 if there is no event left) from the PRDF file.
* We (temporarily) attach the new event data of the Data Node "PRDF" under the topNode

// Calling first-event-only data-processing modules
   if (eventNumber == 1) { mEmcDefGeom->event(topNode); }

// Calling the subsystem modules to process the data ...
   mEmcCalibrator->event(topNode);
   mEmcClusterNew->event(topNode);


* The module mEmcCalibratorModule::event(PHCompositeNode *root) does things like this:

  PHNodeIterator Iter(root);
  PHDataNodeIterator DNiter(root);

// Getting Raw Data from the PRDF Node
  PHDataNode<Event> * thisEventNode = (PHDataNode<Event>*) (Iter.findFirst("PHDataNode","PRDF")) ;

// Setting up dEmcCalibTower and filling it
  PHIODataNode<PHTable>* dEmcCalibTowerNode = (PHIODataNode<PHTable>*)Iter.findFirst("PHIODataNode","dEmcCalibTower");
  dEmcCalibTowerWrapper* dEmcCalibTower = static_cast<dEmcCalibTowerWrapper*>(dEmcCalibTowerNode->getData());

// Processing event ...


// Writing the dstNode structure into the DST root file
   dstOut->write(dstNode);

* The PHNodeIOManager object dstOut  writes the directory structure (starting at dstNode) into the DST file

// Reseting all data tables for this event before reading the next one
   mainIter.cd();
   if (mainIter.cd("DST")) { mainIter.forEach(reset); mainIter.cd(); }
   if (mainIter.cd("EMC")) { mainIter.forEach(reset); mainIter.cd(); }

} // end event loop

// Delete the PHNodeIOManager
   delete dstOut;
   delete parIn;

(Mind that it is really important to delete the PHNodeIOManager object dstOut  otherwise the output DST file is not properly closed ! )


(2) DST  -> HISTOS Analysis:

// Making a node iterator to navigate the "topNode"
   PHNodeIterator mainIter(topNode);
   PHNodeReset reset;

// Setting up the DST input file
   PHNodeIOManager *dstIn = new PHNodeIOManager("dstData.root",PHReadOnly);
   dstIn->read(dstNode);

* This first "read" creates the node structure in memory from the node structure existing on the input file on disk.

// Initialize the tables contained in the DST
   PHIODataNode<PHTable>* dEmcCalibTowerNode   = (PHIODataNode<PHTable>*)mainIter->findFirst("PHIODataNode","dEmcCalibTower");
   PHIODataNode<PHTable>* dEmcClusterLocalNode = (PHIODataNode<PHTable>*)mainIter->findFirst("PHIODataNode","dEmcClusterLocal");

// Initialize the PHOOL Histogram Factory (needslibPhHistogramFactory.so) and get a pointer to it
   PhRootHistogramFactory::buildFactory();
   PhHistogramFactory *hf= PhHistogramFactory::instance();

// Book the DST subsystem histograms
   gROOT->Macro("emcCheckBook.C");

// Starting the event loop
  eventNumber = 1;
  while (eventNumber <= maxEvents) {
    if (eventNumber > 1) dstIn->read(dstNode);

// Grab the data nodes
   dEmcCalibTowerWrapper* dEmcCalibTower = (dEmcCalibTowerWrapper*)dEmcCalibTowerNode->getData();
   dEmcClusterLocalWrapper* dEmcClusterLocal = (dEmcClusterLocalWrapper*)dEmcClusterLocalNode->getData();

* To see in CINT the structure of a wrapped table, type: .class [STAF Table Name]Wrapper

[] .class dEmcCalibTowerWrapper

Within the class listing, we see the "get_" methods for that variable:

(compiled)        0:0    0 public: CORBA_float get_tof(size_t n) const;
(compiled)        0:0    0 public: CORBA_float get_ecal(size_t n) const;

(n is the row number) so one can fill the histogram with the data starting from the row "0" of the table.

// Fill the DST EMC histograms
   nemcclus = (Int_t) dEmcClusterLocal->RowCount();
   emchist1->Fill((Float_t) nemcclus);
   iemc = 0;
   while (iemc < nemcclus) {
      emchist3->Fill((Float_t) dEmcClusterLocal->get_ecal(iemc));
      emchist4->Fill((Float_t) dEmcClusterLocal->get_tof(iemc));
      iemc++;
    }

// Next event
   eventNumber++;

// end event loop
}

// Write Histograms on disk
   hf->Save("histos.root");

Back to my homepage at PHENIX


enterria@in2p3.fr, denterri@bnl.gov

Last modified: Tue Nov 8 19:50:16 EDT 2000