Project
Loading...
Searching...
No Matches
EventManagerFrame.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
16
17#include <TGButton.h>
18#include <TGButtonGroup.h>
19#include <TGNumberEntry.h>
20#include <TGLabel.h>
21#include <TText.h>
22#include <TTimer.h>
23#include <TGDoubleSlider.h>
31#include <Rtypes.h>
32#include <mutex>
33#include <chrono>
34#include <thread>
35#include <filesystem>
36#include <cassert>
37#include <fairlogger/Logger.h>
38
39std::mutex mtx; // mutex for critical section
40
42
43namespace o2
44{
45namespace event_visualisation
46{
47
48EventManagerFrame* EventManagerFrame::mInstance = nullptr;
49
51{
52 assert(mInstance != nullptr);
53 return *mInstance;
54}
55
60
62 : TGMainFrame(gClient->GetRoot(), 400, 100, kVerticalFrame)
63{
64 mInstance = this;
65 mEventManager = &eventManager;
66 this->mTimer = new TTimer(); // Auto-load time in seconds
68 this->mTimer->Connect("Timeout()", "o2::event_visualisation::EventManagerFrame", this, "DoTimeTick()");
69
70 const TString cls("o2::event_visualisation::EventManagerFrame");
71 TGTextButton* b = nullptr;
72 TGRadioButton* r = nullptr;
73 TGHorizontalFrame* f = nullptr;
74
75 auto const options = Options::Instance();
76
77 this->mRunMode = decipherRunMode(options->dataFolder());
78
79 f = new TGHorizontalFrame(this);
80 {
81 Int_t width = 50;
82 this->AddFrame(f, new TGLayoutHints(kLHintsExpandX, 0, 0, 2, 2));
83
84 b = EventManagerFrame::makeButton(f, "First", width, "Go to the first event");
85 b->Connect("Clicked()", cls, this, "DoFirstEvent()");
86 b = EventManagerFrame::makeButton(f, "Prev", width, "Go to the previous event");
87 b->Connect("Clicked()", cls, this, "DoPrevEvent()");
88
89 mEventId = new TGNumberEntry(f, 0, 5, -1, TGNumberFormat::kNESInteger, TGNumberFormat::kNEANonNegative,
90 TGNumberFormat::kNELLimitMinMax, 0, 10000);
91 f->AddFrame(mEventId, new TGLayoutHints(kLHintsNormal, 10, 5, 0, 0));
92 mEventId->Connect("ValueSet(Long_t)", cls, this, "DoSetEvent()");
93
94 b = EventManagerFrame::makeButton(f, "Next", width, "Go to the next event");
95 b->Connect("Clicked()", cls, this, "DoNextEvent()");
96 b = EventManagerFrame::makeButton(f, "Last", width, "Go to the last event");
97 b->Connect("Clicked()", cls, this, "DoLastEvent()");
98 b = EventManagerFrame::makeButton(f, "Screenshot", 2 * width, "Make a screenshot of current event");
99 b->Connect("Clicked()", cls, this, "DoScreenshot()");
100
101 b = EventManagerFrame::makeButton(f, "Save", 2 * width, "Save current event");
102 b->Connect("Clicked()", cls, this, "DoSave()");
103
104 TGHButtonGroup* g = new TGHButtonGroup(f);
105 this->mOnlineModeBtn = b = EventManagerFrame::makeRadioButton(g, "Online", 2 * width,
106 "Change data source to online events",
107 Options::Instance()->online());
108 b->Connect("Clicked()", cls, this, "DoOnlineMode()");
109 this->mSavedModeBtn = b = EventManagerFrame::makeRadioButton(g, "Saved", 2 * width,
110 "Change data source to saved events",
111 !Options::Instance()->online());
112 b->Connect("Clicked()", cls, this, "DoSavedMode()");
113 this->mSequentialModeBtn = b = EventManagerFrame::makeRadioButton(g, "Sequential", 2 * width,
114 "Sequentially display saved events",
115 !Options::Instance()->online());
116 b->Connect("Clicked()", cls, this, "DoSequentialMode()");
117 f->AddFrame(g, new TGLayoutHints(kLHintsNormal, 0, 0, 0, 0));
118
119 // TGHButtonGroup*
120 g = new TGHButtonGroup(f);
121 mNewestRunBtn = r = EventManagerFrame::makeRadioButton(g, "Newest", 2 * width,
122 "Change source directory to newest data",
123 false);
124 r->Connect("Clicked()", cls, this, "DoNewestData()");
125 mSyntheticRunBtn = r = EventManagerFrame::makeRadioButton(g, "Synthetic", 2 * width,
126 "Change source directory to synthetic run",
127 false);
128 r->Connect("Clicked()", cls, this, "DoSyntheticData()");
129 mCosmicsRunBtn = r = EventManagerFrame::makeRadioButton(g, "Cosmics", 2 * width,
130 "Change source directory to cosmics run",
131 false);
132 r->Connect("Clicked()", cls, this, "DoCosmicsData()");
133 mPhysicsRunBtn = r = EventManagerFrame::makeRadioButton(g, "Physics", 2 * width,
134 "Change source directory to physics run",
135 false);
136 r->Connect("Clicked()", cls, this, "DoPhysicsData()");
137 f->AddFrame(g, new TGLayoutHints(kLHintsNormal, 0, 0, 0, 0));
138
139 this->mSavedScreenshotFileName = new TGLabel(f, std::string(128, ' ').c_str());
140 // this->mSavedScreenshotFileName->SetWrapLength(100);
141 f->AddFrame(this->mSavedScreenshotFileName, new TGLayoutHints(kLHintsNormal, 5, 10, 4, 0));
142 }
143
144 f = new TGHorizontalFrame(this);
145 {
146 Int_t width = 50;
147 this->AddFrame(f, new TGLayoutHints(kLHintsExpandX, 0, 0, 2, 2));
148
149 TGLabel* infoLabel = new TGLabel(f);
150 f->AddFrame(infoLabel, new TGLayoutHints(kLHintsNormal, 5, 10, 4, 0));
151
152 f->AddFrame(infoLabel, new TGLayoutHints(kLHintsNormal, 5, 10, 4, 0));
153 this->mTimeFrameSlider = EventManagerFrame::makeSlider(f, "Time", 8 * width);
154 makeSliderRangeEntries(f, 30, this->mTimeFrameSliderMin, "Display the minimum value of the time",
155 this->mTimeFrameSliderMax, "Display the maximum value of the time");
156 this->mTimeFrameSlider->Connect("PositionChanged()", cls, this, "DoTimeFrameSliderChanged()");
157 }
158
159 this->setRunMode(mRunMode);
160 this->mOnlineModeBtn->SetState(kButtonDown);
161 SetCleanup(kDeepCleanup);
162 Layout();
163 MapSubwindows();
164 MapWindow();
165}
166
167TGTextButton* EventManagerFrame::makeButton(TGCompositeFrame* p, const char* txt,
168 Int_t width, const char* txttooltip, Int_t lo, Int_t ro, Int_t to, Int_t bo)
169{
170 TGTextButton* b = new TGTextButton(p, txt);
171
172 if (width > 0) {
173 b->SetWidth(width);
174 b->ChangeOptions(b->GetOptions() | kFixedWidth);
175 }
176
177 if (txttooltip != nullptr) {
178 b->SetToolTipText(txttooltip);
179 }
180
181 p->AddFrame(b, new TGLayoutHints(kLHintsNormal, lo, ro, to, bo));
182 return b;
183}
184
185TGRadioButton* EventManagerFrame::makeRadioButton(TGButtonGroup* g, const char* txt,
186 Int_t width, const char* txttooltip, bool checked, Int_t lo, Int_t ro,
187 Int_t to, Int_t bo)
188{
189 TGRadioButton* b = new TGRadioButton(g, txt);
190
191 if (width > 0) {
192 b->SetWidth(width);
193 b->ChangeOptions(b->GetOptions() | kFixedWidth);
194 }
195
196 if (txttooltip != nullptr) {
197 b->SetToolTipText(txttooltip);
198 }
199
200 b->SetOn(checked);
201
202 return b;
203}
204
205TGDoubleHSlider* EventManagerFrame::makeSlider(TGCompositeFrame* p, const char* txt, Int_t width,
206 Int_t lo, Int_t ro, Int_t to, Int_t bo)
207{
208 TGCompositeFrame* sliderFrame = new TGCompositeFrame(p, width, 20, kHorizontalFrame);
209 TGLabel* sliderLabel = new TGLabel(sliderFrame, txt);
210 sliderFrame->AddFrame(sliderLabel,
211 new TGLayoutHints(kLHintsCenterY | kLHintsLeft, 2, 2, 2, 2));
212 TGDoubleHSlider* slider = new TGDoubleHSlider(sliderFrame, width - 80, kDoubleScaleBoth);
213 slider->SetRange(0, MaxRange);
214 slider->SetPosition(0, MaxRange);
215 sliderFrame->AddFrame(slider, new TGLayoutHints(kLHintsLeft));
216 p->AddFrame(sliderFrame, new TGLayoutHints(kLHintsTop, lo, ro, to, bo));
217 return slider;
218}
219
220void EventManagerFrame::makeSliderRangeEntries(TGCompositeFrame* parent, int height,
221 TGNumberEntryField*& minEntry, const TString& minToolTip,
222 TGNumberEntryField*& maxEntry, const TString& maxToolTip)
223{
224 TGCompositeFrame* frame = new TGCompositeFrame(parent, 80, height, kHorizontalFrame);
225
226 minEntry = new TGNumberEntryField(frame, -1, 0., TGNumberFormat::kNESRealThree,
227 TGNumberFormat::kNEAAnyNumber);
228 minEntry->SetToolTipText(minToolTip.Data());
229 minEntry->Resize(100, height);
230 minEntry->SetState(false);
231 frame->AddFrame(minEntry, new TGLayoutHints(kLHintsLeft, 0, 0, 0, 0));
232
233 maxEntry = new TGNumberEntryField(frame, -1, 0., TGNumberFormat::kNESRealThree,
234 TGNumberFormat::kNEAAnyNumber);
235 maxEntry->SetToolTipText(maxToolTip.Data());
236 maxEntry->Resize(100, height);
237 maxEntry->SetState(false);
238 frame->AddFrame(maxEntry, new TGLayoutHints(kLHintsLeft, 0, 0, 0, 0));
239 parent->AddFrame(frame, new TGLayoutHints(kLHintsTop, 5, 0, 0, 0));
240}
241
242void EventManagerFrame::updateGUI()
243{
244 std::error_code ec{};
245 bool saveFolderExists = std::filesystem::is_directory(Options::Instance()->savedDataFolder(), ec);
246 this->mSavedModeBtn->SetEnabled(saveFolderExists);
247 this->mSequentialModeBtn->SetEnabled(saveFolderExists);
248 this->mEventId->SetIntNumber(mEventManager->getDataSource()->getCurrentEvent());
249 this->mTimeFrameSliderMin->SetNumber(mEventManager->getDataSource()->getTimeFrameMinTrackTime());
250 this->mTimeFrameSliderMax->SetNumber(mEventManager->getDataSource()->getTimeFrameMaxTrackTime());
251 switch (this->mDisplayMode) {
252 case OnlineMode:
253 this->mOnlineModeBtn->SetState(kButtonDown);
254 break;
255 case SavedMode:
256 this->mSavedModeBtn->SetState(kButtonDown);
257 break;
258 case SequentialMode:
259 this->mSequentialModeBtn->SetState(kButtonDown);
260 break;
261 }
262 switch (this->mRunMode) {
264 this->mNewestRunBtn->SetState(kButtonDown, kTRUE);
265 break;
267 this->mSyntheticRunBtn->SetState(kButtonDown, kTRUE);
268 break;
270 this->mCosmicsRunBtn->SetState(kButtonDown, kTRUE);
271 break;
273 this->mPhysicsRunBtn->SetState(kButtonDown, kTRUE);
274 break;
275 }
276 this->mUpdateGui = false;
277}
278
280{
281 if (not setInTick()) {
282 return;
283 }
285 this->updateGUI();
286 clearInTick();
287}
288
290{
291 if (not setInTick()) {
292 return;
293 }
295 this->updateGUI();
296 clearInTick();
297}
298
300{
301 if (not setInTick()) {
302 return;
303 }
305 this->updateGUI();
306 clearInTick();
307}
308
310{
311 if (not setInTick()) {
312 return;
313 }
315 this->updateGUI();
316 clearInTick();
317}
318
320{
321 if (not setInTick()) {
322 return;
323 }
325 this->updateGUI();
326 clearInTick();
327}
328
332
334{
335 if (not setInTick()) {
336 return;
337 }
338
339 std::string outDirectory = ConfigurationManager::getScreenshotPath("screenshot");
340
341 std::time_t time = std::time(nullptr);
342 char time_str[100];
343 std::strftime(time_str, sizeof(time_str), "%Y_%m_%d_%H_%M_%S", std::localtime(&time));
344
345 bool monthDirectory = ConfigurationManager::getScreenshotMonthly();
346
347 if (monthDirectory) {
348 char dir_str[32];
349 std::strftime(dir_str, sizeof(dir_str), "%Y-%m", std::localtime(&time));
350 outDirectory = outDirectory + "/" + dir_str;
351 std::filesystem::create_directory(outDirectory);
352 }
353
354 std::ostringstream filepath;
355 filepath << outDirectory << "/Screenshot_" << time_str << ".png";
356
357 std::string path = filepath.str();
358
359 std::filesystem::path fileName = Screenshot::perform("screenshot", path,
361 this->mEventManager->getDataSource()->getRunNumber(),
362 this->mEventManager->getDataSource()->getFirstTForbit(),
363 this->mEventManager->getDataSource()->getCreationTimeAsString());
364 fileName.replace_extension(
365 std::filesystem::path(mEventManager->getDataSource()->getEventAbsoluteFilePath()).extension());
366 std::error_code ec;
367 std::filesystem::copy_file(mEventManager->getDataSource()->getEventAbsoluteFilePath(), fileName, ec);
368 this->mSavedScreenshotFileName->ChangeText(path.c_str());
369 clearInTick();
370}
371
372void EventManagerFrame::checkMemory()
373{
374 const long memoryLimit = Options::Instance()->memoryLimit();
375 if (memoryLimit != -1) {
376 const char* statmPath = "/proc/self/statm";
377 long size = -1;
378 FILE* f = fopen(statmPath, "r");
379 if (f != nullptr) { // could not read file => no check
380 int success = fscanf(f, "%ld", &size);
381 fclose(f);
382 if (success == 1) { // properly readed
383 size = 4 * size / 1024; // in MB
384 this->memoryUsedInfo = size;
385 LOGF(info, "Memory used: ", size, " memory allowed: ", memoryLimit);
386 if (size > memoryLimit) {
387 LOGF(error, "Memory used: ", size, " exceeds memory allowed: ", memoryLimit);
388 exit(-1);
389 }
390 }
391 }
392 }
393}
394
395void EventManagerFrame::createOutreachScreenshot()
396{
397 static int skipCounter = 0;
398 if (skipCounter > 0) {
399 skipCounter--;
400 } else {
401 string fileName = this->mEventManager->getInstance().getDataSource()->getEventName();
402 if (fileName.size() < 5) {
403 return;
404 }
405
406 string imageFolder = ConfigurationManager::getScreenshotPath("outreach");
407 if (!std::filesystem::is_directory(imageFolder)) {
408 std::filesystem::create_directory(imageFolder);
409 }
410 fileName = imageFolder + "/" + fileName.substr(0, fileName.find_last_of('.')) + ".png";
411 if (!std::filesystem::is_regular_file(fileName)) {
412 std::vector<std::string> ext = {".png"};
414 LOGF(info, "Outreach screenshot: ", fileName);
415
416 Screenshot::perform("outreach", fileName, this->mEventManager->getDataSource()->getDetectorsMask(),
417 this->mEventManager->getDataSource()->getRunNumber(),
418 this->mEventManager->getDataSource()->getFirstTForbit(),
419 this->mEventManager->getDataSource()->getCreationTimeAsString());
420 }
422 }
423}
424
426{
427 static bool firstRefresh = true;
428 if (not setInTick()) {
429 return;
430 }
431 if (firstRefresh) {
432 firstRefresh = false;
434 this->updateGUI();
435 }
436 if (this->mUpdateGui) {
437 this->updateGUI();
438 }
439 checkMemory(); // exits if memory usage too high = prevents freezing long-running machine
440 this->createOutreachScreenshot();
441 bool refreshNeeded = mEventManager->getDataSource()->refresh();
442 if (this->mDisplayMode == SequentialMode) {
444 refreshNeeded = true;
445 }
446
447 if (refreshNeeded) {
449 }
451 clearInTick();
452}
453
455{
456 this->mTimerRunning = kFALSE;
457 if (this->mTimer != nullptr) {
458 this->mTimer->TurnOff();
459 }
460}
461
463{
464 if (this->mTimer != nullptr) {
465 this->mTimer->SetTime((Long_t)(1000 * this->mTime));
466 this->mTimer->Reset();
467 this->mTimer->TurnOn();
468 }
469 this->mTimerRunning = kTRUE;
470}
471
473{
474 if (!Options::Instance()->savedDataFolder().empty()) {
475 if (not setInTick()) {
476 return;
477 }
478 this->mEventManager->getDataSource()->saveCurrentEvent(Options::Instance()->savedDataFolder());
479 clearInTick();
480 }
481}
482
484{
485 if (not setInTick()) {
486 return;
487 }
488 // this->mEventManager->getDataSource()->changeDataFolder(getSourceDirectory(this->mRunMode).Data());
489 this->mDisplayMode = OnlineMode;
490 this->mEventManager->getDataSource()->changeDataFolder(getSourceDirectory(this->mRunMode, this->mDisplayMode));
491 this->mEventManager->setShowDate(true);
492 clearInTick();
495}
496
498{
499 if (!Options::Instance()->savedDataFolder().empty()) {
500 if (not setInTick()) {
501 return;
502 }
503 // this->mEventManager->getDataSource()->changeDataFolder(getSourceDirectory(this->mRunMode).Data());
504 this->mDisplayMode = SavedMode;
505 this->mEventManager->getDataSource()->changeDataFolder(getSourceDirectory(this->mRunMode, this->mDisplayMode));
506 this->mEventManager->setShowDate(true);
509 }
510 clearInTick();
513 }
514}
515
517{
518 if (!Options::Instance()->savedDataFolder().empty()) {
519 if (not setInTick()) {
520 return;
521 }
522 // this->mEventManager->getDataSource()->changeDataFolder(getSourceDirectory(this->mRunMode).Data());
523 this->mDisplayMode = SequentialMode;
524 this->mEventManager->getDataSource()->changeDataFolder(getSourceDirectory(this->mRunMode, this->mDisplayMode));
525 this->mEventManager->setShowDate(false);
528 }
529 clearInTick();
532 }
533}
534
535void EventManagerFrame::changeRunMode(RunMode runMode)
536{
537 if (this->mRunMode != runMode) {
538 if (not setInTick()) {
539 return;
540 }
541
542 this->setRunMode(runMode);
545 clearInTick();
548 }
549}
550
555
560
565
570
571bool EventManagerFrame::setInTick()
572{
573 std::unique_lock<std::mutex> lck(mtx, std::defer_lock);
574 bool inTick;
575 lck.lock();
576 inTick = this->inTick;
577 this->inTick = true;
578 lck.unlock();
579 return not inTick; // it is me who set inTick
580}
581
582void EventManagerFrame::clearInTick()
583{
584 std::unique_lock<std::mutex> lck(mtx, std::defer_lock);
585 lck.lock();
586 this->inTick = false;
587 lck.unlock();
588}
589
591{
592 StopTimer();
593 std::chrono::seconds duration(1); // wait 1 second to give a chance
594 std::this_thread::sleep_for(duration);
595 while (not setInTick()) { // make sure chance was taken
596 continue;
597 }
598 exit(0);
599}
600
602{
603 return mTimeFrameSlider->GetMinPosition();
604}
605
607{
608 return mTimeFrameSlider->GetMaxPosition();
609}
610
612{
613 this->mRunMode = runMode;
614 this->mEventManager->getDataSource()->changeDataFolder(getSourceDirectory(this->mRunMode, this->mDisplayMode));
615}
616
617std::vector<std::string>
619{
620 std::vector<std::string> res;
621 auto const options = Options::Instance();
622
623 if (displayMode == EventManagerFrame::SavedMode || displayMode == EventManagerFrame::SequentialMode) {
624 res.push_back(options->savedDataFolder());
625 } else {
626 switch (runMode) {
631 break;
634 break;
637 break;
640 break;
641 default:
643 break;
644 }
645 }
646 return res;
647}
648
650{
651 if (name == "NEWEST") {
652 return NewestRun;
653 } else if (name == "SYNTHETIC") {
654 return SyntheticRun;
655 } else if (name == "COSMICS") {
656 return CosmicsRun;
657 } else if (name == "PHYSICS") {
658 return PhysicsRun;
659 } else {
660 return defaultRun;
661 }
662}
663
664} // namespace event_visualisation
665} // namespace o2
Grouping reading from file(s)
Loading content of the Folder and returning sorted.
ClassImp(o2::event_visualisation::EventManagerFrame)
std::mutex mtx
GUI (bottom buttons) for visualisation.
int16_t time
Definition RawEventData.h:4
uint32_t res
Definition RawData.h:0
Screenshot functionality.
static std::string getScreenshotPath(const char *prefix)
virtual void changeDataFolder(const std::vector< std::string > &)
Definition DataSource.h:70
virtual std::string getEventAbsoluteFilePath()
Definition DataSource.h:77
virtual std::string getEventName()
Definition DataSource.h:76
virtual o2::detectors::DetID::mask_t getDetectorsMask()=0
virtual void saveCurrentEvent(std::string)
Definition DataSource.h:71
static void removeOldestFiles(const std::string &path, std::vector< std::string > &ext, int remaining)
static std::vector< std::string > getSourceDirectory(EventManagerFrame::RunMode runMode, EventManagerFrame::DisplayMode displayMode)
o2::event_visualisation::EventManager * mEventManager
static EventManagerFrame & getInstance()
Returns an instance of EventManagerFrame.
void setRunMode(EventManagerFrame::RunMode runMode)
EventManagerFrame(o2::event_visualisation::EventManager &eventManager)
static RunMode decipherRunMode(TString name, RunMode defaultRun=SyntheticRun)
static EventManager & getInstance()
Returns an instance of EventManager.
static std::string perform(const char *prefix, std::string fileName, o2::detectors::DetID::mask_t detectorsMask, int runNumber, int firstTFOrbit, const std::string &collisionTime)
GLsizeiptr size
Definition glcorearb.h:659
GLuint const GLchar * name
Definition glcorearb.h:781
GLint GLsizei GLsizei height
Definition glcorearb.h:270
GLint GLsizei width
Definition glcorearb.h:270
GLdouble f
Definition glcorearb.h:310
GLboolean GLboolean GLboolean b
Definition glcorearb.h:1233
GLboolean GLboolean g
Definition glcorearb.h:1233
GLsizei const GLchar *const * path
Definition glcorearb.h:3591
GLboolean r
Definition glcorearb.h:1233
return * this
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
void empty(int)
std::mutex mtx