RootTutorial1
ROOTファイル
ROOTでは、クラスのオブジェクトを簡単にファイルに保存することができる。ROOTファイルでは独自の形式でデータを保管しており、拡張子.rootを付けるのがふつうである。 このようにして作成されたファイルを開くには、TFileというクラスを使って簡単にオブジェクトを読み込むことができる。以下のコードはabc.rootという名前のファイルを開いて、ファイルの中身を表示させるものである。
TFile* f = TFile::Open("abc.root", "READ"); f->ls(); f->Close();
TCanvas
マクロ
ROOTでは、対話的にC++の構文を入力することで逐次コードを実行することが可能である。このような使い方とは別に、C++コードを関数として用意してファイルに保存してから、その関数を呼び出すことができる。このようにすると複雑な処理を何度も入力する必要がなく便利である。 例として、testMacro.Cというファイルを作り以下のコードを記述する。
void testMacro() { TFile* f = TFile::Open("test_out.root", "RECREATE"); TCanvas* c = new TCanvas("c", "", 0, 0, 600, 600); TF1* func1 = new TF1("f1", "sin(x)/x", -100, 100); TF1* func2 = new TF1("f2", "gaus", -10, 10); func2->SetParameter(0, 100); func2->SetParameter(1, 2.0); func2->SetParameter(2, 1.0); func1->SetNpx(10000); func2->SetNpx(10000); c->Draw(); c->Divide(1, 2); c->cd(1); func1->Draw(); c->cd(2); func2->Draw(); func1->Write(); func2->Write(); f->Write(); }
マクロでは、ファイル名(拡張しを除いたもの)と中の関数名が同じでなければならない。 この関数を実行するにはrootを起動して、".x <マクロ名>"コマンドで実行できる。
root [0] .x testMacro.C
宇宙線ミューオン測定のデータ解析
測定データは以下のディレクトリにある。
/nfs/space3/tkohno/work/Lab/Cosmic2018/data/
これらのファイルには、TTreeが一つ入っている。TTreeの中に保存されているデータを読むためにはMakeClassという機能を使うと便利である。
TFile* f = TFile::Open("/nfs/space3/tkohno/work/Lab/Cosmic2018/data/cosmic20181130_01.root", "READ"); TTree* t = dynamic_cast<TTree*>(f->Get("t")); t->MakeClass("CosmicEvent");
これを実行すると、CosmicEvent.hとCosmicEvent.Cというファイルが生成されているはずである。 このように自動的に生成されたファイルには一つ問題があるのでCosmicEvent.Cファイルの最後に次の一行を付け加える必要がある。
#undef CosmicEvent_cxx
これは同じファイルの最初の1行#define CosmicEvent_cxxに対応したもので、この後に書くコードに影響しないように条件を閉じる必要がある。
CosmicEvent.hの中をみると、CosmicEventという名前のクラスの中に以下のデータがある。
Int_t event_number; UInt_t timestamp; UInt_t nadc; UInt_t adc0[3000]; //[Nadc] UInt_t adc1[3000];//[Nadc] UInt_t adc2[3000];//[Nadc] UInt_t adc3[3000];//[Nadc]
TTreeには、ミューオン事象のデータが多数保存されているが、上のデータはそれぞれの事象のデータに対応している。 CosmicEventクラスのように事象データを定義したクラスを使うと簡単にTTreeが保管するデータをファイルから読み込んでプログラムの中で利用することができる。次にそれを行うマクロを書く。
デジタイザの波形を表示する
このTTreeには事象毎に4つのシンチレータからの電圧値の時間変化を4 ns毎にADCでデジタル化した値が入っている。事象の概要を把握するために事象毎に波形データを表示させるマクロを書く。
waveform.C
#include "CosmicEvent.h" #include "TFile.h" #include "TTree.h" #include "TCanvas.h" #include "TGraph.h" #include "TH1.h" #include "TVirtualPad.h" #include "TStyle.h" #include "TAxis.h" void setStyle() { gStyle->SetPadTopMargin(0.03); gStyle->SetPadRightMargin(0.03); gStyle->SetPadBottomMargin(0.15); gStyle->SetPadLeftMargin(0.1); gStyle->SetLabelSize(0.08, "XY"); gStyle->SetTitleSize(0.08, "XY"); gStyle->SetTitleOffset(1.0, "X"); gStyle->SetTitleOffset(0.65, "Y"); gStyle->SetNdivisions(505, "Y"); } void waveform(int eventNumber) { std::string fname="/nfs/space3/tkohno/work/Lab/Cosmic2018/data/cosmic20181130_01.root"; TFile* f = TFile::Open(fname.c_str(), "READ"); TTree* t = dynamic_cast<TTree*>(f->Get("t") ); CosmicEvent event(t); int nevents = t->GetEntries(); int ievent=0; int isample=0; const int nSamples=3000; float x[nSamples]; float y0[nSamples]; char graphName[100]; TH1* hframe=0; setStyle(); TCanvas* c = new TCanvas("c", "", 0, 0, 600, 800); c->Draw(); TFile* fout = TFile::Open("analysisOut.root", "RECREATE"); TGraph* g0=0; if (eventNumber>=0 && eventNumber < nevents) { t->GetEntry(eventNumber); for (isample=0; isample<nSamples; ++isample) { int value = 4096-event.adc0[isample]; x[isample] = isample*4.0; y0[isample] = value; } g0 = new TGraph(nSamples, x, y0); g0->SetMarkerStyle(20); g0->SetMarkerSize(0.35); c->Divide(1, 4); c->cd(1); hframe = gPad->DrawFrame(0, 0, 3000, 4096); g0->Draw("p"); hframe->SetXTitle("Decay time (ns)"); hframe->SetYTitle("Channel 0 ADC value"); } std::sprintf(graphName, "g_event%d_ch%d", eventNumber, 0); g0->Write(graphName); fout->Write(); }
このコードをROOTで以下のように実行する。この関数は事象番号に対応するint型の引数を一つ受け取るので、マクロ名の後に括弧を付けて波形を表示させたい事象番号を与えて実行する必要がある。
root [0] .L CosmicEvent.C+ root [1] .x waveform.C(11)
課題
- チャンネル1~3の波形も表示するように上のマクロを修正せよ。
- 見映えが良くなるように点の色・大きさ、軸ラベルを調整せよ。
解析マクロ
analyzeEvent1.C
#include "CosmicEvent.h" #include "TFile.h" #include "TTree.h" #include "TH1.h" void analyzeEvent1() { std::string fname="/nfs/space3/tkohno/work/Lab/Cosmic2018/data/cosmic20181130_01.root"; TFile* f = TFile::Open(fname.c_str(), "READ"); TTree* t = dynamic_cast<TTree*>(f->Get("t") ); CosmicEvent event(t); int nevents = t->GetEntries(); int ievent=0; int nsamples=3000; int isample=0; unsigned int value=0; unsigned int maxvalue=0; const int nSamples=3000; float x[nSamples]; float y0[nSamples]; int eventNumber=0; TFile* fout = TFile::Open("analysisOut.root", "RECREATE"); TH1* h_adc0_max = new TH1F("h_adc0_max", "", 100, 0, 4096); for (ievent=0; ievent<nevents; ++ievent) { t->GetEntry(ievent); maxvalue = 0; for (isample=0; isample<nsamples; ++isample) { int value = 4096-event.adc0[isample]; if (value > maxvalue) { maxvalue = value; } x[isample] = isample; y0[isample] = value; } h_adc0_max->Fill(maxvalue); } h_adc0_max->Write(); fout->Write(); }
このコードをROOTで以下のように実行する。
root [0] .L CosmicEvent.C+ root [1] .x analyzeEvent1.C root [2] h_adc0_max->Draw();
最初のコマンドは、CosmicEvent.Cに記述したコードをコンパイルして生成されたライブラリを起動中のROOTプログラムに組み込む。次に実行するマクロ(analyzeEvent1.C)ではCosmicEventクラスを使用するため、事前にROOTでCosmicEventの機能を使用可能な状況にするためである。
このマクロでは、各事象でチャンネル0の波形の最大値を取り出してそれをヒストグラムに詰めて分布を作っている。また、光電子増倍管からの電子の流れが電圧値となっているため信号は負の寄与をする。そのため、まず波形を上下反転させている。
課題 1
- 信号の最大値の分布が何故このような分布になるか考えよ。
- 他のチャンネルでも同様の分布を作って、分布の形を考察せよ。
課題 2
チャンネル番号は0, 1, 2, 3と数えることにする。
- ミューオンが検出器に入射したタイミングを各チャンネルで求めよ。どれくらいばらつきがあるか。
- チャンネル2にミューオンが入射した事象とは、どのように定義できるか。このような事象の数を求めよ。
- 全てのチャンネルでをミューオンが通過したかどうかはどのように調べればよいか。このような事象の数を求めよ。
- チャンネル2にミューオンが入射してからしばらく経ってから信号が見られるか。このような事象の数、最初の信号と2番目の信号との時間差の分布を求めよ。
課題 3
- チャンネルごとに適切な閾値を設定せよ。
- 各チャンネルで2個目のピークを求めよ。(タイミングとピークの最大値)
- チャンネル2について、1つ目と2つ目のピークの時間差の分布を作れ。
課題 4
チャンネル2について以下のことを調べよ。
- CH0, 1, 2に信号があって、CH3に信号が見られないときに2つ目のピークの最大値とタイミングの分布を作れ。
- 全てのチャンネルで最初のピークがあったときに、CH2に2つ目のピークがあるか上と同様に最大値とタイミングの分布を作って調べよ。