【超初心者向け】C++とPyROOTの2方法でテキストデータをrootファイルに変換する
方法
今回はC++を使ったオーソドックスな方法とPyROOTを使った方法を紹介する。
ちなみに完成系はこのような形になる。
C++を使った方法
筆者はCentOS8を使用。真似したい場合は以下の記事を参照。
phbe.hateblo.jp
※CERN ROOTを入れいない人は以下の記事を参照。
phbe.hateblo.jp
データの準備
今回は以下の記事で作ったテキストデータをそのまま使用する。
phbe.hateblo.jp
makefileの作成
C++で作ったコードは一度コンパイルしてから実行する。
コンパイルを楽にするおまじない的なものがmakefileだ。
ファイルの名前もそのままmakefileにして作成する。
よくわからない人は丸写しを推奨する。
TARGET = mkNT SRCS = $(TARGET).cc OBJS = $(TARGET).o ROOTFLAGS = $(shell root-config --cflags) ROOTLIBS = $(shell root-config --libs) CXXFLAGS = -Wall -O2 $(ROOTFLAGS) CXXLIBS = $(ROOTLIBS) CC = g++ all: $(TARGET) $(TARGET): $(OBJS) $(CC) $(CXXLIBS) $(OBJS) -o $@ $(TARGET).o:$(TARGET).cc $(CC) $(CXXFLAGS) -c $< clean: rm -f $(TARGET) $(OBJS)
1行目の「mkNT」というのが今回作りたいコードの名前である。
「mkNT.cc」という名前のC++コードをコンパイルできるようになった。
もちろん別の名前のコードをコンパイルしたい場合は「mkNT」の部分をその名前に変えて実行する。
複数のコードを同時にコンパイルする方法もあるが、今回は触れない。
コードの作成
コード作成前に今回のデータを整理する。
今回のデータは以下のように書かれている
イベント番号 | ADC値 | TDC値1~3 | ランダム数1~6 |
整数 | 整数 | 整数 | 小数 |
このうちTDC値を1次元配列に、ランダム数を2次元配列にしてみる
#include "TApplication.h" #include <math.h> #include <TROOT.h> #include <TNtuple.h> #include <TStyle.h> #include <TFile.h> #include <fstream> #include <iostream> using namespace std; const char kNameInFile[20] = "output.dat"; const char kNameOutFile[20] = "output.root"; int main(){ cout << "Input File = " << kNameInFile << endl; cout << "Output File = " << kNameOutFile << endl; // define value Int_t ieve; Int_t adc; Int_t tdc[3]; Double_t rand[2][3]; //open root gROOT->SetStyle("Plain"); gStyle->SetOptStat("neiuoMR"); gStyle->SetPalette(1); TTree *tree = new TTree("raw", "raw tree"); tree->Branch("ieve", &ieve, "ieve/I"); tree->Branch("adc", &adc, "adc/I"); tree->Branch("tdc",tdc, "tdc[3]/I"); tree->Branch("rand",rand, "rand[2][3]/D"); // open dat file ifstream indata(kNameInFile); // file exist check if (indata.fail()) { cout << "### program err ###" << endl; std::cerr << "!!!Failed to open file!!! \n!!!Not found this file!!!" << std::endl; cout << "### program close ###" << endl; return -1; } // get data & write while (indata >> ieve >> adc >> tdc[0] >> tdc[1] >> tdc[2] >> rand[0][0]>> rand[0][1]>> rand[0][2]>> rand[1][0]>> rand[1][1]>> rand[1][2] ) { tree->Fill(); if (ieve%1000 == 0){ cout << "event_loop = "<< ieve << endl;} } cout << "event num = " << ieve+1 << endl; indata.close(); // write rootfile TFile *fout = new TFile(kNameOutFile, "recreate"); tree->Write(); fout->Close(); // end cout << "F!!!!!!!!!!!!!!!!!!!!!!" << endl; return 0; }
コンパイル、実行
[***@localhost **] $ make
エラーとかが出なければコンパイル完了なのでそのまま実行。
[***@localhost **] $ ./mkNT Input File = output.dat Output File = output.root event_loop = 0 event_loop = 1000 event_loop = 2000 event_loop = 3000 event_loop = 4000 event_loop = 5000 event_loop = 6000 event_loop = 7000 event_loop = 8000 event_loop = 9000 event num = 10000 F!!!!!!!!!!!!!!!!!!!
このような出力になれば成功。
PyROOTを使った方法
PyROOTはC++で書いたものよりも浸透していないので記事が少ない。
特に同じことをするためのコードを比較するような記事が少ないので是非確認してほしい。
作成の流れ
- データの準備
- コードの作成
- 実行
データ準備
C++のやり方と同じ方法で行う
コードの作成
今回は「mkNT.py」という名前で作成する。
from ROOT import TTree , std , TH1F, TFile import numpy as np kNameInFile = "output.dat" kNameOutFile = "output.root" print("Input File = "+kNameInFile) print("Output File = "+kNameOutFile) # define value ieve = np.empty((1), dtype="int32") # この書き方でないとバグる adc = np.empty((1), dtype="int32") # この書き方でないとバグる tdc = np.zeros((3,), dtype="int32") # この書き方でないとバグる rand = np.zeros((2,3), dtype="float") # この書き方でないとバグる # open root rawtree = TTree("raw","raw_tree") rawtree.Branch('ieve',ieve,'ieve/I') rawtree.Branch('adc',adc,'adc/I') rawtree.Branch('tdc',tdc,'tdc[3]/I') rawtree.Branch('rand',rand,'rand[2][3]/D') # open dat file fin = open(kNameInFile,"r") # get data & wtite for line in fin: tmp = line.split() if len(tmp)==0: continue ieve[0] = int(tmp[0]) adc[0] = int(tmp[1]) tdc[0] = int(tmp[2]) tdc[1] = int(tmp[3]) tdc[2] = int(tmp[4]) rand[0][0] = float(tmp[5]) rand[0][1] = float(tmp[6]) rand[0][2] = float(tmp[7]) rand[1][0] = float(tmp[8]) rand[1][1] = float(tmp[9]) rand[1][2] = float(tmp[10]) rawtree.Fill() if ieve%1000 == 0: print("event_loop = "+str(ieve)) print("event num = "+str(ieve+1)) fin.close() # write rootfile fout = TFile(kNameOutFile,"recreate") rawtree.Write() fout.Close() # end print("F!!!!!!!!")
実行
Pythonの場合は簡単で、terminal上で以下のコマンドを入力するだけである。
[***@localhost **] $ python3 mkNT.py Input File = output.dat Output File = output.root event_loop = [0] event_loop = [1500] event_loop = [3000] event_loop = [4500] event_loop = [6000] event_loop = [7500] event_loop = [9000] event num = [10000] F!!!!!!!!
このような出力になれば成功。
確認
後は好きなように完成したrootファイルを確認すればよい。
[***@localhost **] $ root output.root root [] .ls root [] raw->Print() root [] raw->Draw("neve") root [] raw->Draw("adc") root [] raw->Draw("tdc[0]") root [] raw->Draw("rand[0][0]") root [] raw->Draw("adc:tdc[0]") root [] raw->Draw("adc:tdc[0]-tdc[1]-tdc[2]")