Журнал LinuxFormat - перейти на главную

LXF83:ROOT

Материал из Linuxformat
Перейти к: навигация, поиск

Содержание

Продолжая традиции: ROOT

Часть 3 Данные мало получить – надо ещё понять, а есть ли от них польза. Евгений Балдин представляет вашему вниманию «новинку» среди приложений для анализа данных.

Даже если данных много – их надо как-то проанализировать. Это может сделать только человек. Компьютер в этом деле только помощник. Выбор инструмента очень важен. ROOT – хороший инструмент. У него был достойный предок и он мог бы быть гораздо лучше. Но здесь и сейчас надо анализировать данные, фиксируя недостатки, дабы исправить их в будущем. Это возможно, потому что ROOT – это свободный продукт.

Примерно через десять лет после возникновения команде PAW (Physics Analysis Workstation) стало скучно, и ее лидер PAW Рене Брюн (Ren Brun) сотоварищи начал новый проект ROOT – An Object Oriented Data Analysis Framework [1].

Компьютеры стали много мощнее, но и поток данных увеличился. ROOT стал разрабатываться в рамках эксперимента NA49, где поток данных за один заход мог превышает 10 Тб [2].

С начала 2006 года ROOT (http://root.cern.ch/) стал выпускаться под лицензией GNU, и, возможно, скоро попадёт во все основные дис трибутивы GNU/Linux.

Сравнение с PAW

PAW является предком ROOT, если уж не в смысле кода, то уж в смысле реализации идей точно. Поэтому полезно понять, чем эти пакеты отличаются и в чём совпадают. Сравнительная таблица не претендует на фундаментальность, а просто отражает личные пристрастия автора.

Почему PAW? Если в вашем проекте PAW уже используется, особых причин для смены инструмента нет. Для стандартных операций анализа ROOT использовать значительно сложнее, чем PAW. Это плата за попытку объять необъятное.

Почему ROOT? [3] С++ популярнее FORTRAN и KUIP. С++ привычнее и с его помощью проще решать задачи, которые являются вспомогательными к анализу – для всего используется один инструмент. ROOT активно поддерживается и развивается. У ROOT есть довольно мощное сообщество. На сайте http://root.cern.ch можно найти ответ почти на все вопросы, касающиеся пакета, в RootTalk (там же) можно задать вопрос любой сложности, на который вам с очень большой вероятностью ответят.

Сравнение PAW и ROOT (IMHO)
Признак PAW ROOT
Авторы Рене Брюн и др. Рене Брюн и др.
Возраст 20 лет Чуть больше 10 лет
GNU Начиная с 2000 года С начала 2006 года
Интерпретатор FORTRAN (COMIS) C++ (CINT)
Командный процессор KUIP C++ (CINT)
Ускорение набора команд Сокращение TAB-completion
Кириллица? Никак Аналогично
Состояние Матёрая, но немного устаревшая система Надо повзрослеть, пора бы уже
Система помощи Подробная официальная документация в

почти 500 страниц, help в командной строке

Пухлое руководство пользователя,

автодокументация по исходным текстам, но нет help.

Что бы сказал Брукс? Старая школа Все признаки «второй системы»
Что есть? То, что нужно для анализа данных То же, плюс много чего ещё лишнего и не очень

Запускаем ROOT

(thumbnail)
ROOT в действии – демонстрация.

Так как ROOT получил лицензию LGPL совсем недавно, то, скорее всего, в вашем настольном дистрибутиве его нет. Поэтому запуск придётся отложить «на потом» после сборки и установки.

Брать исходные тексты лучше всего с основного сайта: http://root.cern.ch. После распаковки дерева пакетов следует внимательно изучить инструкцию README/INSTALL. Сборка стандартная:

> ./configure --prefix=/usr/local ; make ; make install

make install необходимо делать от имени root.

Можно попробовать собрать rpm- или deb-пакет. Собрать deb-пакет под Debian 3.1 (Sarge) без дополнительных телодвижений не удаётся, так как отсутствует пакет, на который указывают зависимости. По-видимому, разработка ведётся для тестовой или нестабильной ветки дистрибутива.

После установки перед запуском необходимо установить переменные окружения. Для bash это будет выглядеть примерно так:

> export ROOTSYS=/usr/local/
> export PATH=$PATH:$ROOTSYS/bin
> export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$ROOTSYS/lib/root

Установка LD_LIBRARY_PATH необходима из-за того, что почти весь функционал ROOT вынесен в разделяемые библиотеки, которые подгружаются во время работы программы. Аналогично можно оформить и свою библиотеку, расширив, таким образом, возможности ROOT.

Всё. Теперь открываем терминал и запускаем ROOT:

> root
***********************************************************
* *
* W E L C O M E to R O O T *
* *
* Version 5.11/02 19 April 2006 *
* *
* You are welcome to visit our Web site *
* http://root.cern.ch *
* *
***********************************************************

FreeType Engine v2.1.9 used to render TrueType fonts.
Compiled on 19 May 2006 for linux with thread support.

CINT/ROOT C/C++ Interpreter version 5.16.11, April 14, 2006
Type ? for help. Commands must be C++ statements.
Enclose multiple statements between { }.
root [0]

Получив приглашение, можно приступать к работе. Сказать "Hello World" из ROOT можно следующим образом:

root [0] cout << "Hello World" << endl;
Hello World

При запуске ROOT считывается файл настроек .rootrc сначала в текущей директории, а, если здесь его нет, то в домашней; затем берётся системный файл /etc/root/system.rootrc. От версии к версии эта последовательность может меняться [4].

По умолчанию есть ещё три файла, которые могут управлять поведением программы:

  • rootlogon.C – выполняется при запуске,
  • rootalias.C – загружается при запуске, но не выполняется,
  • rootlogoff.C – выполняется при завершении сеанса.

ROOT можно запускать и не в интерактивном режиме. Для этого при запуске следует указать опцию -b. Полный список поддерживаемых опций можно получить при указании ключа -h.

Выйти из ROOT можно с помощью команды .q. Если в процессе анализа удалось зациклить программу, то желание выйти можно усилить с помощью команд .qqq, .qqqqq или .qqqqqqq [5]. ^C так же может помочь в непредвиденных ситуациях.

«Командная логика»

В качестве командного процессора используется интерпретатор С++ CINT. Это означает, что интерактивная работа очень похожа на написание обычной программы. Знание языка C/C++ при «общении» с ROOT является обязательным. Как и для PAW, напишем программу по вычислению чисел Фибоначчи:

root [0] {
end with '}', '@':abort > int a=0,b=1;
end with '}', '@':abort > cout << a << " " << b << " ";
end with '}', '@':abort > for (int i=2;i<=10;i++) {
end with '}', '@':abort > int x=a; a=b; b=x+b;
end with '}', '@':abort > cout << b << " ";
end with '}', '@':abort > }
end with '}', '@':abort > cout << endl;
end with '}', '@':abort > }
0 1 1 2 3 5 8 13 21 34 55

Команды группируются с помощью фигурных скобок. Этот же код можно сохранить в файл fibonacci.cxx и выполнить его как скрипт:

root [1] .x fibonacci.cxx
0 1 1 2 3 5 8 13 21 34 55

В случае C++ окончание команды отмечается «;». Если «;» опустить, то из ROOT получится неплохой калькулятор:

root [2] 2*sqrt(5)*sin(2*3.14*75/180)/3.14**2
(const double)2.27312089125660893e-01
root [3] 2**10
(const int)1024
root [4] 2.**1023
(const double)8.98846567431157954e+307

Все вспомогательные команды ROOT начинаются с точки (.). Для выполнения команд оболочки используется команда .!, за которой следуют shell-инструкции:

root [5] .! ls *.cxx
fibonacci.cxx

Полный список вспомогательных команд можно получить с помощью инструкции .?.

Все необходимые для анализа объекты представлены в виде классов. Класс TFile соответствует файлу, в который можно сохранять ROOT-структуры. Объект TTree представляет из себя более изощрённую реализацию идеи ntuple:

root [6] TFile *f=new TFile("ee-ang.root")
root [7] TTree *tree;
root [8] tree= (TTree *) f->Get("h1");
root [9] tree->Draw(«TAB»
void Draw(Option_t* opt)
Long64_t Draw(const char* varexp, const TCut& selection, Option_t*
option = "", Long64_t nentries = 1000000000, Long64_t firstentry = 0)
Long64_t Draw(const char* varexp, const char* selection, Option_t*
option = "", Long64_t nentries = 1000000000, Long64_t firstentry = 0)
root [10] tree->Draw("E1","E1<2.&&f1==-11&&f2==11")

В строке [9] после скобки была нажата клавиша Tab, что привело к выводу подсказки по возможным командам. Отсутствие команды help восполняется автоматически создаваемой подсказкой.

Графический интерфейс

(thumbnail)
Пример графического представления гистограммы (канва E1).

Графическое окно в ROOT называется «канвой» (объект TCanvas). Можно открыть сколько угодно таких окон:

//Создаём новую канву E1.
root [11] TCanvas *E1=new TCanvas("E1")
//Создаём новую канву cfunc.
root [12] TCanvas *cfunc=new TCanvas("func")
//Переходим в канву E1.
root [13] E1->cd();
//Рисуем гистограмму по параметру E1 с условием.
root [14] tree->Draw("E1","E1<2.&&f1==-11&&f2==11")
//Переходим в канву cfunc.
root [15] cfunc->cd()
//Делим канву cfunc на две части по Y.
root [16] cfunc->Divide(1,2)
//Создаём функцию.
root [17] TF1 f1("difr","0.1+(sin(x)/x)**2",-10,10)
//Переходим в верхнюю половину канвы cfunc.
root [18] cfunc->cd(1)
//Отображаем функцию.
root [19] f1->Draw()
//Переходим в нижнюю половину канвы cfunc.
root [20] cfunc->cd(2)
root [21] f1->Draw()
//Устанавливаем для нижней половины канвы cfunc
//логарифмический масштаб для оси Y.
root [22] cfunc->cd(2)->SetLogy()
//Из канвы cfunc создаём векторный eps-файл.
root [23] cfunc->Print("root-cfunc.eps")
//Из канвы E1 создаём растровый png-файл.
root [24] E1->Print("root-E1.png")
(thumbnail)
200pxПример графического представления функции (канва cfunc).

В отличие от своего предка PAW, ROOT позволяет интерактивно менять параметры картинки с помощью выпадающих меню. Тип меню зависит от того, на какой объект направлен указатель мыши. Также с помощью левой кнопки можно интерактивно изменять масштаб графика. Для возврата в исходное состояние в меню, относящемся к выбранной оси, следует выбрать команду UnZoom.

Не стоит этим увлекаться, так как кажущаяся простота увеличивает время, потраченное на создание картинок. В отличие от набранных команд, осмысленные движения и клики мыши сохранить для повторного использования невозможно.

Базовые объекты

ROOT унаследовал все базовые объекты анализа, которые были в PAW. Но, в отличие от PAW, ROOT не ограничивается исключительно анализом. Примером такого подхода, например, служит включение в пакет операций для работы с матрицами (линейная алгебра) и базовых средств для манипуляции объектов OpenGL (отображение физических объёмов). ROOT претендует на нечто большее, чем быть просто пакетом анализа, но всё же в этом разделе будут перечислены только те объекты, которые могут пригодиться для представления данных.

Гистограммы

(thumbnail)
Пример подогнанной гистограммы.

Гистограмма является одним из основных объектов анализа. По сравнению с PAW, в ROOT было добавлено больше типов гистограмм. Конструктор гистограмм имеет вид TH1F. Для двумерной гистограммы вместо 1 надо подставить 2, а для трёхмерной (да, такие тоже есть, правда, непонятно, как их смотреть) – 3. F означает, что на один бин используется Float_t, аналогично возможны и другие типы переменных для хранения значения в бине.

//Создаём новую канву.
root [25] TCanvas *ch=new TCanvas("Hist Test","Hist")
//Создаём гистограмму в 100 бинов от -3. до 3.
root [26] TH1F *h = new TH1F("h","Hist Test",100,-3.,3.)
//Обычно гистограммы заполняются с помощью метода Fill.
root [27] h->Fill(«TAB»
Int_t Fill(Double_t x)
Int_t Fill(Double_t x, Double_t w)
Int_t Fill(const char* name, Double_t w)
//Но мы сейчас идём другим путём:
// а) создаём функцию G,
root [28] TF1 *func = new TF1("G","exp(-x**2)",-3,3)
// б) заполняем гистограмму случайным образом
// по форме функции G.
root [29] h->FillRandom("G",1000)
//Меняем цвет гистограммы.
root [30] h->SetFillColor(45)
//Подгоняем гистограмму распределением Гаусса
root [31] h->Fit("gaus")
…
//Сохраняем полученную картинку.
root [32] ch->Print("root-histexample.eps")

Подгонкой «заведует» всё тот же Minuit, что был и в PAW, правда, переписанный на C++. Алгоритмы не поменялись.

Деревья

(thumbnail)
Графическое представление дерева lkravg. Видно, что красные точки в среднем ниже чёрных, что и требовалось доказать.

Деревья (tree) в ROOT – это логичное развитие идеи ntuple. ntuple, по сути дела, был таблицей со столбцами переменных типа float. В случае деревьев этого ограничения не существует, и в дереве можно сохранять любые объекты.

//Создаём файл на диске.
root [33] TFile *f = new TFile("lkravg.root","RECREATE")
//Заводим новое дерево
root [34] TTree *lkravg = new TTree("lkravg","LKr degrad")
//Считаем файл lkravg.dat - тот самый, что "мучили" в
//статье про PAW
root [35] Long64_t nlines = lkravg->ReadFile("lkravg.dat",
//список переменных
"time:run:avg:avg_er:P:H")
root [36] cout << "Number of lines: " << nlines << endl
//Рисуем картинку: чёрные маркеры - есть магнитное поле,
//красные маркеры - нет магнитного поля.
root [37] lkravg->SetMarkerStyle(5)
root [38] lkravg->Draw("avg:time","H>0.1")
root [39] lkravg->SetMarkerColor(kRed)
root [40] lkravg->Draw("avg:time","H<=0.1","same")
//Пишем дерево в файл и закрываем файл.
root [41] lkravg->Write();
root [42] f->Close();
//Теперь этот файл можно открыть
root [43] TFile *f2 = new TFile("lkravg2.root")
//и посмотреть что в нём есть - дерево сохранилось.
root [44] .ls
TFile** lkravg2.root
TFile* lkravg2.root
KEY: TTree lkravg;1 LKr degrad

В ROOT есть множество способов создать и заполнить дерево. Подробности лучше посмотреть в пользовательской документации.

Функции

(thumbnail)
Примеры графического представления двумерной функции или гистограммы. Множество Мандельброта.

Как и в PAW, в ROOT есть мощная поддержка функций как объектов. С помощью метода Fit можно подогнать гистограмму или график. Но до этого следует определить функцию, например, так:

//Файл mandel.cxx
//Множество Мандельброта
Double_t mandel(Double_t *XP,Double_t *par) {
const Int_t nmax=30;
Double_t xx=0.,yy=0.,tt,x,y;
x=XP[0];y=XP[1];
for (Int_t n=1;n<nmax;n++) {
tt=xx*xx-yy*yy+x;
yy=2.*xx*yy+y;
xx=tt;
if (xx*xx+yy*yy>4.) break;
}
return Double_t(n)/Double_t(nmax);
}

Текст функции следует сохранить в файле mandel.cxx. После с ним можно работать из ROOT:

//Загружаем описание функции mandel.cxx.
//Теперь можно обращаться к функции.
root [45] .L mandel.cxx
root [46] TCanvas *cm=new TCanvas("mandelbrot","Mandelbrot")
//Создаём объект «двумерная функция» TF2
root [47] TF2 *Mandelbrot=new
TF2("Mandelbrot",mandel,-2.4,.8,-1.2,1.2,0)
root [48] cm->Divide(2,2)
root [49] cm->cd(1)
root [50] Mandelbrot->SetNpx(«TAB»
void SetNpx(Int_t npx = 100) // *MENU*
//Увеличиваем число шагов отображения.
//Как и в PAW функции отображаются через гистограммы.
root [51] Mandelbrot->SetNpx(200)
root [52] Mandelbrot->SetNpy(200)
//Контурное графическое представление.
root [53] Mandelbrot->Draw("cont")
root [54] cm->cd(2)
//Графическое представление в виде поверхность.
root [55] Mandelbrot->Draw("surf2")
root [56] cm->cd(3)
//Множество Мандельброта в цилиндрических координатах.
root [57] Mandelbrot->Draw("surf4cyl")
root [58] cm->cd(4)
//Графическое представление в стиле LEGO.
root [59] Mandelbrot->Draw("lego")
root [60] cm->Print("root-mandel.eps")

Интерпретатор C++ (CINT)

Интерпретатор С++ или CINT, который используется в ROOT, был независимым проектом. Сейчас он является составной частью ROOT, но его можно использовать и отдельно. Домашняя страничка CINT доступна по адресу http://root.cern.ch/root/Cint.html.

CINT охватывает примерно 95% конструкций ANSI C и 85% от C++. Следует понимать, что полное соответствие стандартам никогда не было основной целью CINT. Не следует писать больших программ, опираясь на интерпретатор, так как скорость выполнения команд уступает компилируемой версии программы примерно в десять раз. А где один порядок, там и два. Для небольших скриптов автоматизации анализа CINT вполне подходит, но для серьёзных целей надо писать обычные программы. Благо, абсолютно всё, что доступно в ROOT интерактивно, доступно и через библиотечные вызовы. Так уж ROOT сделан.

Для внешних CINT-скриптов есть две полезные команды:

//Выполняем скрипт script.cxx
root [66] .x script.cxx
//Загружаем функции, описанные в lib.cxx
root [67] .L lib.cxx

Одной из отличительных особенностей ROOT является возможность делать функции из внешних библиотек доступными для выполнения в скриптах CINT или интерактивно. Ниже будет приведён пример, как подключить пользовательскую C-библиотеку.

Допустим, у вас есть C-библиотека, в которой есть функции myfunc1() и myfunc2(char*), которые необходимо экспортировать в среду ROOT. Для этого нужно создать заголовочный файл myfile.h примерно следующего вида:

/*Файл myfile.h*/
#ifdef __cplusplus
extern "C" {
#endif
extern void myfunc1();
extern int myfunc2(char *);
#ifdef __cplusplus
}
#endif

Пока всё как обычно. Чтобы экспортировать функции в ROOT, необходимо создать ещё один заголовочный файл myfileLinkDef.h (к myfile добавляется LinkDef):

/*Файл myfileLinkDef.h */
#ifdef __CINT__
#pragma link C++ function myfunc1();
#pragma link C++ function myfunc2(char*);
#endif

Так же можно экспортировать и структуры, подставив вместо слова function слово struct. После создания описанных заголовочных файлов необходимо создать «словарик»:

> rootcint -f myfileDict.cxx -c myfile.h myfileLinkDef.h

В результате будут созданы файлы myfileDict.h и myfileDict.cxx.

Далее нужно собрать саму библиотеку. Пусть для простоты вся библиотека представляет из себя один C-файл myfile.c:

# Компилируем myfile.c.
> gcc -c -fPIC myfile.c
# Компилируем словарик.
> g++ -c -fPIC 'root-config --cflags' myfileDict.cxx
# Создаём разделяемую библиотеку.
> g++ -shared -o myfile.so myfile.o myfileDict.o

Теперь эту вновь созданную библиотеку можно загрузить в ROOT для интерактивной работы:

root [68] gSystem->Load("myfile")
root [69] myfunc1()
root [70] Int_t icount=myfunc2("string")

Это далеко не единственный способ подключить пользовательскую библиотеку к ROOT. Для компиляции скриптов можно использовать подсистему ACLiC.

P.S. Кроме CINT, в среде ROOT можно использовать скрипты, написанные на Python или Ruby. И наоборот: из этих языков можно общаться с библиотеками ROOT. К сожалению, описание этих механизмов выходит за рамки данной статьи.

Заключение

Эта статья – не описание ROOT, а всего лишь набор штрихов к его портрету. Для более подробного знакомства настоятельно рекомендуем посетить http://root.cern.ch.

ROOT – не просто инструмент анализа; это среда для генерации таких инструментов. Он, возможно, неповоротлив и избыточен, но гибок и очень легко расширяем. Это не идеал, но идеал, скорее всего, будет на него похож.

Примечения

  1. Почему ROOT так называется? У меня есть только догадки: OO — видимо, Object Oriented, а сам ROOT от английского «корень» или «источник» (root). Предполагается, что ROOT — это база для разработок, а не просто система анализа, то есть корень всех …
  2. Таких заходов было чуть меньше 5 тысяч. Грубо, <math>1</math>Тб=<math>10^3</math>Гб=<math>10^6</math>Мб.
  3. Я слышал такой вариант ответа: «потому что, в отличие от PAW, в графическом окне ROOT можно мышкой подправить экспериментальные данные» – очень надеюсь, что это была шутка.
  4. В руководстве пользователя в этом месте присутствуют ошибки.
  5. Чем больше q, тем «сильнее» желание.
Персональные инструменты
купить
подписаться
Яндекс.Метрика