18#include <TGButtonGroup.h>
19#include <TGNumberEntry.h>
23#include <TGDoubleSlider.h>
37#include <fairlogger/Logger.h>
45namespace event_visualisation
48EventManagerFrame* EventManagerFrame::mInstance =
nullptr;
52 assert(mInstance !=
nullptr);
62 :
TGMainFrame(gClient->GetRoot(), 400, 100, kVerticalFrame)
66 this->mTimer =
new TTimer();
68 this->mTimer->Connect(
"Timeout()",
"o2::event_visualisation::EventManagerFrame",
this,
"DoTimeTick()");
70 const TString cls(
"o2::event_visualisation::EventManagerFrame");
71 TGTextButton*
b =
nullptr;
72 TGRadioButton*
r =
nullptr;
73 TGHorizontalFrame*
f =
nullptr;
75 auto const options = Options::Instance();
79 f =
new TGHorizontalFrame(
this);
82 this->AddFrame(
f,
new TGLayoutHints(kLHintsExpandX, 0, 0, 2, 2));
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()");
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()");
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()");
101 b = EventManagerFrame::makeButton(
f,
"Save", 2 *
width,
"Save current event");
102 b->Connect(
"Clicked()", cls,
this,
"DoSave()");
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));
120 g =
new TGHButtonGroup(
f);
121 mNewestRunBtn =
r = EventManagerFrame::makeRadioButton(
g,
"Newest", 2 *
width,
122 "Change source directory to newest data",
124 r->Connect(
"Clicked()", cls,
this,
"DoNewestData()");
125 mSyntheticRunBtn =
r = EventManagerFrame::makeRadioButton(
g,
"Synthetic", 2 *
width,
126 "Change source directory to synthetic run",
128 r->Connect(
"Clicked()", cls,
this,
"DoSyntheticData()");
129 mCosmicsRunBtn =
r = EventManagerFrame::makeRadioButton(
g,
"Cosmics", 2 *
width,
130 "Change source directory to cosmics run",
132 r->Connect(
"Clicked()", cls,
this,
"DoCosmicsData()");
133 mPhysicsRunBtn =
r = EventManagerFrame::makeRadioButton(
g,
"Physics", 2 *
width,
134 "Change source directory to physics run",
136 r->Connect(
"Clicked()", cls,
this,
"DoPhysicsData()");
137 f->AddFrame(
g,
new TGLayoutHints(kLHintsNormal, 0, 0, 0, 0));
139 this->mSavedScreenshotFileName =
new TGLabel(
f, std::string(128,
' ').c_str());
141 f->AddFrame(this->mSavedScreenshotFileName,
new TGLayoutHints(kLHintsNormal, 5, 10, 4, 0));
144 f =
new TGHorizontalFrame(
this);
147 this->AddFrame(
f,
new TGLayoutHints(kLHintsExpandX, 0, 0, 2, 2));
149 TGLabel* infoLabel =
new TGLabel(
f);
150 f->AddFrame(infoLabel,
new TGLayoutHints(kLHintsNormal, 5, 10, 4, 0));
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()");
160 this->mOnlineModeBtn->SetState(kButtonDown);
161 SetCleanup(kDeepCleanup);
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)
170 TGTextButton*
b =
new TGTextButton(p, txt);
174 b->ChangeOptions(
b->GetOptions() | kFixedWidth);
177 if (txttooltip !=
nullptr) {
178 b->SetToolTipText(txttooltip);
181 p->AddFrame(
b,
new TGLayoutHints(kLHintsNormal, lo, ro, to, bo));
185TGRadioButton* EventManagerFrame::makeRadioButton(TGButtonGroup*
g,
const char* txt,
186 Int_t
width,
const char* txttooltip,
bool checked, Int_t lo, Int_t ro,
189 TGRadioButton*
b =
new TGRadioButton(
g, txt);
193 b->ChangeOptions(
b->GetOptions() | kFixedWidth);
196 if (txttooltip !=
nullptr) {
197 b->SetToolTipText(txttooltip);
205TGDoubleHSlider* EventManagerFrame::makeSlider(TGCompositeFrame* p,
const char* txt, Int_t
width,
206 Int_t lo, Int_t ro, Int_t to, Int_t bo)
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);
215 sliderFrame->AddFrame(slider,
new TGLayoutHints(kLHintsLeft));
216 p->AddFrame(sliderFrame,
new TGLayoutHints(kLHintsTop, lo, ro, to, bo));
220void EventManagerFrame::makeSliderRangeEntries(TGCompositeFrame* parent,
int height,
221 TGNumberEntryField*& minEntry,
const TString& minToolTip,
222 TGNumberEntryField*& maxEntry,
const TString& maxToolTip)
224 TGCompositeFrame* frame =
new TGCompositeFrame(parent, 80,
height, kHorizontalFrame);
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));
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));
242void EventManagerFrame::updateGUI()
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);
251 switch (this->mDisplayMode) {
253 this->mOnlineModeBtn->SetState(kButtonDown);
256 this->mSavedModeBtn->SetState(kButtonDown);
259 this->mSequentialModeBtn->SetState(kButtonDown);
262 switch (this->mRunMode) {
264 this->mNewestRunBtn->SetState(kButtonDown, kTRUE);
267 this->mSyntheticRunBtn->SetState(kButtonDown, kTRUE);
270 this->mCosmicsRunBtn->SetState(kButtonDown, kTRUE);
273 this->mPhysicsRunBtn->SetState(kButtonDown, kTRUE);
276 this->mUpdateGui =
false;
281 if (not setInTick()) {
291 if (not setInTick()) {
301 if (not setInTick()) {
311 if (not setInTick()) {
321 if (not setInTick()) {
335 if (not setInTick()) {
341 std::time_t
time = std::time(
nullptr);
343 std::strftime(time_str,
sizeof(time_str),
"%Y_%m_%d_%H_%M_%S", std::localtime(&
time));
347 if (monthDirectory) {
349 std::strftime(dir_str,
sizeof(dir_str),
"%Y-%m", std::localtime(&
time));
350 outDirectory = outDirectory +
"/" + dir_str;
351 std::filesystem::create_directory(outDirectory);
354 std::ostringstream filepath;
355 filepath << outDirectory <<
"/Screenshot_" << time_str <<
".png";
357 std::string
path = filepath.str();
361 this->mEventManager->getDataSource()->getRunNumber(),
362 this->mEventManager->getDataSource()->getFirstTForbit(),
363 this->mEventManager->getDataSource()->getCreationTimeAsString());
364 fileName.replace_extension(
368 this->mSavedScreenshotFileName->ChangeText(
path.c_str());
372void EventManagerFrame::checkMemory()
374 const long memoryLimit = Options::Instance()->memoryLimit();
375 if (memoryLimit != -1) {
376 const char* statmPath =
"/proc/self/statm";
378 FILE*
f = fopen(statmPath,
"r");
380 int success = fscanf(
f,
"%ld", &
size);
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);
395void EventManagerFrame::createOutreachScreenshot()
397 static int skipCounter = 0;
398 if (skipCounter > 0) {
402 if (fileName.size() < 5) {
407 if (!std::filesystem::is_directory(imageFolder)) {
408 std::filesystem::create_directory(imageFolder);
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);
417 this->mEventManager->getDataSource()->getRunNumber(),
418 this->mEventManager->getDataSource()->getFirstTForbit(),
419 this->mEventManager->getDataSource()->getCreationTimeAsString());
427 static bool firstRefresh =
true;
428 if (not setInTick()) {
432 firstRefresh =
false;
436 if (this->mUpdateGui) {
440 this->createOutreachScreenshot();
444 refreshNeeded =
true;
456 this->mTimerRunning = kFALSE;
457 if (this->mTimer !=
nullptr) {
458 this->mTimer->TurnOff();
464 if (this->mTimer !=
nullptr) {
465 this->mTimer->SetTime((Long_t)(1000 * this->mTime));
466 this->mTimer->Reset();
467 this->mTimer->TurnOn();
469 this->mTimerRunning = kTRUE;
474 if (!Options::Instance()->savedDataFolder().
empty()) {
475 if (not setInTick()) {
485 if (not setInTick()) {
499 if (!Options::Instance()->savedDataFolder().
empty()) {
500 if (not setInTick()) {
518 if (!Options::Instance()->savedDataFolder().
empty()) {
519 if (not setInTick()) {
535void EventManagerFrame::changeRunMode(RunMode runMode)
537 if (this->mRunMode != runMode) {
538 if (not setInTick()) {
571bool EventManagerFrame::setInTick()
573 std::unique_lock<std::mutex> lck(
mtx, std::defer_lock);
576 inTick = this->inTick;
582void EventManagerFrame::clearInTick()
584 std::unique_lock<std::mutex> lck(
mtx, std::defer_lock);
586 this->inTick =
false;
593 std::chrono::seconds duration(1);
594 std::this_thread::sleep_for(duration);
595 while (not setInTick()) {
603 return mTimeFrameSlider->GetMinPosition();
608 return mTimeFrameSlider->GetMaxPosition();
613 this->mRunMode = runMode;
617std::vector<std::string>
620 std::vector<std::string>
res;
621 auto const options = Options::Instance();
624 res.push_back(options->savedDataFolder());
651 if (
name ==
"NEWEST") {
653 }
else if (
name ==
"SYNTHETIC") {
655 }
else if (
name ==
"COSMICS") {
657 }
else if (
name ==
"PHYSICS") {
Grouping reading from file(s)
Loading content of the Folder and returning sorted.
ClassImp(o2::event_visualisation::EventManagerFrame)
GUI (bottom buttons) for visualisation.
Screenshot functionality.
static std::string getDataCosmicRunDir()
static std::string getScreenshotPath(const char *prefix)
static UInt_t getRefreshRateInSeconds()
static bool getScreenshotMonthly()
static std::string getDataPhysicsRunDir()
static UInt_t getOutreachFilesMax()
static UInt_t getOutreachFrequencyInRefreshRates()
static std::string getDataSyntheticRunDir()
virtual void rollToNext()
virtual void changeDataFolder(const std::vector< std::string > &)
virtual Int_t getCurrentEvent()
float getTimeFrameMaxTrackTime() const
float getTimeFrameMinTrackTime() const
virtual std::string getEventAbsoluteFilePath()
virtual std::string getEventName()
virtual o2::detectors::DetID::mask_t getDetectorsMask()=0
virtual void saveCurrentEvent(std::string)
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)
float getMaxTimeFrameSliderValue() const
o2::event_visualisation::EventManager * mEventManager
static EventManagerFrame & getInstance()
Returns an instance of EventManagerFrame.
void setRunMode(EventManagerFrame::RunMode runMode)
void DoTimeFrameSliderChanged()
~EventManagerFrame() override
EventManagerFrame(o2::event_visualisation::EventManager &eventManager)
static RunMode decipherRunMode(TString name, RunMode defaultRun=SyntheticRun)
float getMinTimeFrameSliderValue() const
static EventManager & getInstance()
Returns an instance of EventManager.
DataSource * getDataSource()
void PrevEvent() override
void setShowDate(bool value)
void GotoEvent(Int_t) override
void displayCurrentEvent()
void NextEvent() override
static std::string perform(const char *prefix, std::string fileName, o2::detectors::DetID::mask_t detectorsMask, int runNumber, int firstTFOrbit, const std::string &collisionTime)
GLuint const GLchar * name
GLint GLsizei GLsizei height
GLboolean GLboolean GLboolean b
GLsizei const GLchar *const * path
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...