PROOF - Tree Example

Рассмотрим пример, в котором информация считывается с четырех веток дерева, вычисляются две дополнительные величины, заполняются гистограммы, и одна из них фитируется. Сначала приведем код, в котором эта задача решается без PROOF.

Предварительный макрос, в котором генерируются четыре случайные величины, и заполняется дерево:

void write_chain6 (std::string outputFileName ="myTree.root",unsigned int numDataPoints = 10000) {
TTree myTree ("myTree","Example Tree");
float px,py,value,temp,pres;
myTree.Branch("px",&px,"px/F");
myTree.Branch("py",&py,"py/F");
myTree.Branch("Temperature",&temp,"Temperature/F");
myTree.Branch("Pressure",&pres,"Pressure/F");

for ( int i=0;i< numDataPoints;++i) {
 px=gRandom->Gaus(1.,2.);
 py=gRandom->Gaus(4.,2.);
 temp=gRandom->Uniform (250.,350.)+gRandom->Gaus(0.,0.3) ;
 pres=gRandom->Uniform (0.5,1.5) *gRandom->Gaus(1.,0.02) ;
 myTree.Fill();
}

TFile ofile (outputFileName.c_str( ),"RECREATE") ;
myTree.Write();
ofile.Close();
}
			

Макрос для считывания дерева (не параллельный вариант):

#include "TFile.h"
#include "TNtuple.h"
#include < iostream >
#include "TTree.h"
#include "TChain.h"
void read_from_tree(){
TFile* f=new TFile("myTree.root");
TTree* treeData=(TTree*)f->Get("myTree");

float px,py,pt,temp,pres,value;
treeData->SetBranchAddress("px",&px);
treeData->SetBranchAddress("py",&py);
treeData->SetBranchAddress("Temperature",&temp);
treeData->SetBranchAddress("Pressure",&pres);

TH1F* h_px=new TH1F("px","px dixtribution",100,-6,14);
TH1F* h_py=new TH1F("py","py distribution",100,-6,14);
TH1F* h_pt=new TH1F("pt","Pt",100,-2,18);
TH1F* h_value=new TH1F("value","value",100,0.,2.5);
TH1F* h_temp=new TH1F("temp","temperature",100,200.,400.);
TH1F* h_pres=new TH1F("pres","pressure",100,-0.,2.);

Int_t nentries=(Int_t)treeData->GetEntries();
for(Int_t i=0;i < nentries;i++){
treeData->GetEntry(i);
h_px->Fill(py);
h_py->Fill(py);
pt=sqrt(px*px+py*py);
h_pt->Fill(pt);
h_temp->Fill(temp);
h_pres->Fill(pres);
value=pt/(10.*0.05*(temp-300.)-0.2*(pres-1.));
h_value->Fill(value);
}
TCanvas* c=new TCanvas("c","title",20,20,1200,600);
c->Divide(3,2);
c->cd(1);
h_px->Draw(); 
c->cd(2);
h_py->Draw();
c->cd(3);   
h_pt->Draw();
c->cd(4);
h_temp->Draw();   
c->cd(5);
h_pres->Draw();
c->cd(6);
h_value->Draw();
h_value->Fit("landau");
}

Теперь перейдем к параллельному способу считывания дерева. В классе TTree реализован метод MakeSelector(), который создает два файла Selector.h и SelectorTree.c, так называемый "скелетный" класс или шаблон, в который необходимо добавить . В представленных ниже файлах черным цветом показаны инструкции, сгенерированные автоматически методом MakeSelector().

#ifndef SelectorTree_h
#define SelectorTree_h

#include < TROOT.h >
#include < TChain.h >
#include < TFile.h >
#include < TSelector.h >
class SelectorTree : public TSelector {
public :
   TTree          *fChain;   //указатель на анализируемое дерево  TTree или цепочку TChain

   // Объявление типов листьев
   Float_t         px;
   Float_t         py;
   
Float_t pt; Float_t value;
Float_t Temperature; Float_t Pressure; // Список ветвей TBranch *b_px; TBranch *b_py; TBranch *b_Temperature; //! TBranch *b_Pressure; //! SelectorTree(TTree * /*tree*/ =0) : fChain(0) { } virtual ~SelectorTree() { } virtual Int_t Version() const { return 2; } virtual void Begin(TTree *tree); virtual void SlaveBegin(TTree *tree); virtual void Init(TTree *tree); virtual Bool_t Notify(); virtual Bool_t Process(Long64_t entry); virtual Int_t GetEntry(Long64_t entry, Int_t getall = 0) { return fChain ? fChain->GetTree()->GetEntry(entry, getall) : 0; } virtual void SetOption(const char *option) { fOption = option; } virtual void SetObject(TObject *obj) { fObject = obj; } virtual void SetInputList(TList *input) { fInput = input; } virtual TList *GetOutputList() const { return fOutput; } virtual void SlaveTerminate(); virtual void Terminate(); ClassDef(SelectorTree,1); }; #endif #ifdef SelectorTree_cxx void SelectorTree::Init(TTree *tree) { // Функция Init() вызывается, когда селектор должен инициализировать новое // дерево или цепочку. Обычно здесь устанавливаются адреса ветвей т указатели на них // Обычно нет необходимости вносить изменения в сгенерированный код, // но при необходимости программа может быть расширена пользователем. // Init() будет вызываться много раз при работе PROOF // (один раз для каждого обрабатываемого файла). // Установка адресов ветвей и указателей на ветви if (!tree) return; fChain = tree; fChain->SetMakeClass(1); fChain->SetBranchAddress("px",&px, &b_px); fChain->SetBranchAddress("py",&py,&b_py); fChain->SetBranchAddress("Temperature", &Temperature, &b_Temperature); fChain->SetBranchAddress("Pressure", &Pressure, &b_Pressure); } Bool_t SelectorTree::Notify() { // Функция Notify() вызывается при открытии нового файла. Это    // может происходить либо для нового TTree в TChain, либо когда новый TTree    // запускается при использовании PROOF. Обычно нет необходимости вносить изменения    // в сгенерированный код, но при необходимости процедура может быть расширена с помощью    // пользователя . Возвращаемое значение в настоящее время не используется. return kTRUE; } #endif // #ifdef SelectorTree_cxx
#define SelectorTree_cxx
// Следующие методы определены в этом файле:
//    Begin():        вызывается каждый раз, когда начинается цикл на дереве,
//                    удобное место для создания ваших гистограмм.
//    SlaveBegin():   вызывается после Begin(), когда PROOF вызывается только на
//                    вспомогательном сервере.
//    Process():      вызывается для каждого события, в этой функции вы решаете, 
//                    считывать и чем заполнять ваши гистограммы.
//    SlaveTerminate: вызавается в конце цикла обработки дерева, если PROOF
//                    вызывается только на вспомогательных серверах.
//    Terminate():    вызывается в конце цикла обработки дереваб
//                    удобное место для рисования / фитирования гистограмм.
//
// Чтобы использовать этот файл, попробуйте следующие команды для вашего Tree T:
//
// Root > T->Process("SelectorTree.C")
// Root > T->Process("SelectorTree.C","some options")
// Root > T->Process("SelectorTree.C+")
//

#include "SelectorTree.h"
#include < TH2.h >
#include < TStyle.h >
#include < TCanvas.h >
#include < iostream >
using namespace std;
UInt_t fNumberOfEvents; TDatime tBegin,tNow; TH1F *h_px,*h_py, *h_pt, *h_value,*h_temp,*h_pres;
void SelectorTree::Begin(TTree * /*tree*/) { TString option = GetOption(); tBegin.Set(); printf("*==* ------------- Begin of Job -------------"); tBegin.Print(); } void SelectorTree::SlaveBegin(TTree * /*tree*/) { TString option = GetOption(); h_px=new TH1F("px","px dixtribution",100,-6,14); h_py=new TH1F("py","py distribution",100,-6,14); h_pt=new TH1F("pt","Pt",100,-2,18); h_temp=new TH1F("temp","temperature",100,200.,400.); h_pres=new TH1F("pres","pressure",100,-0.,2.); h_value=new TH1F("value","value",100,0.,2.5); fOutput->AddAll(gDirectory->GetList()); } Bool_t SelectorTree::Process(Long64_t entry) { GetEntry(entry); ++fNumberOfEvents; h_px->Fill(px); h_py->Fill(py); pt=sqrt(px*px+py*py); h_pt->Fill(pt); h_temp->Fill(Temperature); h_pres->Fill(Pressure); value=pt/(10.*0.05*(Temperature-300.)-0.2*(Pressure-1.)); h_value->Fill(value); return kTRUE; } void SelectorTree::SlaveTerminate() { printf("\n *==* --------- End of Slave Job --------"); tNow.Set(); tNow.Print(); printf("Number of Events: %i, elapsed time: %i sec, rate: %g evts/sec\n", fNumberOfEvents, tNow.Convert()-tBegin.Convert(), float(fNumberOfEvents)/(tNow.Convert()-tBegin.Convert())); } void SelectorTree::Terminate() { TFile hfile("MySelector_Result.root","RECREATE","MuonResults"); fOutput->Write(); TCanvas* c=new TCanvas("c","title",20,20,1200,600); c->Divide(3,2); h_px=dynamic_cast<TH1F *>(fOutput->FindObject("px")); c->cd(1); h_px->Draw(); h_py=dynamic_cast<TH1F *>(fOutput->FindObject("py")); c->cd(2); h_py->Draw(); h_pt=dynamic_cast<TH1F *>(fOutput->FindObject("pt")); c->cd(3); h_pt->Draw(); h_temp=dynamic_cast<TH1F *>(fOutput->FindObject("temp")); c->cd(4); h_temp->Draw(); h_pres=dynamic_cast<TH1F *>(fOutput->FindObject("pres")); c->cd(5); h_pres->Draw(); h_value=dynamic_cast<TH1F *>(fOutput->FindObject("value")); c->cd(6); h_value->Draw(); h_value->Fit("landau"); tNow.Set(); printf("*==* -------- End of Job ------- "); tNow.Print(); }

Создаем цепочку

root[0] TChain* ch=new TChain("treeMy","MyTree")

Присоединяем к цепочке root файл

root[1] ch->Add("treeMy.root")

Открываем сеанс PROOF

root[2] TProof* proof=TProof::Open("lite://","workers=12")

Включаем обработку

root[3] ch->SetProof()

Обрабатываем все записи в этой цепочке, вызывая функции в файле SelectorTree.

root[4] ch->Process("SelectorTree.C++")

Вот что Вы должны увидеть на Ваших экранах: