TTree::DrawのSelection部分(第2引数)はbool型判定だけを行っているわけではない
これまでROOTを使い始めて約6年にして、めちゃくちゃ大きな勘違いをしていることに気づきました。それは
TTree::Drawの第2引数はbool型の判定を行っているだけではなく、int型の場合は重みつけをする
ということです。実際に例を載せます。
例
次のようなTreeデータセットを作ります。x
を1,2,2,3,11,12,12,13,21,22,22,23
として、y
をx
の十の位にセットしたものです。
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すると次のようになりますね。
例えば、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が消えるだけだと思いますよね? その結果がこちらです。
は???????????????????
詰められた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")
(逆に、これを利用出来ればいいなと思いましたが、今の所私には使い所が思いつかない…)
(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
と等価です。