6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

TTreeReader の使い方 (CERN ROOT)

Last updated at Posted at 2020-01-11

TTreeReader とは

ROOT では TTreeTChain からイベントの情報を取り出してデータ解析を行います。それには SetBranchAddress() してから GetEntry() して、というのが伝統的な方法でしたが、よりモダンな方法として TTreeReader を使う方法を紹介します。
実際、以下のページでは

There is a traditional way of doing this (TTree::SetBranchAddress() etc) and a new, recommended one: the TTreeReader.

とあり、TTreeReader がおすすめされています。
ヘッダファイルのコメント を見る限りでは2010年からあったようですが、現時点であまり広まっていないように思えます。というわけで広めるべく使っていきます。

準備

上記のネタ元のページに従って、ROOT に同梱されている $ROOTSYS/tutorials/hsimple.root を使ってやっていきます。

$ root $ROOTSYS/tutorials/hsimple.root
root [0]
Attaching file root/tutorials/hsimple.root as _file0...
(TFile *) 0x7fffba2ba700
root [1] _file0->ls()
TFile**         root/tutorials/hsimple.root     Demo ROOT file with histograms
 TFile*         root/tutorials/hsimple.root     Demo ROOT file with histograms
  KEY: TH1F     hpx;1   This is the px distribution
  KEY: TH2F     hpxpy;1 py vs px
  KEY: TProfile hprof;1 Profile of pz versus px
  KEY: TNtuple  ntuple;1        Demo ntuple
root [2] ntuple->Print()
******************************************************************************
*Tree    :ntuple    : Demo ntuple                                            *
*Entries :    25000 : Total =          504176 bytes  File  Size =     429479 *
*        :          : Tree compression factor =   1.17                       *
******************************************************************************
*Br    0 :px        : Float_t                                                *
*Entries :    25000 : Total  Size=     100755 bytes  File Size  =      92913 *
*Baskets :        4 : Basket Size=      32000 bytes  Compression=   1.08     *
*............................................................................*
*Br    1 :py        : Float_t                                                *
*Entries :    25000 : Total  Size=     100755 bytes  File Size  =      92934 *
*Baskets :        4 : Basket Size=      32000 bytes  Compression=   1.08     *
*............................................................................*
*Br    2 :pz        : Float_t                                                *
*Entries :    25000 : Total  Size=     100755 bytes  File Size  =      91194 *
*Baskets :        4 : Basket Size=      32000 bytes  Compression=   1.10     *
*............................................................................*
*Br    3 :random    : Float_t                                                *
*Entries :    25000 : Total  Size=     100787 bytes  File Size  =      90003 *
*Baskets :        4 : Basket Size=      32000 bytes  Compression=   1.11     *
*............................................................................*
*Br    4 :i         : Float_t                                                *
*Entries :    25000 : Total  Size=     100747 bytes  File Size  =      61673 *
*Baskets :        4 : Basket Size=      32000 bytes  Compression=   1.63     *
*............................................................................*

というわけでこのファイルには、px, py, pzFloat_t 型の TBranch を含んだ TNtuple が入っています1

旧来の方法

先に伝統技法による読み込みをやってみます。

{
  auto file = new TFile("$ROOTSYS/tutorials/hsimple.root");
  auto tree = static_cast<TTree*>(file->Get("ntuple"));

  float px, py, pz;
  tree->SetBranchAddress("px", &px);
  tree->SetBranchAddress("py", &py);
  tree->SetBranchAddress("pz", &pz);

  for (auto i=0; i < tree->GetEntries(); ++i){
    tree->GetEntry(i);
    std::cout << px << " " << py << " " << pz << std::endl;
  }
}

あらかじめ px, py, pz という float の変数を用意しておき、それぞれを TTree の Branch に割り当ててから、イベントを読み込むループを回すという手順です。

TTreeReader を使う方法

次に、TTreeReader を使う方法。

{
  auto file = new TFile("$ROOTSYS/tutorials/hsimple.root");
  TTreeReader reader("ntuple", file);

  TTreeReaderValue<float> pxit(reader, "px");
  TTreeReaderValue<float> pyit(reader, "py");
  TTreeReaderValue<float> pzit(reader, "pz");

  while (reader.Next()) {
    std::cout << *pxit << " " << *pyit << " " << *pzit << std::endl;
  }
}

このコードからは以下のような特徴が見てとれます。

  • TTree は直接このコードには出て来ず、TTreeReader を通してしかアクセスしていない。
  • 旧来のコードで SetBranchAddress していた部分では TTreeReaderValue というのを使っている。
  • イベントループはイタレータっぽくなっている。

ループの書き方は少し見易くなった感はあるものの、それ以上に違うのは SetBranchAddress がなくなったことかと思います。SetBranchAddressscanf のような見た目をしていて C っぽいです。一方 TTreeReaderValue<> はテンプレート引数が出て来て C++ っぽいです。

見た目だけではなく、こう書くことによる利点として、実行時に型チェックが行われるというのがあります。例えば、TTreeReaderValue<double> pxit(reader, "px"); とすると、TTree に記録された float と合わないため実行時エラーとなります。一方で、旧来の方法では double px; tree->SetBranchAddress("px", &px); としてもエラーになってくれません。

その他、注意点として、

  • Branch に配列が入っている場合、TTreeReaderValue<float> ではなく TTreeReaderArray<float> のようになります。
  • TTreeReaderValue の値にアクセスするには、std::vector::iterator などと同様、*pxit のようにする必要があります。
  • 速度については未検証です。少なくとも今回のような小さなサイズで、マクロとして実行した場合には違いは見られませんでした。

Reference

(3年ちょっとぶりの ROOT の記事でした。 前回)

  1. TNtuple は float しか入れられない TTree だと思えば良いです。この例は TNtuple を用いているせいで float 以外の型が出て来ないし、配列を扱わないためあまり良くないのですが、自分で root ファイルを準備するのが面倒だったためこれでいきます。

6
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?