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++")
Вот что Вы должны увидеть на Ваших экранах: