解析ツールとしての root - 国立大学法人...

Post on 21-Jan-2020

1 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

解析ツールとしての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は印刷すると悲惨なのでしなくていいです

top related