TTree::DrawのSelection部分(第2引数)はbool型判定だけを行っているわけではない

これまでROOTを使い始めて約6年にして、めちゃくちゃ大きな勘違いをしていることに気づきました。それは

TTree::Drawの第2引数はbool型の判定を行っているだけではなく、int型の場合は重みつけをする

ということです。実際に例を載せます。

次のようなTreeデータセットを作ります。x1,2,2,3,11,12,12,13,21,22,22,23として、yxの十の位にセットしたものです。

makeTree() {
   TTree *tree = new TTree("tree","tree");
   Int_t x;
   Int_t y;

   tree->Branch("x",&x,"x/I");
   tree->Branch("y",&y,"y/I");

   x = 1; y = 0; tree->Fill();
   x = 2; y = 0; tree->Fill();
   x = 2; y = 0; tree->Fill();
   x = 3; y = 0; tree->Fill();

   x = 11; y = 1; tree->Fill();
   x = 12; y = 1; tree->Fill();
   x = 12; y = 1; tree->Fill();
   x = 13; y = 1; tree->Fill();

   x = 21; y = 2; tree->Fill();
   x = 22; y = 2; tree->Fill();
   x = 22; y = 2; tree->Fill();
   x = 23; y = 2; tree->Fill();

   TFile *file = new TFile("testTree.root","recreate");
   tree->Write();
   file->Close();
}

これをDrawすると次のようになりますね。

static/img/x

例えば、C言語などで、このif文は通りますよね?

int a = 2;
if (a) {
	cout << "a is not 0" << endl;
}
//実行結果: a is not 0

これは、aの値を、boolean型に評価することでcastしていることになります。そのcastにはa != 0の結果になります。例えば、以下のコードでは

int a = 2;
bool aIsNotZero = a;
// aIsNotZeroはtrueになる

こうなり、0でない値のときはtrueになるということです。

TTree::Drawの条件では?

では、上の例にて十の位が0以外のものをDrawしたい時に、これまでこう書いてしまっていたわけです。

tree->Draw("x>>x_y(30,-0.5,29.5)","y");

第2引数はbool型で評価されるのであれば、3本のPeakのうち一番左のPeakが消えるだけだと思いますよね? その結果がこちらです。

static/img/x_y

は???????????????????

詰められたHistogramの値が変わっています。Entry数は8ですが、積分値は12になっています。

真相

ROOTのTTree::DrawのReferenceにはこう書かれています。

is an expression with a combination of the columns. In a selection all the C++ operators are authorized. The value corresponding to the selection expression is used as a weight to fill the histogram. If the expression includes only boolean operations, the result is 0 or 1. If the result is 0, the histogram is not filled. In general, the expression may be of the form: value*(boolean expression) if boolean expression is true, the histogram is filled with a weight = value.

ざっというと

ここにかかれるselectionの値は重みをつけてヒストグラムに詰めます。結果が0ならばヒストグラムに詰めません

ということです。だから

tree->Draw("x>>x_y(30,-0.5,29.5)","y");

とすると、y = 0の部分はヒストグラムにFillされず、y = 2の部分は重みが2としてFillされ、Peakが成長してしまったということになります。 つまり、ROOTの内部的には

x_y->Fill(11,1);
x_y->Fill(12,1);
x_y->Fill(12,1);
x_y->Fill(13,1);
x_y->Fill(21,2);
x_y->Fill(22,2);
x_y->Fill(22,2);
x_y->Fill(23,2);

という操作が行われたことになります。すると、Fillが呼ばれた回数、すなわちEntry数は8、重みがつけられたカウントの個数、すなわちIntegralは12となるわけです。

結論

サボらずにbool型の条件として書きましょう。

tree->Draw("x>>x_y_neq_0(30,-0.5,29.5)","y!=0")

img/x_y_neq_0

(逆に、これを利用出来ればいいなと思いましたが、今の所私には使い所が思いつかない…)

(5/28 追記)
この重みつけを逆に利用する一例を思いつきました。Multiplicityがあるようなデータを規格化するというシチュエーション。例えば、plasticのtiming spectrumを、multiplicityが異なるもの同士で比較したい時

tree->Draw("plastic.fTiming","1./plastic@.GetEntriesFast()");

と書けば、Multiplicityで規格化されたHistogramが出力されます。Event by eventでMultiplicityの違いを吸収してくれるので、これは便利そうですね。

ちなみに

変数yが0であるという条件を書く時に!yという表現はbool型表現となります。これはy==0と等価です。

x_y0

Shoichiro Masuoka

CNS, the Univ. of Tokyo. Dcotoral student

関連項目