解析ツールとしての ROOT - 国立大学法人...
Transcript of 解析ツールとしての ROOT - 国立大学法人...
解析ツールとしてのROOT
山形(計算科学センター)
1. ROOTでグラフを表示する方法
2. 1にするためのデータの格納の例
3. 2にするための生データのデコード手順の例
4. グラフからFitする方法
今回のお題
お手元のPC(とかMac)で、cc.tar.gzを展開しておいて下さい
• kds.kek.jpの「more information」の中にあります
• いきなりtar zxvfすると散らかるのでどっかディレクトリを掘ってから展開して下さい
• lessでC++のソースファイルを見られるようにしておいて下さい
• 画面にソース出すと実質読めないので
まえおき
• CINT
• 豪華クラスライブラリが合体した物
クラスライブラリはかなり豪勢な道具箱
• 何が入ってるのか全部把握するのはほとんどムリ
• やりたいことが出たらまずドキュメントを見て良さそうなものがないか、探してみよう
• リストやベクターなど一見STLにあるからいらなそうなものも
• それらにも存在意義があるのです
ROOTとは
CINT
• C/C++のインタプリタ
• キーボードからC/C++を入力することが出来て、手作業の解析操作に使用する
• ファイルからソースを読み込んでそれに応じた動作も可能
• C,C++を完全サポートしてはいない• むやみとconstをつけまくると動作が変• dynamic castはstatic castと同じ• 「もしcastに失敗したらNULLになる」..ができない
• libcも完全サポートされていない• UNIXのシステムコールは結構ない(accessとか)
インストール
• root.cern.chからバイナリを持ってくる
• tarでどこかに展開
• 展開したところを環境変数ROOTSYSに設定する
% ls $ROOTSYSbin etc include lib share
• LD_LIBRARY_PATHも設定する(たいていは$ROOTSYS/libでよい)
• Macの場合はDYLD_LIBRARY_PATH
• まず「root -l」で立ち上げてみて下さい
• for (int i=0; i<10; i++) { printf("%d\n", i); }
• と入力する(リターンも押す)とそれっぽい動作
• 「.」で始まる特殊命令がある
• .?と入力してみて下さい
• .qで終了。なにかごねたら「.qqqqqqqq」とか入力。
対話的使い方
ファイルから読み込む例
{for (int i=0; i<10; i++) {
for (int j=0; j<10; j++) {printf("%d %d\n", i, j);
}}
}
というファイル(a.cc)をつくる
ファイルから読み込む例
•それを起動時に読み込ませる
• root -l ./a.cc
関数を定義したい
voidmyfunc(int i){
printf("myfunc, arg=%d\n", i);}
voidb(){
for (int i=0; i<3; i++) myfunc(i);}
というファイル(b.cc)をつくる
• root -l ./b.cc で実行
• void b();が実行されていることがわかる
• つまり、ファイル名と一致する関数が呼ばれる
引数も渡せる
voidmyfunc(int i){
printf("myfunc, arg=%d\n", i);}
voidb(int a){
for (int i=0; i<3; i++) myfunc(i+a);}
• root -l ./b.cc(1) で実行
• root -l ./b.ccではエラー
• 文字列の場合はroot -l './b.cc("str")'のように渡す
関数定義はしたいけど実行はしたくない
• CINTを立ち上げてから
• .L b.cc
• とすると関数bは定義されるが、呼び出されない
• .x b.cc
• とすると関数bが定義され、かつ呼び出される
• http://root.cern.ch/root/doc/RootDoc.html• 印刷してだらだら眺める
• http://root.cern.ch/root/Reference.html• 結構重要です
• 後者はプログラムを書いてる最中にやたらと参照することになるので開発マシンに入れておく
読むべきドキュメント
• C++ではポインタはなるべく避けろということになっていますが、ROOTはポインタを非常に多用します
• なので、よくあるROOTのサンプルとちょっと違うかもしれません。
今回はなるべくポインタは使わないでみます。
• intやlongは処理系によってビット長が違うかもしれない
• ふつーの32bit CPU
• Alpha(もういませんかね)
• x86_64
• 昔:intは16bitか?32bitか?
• 今:intは32bitか?64bitか? longは32bitか?64bitか?
• charはsignedか?unsignedか?(ふつうはsignedですね)
基本型
• ROOTの場合は
• Bool_t, Char_t, UChar_t, Short_t, UShort_t, Int_t, UInt_t, Long64_t, Float_t, Double_t
• それぞれのビット幅は違うOSでも同じ
• 64ビットOSでもInt_tは32ビット
様々な基本型がオレオレフレームワークで統一感なく
再定義されているのでROOTもしょうがなく
1. グラフ
グラフの書き方
散布図
ヒストグラム
外からデータを読みこむには
•gnuplot手軽。ユーザーの裾野が広い。他分野にも経験者が見つかりやすい
•ROOT(今回はこっち)ほとんど高エネ業界だけ。複雑なことが出来るが、ひとりぼっちで使うと結構大変
グラフの表示といえば
• ヒストグラムは統計処理するためのもの
• スキャッタプロット(散布図)とは用途が違います
• データの集合に対して
• 傾向をみる
• 平均値をみる
• 分布(ばらつき)をみる
ヒストグラム
• あくまでも点は別々
• スキャッタプロットは作れます
• 最小二乗法でFitとかも出来ます
• 大量の点に対して点別に最小二乗法すると辛い
gnuplotにはヒストグラムがありません
高エネルギー業界では統計処理することが多いので、gnuplotはちょっと用途が異なる
ヒストグラムがないってどゆこと?
• ヒストグラムは「指定しなければ「高さ」が0に決まっておる」
• という前提があるかないか
• 「ヒストグラム」がない場合、全部の点を0と指定してからグラフを用意しなくてはいけない
こんなヒストグラムがあったとする
高さ0のところについて情報を指定しないと等高線プロットが
ROOT
gnuplot
この領域は本来は0の高さのはず
• よくある欲求
• (x,y)の羅列からグラフを表示したい
• (x,y)の渡し方
• テキストファイルで食わせる
• メモリ上の配列で食わせる
• メモリの方からいきます
まずグラフを表示する
グラフの書き方
配列でデータを用意したので、グラフ化したい
散布図
ヒストグラム
オブジェクトを用意して点を格納していきたい
散布図
ヒストグラム
テキストから読み込みたい 散布図
• y = sqrt(x) な配列を作る
• 「root -l」でCINTを立ち上げる
• double x[10], y[10]
• for (int i=0; i<10; i++) { x[i] = i; y[i] = sqrt(i); }
• for (int i=0; i<10; i++) { printf("%f %f\n", x[i], y[i]); }
• 正しく格納されている?
メモリ上に点リストを作ってみる
結果
% root -lroot [0] Double_t x[10], y[10]root [1] for (int i=0; i<10; i++) { x[i] = i; y[i] = sqrt(i); }root [2] for (int i=0; i<10; i++) { printf("%f %f¥n", x[i], y[i]); }0.000000 0.0000001.000000 1.0000002.000000 1.4142143.000000 1.7320514.000000 2.0000005.000000 2.2360686.000000 2.4494907.000000 2.6457518.000000 2.8284279.000000 3.000000
これはまだ.qしないでください
•散布図
•TGraph
•ヒストグラム
•TH2
• ....を使います
データは出来たので、表示しよう
グラフの書き方
配列でデータを用意したので、グラフ化したい
散布図
ヒストグラム
オブジェクトを用意して点を格納していきたい
散布図
ヒストグラム
テキストから読み込みたい 散布図
• TGraph g(10, x, y)• 配列へのポインタと、サイズを渡す
• g.Draw("A*")
• "A" 軸も表示
• "*" マーカーを打つ
• g.Draw()とかg.Draw("L")なども試してみよう
TGraph
g.Draw("A*")
範囲をいじる
この辺にマウスカーソルを持って行く
指さしマークになるので、左ボタンを押したまま6あたりまで移動し、
離す
取り消すときは右クリックから「UnZoom」を選ぶ
g.Draw("A*L")
まだ.qしないでください
「*」について
• 最初Draw("AP")すると小さい点
• 次にDraw("A*")するとでかい点(っていうか星印)
• 次にDraw("AP")してももう小さい点にならない
• Pは「マーカー」を打つ
• *は「マーカー」を星印にして、マーカーを打つ
• 小さい点にもどしたければg.SetMarkerStyle(1)g.Draw("AP")
グラフの書き方
配列でデータを用意したので、グラフ化したい
散布図
ヒストグラム
オブジェクトを用意して点を格納していきたい
散布図
ヒストグラム
テキストから読み込みたい 散布図
TH2
• 2次元ヒストグラム
• TH2は抽象クラス
• 実物はTH2C, TH2S, TH2I, TH2F, TH2Dなどがあります。
• 最後の1文字はマスの中の高さを格納する型です
• char/short/int/float/double
• TH2CだとChar_tなので高さは0~127まで
• TH2Iなら2147483647(約2Gまで)
• TH2FやTH2Dならもっと上までいける
• TH2F h("hist", "histogram of sqrt test", 100, 0, 10, 10, 0, 10);
• 「Name(名前)」「Title(題名)」
• 「x分割数」「xmin」「xmax」
• 「y分割数」「ymin」「ymax」
• for (int i=0; i<10; i++) { h.Fill(x[i], y[i]); }
• h.Draw()
• h.Draw("box")
• ヒストグラムの場合は個別の点についての位置情報はないので、「*」はない
TH2
h.Draw()
0 1 2 3 4 5 6 7 8 9 100
1
2
3
4
5
6
7
8
9
10
histEntries 10Mean x 4.5Mean y 1.931RMS x 2.872RMS y 0.8791
histEntries 10Mean x 4.5Mean y 1.931RMS x 2.872RMS y 0.8791
histogram of sqrt test
点が小さくて見えない
h.Draw("box")
0 1 2 3 4 5 6 7 8 9 100
1
2
3
4
5
6
7
8
9
10
histEntries 10Mean x 4.5Mean y 1.931RMS x 2.872RMS y 0.8791
histEntries 10Mean x 4.5Mean y 1.931RMS x 2.872RMS y 0.8791
histogram of sqrt test
•UsersGuideを見よ
•PDFで「box」を検索して下さい
表示オプションはいろいろある
scat
box
lego2
cont
surf3
text
1 2 7 9 3
3 34 62 60 21 3 1
1 30 196 487 450 195 27 4
3 84 475 1145 1156 463 69 1
6 77 482 1179 1141 459 81 3
1 37 200 460 472 155 21 5
7 24 66 74 34 6 1
2 8 6 1
-10 -8 -6 -4 -2 0 2 4 6 8 10-10
-8
-6
-4
-2
0
2
4
6
8
10
h3Entries 10000Mean x -2.043Mean y -2.001RMS x 2.002RMS y 1.995
h3Entries 10000Mean x -2.043Mean y -2.001RMS x 2.002RMS y 1.995
h3マス目が細かすぎるとだめ
重ね書き
• ヒストグラムを2つ作ってみよう
• root -l ./twohist.cc
• h1とh2が出来ている
h1.Draw()
h2.Draw()
h1.Draw("same")
色くらい変えたい
h1.SetMarkerColor(kBlue)h2.SetMarkerColor(kRed)
h2.Draw()h1.Draw("same")
GUIでもかえられます
• 青が濃いところで右クリックし、コンテキストメニューから「DrawPanel」を選ぶ
• 点の上じゃないとコンテキストメニューが出てこないので薄いヒストグラムの場合は右クリック力が必要
• でなければh1.DrawPanel()って打てばいいです
これらを表示した後、セーブしたい
• ウインドウのメニューバーをみると
とかするとセーブできます。(SaveAsで名前指定も可能)
NameとTitleに関する注意
• ROOTのクラスのインスタンスはNameとTitleを持つ物があります。
• 持つ物もかなりありますが、持たない物もかなりあります
• Nameはある程度ユニークな識別子でなくてはいけません
• スペースとか入れないこと
• Titleは重複してもよく、好きな文章を入れて良い
CINTはNameを自動的に変数に追加してくる
% root -lroot [0] TH1F hogera("h", "histogram", 10, 0, 10)root [1] h(class TH1F*)0x101817000root [2] hogera(class TH1F)4320227328root [3]
hなどという変数は宣言していないのになぜか使用できる
Nameの重複は避けること
% root -l root [0] TH1F h1("h", "h1", 10, 0, 10)root [1] TH1F h2("h", "h2", 10, 0, 10)Warning in <TH1::Build>: Replacing existing histogram: h (Potential memory leak).root [2]
違うインスタンスを生成したつもりでも破壊される
• 2変数(x,y)を表示するときはTGraphとTH2が使える
• 1変数(x)の値の分布を見るときはTGraphは使えない
• TH2と同様に
• TH1F h("h1", "h1 sample", 100, 0, 10);
• h.FillRandom("expo", 1000)
• (指数関数になる乱数分布で1000点埋める)
• h.Draw()
TH1
事前に全部配列に埋めなくてもいい
っていうかむしろ埋めない方が普通
グラフの書き方
配列でデータを用意したので、グラフ化したい
散布図
ヒストグラム
オブジェクトを用意して点を格納していきたい
散布図
ヒストグラム
テキストから読み込みたい 散布図
グラフの書き方
配列でデータを用意したので、グラフ化したい
散布図
ヒストグラム
オブジェクトを用意して点を格納していきたい
散布図
ヒストグラム
テキストから読み込みたい 散布図
• ではCINT一旦終了してください
• 再度立ち上げて
• TGraph g(1000)for (int i=0; i<1000; i++) { g.SetPoint(i, i, sqrt(i)); }g.Draw("AP")
TGraphの場合
結果
グラフの書き方
配列でデータを用意したので、グラフ化したい
散布図
ヒストグラム
オブジェクトを用意して点を格納していきたい
散布図
ヒストグラム
テキストから読み込みたい 散布図
• TH2F h("hist", "histogram test", 100, 0, 1000, 100, 0, 100);for (int i=0; i<1000; i++) { h.Fill(i, sqrt(i)); }h.Draw()
• さっきより見やすい
• 点の数が増えたから
• 点が数個しかない場合はTH2にすると不幸
TH2の場合
• TGraph
• 点の数を指定する必要がある
• 点の数が膨大になると危険(100万点とか)
• TH2
• マス目の範囲・細かさを指定する必要がある
• 範囲の見積もりを誤るとしょうもない表示
最初に指定する内容が異なる
いずれも最初の見積もりが大事
でも測定完了後のデータ処理なら何度でもやりなおせばいいです。
配列の場合はわかった。テキストファイルの場合は?
グラフの書き方
配列でデータを用意したので、グラフ化したい
散布図
ヒストグラム
オブジェクトを用意して点を格納していきたい
散布図
ヒストグラム
テキストから読み込みたい 散布図
• ファイルにはx,yの羅列がある
• 羅列ファイルのつくりかた例
• .>outfile.txtfor (int i=0; i<1000; i++) { printf("%d %f\n", i, sqrt(i)); }.>
• ^Zしてoutfile.txtを見てみよう
TGraphの場合
outfile.txt% head outfile.txt 0 0.0000001 1.0000002 1.4142143 1.7320514 2.0000005 2.2360686 2.4494907 2.6457518 2.8284279 3.000000
こんなふうになってるはず
読み込んで表示
•TGraph g("outfile.txt");•g.Draw("AP")
結果(タイトルがファイル名になっている)
• いい方法はありません
• 一見使えそうな名前のTGraph::GetHistogram()は、軸情報のみを含んだヒストグラムを返す
TH
•それがTTree
• CERNLIBのNTupleに相当する
テキストかオンメモリ以外に方法はないのか?
2. グラフ化するデータの格納
データの格納の仕方
TTree
表を作る
列を作る
行を増やす
列の値からグラフを生成
表のセルに波形を格納
TFileTTreeをセーブする
データの格納の仕方
TTree
表を作る
列を作る
行を増やす
列の値からグラフを生成
表のセルに波形を格納
TFileTTreeをセーブする
• ROOTなので、これはオブジェクトです
• エクセルの表のようなもの(シート。ブックではない)
TTreeとは?
• 「セル」にオブジェクトが格納できる• 構造体も入れられる• 構造体のメンバーを個別のセルに格納しなくてもよい
• 可変長配列も入れられる• 列は名前で指定する• 「行」は増える一方で、行の削除とか詰めるとか入れ替えはできない• 列は一定でなくてはいけない• セル間の参照はできない• グラフ化するときにマスクする行を指定できる• 膨大な行数の処理が出来る• 行はIntではなくLong64_tで指定される• メモリからあふれると古い行を順次ファイルに書き出す
エクセル表との違い
• 「セル」にオブジェクトが格納できる• 構造体も入れられる• 構造体のメンバーを個別のセルに格納しなくてもよい
• 可変長配列も入れられる• 列は名前で指定する• 「行」は増える一方で、行の削除とか詰めるとか入れ替えはできない• 列は一定でなくてはいけない• セル間の参照はできない• グラフ化するときにマスクする行を指定できる• 膨大な行数の処理が出来る• 行はIntではなくLong64_tで指定される• メモリからあふれると古い行を順次ファイルに書き出す
エクセル表との違い
表よりもSQLなDBに
ちょっと近い
用語の対応
•シート => Tree
•列 => Branch
•行 => Entry
データの格納の仕方
TTree
表を作る
列を作る
行を増やす
列の値からグラフを生成
表のセルに波形を格納
TFileTTreeをセーブする
• 表自体をつくる
• TTree t("tree", "tree test")
• これも「名前」と「題名」
• (x,y)を格納するための列をつくる
• Double_t x, y;t.Branch("x", &x, "x/D");t.Branch("y", &y, "y/D");
• 「名前」「バッファへのポインタ」「型情報」
では表を作ってみる
型情報の指定
• 単純な数値の場合
• 「名前」「/」「型」
• “x/D” == xという名前で、Double_tだ
• 配列の場合
• 「名前[長さ]」「/」「型」
Char_t BUChar_t bShort_t SUShort_t sInt_t IUInt_t i
Double_t DFloat_t F
データの格納の仕方
TTree
表を作る
列を作る
行を増やす
列の値からグラフを生成
表のセルに波形を格納
TFileTTreeをセーブする
• for (int i=0; i<1000; i++) { x = i; y = sqrt(i); t.Fill(); }
• t.Fill()した時のx, yの値を行として格納する
• t.Print()
表はできたので、行を追加していく
root [4] for (int i=0; i<1000; i++) { x = i; y = sqrt(i); t.Fill(); }root [5] t.Print()*******************************************************************************Tree : : **Entries : 1000 : Total = 17451 bytes File Size = 0 ** : : Tree compression factor = 1.00 ********************************************************************************Br 0 :x : x/D **Entries : 1000 : Total Size= 8602 bytes One basket in memory **Baskets : 0 : Basket Size= 32000 bytes Compression= 1.00 **............................................................................**Br 1 :y : y/D **Entries : 1000 : Total Size= 8602 bytes One basket in memory **Baskets : 0 : Basket Size= 32000 bytes Compression= 1.00 **............................................................................*
1000行ある
• テキストで見える
• 表示は基本的に%fや%gなので、0x7FFF0001などの32bit値を表示すると残念になる。
t.Scan()root [6] t.Scan()************************************* Row * x * y ************************************** 0 * 0 * 0 ** 1 * 1 * 1 ** 2 * 2 * 1.4142135 ** 3 * 3 * 1.7320508 ** 4 * 4 * 2 ** 5 * 5 * 2.2360679 ** 6 * 6 * 2.4494897 ** 7 * 7 * 2.6457513 ** 8 * 8 * 2.8284271 ** 9 * 9 * 3 ** 10 * 10 * 3.1622776 ** 11 * 11 * 3.3166247 ** 12 * 12 * 3.4641016 ** 13 * 13 * 3.6055512 ** 14 * 14 * 3.7416573 ** 15 * 15 * 3.8729833 *
データの格納の仕方
TTree
表を作る
列を作る
行を増やす
列の値からグラフを生成
表のセルに波形を格納
TFileTTreeをセーブする
• t.Draw("y:x")
• これは散布図
• t.Draw("y")
• これはヒストグラム
グラフで表示する
x0 200 400 600 800 1000
y
0
5
10
15
20
25
30
y:x
htempEntries 1000Mean 21.07RMS 7.465
y0 5 10 15 20 25 300
24
68
10
12141618
2022
htempEntries 1000Mean 21.07RMS 7.465
y
• t.Draw("y:x>>h")
Draw("y:x")でヒストグラムを作る
0 200 400 600 800 10000
5
10
15
20
25
30
hEntries 1000Mean x 499.5Mean y 21.07RMS x 288.7RMS y 7.465
hEntries 1000Mean x 499.5Mean y 21.07RMS x 288.7RMS y 7.465
y:x
「>>名前」で、「名前」をもつヒストグラムに充填することを指示できる。
(ストリームに対するI/Oと一緒の芸風)
• t.Draw("y+x:x")
• t.Draw("y:sqrt(x)")
• あんまりいろいろは使えません
• ビットシフトしたい際に「>>」は使えないことに注意
セルの値からなにか計算して表示する
データの格納の仕方
TTree
表を作る
列を作る
行を増やす
列の値からグラフを生成
表のセルに波形を格納
TFileTTreeをセーブする
• トリガー毎にFlashADCの波形を1行で格納できる
• まずサンプル波形を作ってみよう
• こういうやつ
セルには配列が格納できるので
0 20 40 60 80 1000
0.2
0.4
0.6
0.8
1
Graph
• ガウス分布の関数はTMathクラスの中にある• Double_t TMath::Gaus(Double_t x, Double_t mean = 0,
Double_t sigma = 1, Bool_t norm = kFALSE)
ガウス分布な波形を作ってみる
0 20 40 60 80 1000
0.2
0.4
0.6
0.8
1
Graph
こんな分布
mean = 50
sigma = 10
% root -lroot [0] TGraph g(100)root [1] for (int i=0; i<100; i++) g.SetPoint(i, i,TMath::Gaus(i, 50, 10));root [2] g.Draw("A*L")
信号のタイミングを多少ランダムにしてみる
0 20 40 60 80 1000
0.2
0.4
0.6
0.8
1
Graph ここをランダムに揺らす
libcの乱数はフラット分布しかつくれない
h1Entries 5000Mean 4.997RMS 2.855
0 1 2 3 4 5 6 7 8 9 100
10
20
30
40
50
60
70
80
90
100
h1Entries 5000Mean 4.997RMS 2.855
h1 sample
こんなかんじ
TRandomクラス
• libcと異なり、いろんな分布の乱数を作れる• TRandom rnd などとしてインスタンスを作る• 乱数の「種」はインスタンス毎にある
• インスタンスから分布の形を指定して乱数を生成する• rnd.Uniform(0,10); // 0..10の範囲でフラット分布• rnd.Exp(10);• rnd.Poission(3); (ポアソン分布)• rnd.Gauss(3); (ガウス分布)
h1Entries 5000Mean 2.648RMS 2.311
0 1 2 3 4 5 6 7 8 9 100
20
40
60
80
100
120
140
160
180
200
h1Entries 5000Mean 2.648RMS 2.311
h1 sampleTRandomクラス
• libcと異なり、いろんな分布の乱数を作れる• TRandom rnd などとしてインスタンスを作る• 乱数の「種」はインスタンス毎にある
• インスタンスから分布の形を指定して乱数を生成する• rnd.Uniform(0,10); // 0..10の範囲でフラット分布• rnd.Exp(10);• rnd.Poission(3); (ポアソン分布)• rnd.Gauss(3); (ガウス分布)
h1Entries 5000Mean 2.648RMS 2.311
0 1 2 3 4 5 6 7 8 9 100
20
40
60
80
100
120
140
160
180
200
h1Entries 5000Mean 2.648RMS 2.311
h1 sampleTRandomクラス
• libcと異なり、いろんな分布の乱数を作れる• TRandom rnd などとしてインスタンスを作る• 乱数の「種」はインスタンス毎にある
• インスタンスから分布の形を指定して乱数を生成する• rnd.Uniform(0,10); // 0..10の範囲でフラット分布• rnd.Exp(10);• rnd.Poission(3); (ポアソン分布)• rnd.Gauss(3); (ガウス分布)
h1Entries 5000Mean 2.995RMS 1.738
0 1 2 3 4 5 6 7 8 9 100
200
400
600
800
1000
h1Entries 5000Mean 2.995RMS 1.738
h1 sample
h1Entries 5000Mean 2.648RMS 2.311
0 1 2 3 4 5 6 7 8 9 100
20
40
60
80
100
120
140
160
180
200
h1Entries 5000Mean 2.648RMS 2.311
h1 sampleTRandomクラス
• libcと異なり、いろんな分布の乱数を作れる• TRandom rnd などとしてインスタンスを作る• 乱数の「種」はインスタンス毎にある
• インスタンスから分布の形を指定して乱数を生成する• rnd.Uniform(0,10); // 0..10の範囲でフラット分布• rnd.Exp(10);• rnd.Poission(3); (ポアソン分布)• rnd.Gauss(3); (ガウス分布)
h1Entries 5000Mean 2.995RMS 1.738
0 1 2 3 4 5 6 7 8 9 100
200
400
600
800
1000
h1Entries 5000Mean 2.995RMS 1.738
h1 sample
h1Entries 5000Mean 3.009RMS 0.9818
0 1 2 3 4 5 6 7 8 9 100
2040
6080
100
120140
160180
200220
h1Entries 5000Mean 3.009RMS 0.9818
h1 sample
• TRandom rnd;double center;Graph g(100);
• center = rnd.Exp(10); for (int i=0; i<100; i++) { g.SetPoint(i, i, TMath::Gaus(i, center, 10)); } g.Draw("A*L")2行で入力すること
• ^Pを押してRETURN
• Expなので確かに左に寄ることが多いですね
Expで揺らしてみる
1イベント分の波形を作った。次は?
• これをTTreeの1行に格納する
• 配列を入れよう
• Double_t v[100];t.Branch("signal", v, "signal[100]/D");
• とすればよい
• &vではないことに注意
• signalは縦軸にあたる
• 表示するときの横軸も必要なので、
• t.Branch("x", x, "x[100]/I"); もつける
波形を「1行」に格納するにはどうしたらよいか
0 20 40 60 80 1000
0.2
0.4
0.6
0.8
1
Graph
sign
al
x
• Double_t z[8][100]; // 配列領域の確保t.Branch("z", z, "z[8][100]/D"); //とかする
• Cには厳密な意味での多次元配列はありません
• 「C++ならばvectorとかつかえ」などいろいろな主張があります。
• が、TTreeにvectorはそのままでは格納できない
脱線ですが、2次元配列(っぽいもの)も入ります
具体例波形を1000回入れてみる
% cat randompulse1000.cc { TTree t; Double_t val[100]; Int_t x[100]; t.Branch("signal", val, "signal[100]/D"); t.Branch("x", x, "x[100]/I"); TRandom rnd; for (int event=0; event<1000; event++) { Double_t center = rnd.Exp(10); for (int bin=0; bin<100; bin++) { x[bin] = bin; val[bin] = TMath::Gaus(bin, center, 10); } // now val contains random pulse t.Fill(); }}
• t.Scan()• t.Draw("signal:x")• 重なっててよくわかりませんね• とりあえず数イベントだけ表示してみる• t.Draw("signal[x]:x", "", "", 1)• 1イベントだけ• 点が小さいですね
• t.Draw("signal[x]:x", "", "*", 1)• t.Draw("signal[x]:x", "", "*", 4)
格納できました
• t.Scan()• t.Draw("signal:x")• 重なっててよくわかりませんね• とりあえず数イベントだけ表示してみる• t.Draw("signal[x]:x", "", "", 1)• 1イベントだけ• 点が小さいですね
• t.Draw("signal[x]:x", "", "*", 1)• t.Draw("signal[x]:x", "", "*", 4)
格納できました************************************************ Row * Instance * signal * x ************************************************* 0 * 0 * 0.1744162 * 0 ** 0 * 1 * 0.2092082 * 1 ** 0 * 2 * 0.2484436 * 2 ** 0 * 3 * 0.2921015 * 3 ** 0 * 4 * 0.3400140 * 4 ** 0 * 5 * 0.3918474 * 5 ** 0 * 6 * 0.4470891 * 6 *
• t.Scan()• t.Draw("signal:x")• 重なっててよくわかりませんね• とりあえず数イベントだけ表示してみる• t.Draw("signal[x]:x", "", "", 1)• 1イベントだけ• 点が小さいですね
• t.Draw("signal[x]:x", "", "*", 1)• t.Draw("signal[x]:x", "", "*", 4)
格納できました************************************************ Row * Instance * signal * x ************************************************* 0 * 0 * 0.1744162 * 0 ** 0 * 1 * 0.2092082 * 1 ** 0 * 2 * 0.2484436 * 2 ** 0 * 3 * 0.2921015 * 3 ** 0 * 4 * 0.3400140 * 4 ** 0 * 5 * 0.3918474 * 5 ** 0 * 6 * 0.4470891 * 6 *
• t.Scan()• t.Draw("signal:x")• 重なっててよくわかりませんね• とりあえず数イベントだけ表示してみる• t.Draw("signal[x]:x", "", "", 1)• 1イベントだけ• 点が小さいですね
• t.Draw("signal[x]:x", "", "*", 1)• t.Draw("signal[x]:x", "", "*", 4)
格納できました************************************************ Row * Instance * signal * x ************************************************* 0 * 0 * 0.1744162 * 0 ** 0 * 1 * 0.2092082 * 1 ** 0 * 2 * 0.2484436 * 2 ** 0 * 3 * 0.2921015 * 3 ** 0 * 4 * 0.3400140 * 4 ** 0 * 5 * 0.3918474 * 5 ** 0 * 6 * 0.4470891 * 6 *
x0 20 40 60 80 100
signal
0
0.2
0.4
0.6
0.8
1
signal:x
Drawの引数
• 1つめ: グラフにする点を「:」で羅列した物
• 「y:x」とか「z:y:x」の順序
• 2つめ: 条件式(条件に見合った点だけをプロットする)
• 3つめ: グラフ化するときのオプション(「*」とか「lego」)
• 4つめ: 何行分表示するか
• 5つめ: 何行目から表示するか
• 4つめと5つめを指定することで途中から数イベント分だけ表示、などが可能
• t.Draw("signal[]:x") // さっきと同じ
• t.Draw("signal:x") // さっきと同じ
• 列の要素が配列の場合、[]が指定されているアイテムは配列の要素毎にバラバラの点として扱われる
• []が無い場合も端から端まで走査される
• 2次元配列の場合に重要
• 複数の配列(長さは異なる)が列になっているときも注意
添え字の省略
• t.Draw("signal[0]")の様に、添え字を指定する
• t.Draw(“signal[0]:x”)と書くと、xはx[]と解釈され、 signal[0]:x[0], singal[0]:x[1], signal[0]:x[2], ...がプロットされてしまう
走査したくない場合は?
• いちいち添え字用の列をつくるの?
• そんなことしなくていい
x[n] = n なので、無駄臭く感じる
• Entry$: いま何行目に注目しているか
• Iteration$: []を走査した順番
• つまり、t.Draw("signal:Iteration$")でよい
Drawで使える特殊変数
************************************************ Row * Instance * signal * x ************************************************* 0 * 0 * 0.1744162 * 0 ** 0 * 1 * 0.2092082 * 1 ** 0 * 2 * 0.2484436 * 2 ** 0 * 3 * 0.2921015 * 3 ** 0 * 4 * 0.3400140 * 4 ** 0 * 5 * 0.3918474 * 5 ** 0 * 6 * 0.4470891 * 6 ** 0 * 7 * 0.5050430 * 7 ** 0 * 8 * 0.5648324 * 8 ** 0 * 9 * 0.6254145 * 9 ** 0 * 10 * 0.6856040 * 10 ** 0 * 11 * 0.7441077 * 11 ** 0 * 12 * 0.7995678 * 12 ** 0 * 13 * 0.8506127 * 13 *
• TreeにはAliasがあります
• t.SetAlias("xx", "Iteration$")
• t.Draw("signal:xx")
なげえー
• TTreeには可変長配列も格納できる
• C++では配列を確保するときに変数が使える
• Int_t n;n = ...,Double_t z[n];t.Branch("n", &n, "n/I");t.Branch("z", z, "z[n]/D");
• のようなことをやってもよい(nは必ずBranchにすること)
可変長配列の格納
• 列をつくるときに指定したポインタの中身が変わってはいけない
• 変わっても良いが、変わった場合はそれなりの手続きが必要
• 多次元配列の場合はDouble_t **zDouble_t *z[8]Double_t z[8][100]の違いがわかってから使った方が良い(ROOTは最後のタイプを仮定します)
可変長配列の注意
• ROOTの提供するクラスのインスタンスはたいていはファイルに書き出せます
• クラス定義ではなく、インスタンスをI/Oできる
• ROOT自体がクラスのI/O手続きを用意しているので、バイトオーダーとか気にしなくてもよい
• でもクラス定義そのものを格納することは無理
• インスタンスのI/O方法をROOTが知っている必要がある
• あなたの定義したクラスについては知らないので、教える必要がある
• 自作クラスをI/Oしたい場合はTObjectを継承してクラスを生成し、ROOTが参照するための辞書を作る
• 今回は触れません
• TObjectを継承することは必須ではないが、したほうがいろいろ楽(太るけど)
ファイルへの出力
ファイルに書ける物はソケットにも書ける
• TSocket/TServerSocketクラスを利用することで、別のマシンにオブジェクトを送りつけることが出来る
• TMessageにオブジェクトをWriteし、TSocketでそのTMessageを送りつける
• 受信側はTSocketからTMessage(1個)を読み出し、それからオブジェクトを取り出す
• リストや集合も1個のオブジェクトとして送れる(このときSTLのリストをつかうより便利)
データの格納の仕方
TTree
表を作る
列を作る
行を増やす
列の値からグラフを生成
表のセルに波形を格納
TFileTTreeをセーブする
• インスタンス「等」を格納するためのファイル• 入っているもの一覧はls()で取れる• ファイルから読み出す方法にはGet/GetObject/Read等がある• 先頭から1アイテムづつ読み捨てしなくてもよい• TObject * Get(): TFileのメソッド
• TObject*を返すので、TObjectのメソッドでできることしかしないならこれが楽• Putはないので、WriteObjectを使用する
• void GetObject("名前", ポインタ):• ポインタへのキャストが正しいか確認付き• 見つからないか、キャストが正しくない場合はNULLになる
• Read()/Write(): インスタンスのメソッド• どこのファイルに書くかはgDirectoryに依存する
TFile
• TH1F h1("hist1", "empty histogram 1", 10, 0, 10);TH1F h2("hist2", "empty histogram 2", 10, 0, 10);TFile f("ftest.root", "recreate");f.cd(); // なくても自動的に移動しているh1.Write();h2.Write();f.Close();
• recreate: 一度ファイルを削除するupdate: 追加+上書きreadonly: 無指定
• 書けています
例1: ヒストグラムを格納
中身の確認方法(1)
% root -lroot [0] TFile f("ftest.root")root [1] f.ls()TFile** ftest.root TFile* ftest.root KEY: TH1F hist1;1 empty histogram 1 KEY: TH1F hist2;1 empty histogram 2root [2] .q
ここに出るので、ヒストグラムの名前と題名は識別可能な程度に書きましょう
中身の確認方法(2)
% root -l ./ftest.root root [0] Attaching file ./ftest.root as _file0...root [1] _file0.ls()TFile** ./ftest.root TFile* ./ftest.root KEY: TH1F hist1;1 empty histogram 1 KEY: TH1F hist2;1 empty histogram 2
このとき、宣言していないのにhist1, hist2が使用可能になっている
• どのファイルに対してI/Oしているかを示す大域変数
• TFileは中にディレクトリ構造を持てる
• ディレクトリの中にもディレクトリがたてられる
• なので、gFileではなくgDirectoryという名前です
• I/Oする対象を移動するときはTFile::cd()を使って切り替えます
• 同じNameを持つインスタンスを生成しようとするとCINTによって古い方が破壊されるが、ディレクトリが異なれば破壊されない
gDirectory
異なるディレクトリに同じNameの別のインスタンスを入れてみる
{ TFile f("dtest.root", "recreate"); f.cd();
TH1F h1("hist", "empty histogram 1", 10, 0, 10); h1.Write();
f.mkdir("child1"); f.cd("child1"); TH1F h2("hist", "empty histogram 2", 10, 0, 10); h2.Write();
}
gDirectoryはここで変化する
できたTFileはどうなっているか% root -l ./dtest.rootroot [0] Attaching file ./dtest.root as _file0...root [1] _file0.ls() TFile** ./dtest.root TFile* ./dtest.root KEY: TH1F hist;1 empty histogram 1 KEY: TDirectoryFile child1;1 child1root [2] _file0.cd("child1")(Bool_t)(1)root [3] _file0.ls() TFile** ./dtest.root TFile* ./dtest.root TDirectoryFile* child1 child1 KEY: TH1F hist;1 empty histogram 2 KEY: TH1F hist;1 empty histogram 1 KEY: TDirectoryFile child1;1 child1
ディレクトリがある
ヒストグラムがバラバラに入っている
Nameによって出現するCINTの変数はcdすると勝手に変わる% root -l ./dtest.rootroot [0] Attaching file ./dtest.root as _file0...root [1] _file0.ls() TFile** ./dtest.root TFile* ./dtest.root KEY: TH1F hist;1 empty histogram 1 KEY: TDirectoryFile child1;1 child1root [2] hist(class TH1F*)0x101817400root [3] hist->GetTitle()(const char* 0x1026154f8)"empty histogram 1"root [4] _file0.cd("child1")(Bool_t)(1)root [5] hist(class TH1F*)0x101853000root [6] hist->GetTitle()(const char* 0x1026276a8)"empty histogram 2"
最初はこれだった
cdすると違う物に
• 実は表示しているウインドウ自体もオブジェクトなので、TFileに格納できます
例2: キャンバスを格納
何か表示してみる
% root -lroot [0] TH1F h("h", "histogram", 100, 0, 10)root [1] h.FillRandom("gaus", 1000)root [2] h.Draw() h
Entries 1000Mean 0.8044RMS 0.6168
0 1 2 3 4 5 6 7 8 9 100
10
20
30
40
50
60
70
80
hEntries 1000Mean 0.8044RMS 0.6168
histogram
ウインドウのタイトルバーを見る
• 「c1」と書いてあります
• CINTに「c1」<RETURN>と入力すると(class TCanvas*)0x1018b0e00というので、c1というNameをもつオブジェクトがありそう
• これをセーブする
• 実はc1->SaveAs(“hogera.eps”)とかやるとEPSも出せます
• バッチ処理時に便利
こんなかんじ% root -lroot [0] TH1F h("h", "histogram", 100, 0, 10)root [1] h.FillRandom("gaus", 1000)root [2] h.Draw()<TCanvas::MakeDefCanvas>: created default TCanvas with name c1root [3] TFile f("canvassave.root", "recreate")root [4] c1(class TCanvas*)0x1018b0e00root [5] c1->Write("canvas_c1")(Int_t)(7675)root [6] f.ls()TFile** canvassave.root TFile* canvassave.root KEY: TCanvas canvas_c1;1 c1root [7] f.Close()root [8] .q
内容を確認
% root -l ./canvassave.rootroot [0] Attaching file ./canvassave.root as _file0...root [1] _file0.ls()TFile** ./canvassave.root TFile* ./canvassave.root KEY: TCanvas canvas_c1;1 c1root [2] canvas_c1(class TCanvas*)0x101817400root [3] canvas_c1->Draw()root [4] .q
ここでウインドウが再現される
データの格納の仕方
TTree
表を作る
列を作る
行を増やす
列の値からグラフを生成
表のセルに波形を格納
TFileTTreeをセーブする
• これもTTreeをWrite()すればよい。
• 実はTTreeはFill()した際に古い方をときどきファイルに勝手に書き出している
• 明示的にWriteしなくても。
• でもWriteしないとClose()するときにファイルから抹消される
TTreeをファイルに書く
• 2G(デフォルト)を超えると勝手にTFileはCloseされ、新しいファイルが開かれる。
• 1つのファイルにTTreeと他のものを書いているとTTree以外のものにとって危険
• TTreeは単独でファイルに書くようにしましょう
TTreeでファイルにどんどん書き出されるとファイルがどんどん成長
• 生データが既に違うファイルで用意されている
• テキストファイル
• バイナリファイル
• 直接TTreeで書かれている
• これまでの実験はたいていそうではない
生データの取り扱い
• TTree::ReadFile(filename, branches)を使う
• outfile.txtがあるので、再利用してみます
テキストファイルからTTree
% root -lroot [0] TTree troot [1] t.ReadFile("outfile.txt", "x/D:y/D")(Long64_t)1000root [2] t.Print()*******************************************************************************Tree : : **Entries : 1000 : Total = 17451 bytes File Size = 0 ** : : Tree compression factor = 1.00 ********************************************************************************Br 0 :x : x/D **Entries : 1000 : Total Size= 8602 bytes One basket in memory **Baskets : 0 : Basket Size= 32000 bytes Compression= 1.00 **............................................................................**Br 1 :y : y/D **Entries : 1000 : Total Size= 8602 bytes One basket in memory **Baskets : 0 : Basket Size= 32000 bytes Compression= 1.00 **............................................................................*root [3] t.Draw("y:x")<TCanvas::MakeDefCanvas>: created default TCanvas with name c1
x0 200 400 600 800 1000
y
0
5
10
15
20
25
30
y:x
• TTree::ReadFile(filename, branches)を使う
• outfile.txtがあるので、再利用してみます
テキストファイルからTTree
% root -lroot [0] TTree troot [1] t.ReadFile("outfile.txt", "x/D:y/D")(Long64_t)1000root [2] t.Print()*******************************************************************************Tree : : **Entries : 1000 : Total = 17451 bytes File Size = 0 ** : : Tree compression factor = 1.00 ********************************************************************************Br 0 :x : x/D **Entries : 1000 : Total Size= 8602 bytes One basket in memory **Baskets : 0 : Basket Size= 32000 bytes Compression= 1.00 **............................................................................**Br 1 :y : y/D **Entries : 1000 : Total Size= 8602 bytes One basket in memory **Baskets : 0 : Basket Size= 32000 bytes Compression= 1.00 **............................................................................*root [3] t.Draw("y:x")<TCanvas::MakeDefCanvas>: created default TCanvas with name c1
• TFile outf("outtext.root", "recreate")
• outf.cd()
• t.Write()
• outf.ls()
• outf.Close()
これをTFileにセーブする
3. 実データのデコード例
具体的な作業例
生データのバイナリファイルからTTreeに変換する
TTreeから1イベントづつ読み出してデコードする
デコードした結果を別のTTreeに格納する
Fitする
誤差について考える
• 実習で使うファイルを仮定してみます
• よくある形式
• イベント
• 長さ等を含むヘッダ
• ヘッダが示す長さ分の本体
• ..が羅列されている
• まずデータを書いた人からヘッダ情報を聞き出すこと
典型的なバイナリファイルの構造
header #0
body #0
header+bodyの長さを含む
header #1
body #2
header #1
body #2
以下繰り返し.....
ファイルの先頭
読み出しソフトウェアが生成する
主にハードウェアが生成する
今回の一番外側のヘッダはこうなっている(担当講師情報)
struct event_header { unsigned int magic; unsigned int size; unsigned int event_number; unsigned int run_number; unsigned int node_id; unsigned int type; unsigned int nblock; unsigned int reserve;};
かならず0x45564e54
ヘッダと本体の合計の「ワード長」(バイト長ではない)
ヘッダやフッタの情報を得たら構造体を用意すること
• * ((unsigned int *)p + 5)などと書く人がけっこういます
• 後から読む人の身にもなって下さい
• read/writeと違うところ
• file descriptor(int)ではなくprintfなどと同じくFILE *に対するIO
• バッファリングされている
• 「1要素のサイズ」と「要素の数」の2つを指定する
• 処理したバイト数ではなく処理した要素の数を返す
• 処理が要素の途中で途切れることはない
• (バッファリングされているから)
長さを指定してのI/Oにはfread/fwriteが便利
脱線: 生のsocketからfread/fwriteしたいときは?
• fdopenせよ
#include <Rtypes.h>
#include <stdio.h>#include <assert.h>
struct event_header { unsigned int magic; unsigned int size; unsigned int event_number; unsigned int run_number; unsigned int node_id; unsigned int type; unsigned int nblock; unsigned int reserve;};
main(int argc, char ** argv){ if (argc < 2) exit(0);
UInt_t * body_bin = new UInt_t[1024 * 1024];
for (int i=1; i<argc; i++) { FILE * file_bin = fopen(argv[i], "r");
まずは正しく処理できるかフォーマットチェック
int nevent = 0; while (1) { int ret; struct event_header header;
ret = fread(&header, sizeof(header), 1, file_bin); if (ret != 1) break;
assert(header.magic == 0x45564e54);
int body_nbyte = (header.size*4) - sizeof(header);
ret = fread(body_bin, body_nbyte, 1, file_bin); if (ret != 1) break;
assert(body_bin[0] == 0x7FFF0008);
printf("%d %d¥n", nevent, body_nbyte); nevent++; }
fclose(file_bin); }}
読んでヘッダの確認をするだけ
bincheck.cc
CINT経由じゃなくて実行ファイルを作ってみよう
OPT=-gCXXFLAGS=`root-config --cflags` $(OPT)LDLIBS=`root-config --libs`
今回はMakefileはこのくらいでいい
で、「make bincheck」とかすればよし
脱線ですが、TThreadも使う場合は
LDLIBS=`root-config --libs` -lThread
スレッドライブラリを追加
脱線ですが、グラフ表示も使う場合は
• `root-config --libs` じゃなくて `root-config --glibs`
• assert(式)
• 見た目if文っぽいがthen節がなく、プログラムが死亡する。
• 死亡するときにファイル名・行番号・条件文がstderrに出る
• coreも吐く
• gdbから呼び出すとバックトレースが取れる
• if ... fprintf(stderr でもいいが、実質流れちゃって誰も見ない
• -DNDEBUGしてコンパイルすると、迂回される
• チェックが原因で遅くなって、それでも高速化したければどうぞ
いっぱい出てくるassertって何?
• Cで使える
• 例外の場合もcatchする人がいないと死ぬことは同じ
• 残念ながらそこらへんの物件はcatchしないとか、しても「error」とかprintfするだけ。
• だから動作的にassertと同じ
• assertと違い、どこで例外が発生したか画面を見てもわからない
• どうしたらいいかわかっている場合は例外を投げてcatchを用意する
• 逆にどうしたらいいかわからない場合はassert
• assertで死んで困るようなら正しい対処を考えよう
例外(exception)との違い
ではバイナリをTreeにいれます
• TTree t
• t.Branch("nword", &nword, "nword/I");
• t.Branch("rawdata", body_bin, "rawdata[nword]/i");
• として、Fillすればよい
body_bin[]に生データが入っているので、これをTTreeに配列として入れる
bin2tree.cc
できたファイル% root -l ./rawdata.root root [0] Attaching file ./rawdata.root as _file0...root [1] _file0.ls()TFile** ./rawdata.root TFile* ./rawdata.root KEY: TTree rawdata;1 rawdataroot [2] rawdata(class TTree*)0x101817400root [3] rawdata->Print()*******************************************************************************Tree :rawdata : rawdata **Entries : 1024 : Total = 525615 bytes File Size = 259549 ** : : Tree compression factor = 2.02 ********************************************************************************Br 0 :nword : nword/I **Entries : 1024 : Total Size= 4728 bytes One basket in memory **Baskets : 0 : Basket Size= 32000 bytes Compression= 1.00 **............................................................................**Br 1 :rawdata : rawdata[nword]/i **Entries : 1024 : Total Size= 520648 bytes File Size = 249766 **Baskets : 16 : Basket Size= 32000 bytes Compression= 2.02 **............................................................................*
これをFlashADCの波形にデコードする
具体的な作業例
生データのバイナリファイルからTTreeに変換する
TTreeから1イベントづつ読み出してデコードする
デコードした結果を別のTTreeに格納する
Fitする
誤差について考える
そのためにはbodyの構造を知る必要がある
実習に使うCOPPERの実物
PMC CPU
TriggerModule
FINESSE
FINESSE
FINESSE
FINESSE
FINESSE (ADCやTDCで、最大4つ)をPMC CPUがかき集めて送り出してくる
今回の構造はこのようになっている
0 1 2 3 4 5 6 7 8時間
波高
header #0
COPPER header
500MHz FADC
COPPER footer
ADC 波高情報
FADC header
FADC footer
Ch1 data
Ch0 data
Ch1 data
Ch0 data
Ch1 data
Ch0 data
Ch1 data
Ch0 data
Ch1 data
Ch0 data
0 2 1 3
0 2 1 3
4 6 5 7
4 6 5 7
COPPERのheader/footertypedef struct { UInt_t sw_magic; UInt_t event_number; UInt_t subsystem; UInt_t crate; UInt_t slot; UInt_t ttrx[2]; UInt_t hw_magic; UInt_t total_words; UInt_t fin_words[4];} cprheader;
typedef struct { UInt_t checksum; UInt_t magic;} cprfooter;
0x7FFF00080xFFFFFAFA
500MHz FADCのheader/footer
typedef struct { UInt_t magic; UInt_t ttrx;} finheader;
typedef struct { UInt_t magic;} finfooter;
0xFFAA0000
0xFF55XXXX上位16ビットだけ固定
500MHz FADCのデータ
typedef struct { UChar_t ch0data0; UChar_t ch0data2; UChar_t ch0data1; UChar_t ch0data3;
UChar_t ch1data0; UChar_t ch1data2; UChar_t ch1data1; UChar_t ch1data3;} fadc500data;
• とりあえずファイルをオープンして閉じるだけ。•
#include <TFile.h>main(int argc, char ** argv){ for (int i=1; i<argc; i++) { TFile f(argv[i]); f.ls(); }}
初手(dec1.cc)
#include <TFile.h>#include <TTree.h>
main(int argc, char ** argv){ for (int i=1; i<argc; i++) { TFile f(argv[i]); f.ls(); TTree * t; f.GetObject("rawdata", t); t->Print(); }}
dec2.ccTTreeを取り出す
dec3.cc
TTreeの全ての行をただ走査してみる
dec4.cc
COPPERのレベルだけデコードし(FINESSEは見ない)
ヘッダとフッタをチェックする
dec5.cc
各FINESSEの先頭ワードを表示してみる
FINESSEの取り出し
• COPPERは4つのFINESSEを装着することが出来るが、1つしか装着されていないかもしれない。今回は1つしか装着されていない。
• COPPERのヘッダに4つのFINESSEのデータ長が記録されているので、これが0ならFINESSEが装着されていないとしてよい
UInt_t (&fin_words)[4] = cprhdr->fin_words; // 各FINESSEからのデータ長をCOPPERのヘッダからもってくる
for (int offset = NW(cprheader), fslot=0; fslot<4; offset += fin_words[fslot], fslot++) { if (fin_words[fslot] > 0) { printf("%d %08x¥n", offset, *(p+offset)); }}
data from FINESSE A
data from FINESSE B
data from FINESSE C
data from FINESSE D
COPPER header
COPPER footer
fin_words[0]
fin_words[1]
fin_words[2]
fin_words[3]
fslot==0のときのoffset
fslot==1のときのoffset
fslot==2のときのoffset
fslot==3のときのoffset
pはいつでもここを指している
dec6.cc
ADCのサンプルをひたすらprintfしてみる
TFile** ../rawdata.root TFile* ../rawdata.root KEY: TTree rawdata;1 rawdata*******************************************************************************Tree :rawdata : rawdata **Entries : 1024 : Total = 525615 bytes File Size = 259549 ** : : Tree compression factor = 2.02 ********************************************************************************Br 0 :nword : nword/I **Entries : 1024 : Total Size= 4728 bytes One basket in memory **Baskets : 0 : Basket Size= 32000 bytes Compression= 1.00 **............................................................................**Br 1 :rawdata : rawdata[nword]/i **Entries : 1024 : Total Size= 520648 bytes File Size = 249766 **Baskets : 16 : Basket Size= 32000 bytes Compression= 2.02 **............................................................................*13 ffaa000072 89 85 101, 126 126 125 12698 115 112 127, 125 126 125 126125 140 137 148, 125 127 125 126148 158 157 164, 125 127 125 126164 171 172 174, 125 126 124 127177 175 180 174, 125 127 125 126180 171 177 165, 125 126 125 126172 158 164 149, 125 126 125 126158 137 148 126, 125 127 125 126136 113 123 99, 125 126 124 126109 87 96 75, 124 127 125 12783 62 70 50, 124 126 125 12658 37 44 27, 125 127 125 12633 17 24 8, 124 127 125 12614 0 6 0, 125 126 125 1260 0 0 0, 125 126 125 1260 0 0 0, 125 126 125 1270 4 1 12, 125 127 125 1269 22 18 32, 125 126 125 126
ch0は結構変動しているが、ch1はしていない
ch0について波形を生成し、 TTreeに埋める
具体的な作業例
生データのバイナリファイルからTTreeに変換する
TTreeから1イベントづつ読み出してデコードする
デコードした結果を別のTTreeに格納する
Fitする
誤差について考える
• デコード済波形の出力先TTree
• Branchに使用するバッファ
• TTreeを書き込むファイル
• rawdata.rootを開いたときにgDirectoryは移動してしまうので、波形のTTreeをセーブするときは出力TFileにcdする
さらに追加するもの
dec7.cc
これでch0の波形が1行に入ったTTreeが生成され、
decoded.rootというファイルに格納される
• 可能なら
• process_tree
• decode_ほにゃらら
• 行き先TFile *
• データを格納するTTree
• 書くBranchが使用するバッファ
• をメンバーとして持つようなクラスを定義して使うのがよい
• TTree::MakeClass()を使うとそういうのが比較的楽にできます
こういうのは大域変数で書くと後で収拾がつかないので
• root -l ./decoded.root
• _file0.ls()
• dst->Draw("height:Iteration$", "", "", 1)
• サイン波っぽい
できたので、グラフ表示
Iteration$0 20 40 60 80 100 120 140 160 180 200 220
height
0
20
40
60
80
100
120
140
160
180
200
height:Iteration$
• dst->Draw("heght:Iteration$")
• 画面に表示されているのはGraphというオブジェクト
• 違う物を表示すると壊れるので、
• TGraph * g = Graph->Clone()
• として複製を作っておく
すべてを表示してみる
サイン波っぽいのでFitしてみよう
具体的な作業例
生データのバイナリファイルからTTreeに変換する
TTreeから1イベントづつ読み出してデコードする
デコードした結果を別のTTreeに格納する
Fitする
誤差について考える
• あるべき姿を表す1変数関数を定義する。
• ROOTでは1変数関数はTF1クラスのインスタンスとして定義
• 今回用のサイン波であればTF1 f1("f1", "[0]+[1]*sin([2]*x+[3]) のように定義する。もし直線Fitならば “[0]+[1]*x” などとすればよい
• TF1もDraw()できる
• 3つもパラメータがあるので、Fitのためにスキャンし始めると大変
• 全部おまかせにすると時間がかかる割にへんてこ
ROOTでのFitの方法
• オフセット: 90くらい
• 振幅: 100くらい
• 周期: 90くらい
• 2π / 90 = 0.07が[2]の初期値
• 初期位相: 0っぽい
当たりをつけておく
当たりをつけた関数を表示してみる
• TF1 f1(“f1”, “[0]+[1]*sin([2]*x+[3])”);
• f1.SetParameters(90, 100, 0.07, 0)
• f1.SetRange(0,220); // X軸の範囲を指定する
• f1.Draw() // それっぽい
• g->Draw(“AP”) // グラフを再描画
• f1.Draw(“same”) // 重ね書き
• いまいちですね
もうちょっと変更
• f1.SetParameters(90, 100, 0.075, 0)
• f1.Draw(“same”)
• よさそう!
ではFit• g->Fit(“f1”)
g->Fit("f1") ********** ** 5 **MIGRAD 5000 0.2182 ********** MIGRAD MINIMIZATION HAS CONVERGED. FCN=1.32738e+07 FROM MIGRAD STATUS=CONVERGED 86 CALLS 87 TOTAL EDM=8.02947e-11 STRATEGY= 1 ERROR MATRIX UNCERTAINTY 2.1 per cent EXT PARAMETER STEP FIRST NO. NAME VALUE ERROR SIZE DERIVATIVE 1 p0 8.52948e+01 2.17563e-03 -1.15934e-05 4.22469e-03 2 p1 8.92708e+01 3.10223e-03 3.27677e-05 4.48543e-03 3 p2 7.52849e-02 5.32668e-07 1.17607e-08 -2.97517e+01 4 p3 -4.95441e-02 6.60728e-05 -1.24226e-06 -1.62803e-01 FCN=1.32738e+07 FROM MIGRAD STATUS=CONVERGED 86 CALLS 87 TOTAL EDM=8.02947e-11 STRATEGY= 1 ERROR MATRIX UNCERTAINTY 2.1 per cent EXT PARAMETER STEP FIRST NO. NAME VALUE ERROR SIZE DERIVATIVE 1 p0 8.52948e+01 2.17563e-03 -1.15934e-05 4.22469e-03 2 p1 8.92708e+01 3.10223e-03 3.27677e-05 4.48543e-03 3 p2 7.52849e-02 5.32668e-07 1.17607e-08 -2.97517e+01 4 p3 -4.95441e-02 6.60728e-05 -1.24226e-06 -1.62803e-01(Int_t)(0)
結果の表示
• g->Draw(“AP”)
Fitされたパラメータの取得
• g->GetFunction(“f1”)->GetParameter([]内の番号)
• g->GetFunction(“f1”)->Print() で十分
Fitはしたけど、どの程度正しいの?
• Fitした関数との誤差がどれだけあるか見てみる
• これをサボると先生に怒られます
• TGraph::Apply()を使って誤差の散布図を作ってみよう
• すべての点(x,y)を (x, f(x,y)) に置換するメソッド
具体的な作業例
生データのバイナリファイルからTTreeに変換する
TTreeから1イベントづつ読み出してデコードする
デコードした結果を別のTTreeに格納する
Fitする
誤差について考える
TGraph::Apply()を使って元の散布図から誤差の散布図を作ってみる
dst->Draw("height:Iteration$");TGraph * g = Graph->Clone();TF1 f1("f1", "[0]+[1]*sin([2]*x+[3])");f1.SetParameters(90, 100, 0.075, 0);
g->Fit("f1"); // ここまでは同じ
TF2 errf("errf", "[0]+[1]*sin([2]*x+[3]) - y");for (int i=0; i<4; i++) { errf.SetParameter(i, f1.GetParameter(i)); }
TGraph * gerr = Graph->Clone();gerr->Apply(&errf);gerr->Draw("A*");
誤差計算用の関数 : 誤差 = f(x) - yとする
f1のパラメータをコピー
散布図中の全ての点について(x,y)を(x, errf(x,y))に置き換える
errg.ccにいれてあります
• root -l ./decoded.root ./errg.cc
• とすればよし
なんか中央付近が妙な高さ
拡大すると
xが奇数と偶数で分布が違う
実は今回のFlashADCはそういうものなんです
Ch1 data
Ch0 data
Ch1 data
Ch0 data
Ch1 data
Ch0 data
Ch1 data
Ch0 data
Ch1 data
Ch0 data
0 2 1 3
0 2 1 3
4 6 5 7
4 6 5 7
0 1 2 3 4 5 6 7 8時間
波高
2つのADCチップが交互に波高を見ているので、誤差はそれぞれ異なる
故に偶奇をわけてFitしないとだめ
dst->Draw("height:Iteartion$", "Iteration$ % 2 == 0")
Drawの第2引数は条件にマッチしたものだけ点を打つという指令
最初の散布図を偶奇でわける
errg_even_odd.ccに入ってます• root -l ./decoded.root ./errg_even_odd.cc
なぜか周期的にばらつきが小さい
小さいのはどこだ
ふりきれてるところ
Aliasをつかってもうちょっと確認
dst->SetAlias("expected", "p0+p1*sin(p2*Iteration$ + p3)")
dst->SetAlias("p0", "86.5201")
dst->SetAlias("p1", "90.5027")
dst->SetAlias("p2", "0.0752659")
dst->SetAlias("p3", "-0.122379")
// それぞれの値はf1.Print()で出力されます
dst->Draw("height-expected:height","Iteration$ % == 0")
確かに振り切れるところでばらつきが減っている
まだ続がありそうですが
• 1イベントだけ表示してみる、とかするとだんだん様子がわかってきます
• dst->Draw("height-expected:Iteration$", "", "*L", 1, 0)最後の0を1,2,3,4,...と変えていく
• dst->Draw("height-expected:height", "", "*L", 1, 0)についても同様にしてみる
• 初期位相のズレが寄与する
おしまい
• お疲れ様でした
• とりあえずUsers Guideは印刷しとけ!
• ClassIndexは印刷すると悲惨なのでしなくていいです