TRootanaEventLoop.cxx

Go to the documentation of this file.
00001 // Nothing here..
00002 
00003 // Rootana includes
00004 #include "TRootanaEventLoop.hxx"
00005 #include "XmlOdb.h"
00006 #ifdef OLD_SERVER
00007 #include "midasServer.h"
00008 #endif
00009 #ifdef HAVE_LIBNETDIRECTORY
00010 #include "libNetDirectory/netDirectoryServer.h"
00011 #endif
00012 #include "TPeriodicClass.hxx"
00013 #include "MainWindow.hxx"
00014 
00015 // ROOT includes.
00016 #include <TSystem.h>
00017 #include <TROOT.h>
00018 #include <TH1D.h>
00019 
00020 #include <stdio.h>
00021 #include <sys/time.h>
00022 #include <iostream>
00023 #include <assert.h>
00024 #include <signal.h>
00025 
00026 #include "sys/time.h"
00027 /// Little function for printing the number of processed events and processing rate.
00028 struct timeval raLastTime;  
00029 int raTotalEventsProcessed = 0;
00030 void PrintCurrentStats(){
00031 
00032   if((raTotalEventsProcessed%500)==0){
00033     if(raTotalEventsProcessed==0){
00034       gettimeofday(&raLastTime, NULL);
00035       printf("Processed %d events.\n",raTotalEventsProcessed);
00036     }else{
00037 
00038       struct timeval nowTime;  
00039       gettimeofday(&nowTime, NULL);
00040       
00041       double dtime = nowTime.tv_sec - raLastTime.tv_sec + (nowTime.tv_usec - raLastTime.tv_usec)/1000000.0;
00042       double rate = 0;
00043       if (time !=0)
00044         rate = 500.0/(dtime);
00045       printf("Processed %d events.  Analysis rate = %f events/seconds. \n",raTotalEventsProcessed,rate);
00046       gettimeofday(&raLastTime, NULL);
00047     }
00048   }
00049   
00050   raTotalEventsProcessed++;
00051 
00052 }
00053  
00054 
00055 
00056 
00057 TRootanaEventLoop* TRootanaEventLoop::fTRootanaEventLoop = NULL;
00058 
00059 TRootanaEventLoop& TRootanaEventLoop::Get(void) {
00060   
00061   if(!fTRootanaEventLoop){
00062     std::cerr << "Singleton Not Instantiated! " 
00063               << " Need to call something like SomeClass::CreateSingleton<SomeClass>(); Exiting!"
00064               <<std::endl; exit(0);
00065   }
00066   return *fTRootanaEventLoop;
00067 }
00068   
00069 
00070 
00071 TRootanaEventLoop::TRootanaEventLoop (){
00072 
00073   fOutputFile = 0;
00074   fOutputFilename = std::string("output");
00075   fDisableRootOutput = false;
00076   fODB = 0;
00077   fOnlineHistDir = 0;
00078   fMaxEvents = 0;
00079   fCurrentRunNumber = 0;
00080   fIsOffline = true;
00081 
00082   fCreateMainWindow = true;
00083   fSuppressTimestampWarnings = false;    
00084 
00085   fBufferName = std::string("SYSTEM");
00086   fOnlineName = std::string("rootana");
00087 
00088   fDataContainer = new TDataContainer();
00089 
00090   /// Create the TApplication
00091   char **argv2 = NULL;
00092   fApp = new TApplication("rootana", 0, argv2);
00093 
00094 }
00095 
00096 TRootanaEventLoop::~TRootanaEventLoop (){
00097 
00098   if(fODB) delete fODB;
00099   CloseRootFile();
00100 
00101 }
00102 
00103 
00104 void TRootanaEventLoop::Initialize(void){};
00105   
00106 void TRootanaEventLoop::BeginRun(int transition,int run,int time){};
00107 
00108 void TRootanaEventLoop::EndRun(int transition,int run,int time){};
00109   
00110 void TRootanaEventLoop::Finalize(){};
00111 
00112 void TRootanaEventLoop::Usage(void){};
00113 void TRootanaEventLoop::UsageRAD(void){};
00114   
00115 
00116 bool TRootanaEventLoop::CheckOption(std::string option){return false;}
00117 bool TRootanaEventLoop::CheckOptionRAD(std::string option){return false;}
00118 
00119 
00120 bool TRootanaEventLoop::CheckEventID(int eventId){
00121 
00122   // If we didn't specify list of accepted IDs, then accept all.
00123   if(fProcessEventIDs.size()==0) return true;
00124 
00125   // Otherwise check event ID against list
00126   for(unsigned int i = 0; i < fProcessEventIDs.size(); i++){
00127     if(fProcessEventIDs[i] == (eventId & 0xFFFF))
00128       return true;
00129   }
00130   
00131   return false;
00132 }
00133 
00134 void TRootanaEventLoop::PrintHelp(){
00135 
00136   printf("\nUsage:\n");
00137   printf("\n./analyzer.exe [-h] [-Hhostname] [-Eexptname] [-eMaxEvents] [-P9091] [-p9090] [-m] [-g] [file1 file2 ...]\n");
00138   printf("\n");
00139   printf("\t-h: print this help message\n");
00140   printf("\t-T: test mode - start and serve a test histogram\n");
00141   printf("\t-Hhostname: connect to MIDAS experiment on given host\n");
00142   printf("\t-Eexptname: connect to this MIDAS experiment\n");
00143   printf("\t-bbuffer: connect to this MIDAS buffer\n");
00144   printf("\t-P: Start the TNetDirectory server on specified tcp port (for use with roody -Plocalhost:9091)\n");
00145   printf("\t-p: Start the old midas histogram server on specified tcp port (for use with roody -Hlocalhost:9090)\n");
00146   printf("\t-eXXX: Number of events XXX to read from input data files\n");
00147   //printf("\t-m: Enable memory leak debugging\n");
00148   printf("\t-g: Enable graphics display when processing data files\n");
00149   UsageRAD();  // Print description of TRootanaDisplay options.
00150   Usage();  // Print description of user options.
00151   printf("\n");
00152   printf("Example1: analyze online data: ./analyzer.exe -P9091\n");
00153   printf("Example2: analyze existing data: ./analyzer.exe /data/alpha/current/run00500.mid\n");
00154 
00155   exit(1);
00156 }
00157 
00158 
00159 int TRootanaEventLoop::ExecuteLoop(int argc, char *argv[]){
00160   
00161   setbuf(stdout,NULL);
00162   setbuf(stderr,NULL);
00163   
00164   signal(SIGILL,  SIG_DFL);
00165   signal(SIGBUS,  SIG_DFL);
00166   signal(SIGSEGV, SIG_DFL);
00167 
00168   std::vector<std::string> args;
00169   for (int i=0; i<argc; i++)
00170     {
00171       if (strcmp(argv[i],"-h")==0)
00172         PrintHelp(); // does not return
00173       args.push_back(argv[i]);
00174     }
00175   
00176   
00177   if(gROOT->IsBatch()) {
00178     printf("Cannot run in batch mode\n");
00179     return 1;
00180   }
00181 
00182   bool forceEnableGraphics = false;
00183   bool testMode = false;
00184   int  tcpPort = 0;
00185   const char* hostname = NULL;
00186   const char* exptname = NULL;
00187   
00188   for (unsigned int i=1; i<args.size(); i++) // loop over the commandline options
00189     {
00190       const char* arg = args[i].c_str();
00191       //printf("argv[%d] is %s\n",i,arg);
00192       
00193       if (strncmp(arg,"-e",2)==0)  // Event cutoff flag (only applicable in offline mode)
00194         fMaxEvents = atoi(arg+2);
00195       else if (strncmp(arg,"-m",2)==0) // Enable memory debugging
00196         ;//      gEnableShowMem = true;
00197       else if (strncmp(arg,"-P",2)==0) // Set the histogram server port
00198         tcpPort = atoi(arg+2);
00199       else if (strcmp(arg,"-T")==0)
00200         testMode = true;
00201       else if (strcmp(arg,"-g")==0)
00202         forceEnableGraphics = true;
00203       else if (strncmp(arg,"-H",2)==0)
00204         hostname = strdup(arg+2);
00205       else if (strncmp(arg,"-E",2)==0)
00206         exptname = strdup(arg+2);
00207       else if (strncmp(arg,"-b",2)==0){
00208         fBufferName = std::string(arg+2);        
00209       }else if (strcmp(arg,"-h")==0)
00210         PrintHelp(); // does not return
00211       else if(arg[0] == '-')// Check if a TRootanaDisplay or user-defined options
00212         if(!CheckOptionRAD(args[i]))
00213           if(!CheckOption(args[i]))
00214             PrintHelp(); // does not return
00215     }
00216     
00217   // Do quick check if we are processing online or offline.
00218   // Want to know before we initialize.
00219   fIsOffline = false;  
00220   for (unsigned int i=1; i<args.size(); i++){
00221     const char* arg = args[i].c_str();
00222     if (arg[0] != '-')  
00223       {  
00224         fIsOffline = true;
00225       }
00226   }
00227 
00228 
00229   MainWindow *mainWindow=0;
00230   if(fCreateMainWindow){
00231     mainWindow = new MainWindow(gClient->GetRoot(), 200, 300);
00232   }
00233 
00234    gROOT->cd();
00235    fOnlineHistDir = new TDirectory("rootana", "rootana online plots");
00236 
00237 #ifdef HAVE_LIBNETDIRECTORY
00238    if (tcpPort)
00239      StartNetDirectoryServer(tcpPort, fOnlineHistDir);
00240 #else
00241    if (tcpPort)
00242      fprintf(stderr,"ERROR: No support for the TNetDirectory server!\n");
00243 #endif
00244    
00245    // Initialize the event loop with user initialization.
00246    Initialize();
00247 
00248    for (unsigned int i=1; i<args.size(); i++){
00249      const char* arg = args[i].c_str();
00250      if (arg[0] != '-')  
00251        {  
00252            ProcessMidasFile(fApp,arg);
00253        }
00254    }
00255 
00256    if (testMode){
00257      std::cout << "Entering test mode." << std::endl;
00258      fOnlineHistDir->cd();
00259      TH1D* hh = new TH1D("test", "test", 100, 0, 100);
00260      hh->Fill(1);
00261      hh->Fill(10);
00262      hh->Fill(50);
00263      
00264      fApp->Run(kTRUE);
00265      if(fCreateMainWindow) delete mainWindow;
00266      return 0;
00267    }
00268 
00269    // if we processed some data files,
00270    // do not go into online mode.
00271    if (fIsOffline){
00272      if(fCreateMainWindow) delete mainWindow;
00273      return 0;
00274    }
00275            
00276 #ifdef HAVE_MIDAS
00277    ProcessMidasOnline(fApp, hostname, exptname);;
00278 #endif
00279    
00280    if(fCreateMainWindow) delete mainWindow;
00281    
00282    Finalize();
00283    
00284    return 0;
00285   
00286 }
00287 
00288 
00289 
00290 int TRootanaEventLoop::ProcessMidasFile(TApplication*app,const char*fname)
00291 {
00292   TMidasFile f;
00293   bool tryOpen = f.Open(fname);
00294 
00295   if (!tryOpen){
00296     printf("Cannot open input file \"%s\"\n",fname);
00297     return -1;
00298   }
00299  
00300 
00301   int i=0;
00302   while (1)
00303     {
00304       TMidasEvent event;
00305       if (!f.Read(&event))
00306         break;
00307       
00308       /// Treat the begin run and end run events differently.
00309       int eventId = event.GetEventId();
00310 
00311       
00312 
00313       if ((eventId & 0xFFFF) == 0x8000){// begin run event
00314         
00315         event.Print();
00316         
00317         // Load ODB contents from the ODB XML file
00318         if (fODB) delete fODB;
00319         fODB = new XmlOdb(event.GetData(),event.GetDataSize());
00320         
00321         fCurrentRunNumber = event.GetSerialNumber();
00322         OpenRootFile(fCurrentRunNumber);
00323         BeginRun(0,event.GetSerialNumber(),0);
00324 
00325       } else if ((eventId & 0xFFFF) == 0x8001){// end run event
00326           
00327         event.Print();
00328         //EndRun(0,fCurrentRunNumber,0);
00329         
00330 
00331       } else if ((eventId & 0xFFFF) == 0x8002){
00332 
00333         event.Print(); 
00334         printf("Log message: %s\n", event.GetData()); 
00335 
00336       }else if(CheckEventID(eventId)){ // all other events; check that this event ID should be processed.
00337 
00338         // Set the bank list for midas event.
00339         event.SetBankList();
00340         
00341         // Set the midas event pointer in the physics event.
00342         fDataContainer->SetMidasEventPointer(event);
00343         
00344         //ProcessEvent if prefilter is satisfied...
00345                                 if(PreFilter(*fDataContainer))
00346                                          ProcessMidasEvent(*fDataContainer);
00347         
00348         // Cleanup the information for this event.
00349         fDataContainer->CleanupEvent();
00350         
00351       }
00352  
00353       PrintCurrentStats();
00354 
00355       // Check if we have processed desired number of events.
00356       i++;
00357       if ((fMaxEvents!=0)&&(i>=fMaxEvents)){
00358         printf("Reached event %d, exiting loop.\n",i);
00359         break;
00360       }
00361     }
00362   
00363   f.Close(); 
00364 
00365   EndRun(0,fCurrentRunNumber,0);
00366   CloseRootFile();  
00367 
00368   // start the ROOT GUI event loop
00369   //  app->Run(kTRUE);
00370 
00371   return 0;
00372 }
00373 
00374 
00375 void TRootanaEventLoop::OpenRootFile(int run){
00376 
00377   if(fDisableRootOutput) return;
00378 
00379   if(fOutputFile) {
00380     fOutputFile->Write();
00381     fOutputFile->Close();
00382     fOutputFile=0;
00383   }  
00384   
00385   char filename[1024];
00386   sprintf(filename, "%s%05d.root",fOutputFilename.c_str(), run);
00387   fOutputFile = new TFile(filename,"RECREATE");
00388   std::cout << "Opened output file with name : " << filename << std::endl;
00389 
00390 
00391 #ifdef HAVE_LIBNETDIRECTORY
00392   NetDirectoryExport(fOutputFile, "outputFile");
00393 #endif
00394 }
00395 
00396 
00397 void TRootanaEventLoop::CloseRootFile(){
00398 
00399   if(fOutputFile) {
00400                 std::cout << "Closing ROOT file " << std::endl;
00401     fOutputFile->Write();
00402     fOutputFile->Close();
00403     fOutputFile=0;
00404   } 
00405 
00406 }
00407 
00408 
00409 
00410 /// _________________________________________________________________________
00411 /// _________________________________________________________________________
00412 /// _________________________________________________________________________
00413 /// The following code is only applicable for online MIDAS programs
00414 
00415 #ifdef HAVE_MIDAS
00416 
00417 // This global variable allows us to keep track of whether we are already in the process
00418 // of analyzing a particular event. 
00419 static bool onlineEventLock = false;
00420 
00421 
00422 // number of events consecutively skipped.
00423 int numberConsSkipped=0;
00424 double nextWarn = 1.0;
00425 
00426 // number of events with late (>10sec old) timestamp.
00427 int numberOldTimestamps=0;
00428 double nextWarnTimestamps = 1.0;
00429 
00430 /// We need to use a regular function, so that it can be passed 
00431 /// to the TMidasOnline event handler.  This function calles the 
00432 /// event loop singleton, allowing the user to add their own function code. 
00433 void onlineEventHandler(const void*pheader,const void*pdata,int size)
00434 {
00435 
00436   // If we are already processing a previous event, then just dump this one.
00437   // !!!!!!!!!!! This is adding a potential dangerous race condition!!!!!
00438   // !!!!!!!!!!! Need to think hard if this is safe!!!!!!!!!!!!!!!!!!!!!!
00439   if(onlineEventLock) return;
00440   onlineEventLock = true;
00441 
00442   // Do a check; if the we are using output files, but the output file is null
00443   // then dump the event.  This will usually occur if we try to process additional
00444   // events after the end of the run.  Trying to fill a histogram will result in
00445   // seg-faults, since the histograms will have been deleted when the last ROOT file
00446   // was closed.
00447   if(TRootanaEventLoop::Get().IsRootOutputEnabled() 
00448      && !TRootanaEventLoop::Get().IsRootFileValid()){
00449 
00450     numberConsSkipped++;
00451     if(numberConsSkipped >= nextWarn){
00452       printf("onlineEventHandler Warning:  Output ROOT file is not validly open, so can't fill histograms. Have skipped %i events now.\n",
00453              numberConsSkipped);
00454       nextWarn *= 3.16227;
00455     }
00456 
00457     onlineEventLock = false;
00458     return;
00459   }
00460   numberConsSkipped = 0;
00461   nextWarn = 1.0;
00462 
00463   // Make a MIDAS event.
00464   TMidasEvent event;
00465   memcpy(event.GetEventHeader(), pheader, sizeof(TMidas_EVENT_HEADER));
00466   event.SetData(size, (char*)pdata);
00467   event.SetBankList();
00468   
00469   // Make sure that this is an event that we actually want to process.
00470   if(!TRootanaEventLoop::Get().CheckEventID(event.GetEventId())){
00471     onlineEventLock = false;
00472     return;
00473   }
00474 
00475   /// Set the midas event pointer in the physics event.
00476   TRootanaEventLoop::Get().GetDataContainer()->SetMidasEventPointer(event);
00477 
00478   // Now pass this to the user event function, if pre-filter is satisfied
00479         if(TRootanaEventLoop::Get().PreFilter(*TRootanaEventLoop::Get().GetDataContainer())){           
00480                 TRootanaEventLoop::Get().ProcessMidasEvent(*TRootanaEventLoop::Get().GetDataContainer());
00481         }
00482 
00483   PrintCurrentStats();
00484 
00485   // Cleanup the information for this event.
00486   TRootanaEventLoop::Get().GetDataContainer()->CleanupEvent();
00487 
00488   // Do another check.  If the event timestamp is more than 10 sec older than the current timestamp,
00489   // then the analyzer is probably falling behind the data taking.  Warn user.
00490   if(!TRootanaEventLoop::Get().GetSuppressTimestampWarnings()){
00491     struct timeval now;  
00492     gettimeofday(&now, NULL);
00493     if(event.GetTimeStamp() < now.tv_sec - 10){      
00494       numberOldTimestamps++;
00495       if(numberOldTimestamps >= nextWarnTimestamps){
00496         printf("onlineEventHandler Warning: the time for this bank (%i) is more than 10 sec older \nthan current time (%i). Has happenned %i times now.",       
00497                event.GetTimeStamp(),(int) now.tv_sec,numberOldTimestamps);
00498         printf("Either the analyzer is falling behind the data taking \n(try modifying the fraction of events plotted) or times on different computers are not synchronized.\n");  
00499         
00500         int buffer_level = TMidasOnline::instance()->getBufferLevel();
00501         int buffer_size = TMidasOnline::instance()->getBufferSize();
00502         printf("Buffer level = %i bytes out of %i bytes maximum \n\n",buffer_level,buffer_size);        
00503         nextWarnTimestamps *= 3.16227;
00504       }      
00505     }
00506   }
00507 
00508   onlineEventLock = false;
00509 }
00510 
00511 
00512 void onlineBeginRunHandler(int transition,int run,int time)
00513 {
00514   TRootanaEventLoop::Get().OpenRootFile(run);
00515   TRootanaEventLoop::Get().SetCurrentRunNumber(run);
00516   TRootanaEventLoop::Get().BeginRun(transition,run,time);
00517 }
00518 
00519 void onlineEndRunHandler(int transition,int run,int time)
00520 {
00521   TRootanaEventLoop::Get().SetCurrentRunNumber(run);
00522   TRootanaEventLoop::Get().EndRun(transition,run,time);
00523   TRootanaEventLoop::Get().CloseRootFile();
00524 }
00525 
00526 
00527 void MidasPollHandlerLocal()
00528 {
00529 
00530   if (!(TMidasOnline::instance()->poll(0)))
00531     gSystem->ExitLoop();
00532 }
00533 
00534 int TRootanaEventLoop::ProcessMidasOnline(TApplication*app, const char* hostname, const char* exptname)
00535 {
00536    TMidasOnline *midas = TMidasOnline::instance();
00537 
00538    int err = midas->connect(hostname, exptname, fOnlineName.c_str());
00539    if (err != 0)
00540      {
00541        fprintf(stderr,"Cannot connect to MIDAS, error %d\n", err);
00542        return -1;
00543      }
00544 
00545    fODB = midas;
00546 
00547    /* fill present run parameters */
00548 
00549    fCurrentRunNumber = fODB->odbReadInt("/runinfo/Run number");
00550 
00551    //   if ((fODB->odbReadInt("/runinfo/State") == 3))
00552    //startRun(0,gRunNumber,0);
00553    OpenRootFile(fCurrentRunNumber);
00554    BeginRun(0,fCurrentRunNumber,0);
00555 
00556    // Register begin and end run handlers.
00557    midas->setTransitionHandlers(onlineBeginRunHandler,onlineEndRunHandler,NULL,NULL);
00558    midas->registerTransitions();
00559 
00560    /* reqister event requests */
00561    midas->setEventHandler(onlineEventHandler);
00562 
00563    midas->eventRequest(fBufferName.c_str(),-1,-1,(1<<1));  
00564    //midas->eventRequest(fBufferName.c_str(),-1,-1,(2<<1));  
00565 
00566    // printf("Startup: run %d, is running: %d, is pedestals run: %d\n",gRunNumber,gIsRunning,gIsPedestalsRun);
00567    
00568    TPeriodicClass tm(100,MidasPollHandlerLocal);
00569 
00570    /*---- start main loop ----*/
00571 
00572    //loop_online();
00573    app->Run(kTRUE); // kTRUE means return to here after finished with online processing... this ensures that we can disconnect.
00574    
00575    // Call user-defined EndRun and close the ROOT file.
00576    EndRun(0,fCurrentRunNumber,0);
00577    CloseRootFile();  
00578 
00579    /* disconnect from experiment */
00580    midas->disconnect();
00581 
00582    return 0;
00583 }
00584 
00585 #endif

Generated on 5 May 2014 for ROOT Analyzer by  doxygen 1.6.1