LXF83:ROOT
м (Новая: == Продолжая традиции: ROOT == '' '''ЧАСТЬ 3''' Данные мало получить – надо ещё понять, а есть ли от них польза. ...) |
|||
Строка 1: | Строка 1: | ||
== Продолжая традиции: ROOT == | == Продолжая традиции: ROOT == | ||
'' '''ЧАСТЬ 3''' Данные мало получить – надо ещё понять, а есть ли от них польза. '''Евгений Балдин''' представляет вашему вниманию «новинку» среди приложений для анализа данных.'' | '' '''ЧАСТЬ 3''' Данные мало получить – надо ещё понять, а есть ли от них польза. '''Евгений Балдин''' представляет вашему вниманию «новинку» среди приложений для анализа данных.'' | ||
+ | |||
+ | Даже если данных много – их надо как-то проанализировать. Это может сделать только человек. Компьютер в этом деле только помощник. Выбор инструмента очень важен. ROOT – хороший инструмент. У него был достойный предок и он мог бы быть гораздо лучше. Но здесь и сейчас надо анализировать данные, фиксируя недостатки, дабы исправить их в будущем. Это возможно, потому что ROOT – это свободный продукт. | ||
+ | |||
+ | Примерно через десять лет после возникновения команде PAW (Physics Analysis Workstation) стало скучно, и ее лидер PAW Рене Брюн (Ren Brun) сотоварищи начал новый проект ROOT – An Object Oriented Data Analysis Framework1. | ||
+ | |||
+ | Компьютеры стали много мощнее, но и поток данных увеличился. | ||
+ | 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 (там же) можно | ||
+ | задать вопрос любой сложности, на который вам с очень большой | ||
+ | вероятностью ответят. | ||
+ | |||
+ | === Запускаем 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 или .qqqqqqq5. ^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 | ||
+ | восполняется автоматически создаваемой подсказкой. | ||
+ | |||
+ | === Графический интерфейс === | ||
+ | Графическое окно в 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”) | ||
+ | В отличие от своего предка PAW, ROOT позволяет интерактивно | ||
+ | менять параметры картинки с помощью выпадающих меню. Тип меню | ||
+ | зависит от того, на какой объект направлен указатель мыши. Также с | ||
+ | помощью левой кнопки можно интерактивно изменять масштаб графи- | ||
+ | ка. Для возврата в исходное состояние в меню, относящемся к выбран- | ||
+ | ной оси, следует выбрать команду UnZoom. | ||
+ | Не стоит этим увлекаться, так как кажущаяся простота увеличива- | ||
+ | ет время, потраченное на создание картинок. В отличие от набранных | ||
+ | команд, осмысленные движения и клики мыши сохранить для повтор- | ||
+ | ного использования невозможно. | ||
+ | |||
+ | === Базовые объекты === | ||
+ | ROOT унаследовал все базовые объекты анализа, которые были в | ||
+ | PAW. Но, в отличие от PAW, ROOT не ограничивается исключительно | ||
+ | анализом. Примером такого подхода, например, служит включение в | ||
+ | пакет операций для работы с матрицами (линейная алгебра) и базовых | ||
+ | средств для манипуляции объектов OpenGL (отображение физических | ||
+ | объёмов). ROOT претендует на нечто большее, чем быть просто пакетом | ||
+ | анализа, но всё же в этом разделе будут перечислены только те объекты, | ||
+ | которые могут пригодиться для представления данных. | ||
+ | |||
+ | === Гистограммы === | ||
+ | Гистограмма является одним из основных объектов анализа. По срав- | ||
+ | нению с 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++. Алгоритмы не поменялись. | ||
+ | |||
+ | === Деревья === | ||
+ | Деревья (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 есть множество способов создать и заполнить дерево. | ||
+ | Подробности лучше посмотреть в пользовательской документации. | ||
+ | |||
+ | === Функции === | ||
+ | Как и в 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 – не просто инструмент анализа; это среда для | ||
+ | генерации таких инструментов. Он, возможно, неповорот- | ||
+ | лив и избыточен, но гибок и очень легко расширяем. Это не | ||
+ | идеал, но идеал, скорее всего, будет на него похож. |
Версия 18:21, 10 марта 2008
|
|
|
Содержание |
Продолжая традиции: ROOT
ЧАСТЬ 3 Данные мало получить – надо ещё понять, а есть ли от них польза. Евгений Балдин представляет вашему вниманию «новинку» среди приложений для анализа данных.
Даже если данных много – их надо как-то проанализировать. Это может сделать только человек. Компьютер в этом деле только помощник. Выбор инструмента очень важен. ROOT – хороший инструмент. У него был достойный предок и он мог бы быть гораздо лучше. Но здесь и сейчас надо анализировать данные, фиксируя недостатки, дабы исправить их в будущем. Это возможно, потому что ROOT – это свободный продукт.
Примерно через десять лет после возникновения команде PAW (Physics Analysis Workstation) стало скучно, и ее лидер PAW Рене Брюн (Ren Brun) сотоварищи начал новый проект ROOT – An Object Oriented Data Analysis Framework1.
Компьютеры стали много мощнее, но и поток данных увеличился. 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 (там же) можно задать вопрос любой сложности, на который вам с очень большой вероятностью ответят.
Запускаем 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 или .qqqqqqq5. ^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 восполняется автоматически создаваемой подсказкой.
Графический интерфейс
Графическое окно в 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”) В отличие от своего предка PAW, ROOT позволяет интерактивно менять параметры картинки с помощью выпадающих меню. Тип меню зависит от того, на какой объект направлен указатель мыши. Также с помощью левой кнопки можно интерактивно изменять масштаб графи- ка. Для возврата в исходное состояние в меню, относящемся к выбран- ной оси, следует выбрать команду UnZoom. Не стоит этим увлекаться, так как кажущаяся простота увеличива- ет время, потраченное на создание картинок. В отличие от набранных команд, осмысленные движения и клики мыши сохранить для повтор- ного использования невозможно.
Базовые объекты
ROOT унаследовал все базовые объекты анализа, которые были в PAW. Но, в отличие от PAW, ROOT не ограничивается исключительно анализом. Примером такого подхода, например, служит включение в пакет операций для работы с матрицами (линейная алгебра) и базовых средств для манипуляции объектов OpenGL (отображение физических объёмов). ROOT претендует на нечто большее, чем быть просто пакетом анализа, но всё же в этом разделе будут перечислены только те объекты, которые могут пригодиться для представления данных.
Гистограммы
Гистограмма является одним из основных объектов анализа. По срав- нению с 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++. Алгоритмы не поменялись.
Деревья
Деревья (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 есть множество способов создать и заполнить дерево. Подробности лучше посмотреть в пользовательской документации.
Функции
Как и в 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 – не просто инструмент анализа; это среда для генерации таких инструментов. Он, возможно, неповорот- лив и избыточен, но гибок и очень легко расширяем. Это не идеал, но идеал, скорее всего, будет на него похож.