ATLAS Offline Software
Loading...
Searching...
No Matches
VP1ExecutionScheduler.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3*/
4
6// //
7// Implementation of class VP1ExecutionScheduler //
8// //
9// Author: Thomas Kittelmann <Thomas.Kittelmann@cern.ch> //
10// //
11// Initial version: April 2007 //
12// //
13// History: //
14// R.M.Bianchi <rbianchi@cern.ch> - Feb 2013 //
15// //
17
18//TODO:
19//
20// * Save sys2time data in .vp1 file
21// * Disable custom controllers between events!
22// * Integrate with cruise modes (tab and event)
23// * In tab cruise mode, dont go to next tab until it is ready. Thus,
24// we need to be able to ask the scheduler if a given tab is ready.
25// * "Soon to be visible" priority
26// * General performance optimisation (inline internal methods +
27// cache iterators).
28// * Take care of accumulators.
29// * Accumulate cruise mode (with ETA if it is a given number of events).
30
31/* this to fix the 'ptrdiff_t' does not name a type error with Qt:
32 * refs:
33 * - http://qt-project.org/forums/viewthread/16992
34 * - http://stackoverflow.com/questions/6727193/g-4-6-complains-about-iterator-difference-type-g-4-4-and-visual-studio-don
35 */
36// #include <stddef.h>
37
38
49
50#include "VP1Base/VP1QtUtils.h"
51#include "VP1Base/IVP1System.h"
53#include "VP1Base/VP1Msg.h"
56#include "VP1Base/VP1Settings.h"
57
59
60#include <QApplication>
61#include <QProgressBar>
62#include <QDesktopWidget>
63#include <QMouseEvent>
64#include <QWheelEvent>
65#include <QCursor>
66#include <QTimer>
67#include <QSet>
68#include <QStringList>
69#include <QMessageBox>
70#include <QCommandLineParser>
71
72#include <Inventor/C/errors/debugerror.h>
73#include <Inventor/Qt/SoQt.h>
74
75#include <set>
76#include <cassert>
77#include <iostream> //For "widgetcount" output
78#include <sstream> // std::ostringstream
79#include <ctime>
80#include <stdexcept>
81#include <string>
82#include <vector>
83
84
85
86std::vector<std::string> qstringlistToVecString(const QStringList& list)
87{
88 std::vector<std::string> vec;
89 for (const QString& str : list) {
90 vec.push_back(str.toStdString());
91 }
92 return vec;
93}
94
95
96#ifdef BUILDVP1LIGHT
97 //Qt
98 #include <QSettings>
99
100 // XAOD
101 #include "xAODRootAccess/Init.h"
102 #include "xAODRootAccess/TEvent.h"
103 #include "xAODRootAccess/TStore.h"
108 #include "xAODCore/tools/IOStats.h"
109
110 // // For testing
112 #include <QDebug>
115 #include <regex>
116 #include <QString>
117
118 // ROOT include(s):
119 #include <TTree.h>
120 #include <TFile.h>
121 #include <TError.h>
122
123 template <typename... Args> inline void unused(Args&&...) {} // to declare unused variables (see executeNewEvent() ).
124#endif // BUILDVP1LIGHT
125
126
127
128//___________________________________________________________________
178
179//___________________________________________________________________
181public:
182 GlobalEventFilter():m_lastPopup(QTime::currentTime()),
183 m_lastPopupWasQMenu(false){}
184 bool eventFilter ( QObject * watched, QEvent * event ) {
185 if (event->type()==QEvent::MouseButtonPress
186 ||event->type()==QEvent::MouseButtonDblClick
187 ||event->type()==QEvent::Wheel) {
188 QTime t = QTime::currentTime();
189 int timediff(abs(t.msecsTo(m_lastPopup)));
190 int timecut(m_lastPopupWasQMenu?300:100);
191 if (timediff>timecut) {
192 m_lastPopup = t;
193 QString txt;
194 QMouseEvent*mouseEvent = dynamic_cast<QMouseEvent*>(event);
195 if (mouseEvent) {
196 txt = event->type()==QEvent::MouseButtonDblClick?"Dbl-click"
197 :(mouseEvent->button()&Qt::LeftButton?"Left-click"
198 :(mouseEvent->button()&Qt::RightButton?"Right-click":"Middle-click"));
199 } else {
200 QWheelEvent * wheelEvent = dynamic_cast<QWheelEvent*>(event);
201 if (wheelEvent)
202 txt = "wheel";
203 else
204 txt = "Unknown event";
205 }
206 // std::cout<<"Popup (dt="<<timediff<<") "<<txt.toStdString()<<". watched = "<<watched
207 // <<" (on="<<watched->objectName().toStdString()<<")"
208 // <<" (cn="<<watched->metaObject()->className()<<")"
209 // <<std::endl;
210 QLabel * label = new QLabel(txt,0,Qt::Tool|Qt::FramelessWindowHint
211 |Qt::X11BypassWindowManagerHint|Qt::WindowStaysOnTopHint);
212 label->setStyleSheet("background-color: yellow;color: black;"
213 "font: bold 140%;border: 2px solid black");
214 //"border-radius: 3px;"
215 label->setFrameStyle(QFrame::StyledPanel);
216 label->setAttribute(Qt::WA_ShowWithoutActivating);
217 label->setFocusPolicy(Qt::NoFocus);
218 QPoint p(QCursor::pos().x()-label->sizeHint().width()/2,QCursor::pos().y()-label->sizeHint().height());
219 label->move(p);
220 QTimer::singleShot(0,label,SLOT(show()));
221 QTimer::singleShot(500, label, SLOT(deleteLater()));
222 m_lastPopupWasQMenu = (dynamic_cast<QMenu*>(watched)!=0);
223 }
224 }
225 return false;
226 }
227private:
230};
231
232//___________________________________________________________________
234 StoreGateSvc* eventStore,
235 StoreGateSvc* detStore,
236 ISvcLocator* svcLocator,
237 IToolSvc*toolSvc,
238 VP1AvailEvents * availEvents)
239: QObject(parent), m_d(new Imp)
240{
241 m_d->availEvents = availEvents;
242 VP1AthenaPtrs::setPointers(eventStore,detStore,svcLocator,toolSvc);
243 m_d->eventsProcessed = 0;
244
245 m_d->scheduler = this;
246 m_d->prioritiser = new VP1Prioritiser(this);
247 m_d->mainwindow = new VP1MainWindow(this,availEvents);//mainwindow takes ownership of available events
248
249 m_d->batchMode = false;
250 m_d->batchUtilities = nullptr;
251 m_d->batchModeAllEvents = false;
252 m_d->batchModeNEvents = 0;
253 m_d->batchModeRandomConfig = false;
254
255 m_d->allSystemsRefreshed = false;
256 m_d->goingtonextevent=true;
257 m_d->currentsystemrefreshing=0;
258 m_d->eraseJustAfterRefresh=false;
259 m_d->postponedUncreateAndDeleteCW=0;
260 m_d->refreshtimer = new QTimer(this);
261 connect(m_d->refreshtimer, SIGNAL(timeout()), this, SLOT(processSystemForRefresh()));
262
263 //Connect signals to ensure that prioritiser knows about present channels and their visibility:
264 connect(m_d->mainwindow->channelManager(),SIGNAL(newChannelCreated(IVP1ChannelWidget*)),m_d->prioritiser, SLOT(channelCreated(IVP1ChannelWidget*)));
265 connect(m_d->mainwindow->channelManager(),SIGNAL(channelUncreated(IVP1ChannelWidget*)),m_d->prioritiser, SLOT(channelUncreated(IVP1ChannelWidget*)));
266 connect(m_d->mainwindow->channelManager(),SIGNAL(newChannelCreated(IVP1ChannelWidget*)),this, SLOT(channelCreated(IVP1ChannelWidget*)));
267 connect(m_d->mainwindow->channelManager(),SIGNAL(channelUncreated(IVP1ChannelWidget*)),this, SLOT(channelUncreated(IVP1ChannelWidget*)));
268
269 connect(m_d->mainwindow->tabManager(),SIGNAL(visibleChannelsChanged(const QSet<IVP1ChannelWidget*>&,const QSet<IVP1ChannelWidget*>&,const double&)),
270 m_d->prioritiser,SLOT(visibleChannelsChanged(const QSet<IVP1ChannelWidget*>&,const QSet<IVP1ChannelWidget*>&,const double&)));
271
272
273 // Init and show the main window of VP1
274 SoQt::init( m_d->mainwindow );// SoQt::init( "VP1" );
275
276 // check if 'batch mode'
277 bool batchMode = VP1QtUtils::environmentVariableIsSet("VP1_BATCHMODE"); // ::getenv("VP1_BATCHMODE");
278 if(VP1Msg::debug()){
279 qDebug() << "VP1ExecutionScheduler:: Do we run in 'batch' mode?" << batchMode;
280 }
281 if (batchMode) {
282 VP1Msg::messageWarningAllRed("User has run VP1 in 'batch-mode', so the main window of the program will not be shown.");
283 m_d->batchMode = true;
284
285 // check if the user set the "all events" option as well
286 m_d->batchModeAllEvents = VP1QtUtils::environmentVariableIsSet("VP1_BATCHMODE_ALLEVENTS");
287
288 // check if the user set the "random configuration file" option as well
289 m_d->batchModeRandomConfig = VP1QtUtils::environmentVariableIsSet("VP1_BATCHMODE_RANDOMCONFIG");
290 }
291 else {
292 m_d->mainwindow->show();
293 }
294
295
296 m_d->pb = m_d->mainwindow->progressbar;
297 m_d->pbtimer = new QTimer(this);
298 connect(m_d->pbtimer, SIGNAL(timeout()), this, SLOT(updateProgressBarDuringRefresh()));
299 m_d->calctimethisevent=0;
300 m_d->currentrefreshsystemestimate=0;
301
302 m_d->cruisemode = NONE;
303 m_d->cruisetimer = new QTimer(this);
304 connect(m_d->cruisetimer, SIGNAL(timeout()), this, SLOT(performCruise()));
305 m_d->cruisetab_waitingtoproceed=false;
306
307 #if defined BUILDVP1LIGHT
308 bool checkDisplayMouseClicks = VP1QtUtils::expertSettingIsOn("general","ExpertSettings/VP1_DISPLAY_MOUSE_CLICKS");
309 #else
310 bool checkDisplayMouseClicks = VP1QtUtils::environmentVariableIsOn("VP1_DISPLAY_MOUSE_CLICKS");
311 #endif
312
313 if (checkDisplayMouseClicks) {
314 m_d->globalEventFilter = new Imp::GlobalEventFilter;
315 qApp->installEventFilter(m_d->globalEventFilter);
316 } else {
317 m_d->globalEventFilter = 0;
318 }
319
320 VP1AvailEvtsHttps* availEvtsHttps = dynamic_cast<VP1AvailEvtsHttps*>(availEvents);
321 if(availEvtsHttps) {
322 m_d->skipEvent = true;
323 VP1Authenticator* auth = new VP1Authenticator(m_d->mainwindow,availEvtsHttps->fileinfoLocation());
324
325 connect(auth,SIGNAL(authenticationSuccessful(QNetworkAccessManager*)),
326 availEvtsHttps,SLOT(start(QNetworkAccessManager*)));
327 connect(availEvtsHttps,SIGNAL(freshEventsChanged()),
328 auth,SLOT(accept()));
329
330 SoQt::init(auth);
331 auth->exec();
332 delete auth;
333 }
334 else
335 m_d->skipEvent = false;
336}
337
338//___________________________________________________________________
340{
341 m_d->refreshtimer->stop();
342 delete m_d->batchUtilities;
343 delete m_d->mainwindow;
344 delete m_d->prioritiser;
345 delete m_d->globalEventFilter;
346 delete m_d;
347}
348
349//___________________________________________________________________
351 StoreGateSvc* detStore,
352 ISvcLocator* svcLocator,
353 IToolSvc*toolSvc,
354 const QStringList& joboptions,
355 QString initialCruiseMode,
356 unsigned initialCruiseSeconds,
357 const QString& singleEventSource,
358 const QString& singleEventLocalTmpDir,
359 unsigned localFileCacheLimit,
360 const QStringList& availableLocalInputDirectories )
361{
362 //First we make sure the DISPLAY variable is set (importing ROOT in
363 //athena.py might cause it to be unset!).
364 //
365 //NB: The following might only be relevant in X11 build:
366 if (VP1QtUtils::environmentVariableValue("DISPLAY").isEmpty()) {
367 const bool unset(!VP1QtUtils::environmentVariableIsSet("DISPLAY"));
368 QString alternative = VP1QtUtils::environmentVariableValue("DISPLAY_ORIG");
369 if (alternative.isEmpty()) {
370 VP1Msg::message("ERROR: The DISPLAY environment variable is "+QString(unset?"not set":"empty")+".");
371 VP1Msg::message("This might be because something else in Athena has disabled it.");
372 VP1Msg::message("You can work around this problem by setting "
373 "the DISPLAY_ORIG environment variable to the contents of DISPLAY before launching your job.");
374 VP1Msg::message("E.g., in bash do:");
375 VP1Msg::message(" export DISPLAY_ORIG=$DISPLAY");
376 VP1Msg::message("");
377 VP1Msg::message("For the current job, I will try with DISPLAY=\":0.0\", which is the correct value when running locally.");
378 alternative=":0.0";
379 } else {
380 VP1Msg::message("WARNING: The DISPLAY environment variable is "+QString(unset?"not set":"empty")+". Setting to value found in DISPLAY_ORIG");
381 }
382 VP1Msg::message("WARNING: Setting DISPLAY variable to '"+alternative+"'");
383 VP1QtUtils::setEnvironmentVariable("DISPLAY",alternative);
384 }
385
386
387
388 QCoreApplication::setOrganizationName("ATLAS");
389 #if defined BUILDVP1LIGHT
390 QCoreApplication::setApplicationName("VP1Light");
391 #else
392 QCoreApplication::setApplicationName("VP1");
393 #endif
394 QCoreApplication::setAttribute(Qt::AA_UseDesktopOpenGL);
395
396
397
398 // here we check if the main (and unique!) Qt application has been initialized already. If not we initialize it.
399 if (qApp) {
400 VP1Msg::message("VP1ExecutionScheduler::init ERROR: QApplication already initialized. Expect problems!!!");
401 } else {
402 //NB: Static to avoid scope-problems:
403 static int argc=1;
404 static char execpath[] = "/some/fake/executable/vp1";
405 static char *argv[2];
406 // VP1Msg::messageDebug("setting argv[0]...");
407 argv[0] = execpath;
408 // VP1Msg::messageDebug("setting argv[1]...");
409 argv[1] = NULL;
410 // instead of using the default Qt QApplication class,
411 // we now use our custom inherited class where we
412 // reimplemented the notify() method, in order to catch
413 // C++ exceptions, especially while running it inside Athena.
414 //new QApplication(argc, argv);
415 new VP1QtApplication(argc, argv);
416 }
417
418 VP1AvailEvents * availEvents(0);
419 if (!singleEventSource.isEmpty()&&!singleEventLocalTmpDir.isEmpty()) {
420 const bool httpmode = singleEventSource.startsWith("http://");
421 const bool httpsmode = singleEventSource.startsWith("https://");
422 //Create appropriate instance:
423 if (httpmode) {
424 availEvents = new VP1AvailEvtsHttp(singleEventSource, 60/*update interval*/, 30*60/*time cut for new*/, singleEventLocalTmpDir,localFileCacheLimit);
425 } else if(httpsmode) {
426 availEvents = new VP1AvailEvtsHttps(singleEventSource, 1000/*update interval*/, 30*60/*time cut for new*/, singleEventLocalTmpDir,localFileCacheLimit);
427 } else {
428 availEvents = new VP1AvailEvtsLocalDir(5*60/*time cut for new*/, singleEventSource,
429 singleEventLocalTmpDir,localFileCacheLimit);
430 static_cast<VP1AvailEvtsLocalDir*>(availEvents)->setAvailableSourceDirectories(availableLocalInputDirectories);
431
432 }
433
434 }
435
436 VP1ExecutionScheduler*scheduler = new VP1ExecutionScheduler(0,eventStore,detStore,svcLocator,toolSvc,availEvents);
437
438 //Pass on "joboptions"
439 if (joboptions.empty()) {
440 //scheduler->m_d->mainwindow->tabManager()->addNewTab("My Tab");
441 } else {
442 qDebug() << "config files: " << joboptions; // DEBUG
443 for (const QString& opt : joboptions)
444 scheduler->m_d->mainwindow->loadConfigurationFromFile(opt);
445
446 if ( scheduler->m_d->batchMode ) {
447 if (scheduler->m_d->batchModeRandomConfig ) {
448 if (joboptions.size() != 0 ) {
449 scheduler->m_d->batchUtilities = new VP1BatchUtilities( qstringlistToVecString(joboptions) );
450 }
451 }
452 QString batchNevents = VP1QtUtils::environmentVariableValue("VP1_BATCHMODE_NEVENTS");
453 if (batchNevents > 0 ) {
454 scheduler->m_d->batchModeNEvents = batchNevents.toInt();
455 }
456 }
457 }
458
459
460 if (scheduler->m_d->mainwindow->tabWidget_central->count()<=1) {
461 if (initialCruiseMode=="TAB") {
462 VP1Msg::message("ERROR: Can not start in cruisemode TAB unless there are at least 2 tabs loaded from initial .vp1 files. Reverting to cruise mode NONE.");
463 initialCruiseMode="NONE";
464 } else if (initialCruiseMode=="BOTH") {
465 VP1Msg::message("ERROR: Can not start in cruisemode BOTH unless there are at least 2 tabs loaded from initial .vp1 files. Reverting to cruise mode EVENT.");
466 initialCruiseMode="EVENT";
467 }
468 }
469
470 //Set default value of cruisemode (dont use setCruiseMode() since it starts timers):
471 if (initialCruiseMode=="EVENT") {
472 scheduler->m_d->cruisemode=EVENT;
473 scheduler->m_d->mainwindow->radioButton_cruise_event->setChecked(true);
474 scheduler->m_d->mainwindow->pushButton_cruise->setChecked(true);
475
476 } else if (initialCruiseMode=="TAB") {
477 scheduler->m_d->cruisemode=TAB;
478 scheduler->m_d->mainwindow->radioButton_cruise_tab->setChecked(true);
479 scheduler->m_d->mainwindow->pushButton_cruise->setChecked(true);
480 } else if (initialCruiseMode=="BOTH") {
481 scheduler->m_d->cruisemode=BOTH;
482 scheduler->m_d->mainwindow->radioButton_cruise_both->setChecked(true);
483 scheduler->m_d->mainwindow->pushButton_cruise->setChecked(true);
484 } else {
485 if (initialCruiseMode!="NONE")
486 VP1Msg::message("ERROR: unknown initial cruise mode "+initialCruiseMode+" (valid are NONE/EVENT/TAB/BOTH). Assuming NONE.");
487 scheduler->m_d->cruisemode=NONE;
488 scheduler->m_d->mainwindow->radioButton_cruise_event->setChecked(true);
489 scheduler->m_d->mainwindow->pushButton_cruise->setChecked(false);
490 }
491
493
494 int cruisesecs = ( initialCruiseSeconds == 0 ? 0 :
495 std::max(scheduler->m_d->mainwindow->spinBox_cruise->minimum(),
496 std::min(scheduler->m_d->mainwindow->spinBox_cruise->maximum(),
497 static_cast<int>(initialCruiseSeconds))));
498 if ( cruisesecs>0 )
499 scheduler->m_d->mainwindow->spinBox_cruise->setValue(cruisesecs);
500
501
502 return scheduler;
503}
504
505//___________________________________________________________________
507{
508 #if defined BUILDVP1LIGHT
509 bool checkEnableInformOnEndOfJob = VP1QtUtils::expertSettingIsOn("expert","ExpertSettings/VP1_ENABLE_INFORM_ON_END_OF_JOB");
510 #else
511 bool checkEnableInformOnEndOfJob = VP1QtUtils::environmentVariableIsOn("VP1_ENABLE_INFORM_ON_END_OF_JOB");
512 #endif
513
514 if (checkEnableInformOnEndOfJob && ( !scheduler||!(scheduler->m_d->mainwindow->userRequestedExit()) ) )
515 QMessageBox::information(0, "End of job reached",Qt::convertFromPlainText("Job about to end.\n\nThis is most"
516 " likely since there are no more available events to process."),QMessageBox::Ok,QMessageBox::Ok);
517
518 if (scheduler) {
519 delete scheduler;
520// qApp->processEvents(QEventLoop::DeferredDeletion); // Qt 4
521 qApp->processEvents(); // Qt 5
522 qApp->deleteLater(); // Qt 5
523
526
527 delete qApp;
528 SoQt::done();
529 }
530
531
532
533 const QString quickExitEnv("VP1_HARD_EXIT_AT_END");
534
535 #if defined BUILDVP1LIGHT
536 bool checkHardExitAtEnd = VP1QtUtils::expertSettingIsOn("expert","ExpertSettings/"+quickExitEnv);
537 #else
538 bool checkHardExitAtEnd = VP1QtUtils::environmentVariableIsOn(quickExitEnv);
539 #endif
540
541 if (checkHardExitAtEnd) {
542 VP1Msg::message("Hard job exit (unset "+quickExitEnv+" to disable this behaviour).");
543 exit(0);
544 }
545
546}
547
548//___________________________________________________________________
550{
551 double remaining = prioritiser->estimateRemainingCalcTime();
552 if (remaining>0.0) {
553 pb->setMaximum(static_cast<int>((calctimethisevent+remaining)*10.0));
554 pb->setValue(static_cast<int>((calctimethisevent)*10.0));
555 pb->show();
556 if (!pbtimer->isActive())
557 pbtimer->start(40);//25 "frames"/second. If it is good enough for TV, it is good enough for us.
558 } else {
560 pb->hide();
561 pb->reset();
562 pbtimer->stop();
563 }
564}
565//___________________________________________________________________
567{
568 if (m_d->currentrefreshsystemestimate<1.0)
569 return;
570 double timing=(m_d->prioritiser->elapsedTiming_Refresh())*0.95;//The *0.95 is to give a smoother overall impression.
571 if (timing>m_d->currentrefreshsystemestimate)
572 return;
573 m_d->pb->setValue(static_cast<int>((m_d->calctimethisevent+timing)*10.0));
574}
575
576
577//___________________________________________________________________
579{
580 return m_d->nextRequestedEvent;
581}
582
583//___________________________________________________________________
585{
586 m_d->nextRequestedEvent = f;
587}
588
589//___________________________________________________________________
590bool VP1ExecutionScheduler::executeNewEvent(const int& runnumber, const unsigned long long& eventnumber, const unsigned& triggerType, const unsigned& time)
591{
592 VP1Msg::messageDebug("VP1ExecutionScheduler::executeNewEvent()");
593
594 m_d->nextRequestedEvent="";
595
596#if defined BUILDVP1LIGHT
597 unused(runnumber,eventnumber,triggerType,time); // silences the "unused parameter" warnings when building VP1Light. In this case, in fact, those variables will be used later in loadEvent().
598 if ( !firstlaunch ) {
599 if ( (getEvtNr() >= 0) && (getEvtNr() < m_totEvtNr) ) { // If selected event number is available in file
600 loadEvent();
601 //Pass the event to the AOD System
602 std::set<IVP1System *>::iterator itsys, itsysE = m_d->mainwindow->tabManager()->selectedChannelWidget()->systems().end();
603 for (itsys = m_d->mainwindow->tabManager()->selectedChannelWidget()->systems().begin();itsys!=itsysE;++itsys) {
604 if((*itsys)->name()=="Analysis"){
605 passEvent(*itsys);
606 }
607 }
608 }
609 else if ( (getEvtNr() < 0) && (getEvtNr() >= m_totEvtNr) ) {
610 QMessageBox msgBox;
611 msgBox.setWindowTitle("No more events");
612 msgBox.setText("There are no more events in this file. Returning to previous event.");
613 msgBox.setIcon(QMessageBox::Icon::Information);
614 msgBox.exec();
615 }
616 }
617 else{
618 firstlaunch = false;
619 }
620#else
621 m_d->mainwindow->setRunEvtNumber(runnumber, eventnumber, triggerType, time, !m_d->skipEvent);
622#endif
623
624 m_d->goingtonextevent = false;
625 m_d->calctimethisevent=0;
626 m_d->currentrefreshsystemestimate=0;
627 m_d->updateProgressBar();
628
629 assert(!m_d->refreshtimer->isActive());//fixme: -> if.
630
631
632 VP1Msg::messageDebug("calling refreshtimer->start()...");
633 m_d->refreshtimer->start();
634
635 VP1Msg::messageDebug("calling initCruise...");
636 m_d->initCruise();
637 VP1Msg::messageDebug("initCruise called.");
638
639 //Flush event queue before reenabling controllers, etc.:
640 qApp->processEvents();
641 VP1Msg::messageDebug("qApp->processEvents() called.");
642
643 //Enable various user input:
644 m_d->mainwindow->groupBox_channelcontrols->setEnabled(true);
645 m_d->mainwindow->groupBox_cruise->setEnabled(true);
646 m_d->mainwindow->groupBox_event->setEnabled(true);
647
648
649 VP1Msg::messageDebug("batch mode: " + QString::number(m_d->batchMode));
650
651 if (m_d->batchModeRandomConfig) {
652 VP1Msg::messageDebug("User chose 'batch' and 'batch-random-config'. So we now replace the configuration with a random one from the input set...");
653 QString randomConfigFile = QString::fromStdString( m_d->batchUtilities->getRandomConfigFile() );
654 m_d->mainwindow->replaceConfigurationFile(randomConfigFile);
655 }
656
657 if ( m_d->batchMode && m_d->allVisibleRefreshed() ) { // or m_d->allSystemsRefreshed ???
658 VP1Msg::messageDebug("We're in batch mode, skipping the execution of the GUI...");
659 } else {
660 VP1Msg::messageDebug("skipEvent: " + QString::number(m_d->skipEvent));
661 if(m_d->skipEvent) {
662 VP1Msg::messageDebug("skipEvent");
663 m_d->skipEvent=false;
664 m_d->mainwindow->nextEvent();
665 }
666 else {
667 VP1Msg::messageDebug("calling qApp->exec()...");
668 qApp->exec();//NOTE!!! We then exit the exec() when someone pushes the "next event" button.
669 }
670 }
671
672 VP1Msg::messageDebug("Disabling user inputs...");
673 //Disable various user input:
674 m_d->mainwindow->groupBox_channelcontrols->setEnabled(false);
675 m_d->mainwindow->groupBox_cruise->setEnabled(false);
676 m_d->mainwindow->groupBox_event->setEnabled(false);
677
678 m_d->goingtonextevent = true;
679
680 if (m_d->refreshtimer->isActive()) {
681 m_d->refreshtimer->stop();
682 }
683 m_d->pb->hide();
684 m_d->pb->reset();
685 m_d->pbtimer->stop();
686 //Fixme: Refresh all accumulators that still needs refresh (or just have the button disabled until now)
687
688 //Fixme: wait here until end of any active refreshing...
689
690 VP1Msg::messageDebug("Erasing systems...");
691 assert(!m_d->currentsystemrefreshing);
692 for (IVP1System*s : m_d->prioritiser->getSystemsToEraseByPriority()) {
693 qApp->processEvents(QEventLoop::ExcludeUserInputEvents|QEventLoop::ExcludeSocketNotifiers);
694 eraseSystem(s);
695 }
696
697 ++m_d->eventsProcessed; // we don't use Athena's tools for this, so we can use this in VP1Light as well.
698 VP1Msg::messageDebug("event processed. " + QString::number(m_d->eventsProcessed) + " events processed so far.");
699
700 //Let channels know we are going to the next event now:
701 for (IVP1ChannelWidget*cw : m_d->mainwindow->tabManager()->allChannels()) {
702 cw->goingToNextEvent();
703 }
704
705 qApp->processEvents(QEventLoop::ExcludeUserInputEvents|QEventLoop::ExcludeSocketNotifiers);
706
707
708 VP1Msg::messageDebug("mainwindow->mustQuit ? " + QString::number(m_d->mainwindow->mustQuit()) );
709 return !m_d->mainwindow->mustQuit();
710}
711
712//___________________________________________________________________
714
715 VP1Msg::messageDebug("VP1ExecutionScheduler::eraseSystem()");
716
717 assert(s->state()==IVP1System::REFRESHED);
718 // cppcheck-suppress assertWithSideEffect
719 assert(!s->isRefreshing());
720
721 QString base = QString(s->name())+" from channel "+s->channel()->unique_name();
722 m_d->mainwindow->statusBar()->showMessage( "Erasing system ["+base+"]" );
723 VP1Msg::messageDebug("ERASING - " + base);
724
725 s->disallowUpdateGUI();
726 s->erase();//fixme: time?
727 s->setState(IVP1System::ERASED);
728 m_d->mainwindow->statusBar()->showMessage( "Post-erase update to channel ["+base+"]" );
729 s->channel()->systemErased(s);//fixme: time?
730 m_d->mainwindow->statusBar()->clearMessage();
731}
732
733//___________________________________________________________________
735 IVP1System*s = static_cast<IVP1System*>(sender());
736 assert(s);
737 if (m_d->currentsystemrefreshing!=s) {
738 eraseSystem(s);
739 } else {
740 // cppcheck-suppress assertWithSideEffect
741 assert(s->isRefreshing());
742 m_d->eraseJustAfterRefresh=true;
743 }
744}
745
746//___________________________________________________________________
748{
749 assert(!m_d->goingtonextevent);
750 if (m_d->currentsystemrefreshing)
751 return;
752
753 IVP1System * s = m_d->prioritiser->nextErasedActiveSystemByPriority();
754 if (s) {
755 refreshSystem(s);
756 } else {
757 assert(m_d->refreshtimer->isActive());//fixme: -> if. ???
758 //if (refreshtimer->isActive())
759 m_d->refreshtimer->stop();
760 m_d->pb->hide();
761 m_d->pb->reset();
762 m_d->pbtimer->stop();
763 }
764}
765
766//___________________________________________________________________
768{
769 std::set<IVP1System*>::const_iterator it, itE = cw->systems().end();
770 for (it=cw->systems().begin();it!=itE;++it) {
771 qInfo() << "System name:" << (*it)->name();
772 connect(*it,SIGNAL(inactiveSystemTurnedActive()),this,SLOT(startRefreshQueueIfAppropriate()));
773 connect(*it,SIGNAL(needErase()),this,SLOT(systemNeedErase()));
774 #ifdef BUILDVP1LIGHT
775 connect(*it,SIGNAL(signalLoadEvent(IVP1System*)),this,SLOT(passEvent(IVP1System*)));
776 #endif // BUILDVP1LIGHT
777 }
779
780}
781
782//___________________________________________________________________
784{
785 std::set<IVP1System*>::const_iterator it, itE = cw->systems().end();
786 for (it=cw->systems().begin();it!=itE;++it)
787 disconnect(*it,SIGNAL(inactiveSystemTurnedActive()),this,SLOT(startRefreshQueueIfAppropriate()));
788}
789
790//___________________________________________________________________
792{
793 if (!m_d->goingtonextevent&&!m_d->refreshtimer->isActive())
794 m_d->refreshtimer->start();
795}
796
797//___________________________________________________________________
799{
800 return m_d->currentsystemrefreshing;
801}
802
803//___________________________________________________________________
805{
806 QString sysname = s->name();
807 VP1Msg::messageDebug("VP1ExecutionScheduler::refreshSystem() - system: " + sysname);
808
809 m_d->updateProgressBar();
810
811 assert(s->state()==IVP1System::ERASED);
812 assert(s->activeState()==IVP1System::ON);
813 assert(!m_d->currentsystemrefreshing);
814
815 m_d->currentrefreshsystemestimate = m_d->prioritiser->beginTiming_Refresh(s);
816 m_d->currentsystemrefreshing = s;
817
818 QString base = QString(s->name())+" from channel "+s->channel()->unique_name();
819 m_d->mainwindow->statusBar()->showMessage( "Refreshing system ["+base+"]" );
820
821 s->allowUpdateGUI();
822 s->setRefreshing(true);
824 s->channel()->emitRefreshInfoChanged();
825 s->refresh(VP1AthenaPtrs::eventStore());
826 s->setState(IVP1System::REFRESHED);
827 s->setRefreshing(false);
828 s->disallowUpdateGUI();
829
830 m_d->mainwindow->statusBar()->showMessage( "Post-refresh update to channel ["+base+"]" );
831 s->channel()->systemRefreshed(s);//fixme: time independently?
832
833 m_d->mainwindow->statusBar()->clearMessage();
834 m_d->currentsystemrefreshing = 0;
835 m_d->calctimethisevent += m_d->prioritiser->endTiming_Refresh();
836 m_d->currentrefreshsystemestimate=0;
837 m_d->updateProgressBar();
838
840 s->channel()->emitRefreshInfoChanged();
841
842 VP1Msg::messageDebug("checking if all systems have refreshed...");
843 if (hasAllActiveSystemsRefreshed(s->channel())) {
844
845 VP1Msg::messageDebug("All systems refreshed! - last system refreshed! - system: " + sysname);
846 s->channel()->lastOfActiveSystemsRefreshed();
847
848 m_d->allSystemsRefreshed = true; // check if that is fine for multiple channels window: i.e. VP1 instances with a couple of 3DCkocktail windows, for example.
849
850 } // end of hasAllActiveSystemsRefreshed()
851
852 m_d->performPostRefreshCruiseActions(s->channel());
853
854 if (m_d->eraseJustAfterRefresh) {
855 //Someone asked to erase the system while it was refreshing!
856 m_d->eraseJustAfterRefresh=false;
857 //Check that it still needs to (maybe it was flicked back to ON by the impatient user)
858 if (s->activeState()==IVP1System::OFF)
859 eraseSystem(s);
860 }
861 if (m_d->postponedUncreateAndDeleteCW) {
862 actualUncreateAndDelete(m_d->postponedUncreateAndDeleteCW);
863 m_d->postponedUncreateAndDeleteCW=0;
864 }
865
866 VP1Msg::messageDebug("end of refreshing the system: " + sysname);
867
868// // if in "batch mode", now exit from VP1
869// if (m_d->batchMode) {
870//
873//
874// VP1Msg::messageWarningRed("'batch mode'. Now exiting VP1");
875//
876// // N.B. calling QApplication::quit() here it makes move to the next event;
877// // NOTE!!!! It can be useful for a batch mode on all events of one single file!!
878// // TODO: An additional switch to the command line batch option should be implemented
879// //QApplication::quit();
880//
881// //for the moment, we only quit VP1.
882// //To quit the application completely, we have to call "MainWindow::close()"
883// m_d->mainwindow->close();
885//
886// }
887
888 // ***************************
889 // we now run all the things
890 // that need to be done
891 // after all tabs are drawn...
892 // ***************************
893 if ( hasAllActiveSystemsRefreshed(s->channel()) ) {
894
895
896 if (m_d->batchMode) {
897
898 VP1Msg::messageDebug("we are in 'batch-mode'...");
899 VP1Msg::messageDebug("batchModeNEvents: " + QString::number(m_d->batchModeNEvents) + " - m_d->eventsProcessed: " + QString::number(m_d->eventsProcessed) );
900
901 // saving the snapshot of the 3D window to a file
902 QString save_ok = saveSnaphsotToFile(s, true);
903 if (save_ok == "") {
904 VP1Msg::messageWarningAllRed("FAILED! The snapshot for the channel '" + s->channel()->name() + "' has not been saved!");
905 } else {
906 VP1Msg::message("OK! Snapshot saved to file: " + save_ok);
907 }
908
909
910 if (m_d->batchModeAllEvents) {
911 VP1Msg::messageWarningAllRed("******************************************************************");
912 VP1Msg::messageWarningAllRed("'batch mode' with 'all events' option. Moving to the next event...");
913 VP1Msg::messageWarningAllRed("******************************************************************");
914 // N.B. calling QApplication::quit() here it makes VP1 move to the next event;
915 QApplication::quit();
916 // Now, VP1ExecutionScheduler::executeNewEvent() will end, then VP1Gui::executeNewEvent() will end, then they will start again: first VP1Gui then VP1ExecutionScheduler.
917 } else if ( m_d->batchModeNEvents > 0 ) {
918 if ( m_d->batchModeNEvents == m_d->eventsProcessed+1) { // here we use +1 because this is performed after the creation of the event snapshot. //TODO: maybe we can move this to a more natural place, at the beginning or at the end of an event
919 VP1Msg::messageWarningAllRed("******************************************************************");
920 VP1Msg::messageWarningAllRed("'batch mode' with 'batch-n-events' option. Processed the " + QString::number(m_d->eventsProcessed+1) + " events set by the user. Now exiting VP1");
921 VP1Msg::messageWarningAllRed("******************************************************************");
922 m_d->mainwindow->close();
923 } else {
924 VP1Msg::messageWarningAllRed("'batch mode' with 'batch-n-events' option. Moving to the next event...");
925 // N.B. calling QApplication::quit() here it makes VP1 move to the next event;
926 QApplication::quit();
927 // Now, VP1ExecutionScheduler::executeNewEvent() will end, then VP1Gui::executeNewEvent() will end, then they will start again: first VP1Gui then VP1ExecutionScheduler.
928 }
929 }
930 else {
931 // We come here if the user did not choose to run batch mode on all events.
932 // Thus, we want to close VP1 completely.
933 // So, in order to do that, we have to call "MainWindow::close()"
934 VP1Msg::messageWarningRed("'batch mode'. Done. Now exiting VP1");
935 m_d->mainwindow->close();
936 }
937
938
939 }
940 }
941}
942
943//___________________________________________________________________
945{
946 QString chnlname = s->name().toLower();
947 VP1Msg::messageDebug("VP1ExecutionScheduler::saveSnaphsotToFile() - taking the snapshot of the channel " + chnlname );
948
949 QString currentsaveimagepath = VP1Settings::defaultFileSelectDirectory() + QDir::separator();
950
951
952 if (batch) {
953
954 VP1Msg::messageDebug("Note: 'batch-mode'");
955
956
957 // A FOLDER CONTAINER
958 QString folderName = "";
959
960 // check if use specified an output folder for the batch job
961 QString batchOutFolder = VP1QtUtils::environmentVariableValue("VP1_BATCHMODE_OUT_FOLDER"); // ::getenv("VP1_BATCHMODE");
962 if ( ! (batchOutFolder == "") ) {
963 VP1Msg::messageDebug("Setting 'batch' output folder from user's settings");
964 folderName = batchOutFolder;
965 }
966 else
967 folderName = "atlas_vp1_batch_images";
968
969 // check if the folder already exists, if not make a new folder
970 QDir dir(folderName);
971 if (!dir.exists()) {
972 dir.mkpath(".");
973 }
974
975 QString folder;
976 if (folderName.startsWith("/"))
977 folder = folderName + QDir::separator();
978 else
979 folder = currentsaveimagepath + folderName + QDir::separator();
980
981 VP1Msg::messageDebug("folder set: " + folder);
982
983
984 // EVENT INFO AND TIMESTAMP
985
986 QString runnumb = QString::number(m_d->mainwindow->getRunNumber());
987 QString evnumb = QString::number(m_d->mainwindow->getEventNumber());
988 QString evtimestamp = QString::number(m_d->mainwindow->getEventTimestamp());
989
990 time_t t_evttimestamp = m_d->mainwindow->getEventTimestamp();
991 struct tm human_evtimestamp;
992 localtime_r(&t_evttimestamp, &human_evtimestamp);
993
994 std::ostringstream h_evtimestamp_ostri;
995 h_evtimestamp_ostri << 1900 + human_evtimestamp.tm_year
996 << "-" << 1 + human_evtimestamp.tm_mon // tm_mon is in the range [0, 11], so 1 must be added to get real months
997 << "-" << human_evtimestamp.tm_mday
998 << "T" << human_evtimestamp.tm_hour << "-" << human_evtimestamp.tm_min << "-" << human_evtimestamp.tm_sec << "CEST";
999
1000 std::string h_evtimestamp_str = h_evtimestamp_ostri.str();
1001 QString h_evtimestamp = QString::fromStdString(h_evtimestamp_str);
1002
1003 // IMAGE TIMESTAMP
1004
1005 time_t t_timestamp = time(0); // get time now;
1006 struct tm ltm;
1007 localtime_r(&t_timestamp, &ltm);
1008
1009 // print various components of tm structure.
1010 VP1Msg::messageDebug( "Year: "+ QString::number(1900 + ltm.tm_year)
1011 + " - " + "Month: " + QString::number(1 + ltm.tm_mon) + " - " // tm_mon is in the range [0, 11], so 1 must be added to get real months
1012 + "Day: " + QString::number(ltm.tm_mday)
1013 + " - " "Time: " + QString::number(ltm.tm_hour) + ":" + QString::number(ltm.tm_min) + ":" + QString::number(ltm.tm_sec) + "CEST");
1014
1015 std::ostringstream ostri_unix;
1016 ostri_unix << t_timestamp;
1017
1018 std::ostringstream ostri;
1019 ostri << 1900 + ltm.tm_year
1020 << "-" << 1 + ltm.tm_mon // tm_mon is in the range [0, 11], so 1 must be added to get real months
1021 << "-" << ltm.tm_mday
1022 << "T" << ltm.tm_hour << "-" << ltm.tm_min << "-" << ltm.tm_sec << "CEST";
1023
1024 std::string unixTimestamp = ostri_unix.str();
1025 std::string humanTimestamp = ostri.str();
1026 QString q_unixTimestamp = QString::fromStdString(unixTimestamp);
1027 QString q_humanTimestamp = QString::fromStdString(humanTimestamp);
1028 VP1Msg::messageDebug("Unix timestamp: " + q_unixTimestamp );
1029 VP1Msg::messageDebug("'human readable' timestamp: " + q_humanTimestamp );
1030
1031 /* channel's name is the name of the last channel updated by the executer,
1032 * i.e. the name changes according to the order the channels are refreshed.
1033 * Thus, we don't use the channel's name in the filename,
1034 * because it could be misleading.
1035 */
1036 //QString filename = currentsaveimagepath + "vp1_" + chnlname + "_snapshot_" + q_humanTimestamp + ".png";
1037 QString filename = folder + "vp1_batch_snapshot_r" + runnumb + "_ev" + evnumb + "_evtime_H" + h_evtimestamp + "_U" + evtimestamp + "___imgtime_H" + q_humanTimestamp + "_U" + q_unixTimestamp + ".png";
1038
1039 // taking the actual snapshot
1040 QPixmap pm = s->channel()->getSnapshot();
1041 if (pm.isNull()) {
1042 VP1Msg::messageDebug("QPixmap is null! returning...");
1043 return QString();
1044 }
1045
1046 // saving to file
1047 pm.save(filename);
1048
1049 // save last-saved image filename to working dir
1050 QString latestImageFileName = currentsaveimagepath + QString("latest_vp1image");
1051 QFile latestImage(latestImageFileName);
1052 if(latestImage.exists() && !latestImage.remove())
1053 throw std::runtime_error("Unable to overwrite the existing latest image file");
1054 if(!latestImage.open(QIODevice::WriteOnly | QIODevice::Text))
1055 throw std::runtime_error("Unable to create new latest image file");
1056 latestImage.write(filename.toStdString().c_str());
1057 latestImage.close();
1058
1059
1060 return filename;
1061 }
1062
1063 // default exit
1064 return QString();//filename;
1065
1066}
1067
1068
1069
1070//___________________________________________________________________
1072{
1074
1075 connect(cw,SIGNAL(message(const QString&)),m_d->mainwindow,SLOT(channelAddToMessageBox(const QString&)));
1076
1077 std::set<IVP1System *>::iterator itsys, itsysE = cw->systems().end();
1078 for (itsys = cw->systems().begin();itsys!=itsysE;++itsys) {
1079 assert((*itsys)->state()==IVP1System::CONSTRUCTED);
1080 connect((*itsys),SIGNAL(sysmessage(const QString&)),m_d->mainwindow,SLOT(systemAddToMessageBox(const QString&)));
1081 }
1082 itsysE = cw->systems().end();
1083 for (itsys = cw->systems().begin();itsys!=itsysE;++itsys) {
1084 (*itsys)->setCanRegisterController(true);
1085 (*itsys)->create(VP1AthenaPtrs::detectorStore());
1086 (*itsys)->setCanRegisterController(false);
1087 (*itsys)->setState(IVP1System::ERASED);
1088 }
1090 cw->setCanRegister(true,false);//Ok to register controllers during create.
1091 cw->create();
1092 cw->setCanRegister(false,false);
1094
1095 assert(cw->state()==IVP1ChannelWidget::READY);
1096 //Fixme: statusbar!!!!!
1097}
1098
1099//___________________________________________________________________
1101{
1102 assert(cw->state()==IVP1ChannelWidget::READY);
1103 if (m_d->currentsystemrefreshing&&cw->systems().find(m_d->currentsystemrefreshing)!=cw->systems().end()) {
1104 assert(!m_d->postponedUncreateAndDeleteCW);
1105 m_d->postponedUncreateAndDeleteCW=cw;
1106 } else {
1108 }
1109}
1110
1111//___________________________________________________________________
1113{
1114 assert(cw->state()==IVP1ChannelWidget::READY);
1115 cw->setUpdatesEnabled(false);//Just because...
1116
1117 //From this point on, we are not interested in signals from the channel (and its systems) that could disturb us:
1118 std::set<IVP1System *>::iterator itsys, itsysE = cw->systems().end();
1119 for (itsys = cw->systems().begin();itsys!=itsysE;++itsys) {
1120 (*itsys)->blockSignals(true);
1121 disconnect(*itsys,0,0,0);
1122 }
1123 cw->blockSignals(true);
1124 disconnect(cw,0,0,0);
1125
1126 //Make sure that all systems gets in the ERASED state. Throw assert if any is presently refreshing (BAD PROGRAMMER!!)
1127 for (itsys = cw->systems().begin();itsys!=itsysE;++itsys) {
1128 assert(m_d->currentsystemrefreshing!=(*itsys));
1129 if ((*itsys)->state()==IVP1System::REFRESHED)
1130 eraseSystem(*itsys);
1131 }
1132
1133 //Uncreate systems:
1134 for (itsys = cw->systems().begin();itsys!=itsysE;++itsys) {
1135 assert((*itsys)->state()==IVP1System::ERASED);
1136 (*itsys)->uncreate();
1137 (*itsys)->setState(IVP1System::UNCREATED);
1138 }
1139
1140 //Uncreate channel:
1141 assert(cw->state()==IVP1ChannelWidget::READY);
1142 cw->uncreate();//Fixme: Return codes!!
1144
1145 assert(cw->state()==IVP1ChannelWidget::UNCREATED);
1146
1147 cw->deleteControllers();//Also deletes system controllers.
1148
1149 //Delete:
1150 cw->deleteLater();
1151
1152}
1153
1154//___________________________________________________________________
1156{
1157 QSet<QWidget*> w_ignore;
1158#if QTCORE_VERSION >= 0x050E00
1159 QList<QWidget*> widgets = QApplication::allWidgets();
1160 QSet<QWidget*> wl (widgets.begin(), widgets.end());
1161#else
1162 QSet<QWidget*> wl = QApplication::allWidgets().toSet();
1163#endif
1164 w_ignore<<qApp->desktop();
1165 for (QObject*o : qApp->children()) {
1166 if (o->isWidgetType())
1167 w_ignore << static_cast<QWidget*>(o);
1168 }
1169 for (QWidget * w : wl) {
1170 if (w->objectName().startsWith("internal clipboard"))
1171 w_ignore << w;
1172 if (w->objectName()=="empty_widget")
1173 w_ignore << w;
1174 }
1175 wl.subtract(w_ignore);
1176 if (!wl.empty()) {
1177 std::cout<<std::endl;
1178 std::cout<<"VP1 WARNING: "<<wl.count()<< " widget"<<(wl.count()>1?"s":"")<<" left at end of job:"<<std::endl;
1179 int i(0);
1180 for (QWidget*w : wl) {
1181 std::cout<<++i<<") Address="<<w<<", ObjectName="<<w->objectName().toStdString()<<", ClassName="<<w->metaObject()->className()<<std::endl;
1182 }
1183 std::cout<<std::endl;
1184 }
1185}
1186
1187//___________________________________________________________________
1189{
1190 VP1Msg::messageDebug("VP1ExecutionScheduler::hasAllActiveSystemsRefreshed() - channelWidget: " + cw->name());
1191
1192 std::set<IVP1System*>::const_iterator it, itE = cw->systems().end();
1193 int i=0;
1194 for (it=cw->systems().begin();it!=itE;++it) {
1195
1196 /*
1197 * enum State { CONSTRUCTED=0, REFRESHED, ERASED, UNCREATED };
1198 * enum ActiveState { ON=0, OFF };//Whether it is part of the erase/refresh cycle.
1199 */
1200 if (VP1Msg::verbose()) {
1201 QString name = QString((*it)->name());
1202 QString active = QString::number((*it)->activeState());
1203 QString state = QString::number((*it)->state());
1204 std::cout << i << " - name: " << name.toStdString() << " - active: " << active.toStdString() << " - refreshed: " << state.toStdString() << std::endl;
1205 }
1206 if ((*it)->activeState()==IVP1System::ON&&(*it)->state()!=IVP1System::REFRESHED)
1207 return false;
1208
1209 i++;
1210 }
1211
1212 return true;
1213}
1214
1215//___________________________________________________________________
1217{
1218 for (IVP1ChannelWidget*cw : mainwindow->tabManager()->visibleChannels())
1219 if (!scheduler->hasAllActiveSystemsRefreshed(cw))
1220 return false;
1221 return true;
1222}
1223
1224//___________________________________________________________________
1226{
1227 for (IVP1ChannelWidget*cw : mainwindow->tabManager()->soonVisibleChannels())
1228 if (!scheduler->hasAllActiveSystemsRefreshed(cw))
1229 return false;
1230 return true;
1231}
1232
1233//___________________________________________________________________
1235
1236 //Abort if not in cruise mode, or if the system just refreshed did
1237 //not make cw fully refreshed:
1238 if (cruisemode==NONE||!scheduler->hasAllActiveSystemsRefreshed(cw))
1239 return;
1240
1241 if (cruisemode==EVENT) {
1242 //Abort if this refresh did not make all visible channels refreshed:
1243 if (!mainwindow->tabManager()->isVisible(cw)||!allVisibleRefreshed())
1244 return;
1245 //Start the countdown for the next event:
1246 assert(!cruisetimer->isActive());
1247 cruisetimer->start(mainwindow->spinBox_cruise->value()*1000);
1248 return;
1249 } else if (cruisemode==TAB) {
1251 //We are waiting for channels in the next tab to refresh before
1252 //we can move on, so we should check if this channel refresh
1253 //made all soonvisible channels refreshed. If so: move on.
1255 mainwindow->tabManager()->showNextTab();
1257 //If now all visible are refreshed, we start the timer again.
1258 if (allVisibleRefreshed())
1259 cruisetimer->start(mainwindow->spinBox_cruise->value()*1000);
1260 }
1261 } else {
1262 //Same as in the EVENT case: Check if it is time to start the countdown:
1263 //Abort if this refresh did not make all visible channels refreshed:
1264 if (!mainwindow->tabManager()->isVisible(cw)||!allVisibleRefreshed())
1265 return;
1266 //Start the countdown for the next event:
1267 assert(!cruisetimer->isActive());
1268 cruisetimer->start(mainwindow->spinBox_cruise->value()*1000);
1269 return;
1270 }
1271
1272 return;
1273 } else {
1274 assert(cruisemode==BOTH);
1275 assert(0&&"not implemented");
1276 }
1277}
1278
1279//___________________________________________________________________
1281{
1282 //No matter what we stop the timer when changing mode or starting a new event.
1283 if (cruisetimer->isActive())
1284 cruisetimer->stop();
1286
1287 //FIXME: DO STUFF HERE
1288
1289 switch (cruisemode) {
1290 case NONE:
1291 VP1Msg::messageVerbose("initCruise NONE");
1292 break;
1293 case TAB:
1294 if (allVisibleRefreshed())
1295 cruisetimer->start(mainwindow->spinBox_cruise->value()*1000);
1296 VP1Msg::messageVerbose("initCruise TAB");
1297 break;
1298 case EVENT:
1299 //Start cruise countdown if all visible refreshed:
1300 if (allVisibleRefreshed())
1301 cruisetimer->start(mainwindow->spinBox_cruise->value()*1000);
1302 VP1Msg::messageVerbose("initCruise EVENT");
1303 break;
1304 case BOTH:
1305 VP1Msg::messageVerbose("initCruise BOTH");
1306 break;
1307 default:
1308 assert(0&&"UNKNOWN CRUISE MODE");
1309 break;
1310 }
1311}
1312
1313//___________________________________________________________________
1315{
1316 if (m_d->cruisemode == m)
1317 return;
1318 m_d->cruisemode = m;
1319
1320 m_d->mainwindow->tabManager()->setTabCruiseMode(m==TAB||m==BOTH);
1321
1322 m_d->initCruise();
1323
1324}
1325
1326//Fixme: abort cruise when this and that... (or, sometimes just reset timer).
1327
1328//___________________________________________________________________
1330{
1331 //In any case, we should stop the timer (fixme: What if there are 0 visible channels - when will the timer get started again?):
1332 m_d->cruisetimer->stop();
1333
1334 if (!m_d->mainwindow->okToProceedToNextEvent()) {
1335 //Hmm. Would like to cruise, but that is not ok. Check back in a few seconds.
1336 m_d->cruisetimer->start( (m_d->mainwindow->spinBox_cruise->value() > 5 ? 3000 : 1000) );
1337 return;
1338 }
1339
1340 assert(!m_d->goingtonextevent);//Otherwise it is a bit silly?
1341
1342 switch (m_d->cruisemode) {
1343 case NONE:
1344 assert(0&&"should never happen");
1345 break;
1346 case TAB:
1347 assert(m_d->cruisetab_waitingtoproceed==false);
1348 if (m_d->allSoonVisibleRefreshed()) {
1349 m_d->mainwindow->tabManager()->showNextTab();
1350 //If now all visible are refreshed, we start the timer again.
1351 if (m_d->allVisibleRefreshed())
1352 m_d->cruisetimer->start(m_d->mainwindow->spinBox_cruise->value()*1000);
1353 } else {
1354 m_d->cruisetab_waitingtoproceed=true;
1355 }
1356 break;
1357 case EVENT:
1358 m_d->mainwindow->goToNextEvent();
1359 VP1Msg::messageDebug("Crusing to next event");
1360 break;
1361 case BOTH:
1362 assert(0&&"Not implemented");
1363 VP1Msg::messageDebug("ERROR: BOTH cruise mode not implemented");
1364 break;
1365 default:
1366 assert(0&&"UNKNOWN CRUISE MODE");
1367 VP1Msg::messageDebug("ERROR: Unknown cruise mode");
1368 break;
1369 }
1370}
1371
1372//___________________________________________________________________
1374{
1375 return m_d->mainwindow->userRequestedFiles();
1376}
1377
1378
1379//When in tabcruise mode:
1380// 1) We know that we are not in single-channel FS mode.
1381// 2) Soonvisible next
1382
1383//FS tab mode: What about floating dock widgets? Rather high priority, but those in next tab should get next...
1384
1385//Actually: Floating widgets from other tabs should get docked anyway when going FS-tab when in cruise-TAB mode...
1386
1387
1388//___________________________________________________________________
1389#ifdef BUILDVP1LIGHT
1390void VP1ExecutionScheduler::loadEvent(){
1391 // Get the name of the application:
1392 const char* appName = "VP1Light";
1393
1394 // Initialize the environment:
1395 if( !xAOD::Init( appName ).isSuccess() ) {
1396 ::Error( appName, XAOD_MESSAGE( "Failed to execute xAOD::Init" ) );
1397 return;
1398 }
1399
1400 m_event = new xAOD::TEvent( xAOD::TEvent::kAthenaAccess );
1401
1402 // Get local xAOD and set valid xAOD path
1403 QSettings settings("ATLAS", "VP1Light");
1404 std::string path = settings.value("aod/path").toString().toStdString();
1405
1406 // Open xAOD file and read it in
1407 m_ifile = ::TFile::Open( path.c_str(), "READ" );
1408 if( ! m_ifile ) {
1409 ::Error( appName, XAOD_MESSAGE( "File %s couldn't be opened..." ),
1410 path.c_str() );
1411 return;
1412 }
1413 if( !m_event->readFrom( m_ifile ).isSuccess() ) {
1414 ::Error( appName, XAOD_MESSAGE( "Failed to read from xAOD file %s" ),
1415 path.c_str() );
1416 return;
1417 }
1418
1419 // Check if file is empty:
1420 if( m_event->getEntry( 0 ) < 0 ) {
1421 ::Error( appName, XAOD_MESSAGE( "Couldn't load entry 0 from file %s" ),
1422 path.c_str() );
1423 return;
1424 }
1425
1426 //Load the current event
1427 m_event->getEntry( m_evtNr );
1428
1429 // List for available collections
1430 QStringList jetList;
1431 QStringList vertexList;
1432 QStringList otherList;
1433 QStringList caloClusterList;
1434 QStringList trackParticleList;
1435 QStringList muonList;
1436 QStringList electronList;
1437
1438
1439 // // Loop over all entries in the CollectionTree
1440 TTree* ct = (TTree*)m_ifile->Get("CollectionTree");
1441 m_totEvtNr = ct->GetEntriesFast();
1442 for (int i = 0; i<ct->GetListOfBranches()->GetEntries();i++){
1443 std::string className = ct->GetBranch(ct->GetListOfBranches()->At(i)->GetName())->GetClassName();
1444
1445 // Store collections in their respective QStringList
1446 if(split(className,"_v[1-9]")=="DataVector<xAOD::Vertex>"){
1447 vertexList << ct->GetListOfBranches()->At(i)->GetName();
1448 }
1449 if(split(className,"_v[1-9]")=="xAOD::MissingETContainer"){
1450 otherList << ct->GetListOfBranches()->At(i)->GetName();
1451 }
1452 if(split(className,"_v[1-9]")=="DataVector<xAOD::Jet>"){
1453 jetList << ct->GetListOfBranches()->At(i)->GetName();
1454 }
1455 if(split(className,"_v[1-9]")=="DataVector<xAOD::CaloCluster>"){
1456 caloClusterList << ct->GetListOfBranches()->At(i)->GetName();
1457 }
1458 if(split(className,"_v[1-9]")=="DataVector<xAOD::TrackParticle>"){
1459 trackParticleList << ct->GetListOfBranches()->At(i)->GetName();
1460 }
1461 if(split(className,"_v[1-9]")=="DataVector<xAOD::Muon>"){
1462 muonList << ct->GetListOfBranches()->At(i)->GetName();
1463 }
1464 if(split(className,"_v[1-9]")=="DataVector<xAOD::Electron>"){
1465 electronList << ct->GetListOfBranches()->At(i)->GetName();
1466 }
1467 }
1468
1469 //Fill the collection lists
1470 m_list.append(vertexList);
1471 m_list.append(otherList);
1472 m_list.append(jetList);
1473 m_list.append(caloClusterList);
1474 m_list.append(trackParticleList);
1475 m_list.append(muonList);
1476 m_list.append(electronList);
1477
1478 // Get the event info:
1479 const xAOD::EventInfo *eventInfo = nullptr;
1480 if( !m_event->retrieve (eventInfo, "EventInfo").isSuccess() ) {
1481 VP1Msg::messageWarningRed("Failed to retrieve EventInfo");
1482 return;
1483 }
1484 // Save Event info
1485 m_d->mainwindow->setRunEvtNumber(eventInfo->runNumber(),eventInfo->eventNumber(),eventInfo->level1TriggerType(),eventInfo->timeStamp());
1486
1487 // Update the GUI event counter
1488 QString currentEvt = "Event: " + QString::number(getEvtNr()+1) + "/" + QString::number(getTotEvtNr());
1489 m_d->mainwindow->pushButton_eventselect->setText(currentEvt);
1490}
1491
1492//____________________________________________________________________
1493void VP1ExecutionScheduler::passEvent(IVP1System* sys){
1494 sys->setEvent(m_event);
1495 sys->setObjectList(m_list);
1496}
1497
1498//____________________________________________________________________
1499QString VP1ExecutionScheduler::split(const std::string& input, const std::string& regex) {
1500 std::regex re(regex);
1501 std::sregex_token_iterator first{input.begin(), input.end(), re, -1}, last;
1502 std::vector<std::string> vec = {first, last};
1503 QStringList list;
1504 for (unsigned int i=0;i<vec.size();i++){
1505 list << QString::fromStdString(vec[i]);
1506 }
1507 return list.join("");
1508}
1509#endif // BUILDVP1LIGHT
const boost::regex re(r_e)
std::vector< size_t > vec
#define XAOD_MESSAGE(MESSAGE)
Simple macro for printing error/verbose messages.
TGraphErrors * GetEntries(TH2F *histo)
#define x
std::vector< std::string > qstringlistToVecString(const QStringList &list)
void unused(Args &&...)
void setState(const State &)
const QString & name() const
const std::set< IVP1System * > & systems()
void setCanRegister(const bool &controller, const bool &system)
The Athena Transient Store API.
static StoreGateSvc * eventStore()
static void setPointers(StoreGateSvc *eventStore, StoreGateSvc *detectorStore, ISvcLocator *, IToolSvc *)
static StoreGateSvc * detectorStore()
const QString & fileinfoLocation()
bool eventFilter(QObject *watched, QEvent *event)
IVP1ChannelWidget * postponedUncreateAndDeleteCW
void performPostRefreshCruiseActions(IVP1ChannelWidget *cw)
VP1ExecutionScheduler * scheduler
const QString & nextRequestedEventFile() const
static VP1ExecutionScheduler * init(StoreGateSvc *eventStore, StoreGateSvc *detStore, ISvcLocator *svcLocator, IToolSvc *toolSvc, const QStringList &joboptions, QString initialCruiseMode="NONE", unsigned initialCruiseSeconds=10, const QString &singleEventSource="", const QString &singleEventLocalTmpDir="", unsigned localFileCacheLimit=10, const QStringList &availableLocalInputDirectories=QStringList())
void bringFromConstructedToReady(IVP1ChannelWidget *)
bool executeNewEvent(const int &runnumber, const unsigned long long &eventnumber, const unsigned &triggerType=0, const unsigned &time=0)
void setCruiseMode(const CruiseMode &)
QString saveSnaphsotToFile(IVP1System *s, bool batch=false)
void actualUncreateAndDelete(IVP1ChannelWidget *)
void refreshingStatusChanged(bool)
void channelUncreated(IVP1ChannelWidget *)
bool hasAllActiveSystemsRefreshed(IVP1ChannelWidget *) const
void channelCreated(IVP1ChannelWidget *)
VP1ExecutionScheduler(QObject *parent, StoreGateSvc *eventStore, StoreGateSvc *detStore, ISvcLocator *svcLocator, IToolSvc *toolSvc, VP1AvailEvents *availEvents)
static void cleanup(VP1ExecutionScheduler *)
void setNextRequestedEventFile(const QString &)
void uncreateAndDelete(IVP1ChannelWidget *)
static void warnUndeletedInstances()
void request_cruisemodechange()
void loadConfigurationFromFile(const QString &file)
bool userRequestedExit()
static bool debug()
Definition VP1Msg.h:32
static void messageVerbose(const QString &)
Definition VP1Msg.cxx:84
static bool verbose()
Definition VP1Msg.h:31
static void messageDebug(const QString &)
Definition VP1Msg.cxx:39
static void message(const QString &, IVP1System *sys=0)
Definition VP1Msg.cxx:30
static void messageWarningRed(const QString &str, IVP1System *sys=0)
Definition VP1Msg.cxx:57
static void messageWarningAllRed(const QString &str, IVP1System *sys=0)
Definition VP1Msg.cxx:70
static bool environmentVariableIsOn(const QString &name)
static bool environmentVariableIsSet(const QString &name)
static QString environmentVariableValue(const QString &name)
static bool expertSettingIsOn(const QString &type, const QString &name)
static void setEnvironmentVariable(const QString &name, const QString &content)
static QString defaultFileSelectDirectory()
uint16_t level1TriggerType() const
The Level-1 trigger type.
uint32_t timeStamp() const
POSIX time in seconds from 1970. January 1st.
uint32_t runNumber() const
The current event's run number.
uint64_t eventNumber() const
The current event's event number.
@ kAthenaAccess
Access containers/objects like Athena does.
std::string base
Definition hcg.cxx:81
std::vector< std::string > split(const std::string &s, const std::string &t=":")
Definition hcg.cxx:177
static std::vector< uint32_t > runnumber
Definition iLumiCalc.h:37
std::string label(const std::string &format, int i)
Definition label.h:19
bool first
Definition DeMoScan.py:534
path
python interpreter configuration --------------------------------------—
Definition athena.py:128
list(name, path='/')
Definition histSizes.py:38
StatusCode Init(const char *appname)
Function initialising ROOT/PyROOT for using the ATLAS EDM.
Definition Init.cxx:31
EventInfo_v1 EventInfo
Definition of the latest event info version.