2.4 编写可编译执行的分析程序(2)¶

  • 2.3节分析程序的写法, 用户需要改动由MakeClass生成的.h和.C程序,导致ROOT自动生成的代码与用户代码混在一起。

避免上述问题的方法是建立分析代码类(class ana),该类继承由MakeClass生成的类(class tracking)。这样可不改动原来的类,并将用户分析代码与原来的代码分开,互不干扰。

文件和目录的组织¶

主目录: ./tracking

      ./tracking 
          - main.cpp  - 主程序
          - Makefile -编译方法

      ./tracking/include/  
          - tracking.h   - MakeClass 生成的头文件
          - ana.h         - 用户分析头文件

      ./tracking/src/ 
          - tracking.C  -MakeClass生成的源文件
          - ana.cpp       用户分析源文件

0. 利用MakeClass生成.h 和.C文件¶

root -l f8ppac001.root

[0] tree->MakeClass("tracking")

生成 tracking.h 和 tracking.C

将tracking.h 移至 tracking/include目录, 将tracking.C 移至 tracking/src目录¶

1. ./tracking/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)
{
   if(argc !=2) {
       cout<<"Usage: ./"<<argv[0]<<" run_number "<<endl;
       return -1;
   }
   int run_number = atoi(argv[1]);
   TString InputPath, OutputPath, infile, outfile;  
    InputPath = "./";
    OutputPath = "./";
    infile.Form("%sf8ppac%03d.root", InputPath.Data(), run_number);
    outfile.Form("%sout%03d.root", OutputPath.Data(), run_number);
    //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","ppac tracking");

    cout << "Inputfile: "<<infile.Data() << endl;
    cout << "Outputfile: "<<outfile.Data() << endl;
    //
    ana *tk = new ana(run_number,ipt); 
    tk->Analysis(opt); //等价于原Loop函数

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

2. ./tracking/include/ana.h ,用户分析类头文件¶

#ifndef ana_h
#define ana_h

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

using namespace std;

class ana : public tracking //从tracking类中继承其成员变量和成员函数
{
public:
 int run; //run_number
 Double_t xx[3], xz[3], yy[3], yz[3];//1A,2A,3
 Double_t p2bx, p2by;//2B x-y
 Double_t dx[3], dy[3];
 Double_t tx, ty;//target pos
 Double_t c2nx, c2ny;//chi2/ndf for xfit,yfit
 TH2D *htf8x, *htf8y, *htar;

 //构造函数:将传入的tree传递给tracking基类,完成初始化
ana(int run_number, TTree* tree): tracking(tree), run(run_number) {} //tracking = tree; run=run_number;
 virtual ~ana() {};
 virtual void     Analysis(TTree *tree);//分析函数,作用等价于原Loop函数
 virtual void     SetOutBranch(TTree *tree);
 virtual void     TrackInit();
 virtual void     SetTrace(TH2D *h, Double_t k, Double_t b, Int_t min, Int_t max);

};
#endif

3. ./tracking/include/ana.cpp ,用户分析类-具体实现¶

#include <TH2.h>
#include <TStyle.h>
#include <TCanvas.h>
#include <TF1.h>
#include <TFitResult.h>
#include <TGraph.h>
#include "ana.h"
using namespace std;

void ana::SetOutBranch(TTree *tree)
{
  //measured pos
  tree->Branch("xx",&xx,"xx[3]/D");//1A,2A,3
  tree->Branch("xz",&xz,"xz[3]/D");
  tree->Branch("yy",&yy,"yy[3]/D");
  tree->Branch("yz",&yz,"yz[3]/D");

  ...
}

void ana::TrackInit()
{
  tx = -999;
  ty = -999;

  //1A
  xx[0] = PPACF8[0][0];
  yy[0] = PPACF8[0][1];
  xz[0] = PPACF8[0][2];
  yz[0] = PPACF8[0][3];

  ...

}

void ana::SetTrace(TH2D *h, Double_t k, Double_t b, Int_t min, Int_t max){
    if(h == 0) return;
    if(min >= max) return;

    ...
}


void ana::Analysis(TTree *tree)
{
   TH2D *htf8x = new TH2D("htf8x","x trace by ppac", 2200, -2000, 200, 300, -150, 150);
   TH2D *htf8y = new TH2D("htf8y","y trace by ppac", 2200, -2000, 200, 300, -150, 150);
   TH2D *htar = new TH2D("htar","distribution on target", 100, -50, 50, 100, -50, 50);

   SetOutBranch(tree);

   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;

      ...

   }

   ...
}

使用方法:¶

make clean

make

./tracking 1