編集メニュー > 新規作成 編集 コピー 名前の変更 アップロード 添付ファイル一覧 バックアップ

* TTree [#kd8fa256]

** SetBranchStatus [#x8cf71be]
これを使うと使用しないBranchを読むのをスキップするので解析を速くできる。
これを使うと使用しないBranchのactivate/disableを設定できて、余計なBranchを読むのをスキップするので解析を速くできる。


** TEventList [#reb43109]
これを使うと、無駄にGetEntryをしなくて済むようになるので、解析が速くなる。自分の場合は30分かかるものが5分になった。以下は例。例1の方が何が起こっているかを知るためにはわかりやすい。複数のtreeをchainしている時は、globalなentryと各tree内のlocalなentryがあるので気をつけないといけない。elist->GetEntry(i)はあるtreeのlocalなentryを返すので、chain->GetEntry(elist->GetEntry(i))としてはいけない。またchain->SetEntryList(elist)は省略できない。

*** 例1 [#z0c73ae1]
  chain->Draw(">>elist","fabs(frag_z-7)<0.35&&fabs(frag_aoz-3)<0.05","entrylist");
  TEntryList *elist = (TEntryList*)gDirectory->FindObject("elist");
  chain->SetEntryList(elist);
 
  Int_t itree=0;
  Int_t listEntries = elist->GetN();
  cout<<setw(10)<<" i/listEnt itree c_Entry t_Entry el_GetEnt"<<endl;
  for (Long64_t i=0;i<listEntries;i++){
    Long64_t treeEntry = elist->GetEntryAndTree(i,itree);
    Long64_t chainEntry = treeEntry + chain->GetTreeOffset()[itree];
    chain->GetEntry(chainEntry);
 
    cout<<" "
        <<setw(2)
        <<i<<"/"
        <<listEntries<<"      "
        <<itree<<"    "
        <<setw(7)<<chainEntry<<" "
        <<setw(7)<<treeEntry<<"   "
        <<setw(7)<<elist->GetEntry(i)<<" "
        <<endl;
 
  }

output

 i/listEnt itree c_Entry t_Entry el_GetEnt
  0/13      0      15820   15820     15820 
  1/13      0      16673   16673     16673 
  2/13      0      22085   22085     22085 
  3/13      0      22688   22688     22688 
  4/13      0      29111   29111     29111 
  5/13      0      31800   31800     31800 
  6/13      0      33152   33152     33152 
  7/13      1      62622    6652      6652 
  8/13      1      68255   12285     12285 
  9/13      1      83823   27853     27853 
 10/13      1      99632   43662     43662 
 11/13      1     104841   48871     48871 
 12/13      1     108282   52312     52312 

*** 例2 [#h27d1504]

  chain->Draw(">>elist","fabs(frag_z-7)<0.35&&fabs(frag_aoz-3)<0.05","entrylist");
  TEntryList *elist = (TEntryList*)gDirectory->FindObject("elist");
  chain->SetEntryList(elist);
 
  Int_t listEntries = elist->GetN();
  cout<<setw(10)<<" i/listEnt c_Entry el_GetEnt"<<endl;
  for (Long64_t i=0;i<listEntries;i++){
    Long64_t c_entry = chain->GetEntryNumber(i);
    if (c_entry<0) {
      cout<<"TChain Load Error!"<<endl;
      break;
    }
 
    chain->GetEntry(c_entry);
 
    cout<<" "
        <<setw(2)<<i<<"/"
        <<listEntries<<"     "
        <<setw(7)<<c_entry<<"   "
        <<setw(7)<<elist->GetEntry(i)<<" "
        <<endl;
 
  }

output
 i/listEnt c_Entry el_GetEnt
  0/13       15820     15820 
  1/13       16673     16673 
  2/13       22085     22085 
  3/13       22688     22688 
  4/13       29111     29111 
  5/13       31800     31800 
  6/13       33152     33152 
  7/13       62622      6652 
  8/13       68255     12285 
  9/13       83823     27853 
 10/13       99632     43662 
 11/13      104841     48871 
 12/13      108282     52312 


** 複数のtreeの結合 [#b08fd263]
AddFriendを使えばできるみたいだが、これはEntry数が同じでないといけない。つまり全部のイベントをtreeに詰めて、多くのイベントはダミーの値を入れておくことになる。無駄なイベントを除去してtreeに詰めたいのに。。。イベント数が一致するものを探して、っていうコードを書くと遅いかな?間違えそうなのも少し危険か?

*** 妥協案? [#q55bc6e2]
上の無駄なイベントを詰めるのを回避する方法として、
+比較的早く解析できる部分でtreeを作り、無駄なイベントを除く
+別の検出器を解析するときにそのtreeを読み込み、イベント番号でスキップする。

こうするとEntry数は同じになるので、AddFriendで結合できる。
ただし、あとから作るtreeはすべて初めに作成するtreeに依存してしまう。

** Drawのゲートに文字列 [#we1086e7]
Drawの時に
 tree->Draw("Tracks.fPosition.fX","Tracks.fID==1")
のようにゲートを掛けてプロットしたりするが、これが文字列の比較の場合なんか少し変。例えばfNameというTStringでゲートを掛ける時には
 tree->Draw("Tracks.fPosition.fX","Tracks.fName.Data()==\"Target\"")
とするとうまくいく。うーんこれはたまたま?charの比較を==で行っているのでとっても気持ち悪い。使わないようにした方がいい気がする。。。

** vectorの読み書き [#l44e7a9c]
http://root.cern.ch/root/html/tutorials/tree/hvector.C.html
に例がある。書き出すときは
 std::vector<float> vpx;
 ...
 t->Branch("vpx",&vpx);
となっているので、ポインタを渡す。
読み込むときは
 std::vector<float> *vpx = 0;
 TBranch *bvpx = 0;
 t->SetBranchAddress("vpx",&vpx,&bvpx);
となっているので、ポインタのアドレスを渡す。

** TClonesArrayの読み書き [#mc8624d1]
TClonesArrayをTTreeに詰めるときには以下のように書く。

 TClonesArray *arr = new TClonesArray("TLine");
 T.Branch("tcl",&arr);

つまりポインタのポインタをSetBranchAddressする。
こうして作ったTTreeから取り出す時には同様に

 TClonesArray *arr = new TClonesArray("TLine");
 T->GetBranch("tcl")->SetAutoDelete(kFALSE);
 T->SetBranchAddress("tcl",&arr);

とポインタのポインタを渡す。

配列の時には
 float y[20];
 tr->SetBranchAddress("y",y);
と書いたりするんですよね。。。いっつもこれと混同してしまう。


SetAutoDeleteをkFALSEとした場合にはt->GetEntry(i)する前にTClonesArray->Delete()またはClear()をしないといけない。

forループ内で
  tree->GetEntry(ieve);
  bool IsOK=false;
  for (int i=0;i<array->GetEntries();++i){
    Tnanka *obj = (Tnanka*)array->At(i);
    if (obj->GetA() > value){
      IsOK=true;
      break;
    }
    ...
  }
  ...
  if (!IsOK) continue;
  ...
とか書いているときにあるイベントでarray->At(0)が0x0になっていることがある???なぜだか全然分からない。。。こういう場合は
  array->Delete();
  tree->GetEntry(ieve);
  ...
としておくとそんなことにはならない。ということがあったりするので安全のためにSetAutoDelete(kFALSE)しなくてもDelete()しておいた方が良いかも。