複雑な構造のデータを読み込みたい( TTree::Branch

… code:: cpp

tree->Branch("run", &run, "run/I")
1TBranch* Branch(const char* name,
2                Long_t address,
3                const char* leaflist,
4                Int_t bufsize = 32000)
name

ブランチ名を指定します。 変数名とのひも付けは次のaddressで行います。

address

変数のアドレスを指定します。 変数は事前に宣言をしておきます。 変数が実体の場合は&が先頭に必要です。 配列の場合はそのまま(array)もしくは配列の最初のアドレス(&array[0])を指定します。

leaflist

変数の型を指定します。 変数/型という形式で記述し、int型ifloat型 / double型Fなど。

サンプルコード

 1// data2tree.C
 2{
 3    // STEP1: データファイルを読み込む
 4    TString ifn = "inputfilename"
 5    ifstream fin;
 6    fin.open(ifn);
 7
 8    // STEP2: データを格納するための変数を定義する
 9    int val1, val2, val3, val4;
10
11    // STEP3: TTreeを作成する
12    TTree *tree = new TTree("name", "title);
13
14    // STEP4: TTree::Branch(...)を使って、各変数のブランチを作成する
15    tree->Branch("val1", &val1, "val1/I");
16    tree->Branch("val2", &val2, "val2/I");
17    tree->Branch("val3", &val3, "val3/I");
18    tree->Branch("val4", &val4, "val4/I");
19
20    // STEP5: cppでファイルを読み込むときの常套手段
21    while (fin >> val1 >> val2 >> val3 >> val4) {
22        // STEP6: データのエントリの区切りで必ずTTree::Fill()する
23        tree->Fill();
24    }
25
26    // STEP7: 作成したTTreeを保存するためのTFileを作成する
27    TString ofn = "outputfilename";
28    TFile *fout = new TFile(ofn, "recreate");
29
30    // STEP8: TFileにTTreeを書き込む
31    tree->Write();  //
32
33    // STEP9: TFileを閉じる
34    // プログラム(やマクロ)終了時に勝手に閉じてくれるらしいが一応
35    fout->Close();
36
37    return;
38}

TTree::ReadFileを使った方法と比べると、 コードの行数がぐーんと多くなりました。

行数が増えた分(?)、汎用性は高くなっています。 この方法だと、ブランチに配列を設定ができます。

ブランチに配列を使いたい

1Int_t val1[100];
2TTree *tree = new TTree("tree", "tree using array");
3tree->Branch("val1", val1, "val1[100]/I");

第1引数はブランチの名前なので、任意の文字列を指定します。 第2引数には変数のアドレスが必要とされています。 配列の変数名は、その先頭アドレスを返すので、そのままval1と書けばよいです。 第3引数では、変数名に配列の長さをベタ書きします。

ブランチに可変長配列を使いたい

少し手間を加えると可変長配列も扱えます。

  1. 配列の大きさ fN を定義する

  2. 配列 val を定義する

  3. fN のブランチを作る

  4. val のブランチを作る

1Int_t fN;                                 // (1) 設定したい配列の大きさ
2Int_t val[max];                           // (2) val[max]: maxはfNよりも大きな数
3tree->Branch("nch", &fN, "nch/I");        // (3) まずfNをブランチにセットする;fNだと何の変数か分かりづらいので、nch(全チャンネル数の意)に変更した点に注意
4tree->Branch("val", val, "val[nch]/I");   // (4) 次にval[fN]をセットする;maxでも、fNでもなくなく、nchにする点に注意
5
6// (4)を以下のようにすると、"Illegal leaf ..." と怒られる
7tree->Branch("val", val, "val[fN]/I");    // fNには、ブランチ名を入れる必要があるらしい(

可変長文字列を使いたい

 1#include <string.h>    // strlen()を使うために必要
 2
 3const Int_t NMAX_MOJI = 100;
 4char hoge[NMAX_MOJI];
 5Int_t nmoji;
 6tree->Branch("nmoji", &nmoji, "nmoji/I");
 7tree->Branch("moji", hoge, "hoge[nmoji]/C");
 8
 9sprintf(hoge, "hoge-hoge-fuga-ga");
10nmoji = strlen(hoge)
11tree->Fill()

std::vectorを使いたい

1#include <vector>
2
3std::vector<Double_t> vec;
4TTree *tree = new TTree("tree", "tree using vector");
5tree->Branch("vec", &vec);

<vector>をincludeする。 namespaceを定義しない場合はstd::vector<型> 変数名と宣言すること。 当たり前のことだけど、結構忘れてしまう。 ROOT(CINT)を起動させるとvector<型> 変数名で使えてしまうため、よく忘れる…orz。 vector型の変数は実体であるため、第2引数は先頭に&が必要。 arrayと同じようにすると怒られる。 ROOTが空気を読んでくれるため、第3引数はなくてよいみたい。 まぁでも一番最後のブランチにするのが無難かもしれない。