]> git.uio.no Git - u/mrichter/AliRoot.git/blobdiff - FMD/AliFMDBaseDA.cxx
Some changes to make it possible to run the DA's
[u/mrichter/AliRoot.git] / FMD / AliFMDBaseDA.cxx
index 8654f38bc0a166a326147b04feed1a0812145240..26da4c309bd3211278c1f3a83c1ad5ee7563a3e4 100644 (file)
     @brief   Base class for detector algorithms.
 */
 //
-//This is the implementation of the (virtual) base class for the FMD detector 
-//algorithms(DA). It implements the creation of the relevant containers and handles the 
-//loop over the raw data. The derived classes can control the parameters and action
-//to be taken making this the base class for the Pedestal, Gain and Physics DA.
+// This is the implementation of the (virtual) base class for the FMD
+// detector algorithms(DA). It implements the creation of the relevant
+// containers and handles the loop over the raw data. The derived
+// classes can control the parameters and action to be taken making
+// this the base class for the Pedestal, Gain and Physics DA.
 //
 
 #include "AliFMDBaseDA.h"
-#include "iostream"
-
+#include "AliRawReader.h"
+#include "AliFMDDigit.h"
+#include "AliFMDParameters.h"
 #include "AliFMDRawReader.h"
+#include "AliFMDCalibSampleRate.h"
+#include "AliFMDCalibStripRange.h"
 #include "AliLog.h"
+#include "AliRawEventHeaderBase.h"
+#include "AliFMDDigit.h"
+#include <TClonesArray.h>
+#include <TFile.h>
+#include <TDatime.h>
+#include <TSystem.h>
+#include <TH2F.h>
+#include <TStopwatch.h>
+#include <TROOT.h>
+#include <TPluginManager.h>
+#include <iostream>
+#include <fstream>
+
 //_____________________________________________________________________
 ClassImp(AliFMDBaseDA)
+#if 0 
+; // Do not delete  - to let Emacs for mat the code
+#endif
+
+//_____________________________________________________________________
+const char*
+AliFMDBaseDA::GetStripPath(UShort_t det, 
+                          Char_t   ring, 
+                          UShort_t sec, 
+                          UShort_t str, 
+                          Bool_t   full) const
+{
+  // Get the strip path 
+  // 
+  // Parameters 
+  //     det      Detector number
+  //     ring     Ring identifier 
+  //     sec      Sector number 
+  //     str      Strip number
+  //     full     If true, return full path 
+  // 
+  // Return 
+  //     The path
+  return Form("%s%sFMD%d%c[%02d,%03d]", 
+             (full ? GetSectorPath(det, ring, sec, full) : ""), 
+             (full ? "/" : ""), det, ring, sec, str);
+}
+//_____________________________________________________________________
+const char*
+AliFMDBaseDA::GetSectorPath(UShort_t det, 
+                           Char_t   ring, 
+                           UShort_t sec, 
+                           Bool_t   full) const
+{
+  // Get the strip path 
+  // 
+  // Parameters 
+  //     det      Detector number
+  //     ring     Ring identifier 
+  //     sec      Sector number 
+  //     str      Strip number
+  //     full     If true, return full path 
+  // 
+  // Return 
+  //     The path
+  return Form("%s%sFMD%d%c[%02d]", 
+             (full ? GetRingPath(det, ring, full) : ""), 
+             (full ? "/" : ""), det, ring, sec);
+}
+//_____________________________________________________________________
+const char*
+AliFMDBaseDA::GetRingPath(UShort_t det, 
+                         Char_t   ring, 
+                         Bool_t   full) const
+{
+  // Get the strip path 
+  // 
+  // Parameters 
+  //     det      Detector number
+  //     ring     Ring identifier 
+  //     sec      Sector number 
+  //     str      Strip number
+  //     full     If true, return full path 
+  // 
+  // Return 
+  //     The path
+  return Form("%s%sFMD%d%c", 
+             (full ? GetDetectorPath(det, full) : ""), 
+             (full ? "/" : ""), det, ring);
+}
+//_____________________________________________________________________
+const char*
+AliFMDBaseDA::GetDetectorPath(UShort_t det, 
+                             Bool_t   full) const
+{
+  // Get the strip path 
+  // 
+  // Parameters 
+  //     det      Detector number
+  //     ring     Ring identifier 
+  //     sec      Sector number 
+  //     str      Strip number
+  //     full     If true, return full path 
+  // 
+  // Return 
+  //     The path
+  return Form("%s%sFMD%d", 
+             (full ? fDiagnosticsFilename.Data() : ""), 
+             (full ? ":/" : ""), det);
+}
 
 //_____________________________________________________________________
-AliFMDBaseDA::AliFMDBaseDA() : TNamed(),
+AliFMDBaseDA::AliFMDBaseDA() : 
+  TNamed(),
   fDiagnosticsFilename("diagnosticsHistograms.root"),
   fOutputFile(),
   fConditionsFile(),
   fSaveHistograms(kFALSE),
+  fMakeSummaries(kFALSE),
   fDetectorArray(),
+  fPulseSize(10),
+  fPulseLength(10),
   fRequiredEvents(0),
-  fCurrentEvent(0)
+  fCurrentEvent(0), 
+  fRunno(0),
+  fSummaries(0),
+  fAll(false)
 {
+  //Constructor
+  for(Int_t i = 0; i< 3;i++) {
+    fSeenDetectors[i] = false;
+    fNEventsPerDetector[i] = 0;
+  }
   fDetectorArray.SetOwner();
+  Rotate("conditions.csv", 3);
   fConditionsFile.open("conditions.csv");
 }
 //_____________________________________________________________________
 AliFMDBaseDA::AliFMDBaseDA(const AliFMDBaseDA & baseDA) : 
   TNamed(baseDA),
-  fDiagnosticsFilename(baseDA.fDiagnosticsFilename),
+  fDiagnosticsFilename(baseDA.fDiagnosticsFilename.Data()),
   fOutputFile(),
   fConditionsFile(),
   fSaveHistograms(baseDA.fSaveHistograms),
+  fMakeSummaries(baseDA.fMakeSummaries),
   fDetectorArray(baseDA.fDetectorArray),
+  fPulseSize(baseDA.fPulseSize),
+  fPulseLength(baseDA.fPulseLength),
   fRequiredEvents(baseDA.fRequiredEvents),
-  fCurrentEvent(baseDA.fCurrentEvent)
+  fCurrentEvent(baseDA.fCurrentEvent),
+  fRunno(baseDA.fRunno),
+  fSummaries(0),
+  fAll(baseDA.fAll)
 {
-  fDetectorArray.SetOwner();
-  
+  //Copy constructor
+  for(Int_t i = 0; i< 3;i++) {
+    fSeenDetectors[i] = baseDA.fSeenDetectors[0];
+    fNEventsPerDetector[i] = baseDA.fNEventsPerDetector[i];
+  }
+
+  fDetectorArray.SetOwner();  
 }
 
-//_____________________________________________________________________
-AliFMDBaseDA::~AliFMDBaseDA() {
 
+//_____________________________________________________________________
+AliFMDBaseDA::~AliFMDBaseDA() 
+{
   //destructor
-  
 }
 
 //_____________________________________________________________________
-void AliFMDBaseDA::Run(AliRawReader* reader) {
-  
-  
-  
-  InitContainer();
+Bool_t AliFMDBaseDA::HaveEnough(Int_t nEvents) const
+{
+  // if (!fAll) return nEvents > GetRequiredEvents();
+  if (nEvents <= 1) return false;
 
-  Init();
+  Bool_t ret = true; // Assume we have it 
+  for (Int_t i = 0; i < 3; i++) { 
+    if (!fSeenDetectors[i]) continue;
+    if (fNEventsPerDetector[i] <= GetRequiredEvents()) ret = false;
+  }
+  return ret;
+}
+//_____________________________________________________________________
+UShort_t AliFMDBaseDA::GetProgress(Int_t nEvents) const
+{
+  // if (!fAll) 
+  //  return UShort_t((nEvents *100)/ GetRequiredEvents());
+
+  if (nEvents <= 1) return 0;
+
+  Int_t got = 0;
+  Int_t total = 0;
+  for (Int_t i = 0; i < 3; i++) {
+    if (!fSeenDetectors[i]) continue;
+    got   += fNEventsPerDetector[i];
+    total += GetRequiredEvents();
+  }
+  return UShort_t((got * 100.) / total);
+}
 
+//_____________________________________________________________________
+void AliFMDBaseDA::Run(AliRawReader* reader) 
+{
+  //Run the FMD DA
   TFile* diagFile = 0;
-  if(fSaveHistograms)
-    {
-      diagFile = TFile::Open(fDiagnosticsFilename,"RECREATE");
-      for(UShort_t det=1;det<=3;det++) {
-       UShort_t FirstRing = (det == 1 ? 1 : 0);
-       
-       for (UShort_t ir = FirstRing; ir < 2; ir++) {
-         Char_t   ring = (ir == 0 ? 'O' : 'I');
-         UShort_t nsec = (ir == 0 ? 40  : 20);
-         UShort_t nstr = (ir == 0 ? 256 : 512);
-         
-         gDirectory->cd(Form("%s:/",fDiagnosticsFilename));
-         gDirectory->mkdir(Form("FMD%d%c",det,ring),Form("FMD%d%c",det,ring));
-         for(UShort_t sec =0; sec < nsec;  sec++)  {
-           gDirectory->cd(Form("%s:/FMD%d%c",fDiagnosticsFilename,det,ring));
-           gDirectory->mkdir(Form("sector_%d",sec));
-           for(UShort_t strip = 0; strip < nstr; strip++) {
-             gDirectory->cd(Form("%s:/FMD%d%c/sector_%d",fDiagnosticsFilename,det,ring,sec));
-             gDirectory->mkdir(Form("strip_%d",strip));
-             
-            }
-         }
-       }
-      }
-      
-    }
-    
-  reader->Reset();
+  // if (fSaveHistograms)
+  //  diagFile = TFile::Open(fDiagnosticsFilename.Data(),"RECREATE");
   
+  reader->Reset();
+  fRunno = reader->GetRunNumber();
+
+  AliFMDRawReader* fmdReader  = new AliFMDRawReader(reader,0);
+  TClonesArray*    digitArray = new TClonesArray("AliFMDDigit",0);
   
+  Bool_t sodread = kFALSE;
   
-  AliFMDRawReader* fmdReader = new AliFMDRawReader(reader,0);
-  TClonesArray* digitArray   = new TClonesArray("AliFMDDigit",0);
+  for(Int_t i=0;i<3;i++) {
+    if (!reader->NextEvent()) { 
+      // Read Start-of-Run / Start-of-Files event
+      AliWarning(Form("Failed to read the %d%s event",
+                     i+1, (i == 0 ? "st" : (i == 1 ? "nd" : "rd"))));
+      break;
+    }
+    
+    UInt_t eventType = reader->GetType();
+    if(eventType == AliRawEventHeaderBase::kStartOfData || 
+       eventType == AliRawEventHeaderBase::kFormatError) { 
+      
+      WriteConditionsData(fmdReader);
+      Init();
+      sodread = kTRUE;
+      break;
+    }
+  }
   
-  WriteConditionsData();
+  InitContainer(diagFile);
+  if (AliLog::GetDebugLevel("FMD","") >= 3) { 
+    fDetectorArray.ls();
+  }
   
-  reader->NextEvent();
-  reader->NextEvent();
+  if(!sodread) 
+    AliWarning("No SOD event detected!");
   
+  int lastProgress = 0;
   
-  for(Int_t n =1;n <= GetRequiredEvents(); n++)
-    {
-      if(!reader->NextEvent()) 
-       continue;
-      
-      SetCurrentEvent(*(reader->GetEventId()));
-      
-      digitArray->Clear();
-      fmdReader->ReadAdcs(digitArray);
-      
-      
-      //std::cout<<"In event # "<< *(reader->GetEventId()) << " with " <<digitArray->GetEntries()<<" digits     \r"<<std::flush;
-      
-      
-      for(Int_t i = 0; i<digitArray->GetEntries();i++) {
-       AliFMDDigit* digit = static_cast<AliFMDDigit*>(digitArray->At(i));
+  for(Int_t i = 0; i< 3;i++) fNEventsPerDetector[i] = 0;
+
+  for(Int_t n = 1; !HaveEnough(n); n++) {
+    AliInfoF("Get the next event %d", n);
+    if(!reader->NextEvent()) { n--; continue; }
+    UInt_t eventType = reader->GetType();
+    AliInfoF("Event type is %d", eventType);
+    if(eventType != AliRawEventHeaderBase::kPhysicsEvent) { n--; continue; }
+
+    SetCurrentEvent(n);
+    digitArray->Clear();
+    fmdReader->ReadAdcs(digitArray);
+    
+    Bool_t seen[] = { false, false, false };
+    for(Int_t i = 0; i<digitArray->GetEntriesFast();i++) {
+      AliFMDDigit* digit = static_cast<AliFMDDigit*>(digitArray->At(i));
+      UShort_t det = digit->Detector();
+      fSeenDetectors[det-1] = true;
+      seen[det-1]           = true;
+
+      // Only fill if we do not have enough for this detector 
+      if (fNEventsPerDetector[det-1] < GetRequiredEvents()) 
        FillChannels(digit);
-      }
-      
-      FinishEvent();
+    }
+    
+    for(Int_t i = 0; i< 3;i++) 
+      if (seen[i]) (fNEventsPerDetector[i])++;
       
+    FinishEvent();
+    
+    Int_t nReq = GetRequiredEvents();
+    AliInfoF("%9d: %6d/%6d %6d/%6d %6d/%6d", n, 
+            fNEventsPerDetector[0], nReq,
+            fNEventsPerDetector[1], nReq,
+            fNEventsPerDetector[2], nReq);
+
+    int progress = GetProgress(n);
+    if (progress <= lastProgress) continue;
+    lastProgress = progress;
+    std::cout << "Progress: " << lastProgress << " / 100 " << std::endl;
+
+    if (AliLog::GetDebugLevel("FMD","") >= 0) { 
     }
-  AliInfo(Form("Looped over %d events",GetCurrentEvent()));
+    
+  }
+  
+  AliInfoF("Looped over %d events (%d,%d,%d)",GetCurrentEvent(),
+          fNEventsPerDetector[0], 
+          fNEventsPerDetector[1], 
+          fNEventsPerDetector[2]);
   WriteHeaderToFile();
   
   for(UShort_t det=1;det<=3;det++) {
-    UShort_t FirstRing = (det == 1 ? 1 : 0);
-    for (UShort_t ir = FirstRing; ir < 2; ir++) {
+    if (!fSeenDetectors[det-1]) continue;
+    std::cout << "FMD" << det << std::endl;
+    UShort_t firstRing = (det == 1 ? 1 : 0);
+    for (UShort_t ir = firstRing; ir < 2; ir++) {
       Char_t   ring = (ir == 0 ? 'O' : 'I');
       UShort_t nsec = (ir == 0 ? 40  : 20);
       UShort_t nstr = (ir == 0 ? 256 : 512);
+
+      if (fMakeSummaries) MakeSummary(det, ring);
+
+      std::cout << " Ring " << ring << ": " << std::flush;
       for(UShort_t sec =0; sec < nsec;  sec++)  {
        for(UShort_t strip = 0; strip < nstr; strip++) {
          Analyse(det,ring,sec,strip);
-         
        }
+       std::cout << '.' << std::flush;
       }
+      // if(fSaveHistograms)
+      // diagFile->Flush();
+      std::cout << "done" << std::endl;
     }
   }
-
+  
   if(fOutputFile.is_open()) {
-    
     fOutputFile.write("# EOF\n",6);
     fOutputFile.close();
-    
   }
   
+  Terminate(diagFile);
+    
   if(fSaveHistograms ) {
-    AliInfo("Closing diagnostics file...please wait");
+    diagFile = TFile::Open(fDiagnosticsFilename.Data(),"RECREATE");
+    fDetectorArray.Write("FMD", TObject::kSingleKey);
+    fSummaries.Write();
+    AliInfo("Closing diagnostics file - please wait ...");
+    // diagFile->Write();
     diagFile->Close();
+    AliInfo("done");
+    
   }
 }
 //_____________________________________________________________________
 
-void AliFMDBaseDA::InitContainer(){
+void AliFMDBaseDA::InitContainer(TDirectory* diagFile)
+{
+  //Prepare container for diagnostics    
+  TDirectory* savDir   = gDirectory;
 
-  TObjArray* detArray;
-  TObjArray* ringArray;
-  TObjArray* sectorArray;
-    
   for(UShort_t det=1;det<=3;det++) {
-    detArray = new TObjArray();
+    TObjArray* detArray = new TObjArray(det == 1 ? 1 : 2);
     detArray->SetOwner();
+    detArray->SetName(GetDetectorPath(det, false));
     fDetectorArray.AddAtAndExpand(detArray,det);
+
+    TDirectory* detDir = 0;
+    if (diagFile) {
+      diagFile->cd();
+      detDir = diagFile->mkdir(GetDetectorPath(det, kFALSE));
+    }
+
     UShort_t FirstRing = (det == 1 ? 1 : 0);
     for (UShort_t ir = FirstRing; ir < 2; ir++) {
       Char_t   ring = (ir == 0 ? 'O' : 'I');
       UShort_t nsec = (ir == 0 ? 40  : 20);
       UShort_t nstr = (ir == 0 ? 256 : 512);
-      ringArray = new TObjArray();
+      TObjArray* ringArray = new TObjArray(nsec);
       ringArray->SetOwner();
+      ringArray->SetName(GetRingPath(det, ring, false));
       detArray->AddAtAndExpand(ringArray,ir);
+
+
+      TDirectory* ringDir = 0;
+      if (detDir) { 
+       detDir->cd();
+       ringDir = detDir->mkdir(GetRingPath(det,ring, kFALSE));
+      }
+      
+
       for(UShort_t sec =0; sec < nsec;  sec++)  {
-       sectorArray = new TObjArray();
+       TObjArray* sectorArray = new TObjArray(nstr);
        sectorArray->SetOwner();
+       sectorArray->SetName(GetSectorPath(det, ring, sec, false));
        ringArray->AddAtAndExpand(sectorArray,sec);
+
+
+       TDirectory* secDir = 0;
+       if (ringDir) { 
+         ringDir->cd();
+         secDir = ringDir->mkdir(GetSectorPath(det, ring, sec, kFALSE));
+       }
+       
        for(UShort_t strip = 0; strip < nstr; strip++) {
-         AddChannelContainer(sectorArray, det, ring, sec, strip);
+         if (secDir) { 
+           secDir->cd();
+           secDir->mkdir(GetStripPath(det, ring, sec, strip, kFALSE));
+         }
+         TObjArray* stripArray = new TObjArray(0);
+         stripArray->SetOwner(true);
+         stripArray->SetName(GetStripPath(det, ring, sec, strip, false));
+         sectorArray->AddAtAndExpand(stripArray, strip);
+         AddChannelContainer(stripArray, det, ring, sec, strip);
        }
+       AddSectorSummary(sectorArray, det, ring, sec, nstr);
       }
     }
   }
+  savDir->cd();
 }
 
 //_____________________________________________________________________ 
-void AliFMDBaseDA::WriteConditionsData() {
-  
+void AliFMDBaseDA::WriteConditionsData(AliFMDRawReader* fmdReader) 
+{
+  //Write the conditions data to file
   AliFMDParameters* pars       = AliFMDParameters::Instance();
   fConditionsFile.write(Form("# %s \n",pars->GetConditionsShuttleID()),14);
-  fConditionsFile.write("# Sample Rate, timebins \n",25);
-  
-  UInt_t sampleRate = 4;
-  UInt_t timebins   = 544;
-  fConditionsFile     << sampleRate   << ',' 
-                     << timebins     <<"\n";
-  //if(fConditionsFile.is_open()) {
-  //  
-  //  fConditionsFile.write("# EOF\n",6);
-  //  fConditionsFile.close();
+  TDatime now;
+  fConditionsFile << "# This file created from run number " << fRunno 
+                 << " at " << now.AsString() << std::endl;
+  
+  AliFMDCalibSampleRate* sampleRate = new AliFMDCalibSampleRate();
+  AliFMDCalibStripRange* stripRange = new AliFMDCalibStripRange();
+  
+  fmdReader->ReadSODevent(sampleRate,stripRange,fPulseSize,fPulseLength,
+                         fSeenDetectors);
+
+  sampleRate->WriteToFile(fConditionsFile, fSeenDetectors);
+  stripRange->WriteToFile(fConditionsFile, fSeenDetectors);
+
+  // Zero Suppresion
+  
+  // Strip Range
+  
+  fConditionsFile.write("# Gain Events \n",15);
+  
+  for(UShort_t det=1; det<=3;det++) {
+    if (!fSeenDetectors[det-1]) { 
+      continue;
+    }
+    UShort_t firstring = (det == 1 ? 1 : 0);
+    for(UShort_t iring = firstring; iring <=1;iring++) {
+      Char_t ring = (iring == 1 ? 'I' : 'O');
+      for(UShort_t board =0 ; board <=1; board++) {
+       
+       Int_t idx = GetHalfringIndex(det,ring,board);
+       
+       fConditionsFile << det                     << ','
+                       << ring                    << ','
+                       << board                   << ','
+                       << fPulseLength.At(idx)    << "\n";
+       
+      }
+    }
+  }
+  
+  fConditionsFile.write("# Gain Pulse \n",14);
+  
+  for(UShort_t det=1; det<=3;det++) {
+    if (!fSeenDetectors[det-1]) { 
+      continue;
+    }
+    UShort_t firstring = (det == 1 ? 1 : 0);
+    for(UShort_t iring = firstring; iring <=1;iring++) {
+      Char_t ring = (iring == 1 ? 'I' : 'O');
+      for(UShort_t board =0 ; board <=1; board++) {
+       
+       Int_t idx = GetHalfringIndex(det,ring,board);
+       
+       fConditionsFile << det                     << ','
+                       << ring                    << ','
+                       << board                   << ','
+                       << fPulseSize.At(idx)      << "\n";
+       
+      }
+    }
+  }
+  // sampleRate->WriteToFile(std::cout, fSeenDetectors);
+  // stripRange->WriteToFile(std::cout, fSeenDetectors);
+
+  if(fConditionsFile.is_open()) {
+    
+    fConditionsFile.write("# EOF\n",6);
+    fConditionsFile.close();
+    
+  }
+  
+}
+//_____________________________________________________________________ 
+Int_t AliFMDBaseDA::GetHalfringIndex(UShort_t det, Char_t ring, 
+                                    UShort_t board) const 
+{
+  // Get the index corresponding to a half-ring 
+  // 
+  // Parameters: 
+  //   det    Detector number 
+  //   ring   Ring identifier 
+  //   board  Board number 
+  //
+  // Return 
+  //   Internal index of the board 
+  UShort_t iring  =  (ring == 'I' ? 1 : 0);
+  
+  Int_t index = (((det-1) << 2) | (iring << 1) | (board << 0));
+  
+  return index-2;
+  
+}
+//_____________________________________________________________________ 
+void AliFMDBaseDA::Rotate(const char* base, int max) const
+{
+  // 
+  // Rotate a set of files.   base is the basic name of the files.
+  // If the file base.max exists it is removed. 
+  // If the file base.n exists (where n < max) it is renamed to
+  // base.(n-1).  
+  // If the file base exists, it is renamed to base.1 
+  //
+  // Parameters:
+  //   base Base name of the files
+  //   max  Maximum number to keep (minus one for the current).
+
+  // Note:  TSystem::AccessPathName returns false if the condition is
+  // fulfilled! 
+
+  // Check if we have base.max, and if so, remove it. 
+  TString testName(Form("%s.%d", base, max));
+  if (!gSystem->AccessPathName(testName.Data())) 
+    gSystem->Unlink(testName.Data());
     
-  //}
+  // Loop down from max-1 to 1 and move files 
+  for (int i = max-1; i >= 1; i--) { 
+    testName = Form("%s.%d", base, i);
+    if (!gSystem->AccessPathName(testName.Data())) {
+      TString newName(Form("%s.%d", base, i+1));
+      gSystem->Rename(testName.Data(), newName.Data());
+    }
+  }
+
+  // If we have the file base, rename it to base.1 
+  testName = Form("%s", base);
+  if (!gSystem->AccessPathName(testName.Data())){
+    TString newName(Form("%s.%d", base, 1));
+    gSystem->Rename(testName.Data(), newName.Data());
+  }
+}
+
+//_____________________________________________________________________ 
+TH2*
+AliFMDBaseDA::MakeSummaryHistogram(const char* prefix, const char* title, 
+                                  UShort_t d, Char_t r) 
+{
+  // 
+  // Utility function for defining summary histograms 
+  // 
+  // Parameters:
+  //    det    Detector 
+  //    ring   Ring identifier 
+  //    prefix Histogram prefix 
+  //    title  Histogram title 
+  //
+  Int_t nX = ((d == 1 || r == 'I' || r == 'i') ?  20 :  40);
+  Int_t nY = ((d == 1 || r == 'I' || r == 'i') ? 512 : 256);
   
+  TH2* ret = new TH2F(Form("%sFMD%d%c", prefix, d, r), 
+                     Form("%s for FMD%d%c", title, d, r), 
+                     nX, -0.5, nX-0.5, nY, -0.5, nY-0.5);
+  ret->SetXTitle("Sector #");
+  ret->SetYTitle("Strip #");
+  ret->SetDirectory(0);
+  // if (!fSummaries) fSummaries = new TObjArray;
+  fSummaries.Add(ret);
+  return ret;
+}
+
+//_____________________________________________________________________ 
+TObjArray*
+AliFMDBaseDA::GetDetectorArray(UShort_t det)
+{
+  if (det < 1 || det > 3) { 
+    AliErrorF("Detector index %d out of bounds", det);
+    return 0;
+  }
+  return static_cast<TObjArray*>(fDetectorArray.At(det));
+}
+//_____________________________________________________________________ 
+TObjArray*
+AliFMDBaseDA::GetRingArray(UShort_t det, Char_t ring)
+{
+  Int_t idx = (ring == 'O' || ring == 'o' ? 0 : 1);
+  TObjArray* array = GetDetectorArray(det);
+  if (!array) return 0;
+  array = static_cast<TObjArray*>(array->At(idx));
+  if (!array) AliErrorF("No ring array for FMD%d%c (%d)", det, ring, idx);
+  return array;
+}
+//_____________________________________________________________________ 
+TObjArray*
+AliFMDBaseDA::GetSectorArray(UShort_t det, Char_t ring, UShort_t sector)
+{
+  TObjArray* array = GetRingArray(det,ring);
+  if (!array) return 0;
+  array = static_cast<TObjArray*>(array->At(sector));
+  if (!array) AliErrorF("No sector array for FMD%d%c[%02d]", det, ring, sector);
+  return array;
+}
+//_____________________________________________________________________ 
+TObjArray*
+AliFMDBaseDA::GetStripArray(UShort_t det, Char_t ring, 
+                           UShort_t sector, UShort_t strip)
+{
+  TObjArray* array = GetSectorArray(det,ring,sector);
+  if (!array) return 0;
+  array = static_cast<TObjArray*>(array->At(strip));
+  if (!array) AliErrorF("No strip array for FMD%d%c[%02d,%03d]", 
+                       det, ring, sector, strip);
+  return array;
 }
 
+//=====================================================================
+AliFMDBaseDA::Runner::Runner()
+  : fReader(0),
+    fDiagFile(""), 
+    fDiag(false),
+    fAll(false)
+{}
+
+//_____________________________________________________________________ 
+void
+AliFMDBaseDA::Runner::AddHandlers()
+{
+  gROOT->GetPluginManager()->AddHandler("TVirtualStreamerInfo",
+                                       "*",
+                                       "TStreamerInfo",
+                                       "RIO",
+                                       "TStreamerInfo()");
+  gROOT->GetPluginManager()->AddHandler("ROOT::Math::Minimizer", "Minuit", 
+                                       "TMinuitMinimizer",
+                                       "Minuit", 
+                                       "TMinuitMinimizer(const char *)");
+  gROOT->GetPluginManager()->AddHandler("ROOT::Math::Minimizer", 
+                                       "GSLMultiMin", 
+                                       "ROOT::Math::GSLMinimizer",
+                                       "MathMore", 
+                                       "GSLMinimizer(const char *)");
+  gROOT->GetPluginManager()->AddHandler("ROOT::Math::Minimizer", 
+                                       "GSLMultiFit", 
+                                       "ROOT::Math::GSLNLSMinimizer",
+                                       "MathMore", "GSLNLSMinimizer(int)");
+  gROOT->GetPluginManager()->AddHandler("ROOT::Math::Minimizer", 
+                                       "GSLSimAn", 
+                                       "ROOT::Math::GSLSimAnMinimizer",
+                                       "MathMore", 
+                                       "GSLSimAnMinimizer(int)");
+  gROOT->GetPluginManager()->AddHandler("ROOT::Math::Minimizer", 
+                                       "Linear", 
+                                       "TLinearMinimizer",
+                                       "Minuit", 
+                                       "TLinearMinimizer(const char *)");
+  gROOT->GetPluginManager()->AddHandler("ROOT::Math::Minimizer", 
+                                       "Fumili", 
+                                       "TFumiliMinimizer",
+                                       "Fumili", 
+                                       "TFumiliMinimizer(int)");
+}
+//_____________________________________________________________________ 
+void
+AliFMDBaseDA::Runner::ShowUsage(std::ostream& o, const char* progname)
+{
+  o << "Usage: " << progname << " SOURCE [OPTIONS]\n\n"
+    << "Options:\n"
+    << "   -h,--help                Show this help\n"
+    << "   -d,--diagnostics[=FILE]  Write diagnostics to file\n"
+    << "   -D,--debug=LEVEL         Set the debug level\n"
+    << "   -A,--all                 Try to get data from all detectors\n\n"
+    << "SOURCE is one of\n"
+    << " * FILE.raw                Raw data file\n"
+    << " * FILE.root               ROOT'ified raw data file\n"
+    << " * collection://FILE.root  Event list in a ROOT file\n"
+    << " * collection://FILE       File containing list of ROOT files\n"
+    << " * ^FMD                    Monitor source\n"
+    << "There are other options too.  Check the AliRawReader docs\n"
+    << std::endl;
+}
+//_____________________________________________________________________ 
+namespace {
+  Bool_t ExtractValue(const TString& arg, TString& val)
+  {
+    val = "";
+    Int_t eq = arg.Index("=");
+    if (eq == kNPOS) return false;
+    
+    val = arg(eq+1, arg.Length()-eq-1);
+    return true;
+  }
+}
+      
+//_____________________________________________________________________ 
+Int_t
+AliFMDBaseDA::Runner::Init(int argc, char** argv)
+{
+  AddHandlers();
+
+  // --- Process the command line ------------------------------------
+  TString source;
+  Int_t   debugLevel  = 0;
+  Bool_t  help        = false;
+
+  for (int i = 1; i < argc; i++) { 
+    TString arg(argv[i]);
+    Bool_t  badOption   = false;
+    
+    if (arg[0] == '-') { // It's an option 
+      if (arg[1] == '-') { // It's a long option 
+       TString val;
+       if      (arg.EqualTo("--help"))     help = true; 
+       else if (arg.BeginsWith("--debug")) {
+         if (ExtractValue(arg, val))
+           debugLevel = val.Atoi();
+       }
+       else if (arg.BeginsWith("--diagnostics")) { 
+         fDiag = true;
+         if (ExtractValue(arg, val)) 
+           fDiagFile = val;
+       }
+       else if (arg.EqualTo("--all"))  fAll = true;
+       else badOption = true;
+      }
+      else { // Short option 
+       TString next(i < argc-1 ? argv[i+1] : "");
+       switch (arg[1]) { 
+       case 'h': help = true; break;
+       case 'd': fDiag = true; 
+         if (!next.IsNull() && next[0] != '-') {
+           fDiagFile = next;
+           i++;
+         }
+         break;
+       case 'D': 
+         if (!next.IsNull() && next[0] != '-') {
+           debugLevel = next.Atoi();
+           i++;
+         }
+         break;
+       case 'A': fAll = true ; break ;
+       default: badOption = true;
+       }
+      } // End of options
+      if (badOption) { 
+       std::cerr << argv[0] << ": Unknown option " << argv[i] 
+                 << std::endl;
+       return -1;
+      }
+    }
+    else { // source or compatibility debug level 
+      if (source.IsNull()) source = arg;
+      else                 debugLevel = arg.Atoi();
+    }
+  }
+  
+  // --- Check if help was requested ---------------------------------
+  if (help) { 
+    ShowUsage(std::cout, argv[0]);
+    return 1;
+  }
+
+  // --- Check if we have a source -----------------------------------
+  if (source.IsNull()) { 
+    std::cerr << "No source given" << std::endl;
+    return -2;
+  }
+
+  // --- Initialize various things -----------------------------------
+  AliFMDParameters::Instance()->Init(kFALSE,0);
+
+  //This will only work for FDR 1 data. When newer data becomes
+  //available the ! must be removed!
+  Bool_t old = kTRUE;
+  AliFMDParameters::Instance()->UseCompleteHeader(old);
+  
+  AliLog::EnableDebug(debugLevel > 0);
+  AliLog::SetModuleDebugLevel("FMD", debugLevel);
+
+  // --- Make our reader ---------------------------------------------
+  fReader = AliRawReader::Create(source);
+  if (!fReader) { 
+    std::cerr << "Failed to make raw reader for source \"" << source 
+             << "\"" << std::endl;
+    return -3;
+  }
+  return 0;
+}
+
+//_____________________________________________________________________ 
+Int_t
+AliFMDBaseDA::Runner::RunNumber() const
+{ 
+  if (!fReader) return -1;
+  return fReader->GetRunNumber(); 
+}
+
+//_____________________________________________________________________ 
+void
+AliFMDBaseDA::Runner::Exec(AliFMDBaseDA& da)
+{
+  TStopwatch timer;
+  timer.Start();
+
+  da.SetSaveDiagnostics(fDiag || !fDiagFile.IsNull());
+  da.SetTryAll(fAll);
+  if (!fDiagFile.IsNull()) da.SetDiagnosticsFilename(fDiagFile);
+
+  da.Run(fReader);
+
+  timer.Stop();
+  timer.Print();
+
+#ifdef ALI_AMORE
+  try { 
+    amore::da::AmoreDA myAmore(amore::da::AmoreDA::kSender);
+
+    for (UShort_t det = 1; det <= 3; det++) {
+      if (!da.HasSeenDetector(det)) continue;
+      TObject* runNo = new TObject;
+      runNo->SetUniqueID(fReader->GetRunNumber());
+      myAmore.Send(Form("gainRunNoFMD%d", det), runNo);
+    }
+    
+    TIter     next(&da.GetSummaries());
+    TObject*  obj = 0;
+    while ((obj = next())) 
+      myAmore.Send(obj->GetName(), obj);
+    
+  }
+  catch (exception& e) {
+    cerr << "Failed to make AMORE instance: " << e.what() << endl;
+  }
+                              
+#endif
+}
+
+
+  
+  
+  
+//_____________________________________________________________________ 
+
 //_____________________________________________________________________ 
 //
 // EOF