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
// 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