Revision 7 as of 2012-08-04 15:18:45

Clear message
Locked History Actions

ANAROOT/Manual/tutorial

Page for understanding ANAROOT. Sorry for Japanese only.

はじめに

ここではANAROOTの初歩的な扱いに慣れた人がANAROOTの構造を理解するためのtutorial。 試験的に作成している段階なので変だと思う所は直接コメントを書いたりメールしてください。

演習1

ANAROOTは解析するためのライブラリ群で、これをコード上で呼ぶことで解析する。 ここではbookだとかstartだとかのANAROOTのコマンドは一切使わない。

step 1.0

まず少しだけ前準備をしておく。 ただし、理研や東工大の解析マシンで

anarootlogon

などのshell commandがある場合は特に準備する必要はないはず。

ディレクトリ構造

ここでは解析を行うベースディレクトリを"mayoi"としたとき、

mayoi
mayoi/db
mayoi/macros
mayoi/matrix
mayoi/ridf
mayoi/rootlogon.C
mayoi/src

というディレクトリ構造を想定する。 公式に配布されているANAROOTの書庫をmayoi/src以下に展開し、make & make install すると ライブラリがmayoi/src/lib以下にinstallされる。 compile・install周りの詳しいことは公式サイトを見てください。

rootlogon.C

ANAROOTは単なるライブラリ群(libanaroot.so等, 動的ライブラリで検索)なので、 ROOTではこれを明示的に指定・呼び出ししてあげないと使いようがない。 そのために、例えばROOT起動時に実行される rootlogon.C にライブラリの場所の指定・呼び出しを書いといてあげる。

以下は愚直に書く場合の例。

void rootlogon()
{
  gSystem->AddIncludePath("-Isrc/include");
  gSystem->Load("libXMLParser.so");
  gSystem->Load("src/lib/libanaroot.so");
}

これをmayoi/rootlogon.Cとして保存しておく。 場合によってはカレントディレクトリにあるrootlogon.Cを読むように指定してない場合もあり、 その場合は.rootrcを編集する必要があるかもしれません。

step 1.1

まずは最小のプログラムを理解しよう。 こちら(ArtAnalyzeDALI1.C)をダウンロードください。 このstep 1.1が本質で、あとは拡張するだけなので。

念のため実行方法を説明しておく。 cint上(rootを実行したときのコマンド入力画面)で実行する場合には以下の四つの方法がある。

// cint上でコンパイルしない方法
root[0] .x ArtAnalyzeDALI1.C

// cint上でコンパイルする方法
root[0] .x ArtAnalyzeDALI1.C+

// ロードして実行
root[0] .L ArtAnalyzeDALI1.C
root[1] ArtAnalyzeDALI1()

// コンパイル&ロードして実行
root[0] .L ArtAnalyzeDALI1.C+
root[1] ArtAnalyzeDALI1()

cintは完全にc・c++の文法を理解できるわけではない(関数ポインタ、演算子のオーバーロード、テンプレート引数にオブジェクト等)のと自分の書いたコードのDEBUGという観点からコンパイルして実行することを勧める。 つまり、.x ArtAnalyzeDALI1.C+と最後に"+"をつけて実行する方法が推奨される。

では、説明を加えると、

#ifndef __CINT__
...
#endif

これは.x ArtAnalyzeDALI1.Cで呼んだときと、.x ArtAnalyzeDALI1.C+で呼んだときで ヘッダーファイルの読み込みがされない/されるを切り替えるため。 詳しくはプリプロセッサとかで調べてください。

"TArtHoge.hh"

TArtはANAROOT独自のオブジェクトということを表している単なる命名規則の一つ。 作法としてTArtHoge.hhにはTArtHogeクラスが定義されている (たまに継承したクラスも一緒にかかれていることがあるので注意)。 たとえばDALIのEnergyの情報を取ってきたいと思ったときに見るべきファイルはTArtCalibDALI.hhやTArtCalibDALI.ccとなる。 物理に関わるところは全てReconstructフォルダ以下にまとまっているが、見つからない時は、 ファイル検索であればfindやlocate、ファイルの中身の検索であればgrep等のlinux標準のコマンドを使えばよい。

TArtEventStore.hh: ridfファイルを読み込んでデコードしてrawdata型に詰めてくれる一番偉い人
TArtDALIParameters.hh: DALIのparameterを読み込んでDALIのparameter型に詰め込む
TArtCalibDALI.hh: DALIへの窓口&本体。DALIという検出器その物を表したクラスではないということに注意。
TArtDALINaI.hh: DALIの素要素であるNaI一つのデータ形式
TArtDALIPara.hh: DALIのNaI用のparameterのデータ形式

ここで人によっては、DALI全体を表すクラスが独立にないことを気持ち悪いと思うかもしれないが、 諸事情により、素要素を定義するクラスの集合(vector<TArtDALINaI>の様なイメージ)を一つの検出器として扱っている。 具体的にはTClonesArrayというROOT標準のクラスに詰め込んでいる。 また一方ではbeam lineのplasticをTClonesArrayにまとめて突っ込んでたりする。 おそらくこの時点では何を言っているかわからないと思うが、 とりあえず構造がオブジェクト指向のセオリーに完全には乗っていないことだけは覚えていてほしい。 あと、Calibなんたらとついているものはあくまで”窓口兼本体”であることをよく頭に入れておくこと。

注意点をいくつか述べておく。

  • EventStore周りは深追いしても何も良い事はないので関数の中身を見て雰囲気を理解するぐらいにしておくべき。逆に、TArtCalibDALIだとかDALINaIとかはその先のコードまで理解できていることが望ましい。

  • クラスをまたがるコンストラクタや関数内部で結構やっているので、その辺はとりあえず慣れてください。例えばTArtCalibDALIより先にTArtDALIParametersをコンストラクトしなければならない(コンストラクトする順番に依存するのは設計としては良くないとか突っ込まない)とか。

step 1.2

step 1.1にhistogramの定義を追加する。 こちら(ArtAnalyzeDALI2.C)をダウンロードください。

このマクロを回したら、.lsかls() すればhistogramが出来ているのが見えるはずである。 あとはhid->Draw()やhn()とすればちゃん表示されるはず。

多くのユーザーがちゃんとc++を勉強していない感があるので"new"について少し。 普通に変数を宣言してオブジェクトを生成する場合はスコープを抜けるときにそのオブジェクトは勝手に破棄(デストラクト)される。 一方newでオブジェクトを生成(コンストラクト)した場合はスコープを抜けてもそのオブジェクトは破棄されずメモリ上に残る。 例えばヒストグラム(TH1)はmacroで処理した後も参照したいのでメモリ上に残しておく必要があり、 敢えてnewして且つ敢えてdeleteしない。 これとは別にポインタの方が汎用的に扱えるという理由からnewしてしまう場合もあるが、 明確に目的が違うので混同しないこと。 TArtAnalyzeDALI2でnewしたTH1DのオブジェクトをTH1という親の型のポインタで受けているのは両方の目的がある。

もう一つ、ROOT標準の型の調べ方について。 基本的に"TH1 ROOT"とかでググれば公式に自動生成されているクラスリファレンスがhitする。 このページで、引数、関数名、戻り値、でそれっぽい関数はだいたい見つかる。 でも、例えばオブジェクトの名前を変える関数はTH1には載っていなくて、 これは親の関数の処理だから。 継承関係はClass ChartsのInheritanceに図で示されている。 子は親の処理はなんでも使えて、例えば名前の変更だったらTNamedというクラスにSetNameという名前で実装されている。 これを表すのにTNamed::SetNameって書くこともよくある。 継承とかはぱっと理解できるものではないので徐々に理解していってください。 動物である人間は動物ができることは人間もできるみたいなそういうごく自然な関係をプログラムで実現しているだけです。

あれやりたい、これやりたい、って漠然としたことは英語で"histogram title ROOT cern"とかで検索すればRoot Talkのスレッドが引っかかることも。

演習2

ここではCalibなんたらをいじっていきます。

step 2.0

共有のsrcを使っている場合はそれを勝手に書き換えるわけにもいかないのでまずは下準備。 東工大の人向け。

共有のsrcを使っている人はおそらく

$ ls -la 

すると、

src -> /home/samurai/exp/sm_com/anaroot/src

とかそんな感じでリンク先が表示されるかもしれません。 このリンクをやめて、実体に置き換えます。

$ rm src
$ cp -r /svn/anaroot/branches/2012SAMURAI.dayone.tanaka ./src
$ cd src
$ ./autogen.sh --prefix=$PWD
$ make
$ make install

とかしてください。 ただし、かならず何をしているか考えた上でここに書いてあることを実行してください。

step 2.1

上で使ったDALIのソースの中で計算すれば確かに何でも計算できるが、 これではみんながみんな似たような事を何回も書かなくてはいけなくなり、バグが指数関数的に増えていく(面倒という以上に問題)。 設計思想としては誰でも・いつでも必要とするものはTArtCalibDALIなどのクラスの中で計算しようということになっている。 誰でも・いつでもではないけどこの実験では、みたいなものはTAlなんたらの中で計算することがあるが、これは後ほど。 今だけちょこっと計算したいものは上記のようなmacroの中でちょろちょろっと計算する。 TArtCalib何たらはそのクラス単独で計算が簡潔するクラスで、 TArtReco何たらは他のCalibなどを使って計算する(粒子の運動量とか)クラス。 本質的な違いはないが実装の詳細は結構違うのでCalibに慣れてからRecoなんたらを考えるようにしてください。

では、TArtCalibDALIを見ていきます。 まずはsource/Reconstruct/DALI/include/TArtCalibDALI.hhを開きましょう。 他のTArtCalibなんたらと比べるとわかりますが、 LoadData(), ClearData(), ReconstructData() は必ず実装されている関数です。 基本的にはrawdataをloadしてreconstruct(要は計算)してclearする、という単純な流れです。 つまり基本的にはReconstructData()を適当にいじればよいということ。 ではsource/Reconstruct/DALI/include/TArtCalibDALI.ccを開いてTArtCalibDALI::ReconstructDataを見てみましょう。

void TArtCalibDALI::ReconstructData() { // call after the raw data are loaded // このコメントはもう古いので無視

  if(!fDataLoaded) LoadData(); // DALIのrawデータをもらってくる。RIDFからrawdataそのものを読み込むわけではない。

// 以下のまとまりについて解説すると、Tref(DALIの使っているTDCはジッターを除くためにTiming Referenceが必要)は
必ずfNaIArrayの最後に詰められる(ほんとにこの動作が保証されているかは知らない)ことを前提にして、
一番最後のNaIを取ってきてそこに格納されているTDC情報をtrefとして取ってきている。DALIに特有な処理なのでまぁあまり気にする必要はない。
// ----------------------------------------------
  TArtDALINaI *nainai = 0; // DALIの要素であるNaI一個。ローカル変数の命名規則的にはTArtを除いて全て小文字にしたdalinaiとするべき。"= 0"はポインタの初期化。
  Int_t tref = 0; // DALIの使っているTDCはジッターを除くためにTiming Referenceが必要(Decoderで差っ引くこともある)。
  if(GetNumNaI() > 0){ // そのeventにおいて情報のあったNaIの数がGetNumNaIで返ってくる。情報が何もなかった場合のエラー処理。
    nainai = (TArtDALINaI*)fNaIArray->At(GetNumNaI()-1); // fNaIArrayはそのeventにおいて情報のあったNaIが詰め込まれた配列みたいなもの。TClonesArrayというROOT標準のクラス。かなり特殊なのでROOTに慣れていない人はとりあえずvectorのようなものだと思っておけばよい。At()はその順番(IDではなくfNaIArrayに詰められた順番)のNaIを返す。戻り値の型はTObject型なのでTArtDALINaI型に明示的にキャストしてる。これはダウンキャストと呼ばれる危険なキャストなので知識がなければ放置。
    tref = nainai->GetRawTDC(); // さっき取ってきたNaIに格納されているTDCのrawデータを取り出している。
  }
// ----------------------------------------------

  for(Int_t i=0;i<GetNumNaI();i++){ // 情報のあった全てのNaIに対してloop処理
    TArtDALINaI *nai = (TArtDALINaI*)fNaIArray->At(i); // i番目に詰め込まれたNaIを取ってくる。
    TArtDALINaIPara *para = fNaIParaArray[i]; // i番目に詰め込まれたNaIに対応するParameterを取ってくる。
 
  }

  fReconstructed = true; // ANAROOTのお約束としてフラグ立てしておく。
  return;
}

演習3

TAlのいじり方