Monitory w HAL-u
Dane w analizie powinny być "monitorowane". W HAL-u istnieją 3 rodzaje monitorów i działają one w następujący sposób:
- dany obiekt (cząstka, event) jest sprawdzany przez cięcia szybkie (dodane z flagą "fast")
- jeśli obiekt przejdzie cięcia szybkie idzie do cięć wolnych
- jeśli obiekt przejdzie cięcia wolne idzie do analizy, na tym etapie wypełniane są dwa histogramy w każdym monitorze:
- jeśli obiekt przeszedł cięcia wolne to jego dane wypełniają histogram "passed"
- jeśli nie, to jego dane wypełniają histogram "failed"
W HAL-u istnieją 3 rodzaje monitorów:
Rodzaj monitora | Konstruktor | Zalety | Wady |
Monitor pól | Monitor(ID pola1, ...) | Nie trzeba dodawać żadnych cięć, ani tworzyć własnej klasy | Monitorować można tylko określone wartości zdefiniowane przez pola |
Monitor właściwości | Określony przez użytkownika | Sami definiujemy co chcemy na wykresach | Musimy stworzyć własną klasę będącą monitorem |
Monitor cięć | Monitor(nazwa_cięcia, id parametru..) | Nie trzeba tworzyć własnych klas (o ile istnieją odpowiednie cięćia) | W analizie musi istnieć cięcie które będzie monitorowane |
Monitory pól były omówione wcześniej więc opiszmy 2 pozostałe grupy.
Monitory dodaje się do analizy przy pomocy AddCutMonitor, podobnie jak w przypadku cięć można określić tu kolekcję, do której dodajemy cięcie oraz zdefiniować czy cięcie ma być rzeczywiste czy urojone. Istnieje tu jednak zasadnicza różnica między monitorami a cięciami - cięcie domyślnie ma dodatnie ID kolekcji, a brak odpowiedniej kolekcji wymusi jej stworzenie, monitor cięć nie może wymusić stworzenia nowej kolecji, co więcej domyślnie monitor cięć jest dodawany do każdej kolekcji chyba, że użytkownik sprecyzuje określone ID kolekcji.
Monitory cięć
Monitor cięć to klasa, która działa podobnie jak monitor pól, z tym że zamiast używać jakiegoś ID pola bierze ona wartość wyliczoną przez algorytm selekcji danych. Przykładowo jeśli w poprzednich dodaliśmy do analizy Hal::EventTotalTrackNoCut mogliśmy zamiast używać pola ID do wyświetlenia krotności, użyć monitora bazującego na tym cięciu.
Monitor aby działał potrzebuje cięcia - tzn. jeśli skonfigurujemy poprawnie monitor ale nie dodamy go do analizy to i tak nie zostanie on "aktywowany". Jest to zasadnicza różnica między monitorem cięć a monitorem pól. Monitory tworzymy w następujący sposób:
void cut_mon() { auto run = new Hal::AnalysisManager(); auto source = new Hal::RootSource("/opt/temp/glauber.root"); run->SetOutput("/opt/temp/dataB.root"); run->SetSource(source); HalOTF::Reader* reader = new HalOTF::Reader(); run->AddTask(reader); Hal::EventAna* ana = new Hal::EventAna(); Hal::EventVertexXYZCut vertex; vertex.SetMinMax(0, 237); ana->AddCut(vertex, "{0}+re");//cięcie musi być dodane do analizy jeśli chcemy użyć monitora Hal::CutMonitorXY monitor(vertex.CutName("re"), 1, vertex.CutName("re"), 2); monitor.SetXaxis(100, -1, 1); monitor.SetYaxis(100, -1, 1); ana->AddCutMonitor(monitor); run->AddTask(ana); run->Init(); run->Run(0, 1000); }
W analizie używamy cięcia Hal::EventVertexXYZCut, to jest cięcie, które tak naprawdę sprawdza cztery parametry na raz - Rt, X,Y,Z gdzie $R_t=\sqrt{x^2+y^2+z^2}$. Dlatego w konstruktorze oprócz podawania nazwy cięcia (CutName) określiliśmy, które wartości chcemy monitorować - 1 to X a 2 to Y. Zauważmy też, że CutName wywołujemy z flagą "re" - jest to konsekwencja tego, że cięcie jest również dodane z flagą "re" - czyli monitoruje dane zrekonstruowane.
W HAL-u możemy mieć dowolną liczbę monitorów, zasada jest jednak taka, że należy monitorować cięcia z tego samego tieru tzn. cięcia zderzeniowe ze zderzeniowymi, cząstkowe z cząstkowymi itd. Przy dodawaniu cięć działają te same opcje jak w przypadku cięć, z tym, że jeśli nie sprecyzujemy kolekcji do której dodawany jest monitor, to zostanie on dodany do każdej kolekcji (cięcie zawsze jest dodawane do jednej kolekcji o ile nie użyjemy jakiś magicznych flag). Oznacza to, że ten sam efekt co w kodzie wyżej można osiągnać w ten sposób:
Hal::CutMonitorXY monitor(vertex.CutName(), 1, vertex.CutName(), 2); monitor.SetXaxis(100, -1, 1); monitor.SetYaxis(100, -1, 1); ana->AddCutMonitor(monitor, "re");
Jak widać tutaj nie mówimy, że chcemy monitorować "rzeczywiste" cięcia w konstruktorze a dopiero w monitorze to określamy.
Monitor cięci zadziała jeśli cięcia są obecne w analizie, jednak jest w tej regule pewien wyjątek. Jeśli cięcie jest dodawane z flagą "fast" to jest ono uruchamiane w trybie szybkim, tzn. HAL odrzuca od razu złe obiekty (zderzenia, cząstki). Takich cięć nie da się monitorować - w zasadzie obiekty odrzucone w cięciach szybkich nie są nawet widoczne jako "failed".
Monitory właściwości
Poza monitorami pól i cięć istnieją również monitory właściwości. Są to klasy w których sami definiujemy co znajdzie się w histogramie, musimy więc tworzyć własną klasę. Monitor 1-wymiarowy wygląda następująco:
class MyClass : public Hal::PropertyMonitorX { public: MyClass(): PropertyMonitorX(__XLABEL__, __YLABEL__, __UPDATE__){}; MyClass(std::initializer_listx):PropertyMonitorTemplateX() { SetAxisList(x, 'x'); } virtual void Update(Bool_t passed, TObject* obj){ // Update method if (passed) { fHistoPassed->Fill(__XYZ__); } else { fHistoFailed->Fill(__XYX__) }} virtual Bool_t Init(Int_t task_id){ return kTRUE; } virtual CutMonitor* MakeCopy() const{ return new MyClass(*this); } virtual ~MyClass(){}; ClassDef(MyClass, 1) };
- W konstruktorze podajemy wartości __XLABEL__ i __Y_LABEL__ to nazwy monitorowanych wartości, HAL używa konwencji "nazwa [jednostka]", te wartości są używane przy opisie osi histogramów. _UPDATE_ definiuje do którego tieru należy nasz monitor np. jeśli damy ECutUpdate::kEventUpdate jest to tier zderzeniowy czyli monitor jest aktualizowany przy przejści z jednego zderzenia na drugie. SetAxisList jest używane do podania domyślnej liczby binów + zakresu histgramu, 'x' oznacza że konfigurujemy oś X.
- Metoda Update to "mięsko" tutaj powinniśmy nasz obiekt *obj rzutować na odpowiedni typ (zgodny z _UPDATE_ czy lin. da ECutUpddate::kEventUdate będzie to Hal::Event) i w zależności od flagi passed wrzucić do histogramu dobrych (passed) lub złych (failed) obiektów.
- Metoda Init jest opcjonalna, służy do sprawdzania czy np. nasz format danych jest kompatybilny z naszym monitorem, jeśli monitor nie może być użyty to funkcja ta powinna zwracać kFALSE.
- Metoda MakeCopy zwraca kopię monitora. W przypadku gdy piszemy kompilowaną klasę ta metoda jest zbędna bo HAL użyjem metody Clone do skopiowania klasy. Jeśli jednak klasę definiujemy w makrze to Clone nie działa i wtedy ta metoda musi być zaimplementowana.
Aby ułatwić tworzenie nowych monitorów w HAL->Javaskrypty->Monitor cięć jest prosty kreator.
Odwrócenie problemu