1.1 用TTree 结构存储事件数据¶

目的:学习如何将事件以TTree的格式存储到ROOT文件¶

实验设置:¶

  • 束流入射到靶上产生核反应,生成中子和$\gamma$。中子和$\gamma$入射到长条型塑料闪烁体探测器的不同位置,并在不同深度与探测介质产生相互作用。

  • 束流的时间信息$T_{Beam}$由薄塑料闪烁体+PMT给出。

  • 入射粒子形成的光信号向探测器两端传输,经PMT放大形成输出信号。

  • 输出信号分成两路,一路经CFD甄别后形成时间信号$t_u$和$t_d$,送入TDC的stop端;另一路送入QDC,得到能量信号 $q_u, q_d$。

Image

Trigger:¶

  • 获取系统的触发为 $T_u$ x $T_d$ x $T_{Beam}$, 触发信号中$T_{Beam}$的时间为主时序。

  • 触发信号经适当调节(延迟+展宽)送到TDC的Start端和QDC的Gate端。

root文件:¶

  • 将入射粒子的原始信息,以及探测器信息逐事件存入root文件的TTree结构中。
    • 入射粒子原始信息:粒子种类、能量,粒子在探测器上的入射位置、入射深度等。
    • 探测器信息: 两端时间信息$t_u$, $t_d$,能量沉积信息$q_u$, $q_d$
  • 打开root文件,进行基本的分析。

飞行时间(Time Of Flight)测量原理¶

束流¶

束流的能量是单能的,束流从薄闪烁体到靶的飞行时间取决于束流的能量(速度)和距离,可视为常数。

探测器参数¶

探测器的几何设置见下图:

  • 探测器长度:2$L$, 忽略探测器宽度。
  • 探测器厚度:$\Delta D$
  • 光在闪烁体的传播速度: $v_{sc}$
  • 光在闪烁体的衰减常数:$\lambda$
  • 粒子从起始位置到探测器中心的距离:$D$
  • 粒子入射位置:$x$
  • 粒子相互作用的位置(深度):$(-\frac{\Delta D}{2} \le D'\le +\frac{\Delta D}{2})$

公式¶

  • 飞行距离,假设相对于探测器中心粒子的相互作用点深度$D'$:
$$ d=\sqrt{(D+D')^2+x^2} $$
  • 飞行时间, 以靶为起点:
$$ \begin{align} 中子:TOF_n(ns)&= \frac{72.29824 \cdot d(m)}{\sqrt{E_n(MeV)}} \\ \gamma:TOF_{\gamma}(ns)&= 3.333\cdot d(m) \end{align} $$
  • 探测器两端时间信号(不考虑时间offset):
$$ \begin{align} t_u &= TOF+(L-x)/v_{sc}\\ t_d &= TOF+(L+x)/v_{sc}\\ x &= (t_d-t_u)*v_{sc}/2\\ TOF&=(t_u+t_d)/2 -L/v_{sc}\\ \end{align} $$
  • 探测器两端时间信号,考虑 time offset(包括束流飞行时间、PMT渡越时间、信号在电缆+电子学上的延迟时间等):
$$ \begin{equation} t_u=TOF+(L-x)/v_{sc}+t_{u_{\text{off}}}\\ t_d=TOF+(L+x)/v_{sc}+t_{d_{\text{off}}}\\ x=(t_d-t_u)*v_{sc}/2+C_x\\ TOF=(t_u+t_d)/2 +C_{\text{tof}}\\ \end{equation} $$$$ \begin{align} C_x&=(t_{u_{off}}-t_{d_{off}})*v_{sc}/2\\ C_{\text{tof}}&=-L/v_{sc}+(t_{u_{\text{off}}}-t_{d_{\text{off}}})/2 \end{align} $$
  • 探测器两端能量,设x 处能量沉积 $2Q_0$:
$$ q_u=Q_0 e^{-(L-x)/\lambda} \\ q_d=Q_0 e^{-(L+x)/\lambda}\\ x=\frac{\lambda}{2}ln\frac{q_u}{q_d}\\ Q_0^2=e^{2L/\lambda}*q_u*q_d\\ $$

探测器分辨率:

  • 时间分辨率(FWHM):$\space t_{Res.}$
  • 相对能量分辨率 ($\Delta E/E$) : $\space e_{Res.}$

随机数:

  • TRandom3 class
    • Uniform(Double_t x1, Double_t x2);
    • Gaus(Double_t mean, Double_t sigma)

代码¶

运行方法:¶

  • 将下列代码保存到tree.cc

  • 在ROOT命令行运行:

    • 进入ROOT环境: root -l
    • 运行脚本: .x tree.cc
    • 退出root环境:.q
    • 打开ROOT文件: root -l tree.root
// tree.cc
void tree(){ 
//常量声明
  const Double_t D = 500.;//cm, distance between target and the scin.(Center)
  const Double_t L = 100.;//cm, half length of the scin.
  const Double_t dD = 5.;//cm, thickness of the scin.
  const Double_t tRes = 1.;//ns, time resolution(FWHM) of the scintillator.
  const Double_t Lambda = 380.;//cm, attenuation lenght of the scin.
  const Double_t qRes = 0.1;//relative energy resolution(FWHM) of the scin. 
  const Double_t Vsc = 7.5;//ns/cm, speed of light in the scin.
  const Double_t En0 = 100;//MeV, average neutron energy
  const Double_t EnFWHM = 50.;//MeV, energy spread of neutron(FWHM)
  const Double_t Eg0 = 1;//MeV, gamma energy  
  const Double_t RatioGamma = 0.3;//ratio of gamma,ratio of neutron 1-Rg 

  //1. 声明tree中Branch的变量
  Double_t x;//入射位置
  Double_t e;//能量
  int pid;    //粒子种类,n:pid=1,g:pid=0
  Double_t tof, ctof;//TOF:粒子实际飞行时间,cTOF:计算得到的TOF
  Double_t tu, td;
  Double_t qu, qd;

  Double_t tuOff = 5.5;//time offset,
  Double_t tdOff = 20.4;//time offset 

 //2. 定义新ROOT文件,声明新的Tree 
  TFile *opf = new TFile("tree.root", "recreate");//新文件tree.root,指针 *opf
  TTree *opt = new TTree("tree", "tree structure");//新tree,指针 *opt

  //3. 将变量地址添加到tree结构中
    //第一个参数为变量名称,第二个为上面定义的变量地址,第三个为变量的类型说明,D表示Double_t,I表示 Int_t。
  opt->Branch("x", &x, "x/D");
  opt->Branch("e", &e, "e/D");
  opt->Branch("tof", &tof, "tof/D");
  opt->Branch("ctof",&ctof,"ctof/D");
  opt->Branch("pid", &pid, "pid/I");
  opt->Branch("tu", &tu, "tu/D");
  opt->Branch("td", &td, "td/D");
  opt->Branch("qu", &qu, "qu/D"); 
  opt->Branch("qd", &qd, "qd/D");

tree.root 内 TTree格式¶

Image
// histogram,ROOT文件中除了TTree结构外,还可存储histogram,graph等
  TH1D *hctof = new TH1D("hctof", "neutron time of flight", 1000, 0, 100);
  TRandom3 *gr = new TRandom3(0);//声明随机数

  //4. 循环,计算变量的值,逐事件往tree结构添加变量值。
  for(int i = 0; i < 100000; i++){
    x = gr->Uniform(-L, L);//粒子入射位置,在-L,L范围内均匀抽样.
    Double_t Dr = D + gr->Uniform(-0.5, 0.5) * dD;//粒子在探测器厚度范围内均匀产生光信号
    Double_t d = TMath::Sqrt(Dr * Dr + x * x);//粒子实际飞行距离
    if(gr->Uniform() < RatioGamma) { //判断为gamma入射
       pid = 0;
       e = Eg0;
       tof = 3.333 * (d * 0.01);
    }
    else {  //neutron
        pid = 1;
        e = gr->Gaus(En0, EnFWHM/2.35); // energy of neutrons
        tof = 72.29824/TMath::Sqrt(e) * (d * 0.01);//ns
    }
    if(isnan(tof)) continue; //check ZeroDivisionError

    tu = tof + (L - x)/Vsc + tuOff;
    tu = gr->Gaus(tu, tRes/2.35);
    td = tof + (L + x) / Vsc + tdOff;
    td = gr->Gaus(td, tRes/2.35);
    ctof = (tu + td)/2.;//simplified calculation.
    hctof->Fill(ctof);
//neutron:energy of recoil proton in plas. q0=0-En; gamma:q0=0-Egamma,compton plateau
    Double_t Q0 = e * gr->Uniform(); //light response of Qee = f(Ep) is not considered
    qu = Q0 *TMath::Exp(-(L - x)/Lambda);
    qu = gr->Gaus(qu, qu * qRes/2.35);//QRes, relative energy resolution
    qd = Q0 * TMath::Exp(-(L + x)/Lambda);
    qd = gr->Gaus(qd, qd * qRes/2.35);

    //5.将计算好的变量值填到Tree中
    opt->Fill();

    if(i%1000 == 0) cout << ".";
  }
  cout << endl;

  // 6.将数据写入root文件中
  hctof->Write(); // 将预定义的histogram写到文件
  opt->Write();   // 将TTree到文件
  opf->Close();   // 关闭文件
}

练习:¶

  • 理解上述1.-6.步骤的逻辑关系。自行练习如何将数据以TTree格式存到ROOT文件中。
  • 理解如何在模拟中加入探测器分辨。

查看ROOT文件¶

In [1]:
//%jsroot on
In [2]:
TFile *ipf = new TFile("tree.root");//root -l tree.root
ipf->ls()//ROOT 环境下 > .ls
TFile**		tree.root	
 TFile*		tree.root	
  KEY: TH1D	hctof;1	neutron time of flight
  KEY: TTree	tree;1	tree structure
In [3]:
//观察tree的结构
tree->Print()
******************************************************************************
*Tree    :tree      : tree structure                                         *
*Entries :   100000 : Total =         6822821 bytes  File  Size =    5757666 *
*        :          : Tree compression factor =   1.18                       *
******************************************************************************
*Br    0 :x         : x/D                                                    *
*Entries :   100000 : Total  Size=     802585 bytes  File Size  =     614425 *
*Baskets :       26 : Basket Size=      32000 bytes  Compression=   1.30     *
*............................................................................*
*Br    1 :e         : e/D                                                    *
*Entries :   100000 : Total  Size=     802585 bytes  File Size  =     565296 *
*Baskets :       26 : Basket Size=      32000 bytes  Compression=   1.42     *
*............................................................................*
*Br    2 :tof       : tof/D                                                  *
*Entries :   100000 : Total  Size=     802645 bytes  File Size  =     742158 *
*Baskets :       26 : Basket Size=      32000 bytes  Compression=   1.08     *
*............................................................................*
*Br    3 :ctof      : ctof/D                                                 *
*Entries :   100000 : Total  Size=     802675 bytes  File Size  =     741645 *
*Baskets :       26 : Basket Size=      32000 bytes  Compression=   1.08     *
*............................................................................*
*Br    4 :pid       : pid/I                                                  *
*Entries :   100000 : Total  Size=     401467 bytes  File Size  =      42459 *
*Baskets :       13 : Basket Size=      32000 bytes  Compression=   9.44     *
*............................................................................*
*Br    5 :tu        : tu/D                                                   *
*Entries :   100000 : Total  Size=     802615 bytes  File Size  =     755898 *
*Baskets :       26 : Basket Size=      32000 bytes  Compression=   1.06     *
*............................................................................*
*Br    6 :td        : td/D                                                   *
*Entries :   100000 : Total  Size=     802615 bytes  File Size  =     754249 *
*Baskets :       26 : Basket Size=      32000 bytes  Compression=   1.06     *
*............................................................................*
*Br    7 :qu        : qu/D                                                   *
*Entries :   100000 : Total  Size=     802615 bytes  File Size  =     769589 *
*Baskets :       26 : Basket Size=      32000 bytes  Compression=   1.04     *
*............................................................................*
*Br    8 :qd        : qd/D                                                   *
*Entries :   100000 : Total  Size=     802615 bytes  File Size  =     769457 *
*Baskets :       26 : Basket Size=      32000 bytes  Compression=   1.04     *
*............................................................................*

观察指定事件数据¶

In [4]:
tree->Show(0);//显示指定的事件数据 event=1
======> EVENT:0
 x               = 13.6236
 e               = 92.3101
 tof             = 37.8187
 ctof            = 63.8957
 pid             = 1
 tu              = 54.7111
 td              = 73.0803
 qu              = 15.7843
 qd              = 15.5499
In [5]:
tree->Show(100);
======> EVENT:100
 x               = 11.7554
 e               = 92.9767
 tof             = 37.422
 ctof            = 64.145
 pid             = 1
 tu              = 55.3905
 td              = 72.8995
 qu              = 26.0771
 qd              = 24.3129
In [6]:
TCanvas *c1 = new TCanvas();//* 在ROOT环境下可省略
c1->Clear();//* 在ROOT环境下可省略
tree->Draw("td-tu>>htx(500,-20,50)");//位置一维分布
c1->Draw();//* 在ROOT环境下可省略
In [7]:
tree->Draw("tof>>hh(1000,0,100)");//实际飞行时间
c1->SetLogy();
c1->Draw();
In [8]:
TH1D *hh = (TH1D*) ipf->Get("hctof"); //在代码中得到文件内数据指针的方法,在ROOT环境下课直接用 hctof->Draw()
hh->Draw();//画图
c1->Draw();

思考题1:观察上两个图有什么不同,分析其原因¶

In [9]:
c1->SetLogy(0);
tree->Draw("ctof:td-tu>>(2000,-20,50,1000,0,100)","","colz");//二维图显示
c1->Draw();

检查参数之间的关系是否与物理条件一致¶

  • gamma的到达探测器的时间(飞行时间)与探测器的x位置无关?
In [10]:
tree->Draw("ctof:td-tu>>(2000,-20,50,50,40,46)","pid == 0","colz");//加入条件,gamma
c1->Draw();//为什么在两侧上弯?
In [11]:
tree->Draw("td-tu:x>>(100,-100,100,100,-15,50)","","colz");//观察两个参量的关联
c1->Draw();
In [12]:
tree->Draw("log(qu/qd):x","","colz");
c1->Draw();