TTree Branch with vector

  • 利用vector可将hit结构描述进一步简化。
  • 以data_16C.root数据为例,内部包含固定数组,动态数组两种数据结构:

fixed array:

Double_t d1x[32],d2x[32],d3x[32];//xe
Double_t d1y[32],d2x[32],d3x[32];//ye
Double_t d1t[32],d2t[32],d3t[32];//xt

dynamic array(hit):

Int_t d1xhit, d2xhit,d3xhit;//hit
Int_t d1yhit, d2yhit,d3yhit;

Int_t    d1xs[d1xhit],d2xs[d2xhit],d3xs[d3xhit];//strip
Double_t d1xe[d1xhit],d2xe[d2xhit],d3xe[d3xhit];//energy

Int_t    d1ys[d1yhit],d2ys[d2yhit],d3ys[d3yhit];
Double_t d1ye[d1yhit],d2ye[d2yhit],d3ye[d3yhit];
  • 可将动态数组结构表达成如下的vector结构

vector:

//vec.h
struct dssd
{
  Int_t id;
  Double_t e;
  Doutle_t t;
};
vector<dssd> x1v,x2v,x3v;
vector<dssd> y1v,y2v,y3v;

1.从不包含vector类型Branch的ROOT文件中生成

  1. 按照2.4节的做法,先利用makeclass生成$*$.C, $*$.h 文件,将相应的文件放到 src和include目录下
  2. 编写main.cpp, makefile, ana.h, ana.cpp 放到相应目录下
  3. 编译运行

./main.cpp

#include <iostream> 
#include <TFile.h>
#include <TTree.h>
#include <TString.h>
#include "ana.h"  //用户代码头文件
using namespace std;

int main(int argc, char** argv)
{

   TString InputPath, OutputPath, infile, outfile;  
    InputPath = "./";
    OutputPath = "./";
    infile.Form("%scal_16C.root", InputPath.Data());
    outfile.Form("%svec_16C.root", OutputPath.Data());
    //input
    TFile *ipf = new TFile(infile);
    if(!ipf->IsOpen()) {
        cout<<"Cannot open input file: "<<infile<<endl;
        return -1;
    }
    TTree *ipt = (TTree*)ipf->Get("tree");

    //output
    TFile *opf = new TFile(outfile,"RECREATE");
    TTree *opt = new TTree("tree","vector branch");

    //
    ana *tk = new ana(ipt,opt); 
    tk->Analysis(); //等价于原Loop函数

    opt->Write();
    //
    ipf->Close();
    opf->Close();
    return 1;       
}

./include/ana.h

#ifndef ana_h
#define ana_h

#include <TRandom3.h>
#include <iostream>
#include "test.h"  //包含基类头文件

using namespace std;

struct dssd
{
  Int_t id;
  Double_t e;
  Double_t t;
};

class ana : public test //从test类中继承其成员变量和成员函数
{
 public:
  vector<dssd> x1v,x2v,x3v;
  vector<dssd> y1v,y2v,y3v;
  TTree *opt;
  TRandom3 *gr;

 ana(TTree* ipt_,TTree *opt_): test(ipt_),opt(opt_) {} 
  virtual ~ana() {};
  virtual void     Analysis();//分析函数,作用等价于原Loop函数
  virtual void     SetOutBranch();
  virtual void     ProcessDS(Double_t ee[32], vector<dssd> &vec);

};
#endif

./src/ana.cpp

#include "ana.h"
using namespace std;
void ana::SetOutBranch()
{
  opt->Branch("x1v",&x1v);
  opt->Branch("x2v",&x2v);
  opt->Branch("x3v",&x3v);
  opt->Branch("y1v",&y1v);
  opt->Branch("y2v",&y2v);
  opt->Branch("y3v",&y3v);
  opt->Branch("sx1e",&sx1e,"sx1e");//normal branch
  opt->Branch("sx2e",&sx2e,"sx2e");
  opt->Branch("sx3e",&sx3e,"sx3e");
  opt->Branch("sy1e",&sy1e,"sy1e");
  opt->Branch("sy2e",&sy2e,"sy2e");
  opt->Branch("sy3e",&sy3e,"sy3e");
}

void ana::ProcessDS(Double_t ee[32], vector<dssd> &vec)
{
   vec.clear();
    dssd ds;
    for(int i=0;i<32;i++) {
      if(ee[i]<1) continue;
    ds.id=i;
    ds.e=ee[i];
    vec.push_back(ds);
    }
}
void ana::Analysis()
{
  SetOutBranch();
  if (fChain == 0) return;
  Long64_t nentries = fChain->GetEntriesFast();
  Long64_t nbytes = 0, nb = 0;
  for (Long64_t jentry=0; jentry<nentries;jentry++) {
    Long64_t ientry = LoadTree(jentry);
    if (ientry < 0) break;
    nb = fChain->GetEntry(jentry);   nbytes += nb;
    ProcessDS(d1x,x1v);
    ProcessDS(d1y,y1v);
    ProcessDS(d2x,x2v);
    ProcessDS(d2y,y2v);
    ProcessDS(d3x,x3v);
    ProcessDS(d3y,y3v);
    bool b1=x1v.size()>0 || y1v.size()>0;
    bool b2=x2v.size()>0 || y2v.size()>0;
    bool b3=x3v.size()>0 || x3v.size()>0;
    if(b1||b2||b3) opt->Fill();

    if((jentry) % 1000 == 0) {
      printf("Process %.2f % %dk / %dk\r",Double_t(jentry)/nentries*100.,
         int(jentry/1000), int(nentries/1000));
      fflush(stdout);
    }
  }
}

当存储自定义的结构体等类型时,需要用将类型声明写到Linkdef.h文件,并通过makefile连接

./Linkdef.h

#ifdef __CINT__

#pragma link off all globals;
#pragma link off all classes;
#pragma link off all functions;
#pragma link C++ nestedclasses;

// 添加/修改以下内容
#pragma link C++ class dssd+;//声明用到的结构体
#pragma link C++ class vector<dssd>+;//声明vector 

#endif

./makefile

#############################################################################
OBJ = dssd
MainFile = main.cpp

###############################################################################

LinkFile = LinkDict.cc

###############################################################################

SourceFile := $(LinkFile) $(MainFile) $(wildcard $(shell pwd)/src/*.c $(shell pwd)/src/*.cc $(shell pwd)/src/*.C $(shell pwd)/src/*.cpp $(shell pwd)/src/*.cxx) 
IncludeFile := $(wildcard $(shell pwd)/include/*.h $(shell pwd)/include/*.hh $(shell pwd)/include/*.hpp)

###############################################################################

ROOTCFLAGS  = $(shell root-config --cflags)
ROOTLIBS    = $(shell root-config --libs)
ROOTGLIBS = $(shell root-config --glibs)

GXX = g++ 
# -Wl ,--no-as-needed
DIR_INC = -I$(ROOTSYS)/include  -I$(shell pwd)/include
CFLAGS = -Wall -O2 $(DIR_INC) -I$(ROOTSYS)/include  $(ROOTLIBS) -lSpectrum -lXMLParser  -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64

###############################################################################

all:$(OBJ)

#以下在 Linkdef.h 之前添加 Linkdef.h 中包含 vector 类的文件
$(LinkFile) : include/ana.h Linkdef.h
    rootcling -f $(LinkFile) -c $^  

$(OBJ): $(SourceFile)
    $(GXX) $(CFLAGS) $(ROOTCFLAGS) $(ROOTLIBS) $(ROOTGLIBS) -o $@ $(SourceFile)
    @echo "=============================================================="
    @echo "$@ done !"
    @echo "=============================================================="
clean:
    rm -f *.o *.d $(OBJ) *Dict*

2.使用含vector类型Branch的ROOT文件进行分析-ROOT命令行

In [1]:
TCanvas *c1=new TCanvas;
TFile *ff=new TFile("vec_16C.root");
Warning in <TClass::Init>: no dictionary for class dssd is available

得到vector的大小:@vec.size()

In [3]:
tree->Draw("@x1v.size()");//显示vector的大小
c1->Draw();

访问vector的第i个元素的e值:vec[i].e

In [5]:
tree->Scan("x1v[0].id:x1v[0].e:x1v[0].t:x1v[1].id:x1v[1].e:x1v[1].t","@x1v.size()==2","",10,1)
************************************************************************************
*    Row   * x1v[0].id *  x1v[0].e *  x1v[0].t * x1v[1].id *  x1v[1].e *  x1v[1].t *
************************************************************************************
*        1 *        17 * 4800.3649 * 5243.6104 *        18 * 982.70089 * 5285.5599 *
*        2 *        23 * 3069.6758 * 5273.0678 *        24 * 341.06779 * 5240.3867 *
*        3 *        23 * 5325.9910 * 5260.0678 *        24 * 46.852453 *       nan *
*        4 *        21 * 5822.8352 * 5247.1507 *        22 * 51.872362 *       nan *
*        5 *        11 * 4048.3422 * 5244.0956 *        12 * 1149.1993 * 5262.0818 *
*        6 *        13 * 374.31296 *  5295.015 *        14 * 3719.9419 * 5234.8849 *
************************************************************************************
==> 6 selected entries
(long long) 6
In [6]:
tree->Scan("x1v.id:x1v.e:x1v.t","@x1v.size()==2","",10,1)
***********************************************************
*    Row   * Instance *    x1v.id *     x1v.e *     x1v.t *
***********************************************************
*        1 *        0 *        17 * 4800.3649 * 5243.6104 *
*        1 *        1 *        18 * 982.70089 * 5285.5599 *
*        2 *        0 *        23 * 3069.6758 * 5273.0678 *
*        2 *        1 *        24 * 341.06779 * 5240.3867 *
*        3 *        0 *        23 * 5325.9910 * 5260.0678 *
*        3 *        1 *        24 * 46.852453 *       nan *
*        4 *        0 *        21 * 5822.8352 * 5247.1507 *
*        4 *        1 *        22 * 51.872362 *       nan *
*        5 *        0 *        11 * 4048.3422 * 5244.0956 *
*        5 *        1 *        12 * 1149.1993 * 5262.0818 *
*        6 *        0 *        13 * 374.31296 *  5295.015 *
*        6 *        1 *        14 * 3719.9419 * 5234.8849 *
***********************************************************
==> 12 selected entries
(long long) 12

3.使用含vector类型Branch的ROOT文件进行分析

  • 当使用makeclass方法调用含vector类型Branch的数据文件时,makeclass将vector解释成如tree->Print()中显示的那样的动态数组结构。
In [9]:
tree->Print();
******************************************************************************
*Tree    :tree      : vector branch                                          *
*Entries :  2023076 : Total =       744983759 bytes  File  Size =  335786363 *
*        :          : Tree compression factor =   2.22                       *
******************************************************************************
*Br    0 :x1v       : Int_t x1v_                                             *
*Entries :  2023076 : Total  Size=   16284062 bytes  File Size  =    3881644 *
*Baskets :      764 : Basket Size=      32000 bytes  Compression=   4.18     *
*............................................................................*
*Br    1 :x1v.id    : Int_t id[x1v_]                                         *
*Entries :  2023076 : Total  Size=   25352263 bytes  File Size  =    6320782 *
*Baskets :       98 : Basket Size=    3794944 bytes  Compression=   4.01     *
*............................................................................*
*Br    2 :x1v.e     : Double_t e[x1v_]                                       *
*Entries :  2023076 : Total  Size=   42606133 bytes  File Size  =   32524001 *
*Baskets :      141 : Basket Size=    5379584 bytes  Compression=   1.31     *
*............................................................................*
*Br    3 :x1v.t     : Double_t t[x1v_]                                       *
*Entries :  2023076 : Total  Size=   42606133 bytes  File Size  =   13246169 *
*Baskets :      141 : Basket Size=    5379584 bytes  Compression=   3.22     *
*............................................................................*
*Br    4 :x2v       : Int_t x2v_                                             *
*Entries :  2023076 : Total  Size=   16285402 bytes  File Size  =    4196636 *
*Baskets :      764 : Basket Size=      32000 bytes  Compression=   3.87     *
*............................................................................*
*Br    5 :x2v.id    : Int_t id[x2v_]                                         *
*Entries :  2023076 : Total  Size=   28880153 bytes  File Size  =    8438087 *
*Baskets :      112 : Basket Size=    4293120 bytes  Compression=   3.42     *
*............................................................................*
*Br    6 :x2v.e     : Double_t e[x2v_]                                       *
*Entries :  2023076 : Total  Size=   49661789 bytes  File Size  =   38240269 *
*Baskets :      168 : Basket Size=    6375936 bytes  Compression=   1.30     *
*............................................................................*
*Br    7 :x2v.t     : Double_t t[x2v_]                                       *
*Entries :  2023076 : Total  Size=   49661789 bytes  File Size  =   17650173 *
*Baskets :      168 : Basket Size=    6375936 bytes  Compression=   2.81     *
*............................................................................*
*Br    8 :x3v       : Int_t x3v_                                             *
*Entries :  2023076 : Total  Size=   16282902 bytes  File Size  =    3994156 *
*Baskets :      764 : Basket Size=      32000 bytes  Compression=   4.07     *
*............................................................................*
*Br    9 :x3v.id    : Int_t id[x3v_]                                         *
*Entries :  2023076 : Total  Size=   20228212 bytes  File Size  =    6121364 *
*Baskets :       87 : Basket Size=    3377664 bytes  Compression=   3.30     *
*............................................................................*
*Br   10 :x3v.e     : Double_t e[x3v_]                                       *
*Entries :  2023076 : Total  Size=   32357957 bytes  File Size  =   23241034 *
*Baskets :      118 : Basket Size=    4545024 bytes  Compression=   1.39     *
*............................................................................*
*Br   11 :x3v.t     : Double_t t[x3v_]                                       *
*Entries :  2023076 : Total  Size=   32357957 bytes  File Size  =   10010541 *
*Baskets :      118 : Basket Size=    4545024 bytes  Compression=   3.23     *
*............................................................................*
*Br   12 :x1v       : Int_t x1v_                                             *
*Entries :  2023076 : Total  Size=   16284042 bytes  File Size  =    3881644 *
*Baskets :      764 : Basket Size=      32000 bytes  Compression=   4.18     *
*............................................................................*
*Br   13 :x1v.id    : Int_t id[x1v_]                                         *
*Entries :  2023076 : Total  Size=   25352259 bytes  File Size  =    6320782 *
*Baskets :       98 : Basket Size=    3794944 bytes  Compression=   4.01     *
*............................................................................*
*Br   14 :x1v.e     : Double_t e[x1v_]                                       *
*Entries :  2023076 : Total  Size=   42606129 bytes  File Size  =   32524001 *
*Baskets :      141 : Basket Size=    5379584 bytes  Compression=   1.31     *
*............................................................................*
*Br   15 :x1v.t     : Double_t t[x1v_]                                       *
*Entries :  2023076 : Total  Size=   42606129 bytes  File Size  =   13246169 *
*Baskets :      141 : Basket Size=    5379584 bytes  Compression=   3.22     *
*............................................................................*
*Br   16 :x2v       : Int_t x2v_                                             *
*Entries :  2023076 : Total  Size=   16285402 bytes  File Size  =    4196636 *
*Baskets :      764 : Basket Size=      32000 bytes  Compression=   3.87     *
*............................................................................*
*Br   17 :x2v.id    : Int_t id[x2v_]                                         *
*Entries :  2023076 : Total  Size=   28880153 bytes  File Size  =    8438087 *
*Baskets :      112 : Basket Size=    4293120 bytes  Compression=   3.42     *
*............................................................................*
*Br   18 :x2v.e     : Double_t e[x2v_]                                       *
*Entries :  2023076 : Total  Size=   49661789 bytes  File Size  =   38240269 *
*Baskets :      168 : Basket Size=    6375936 bytes  Compression=   1.30     *
*............................................................................*
*Br   19 :x2v.t     : Double_t t[x2v_]                                       *
*Entries :  2023076 : Total  Size=   49661789 bytes  File Size  =   17650173 *
*Baskets :      168 : Basket Size=    6375936 bytes  Compression=   2.81     *
*............................................................................*
*Br   20 :x3v       : Int_t x3v_                                             *
*Entries :  2023076 : Total  Size=   16282902 bytes  File Size  =    3994156 *
*Baskets :      764 : Basket Size=      32000 bytes  Compression=   4.07     *
*............................................................................*
*Br   21 :x3v.id    : Int_t id[x3v_]                                         *
*Entries :  2023076 : Total  Size=   20228212 bytes  File Size  =    6121364 *
*Baskets :       87 : Basket Size=    3377664 bytes  Compression=   3.30     *
*............................................................................*
*Br   22 :x3v.e     : Double_t e[x3v_]                                       *
*Entries :  2023076 : Total  Size=   32357957 bytes  File Size  =   23241034 *
*Baskets :      118 : Basket Size=    4545024 bytes  Compression=   1.39     *
*............................................................................*
*Br   23 :x3v.t     : Double_t t[x3v_]                                       *
*Entries :  2023076 : Total  Size=   32357957 bytes  File Size  =   10010541 *
*Baskets :      118 : Basket Size=    4545024 bytes  Compression=   3.23     *
*............................................................................*

1.3 分析代码中保持原有的vector类型Branch

  • 如果要在分析代码中保持原有的vector类型Branch,则不能使用makeclass方法。
  • 要按照1.2节手动设置SetBranchAddress.

./include/ana.h

#ifndef ana_h
#define ana_h

#include <vector>
#include <algorithm>
#include <TFile.h>
#include <TTree.h>

using namespace std;
struct dssd//aside
{
  Int_t id;
  Double_t e;
  Double_t t;
};

struct DSSD//x-y side
{
 int xid;
 int yid;
 double xe;//xe
 double ye;//xt
};

class ana 
{
 public:
  vector<dssd> *br_x1v, *br_x2v, *br_x3v;  //声明vector指针
  vector<dssd> *br_y1v, *br_y2v, *br_y3v;
  Double_t sx1e,sx2e,sx3e;//sum
  Double_t sy1e,sy2e,sy3e;    
  TTree *ipt;
  TTree *opt;

  vector<DSSD> d1,d2,d3; //output

 ana(TTree* ipt_,TTree *opt_): ipt(ipt_),opt(opt_) {} 
  virtual ~ana() {};
  virtual void     SetBranchInput();
  virtual void     GetDSSD(vector<dssd> *x, vector<dssd> *y, vector<DSSD> &xy);
  virtual void     Analysis();
  virtual void     BranchOutput();
};
#endif

./src/ana.cpp

#include "ana.h"
using namespace std;

void ana::SetBranchInput()
{
  br_x1v = NULL; //给指针初始化, 这一步必需。
  br_x2v = NULL;
  br_x3v = NULL;
  br_y1v = NULL;
  br_y2v = NULL;
  br_y3v = NULL;
  ipt->SetBranchAddress("x1v", &br_x1v); //将变量指向对应Branch的地址
  ipt->SetBranchAddress("x2v", &br_x2v);
  ipt->SetBranchAddress("x3v", &br_x3v);
  ipt->SetBranchAddress("y1v", &br_y1v);
  ipt->SetBranchAddress("y1v", &br_y2v);
  ipt->SetBranchAddress("y1v", &br_y3v);
  ipt->SetBranchAddress("sx1e", &sx1e);  
  ipt->SetBranchAddress("sx2e", &sx2e);  
  ipt->SetBranchAddress("sx3e", &sx3e);  
  ipt->SetBranchAddress("sy1e", &sy1e);  
  ipt->SetBranchAddress("sy2e", &sy2e);  
  ipt->SetBranchAddress("sy3e", &sy3e);  
}

void ana::BranchOutput()
{ 
  opt->Branch("d1",&d1);
  opt->Branch("d2",&d2);
  opt->Branch("d3",&d3);
}

bool SortDS(dssd *a,dssd *b)
{
  return a->e > b->e;
}

void ana::GetDSSD(vector<dssd> *x, vector<dssd> *y, vector<DSSD> &xy)
{
 int hit=min(x->size(),y->size());
 xy.clear();
 DSSD dxy;
 for(int i=0;i<hit;i++) {
     double xe=(*x)[i].e;//按照下标读取vector内的值 
     double ye=(*y)[i].e;
     int ix=(*x)[i].id;
     int iy=(*y)[i].id;     
     if(abs(xe-ye)<50) {
         dxy.xe=xe;
         dxy.ye=ye;
         dxy.xid=ix;
         dxy.yid=iy;
         xy.push_back(dxy);
     }
 }     
}

void ana::Analysis()
{
  SetBranchInput();
  BranchOutput();
  if (ipt == 0) return;
  Long64_t nentries = ipt->GetEntriesFast();
  for (Long64_t jentry=0; jentry<nentries;jentry++) {
    ipt->GetEntry(jentry);
    sort(br_x1v.begin(),br_x1v.end(),SortDS);
    sort(br_y1v.begin(),br_y1v.end(),SortDS);  
    sort(br_x2v.begin(),br_x2v.end(),SortDS);
    sort(br_y2v.begin(),br_y2v.end(),SortDS);
    sort(br_x3v.begin(),br_x3v.end(),SortDS);
    sort(br_y3v.begin(),br_y3v.end(),SortDS);
    getDSSD(br_x1v,br_y1v,d1);
    getDSSD(br_x2v,br_y2v,d2);
    getDSSD(br_x3v,br_y3v,d3);
    if(d1.size()>0 || d2.size()>0 || d3.size()>0)
        opt->Fill();

    if((jentry) % 1000 == 0) {
      printf("Process %.2f %, %dk / %dk\r",Double_t(jentry)/nentries*100.,
         int(jentry/1000), int(nentries/1000));
      fflush(stdout);
    }
  }
}

./main.cpp

#include <iostream> 
#include <TFile.h>
#include <TTree.h>
#include <TString.h>
#include "ana.h"  //用户代码头文件
using namespace std;

int main(int argc, char** argv)
{

   TString InputPath, OutputPath, infile, outfile;  
    InputPath = "./";
    OutputPath = "./";
    infile.Form("%svec_16C.root", InputPath.Data());
    outfile.Form("%ssort_16C.root", OutputPath.Data());
    //input
    TFile *ipf = new TFile(infile);
    if(!ipf->IsOpen()) {
        cout<<"Cannot open input file: "<<infile<<endl;
        return -1;
    }
    TTree *ipt = (TTree*)ipf->Get("tree");

    //output
    TFile *opf = new TFile(outfile,"RECREATE");
    TTree *opt = new TTree("tree","vector branch");

    //
    ana *tk = new ana(ipt,opt); 
    tk->Analysis(); //等价于原Loop函数

    opt->Write();
    //
    ipf->Close();
    opf->Close();
    return 1;       
}

./Linkdef.h

#ifdef __CINT__

#pragma link off all globals;
#pragma link off all classes;
#pragma link off all functions;
#pragma link C++ nestedclasses;

// 添加/修改以下内容
#pragma link C++ class dssd+;//声明用到的结构体
#pragma link C++ class vector<dssd>+;//声明vector 
#pragma link C++ class DSSD+;//声明用到的结构体
#pragma link C++ class vector<DSSD>+;//声明vector

#endif

附录:vector类的用法

成员函数

vector::size(); //返回 vector 大小
 vector::clear();//清空 vector
 vector::push_back(value);//在vector内填入元素
 vector::begin();//返回vector的首地址
 vector::end();//返回vector的尾地址
 vector::assign(v1.begin(), v2.end());//将v1拷贝到vector中
 vector::erase(it);//删除it位置变量,返回下一个元素的指针

常用代码

  • 排序
bool SortDS(dssd &a,dssd &b)
{
  return a.e > b.e;
}
sort(x1v.begin(),x1v.end(),SortDS);
  • 删除重复元素
bool Equal(dssd &a, dssd &b)
{
  return Long64_t(a.e- b.e)==0 && a.id==b.id;
}
void Unique(vector<dssd> &a) 
{
  a.erase(unique(a.begin(),a.end(),Equal),a.end());
}
//remove identical events, probably caused by bugs in Digital modules
Unique(xvec);
  • 删除指定元素
void tCut(vector<dssd> &a, vector<dssd> &b, double t1,double t2)
{
   if(b.size()>0) {   
     for(auto it=a.begin();it!=a.end() ; ) {
       int dt=Long64_t(it->ts-b[0].t);
       if(dt<t1 || dt>t2) 
         it=a.erase(it);
       else
         ++it;
     }
   }
}
tCut(x1v,x1v,-20,20);
In [ ]: