Some changes to make it possible to run the DA's
[u/mrichter/AliRoot.git] / FMD / AliFMDInput.cxx
index a819d92..49a60a4 100644 (file)
 #include "AliRawReaderFile.h"   // ALIRAWREADERFILE_H
 #include "AliRawReaderRoot.h"   // ALIRAWREADERROOT_H
 #include "AliRawReaderDate.h"   // ALIRAWREADERDATE_H
+#include "AliRawEventHeaderBase.h" 
 #include "AliFMD.h"             // ALIFMD_H
 #include "AliFMDHit.h"         // ALIFMDHIT_H
 #include "AliFMDDigit.h"       // ALIFMDDigit_H
 #include "AliFMDSDigit.h"      // ALIFMDDigit_H
 #include "AliFMDRecPoint.h"    // ALIFMDRECPOINT_H
 #include "AliFMDRawReader.h"    // ALIFMDRAWREADER_H
+#include "AliFMDGeometry.h"
 #include <AliESD.h>
 #include <AliESDFMD.h>
 #include <AliESDEvent.h>
@@ -69,6 +71,19 @@ ClassImp(AliFMDInput)
   ; // This is here to keep Emacs for indenting the next line
 #endif
 
+//____________________________________________________________________
+const AliFMDInput::ETrees AliFMDInput::fgkAllLoads[] = { kHits,       
+                                                        kKinematics,
+                                                        kDigits,    
+                                                        kSDigits,   
+                                                        kHeader,    
+                                                        kRecPoints, 
+                                                        kESD,       
+                                                        kRaw,       
+                                                        kGeometry,  
+                                                        kTrackRefs, 
+                                                        kRawCalib,  
+                                                        kUser };
 
 //____________________________________________________________________
 AliFMDInput::AliFMDInput()
@@ -93,6 +108,7 @@ AliFMDInput::AliFMDInput()
     fChainE(0),
     fArrayE(0),
     fArrayH(0),
+    fArrayTR(0), 
     fArrayD(0),
     fArrayS(0), 
     fArrayR(0), 
@@ -101,8 +117,10 @@ AliFMDInput::AliFMDInput()
     fGeoManager(0),
     fTreeMask(0), 
     fRawFile(""),
+    fInputDir("."),
     fIsInit(kFALSE),
-    fEventCount(0)
+    fEventCount(0), 
+    fNEvents(-1)
 {
 
   // Constructor of an FMD input object.  Specify what data to read in
@@ -136,6 +154,7 @@ AliFMDInput::AliFMDInput(const char* gAliceFile)
     fChainE(0),
     fArrayE(0),
     fArrayH(0),
+    fArrayTR(0), 
     fArrayD(0),
     fArrayS(0), 
     fArrayR(0), 
@@ -144,8 +163,10 @@ AliFMDInput::AliFMDInput(const char* gAliceFile)
     fGeoManager(0),
     fTreeMask(0), 
     fRawFile(""),
+    fInputDir("."),
     fIsInit(kFALSE),
-    fEventCount(0)
+    fEventCount(0),
+    fNEvents(-1)
 {
   
   // Constructor of an FMD input object.  Specify what data to read in
@@ -155,11 +176,120 @@ AliFMDInput::AliFMDInput(const char* gAliceFile)
 }
 
 //____________________________________________________________________
+void
+AliFMDInput::SetLoads(UInt_t mask)
+{
+  for (UInt_t i = 0; i < sizeof(mask); i++) { 
+    if (!(mask & (1 << i))) continue;
+    const ETrees *ptype = fgkAllLoads;
+    do { 
+      ETrees type = *ptype;
+      if (i != UInt_t(type)) continue;
+      AddLoad(type);
+      break;
+    } while (*ptype++ != kUser);
+  }
+}
+     
+//____________________________________________________________________
+void
+AliFMDInput::SetLoads(const char* what) 
+{
+  TString    l(what);
+  TObjArray* ll = l.Tokenize(", ");
+  TIter      next(ll);
+  TObject*   os = 0;
+  while ((os = next())) { 
+    ETrees type = ParseLoad(os->GetName());
+    AddLoad(type);
+  }
+  delete ll;
+}
+    
+
+//____________________________________________________________________
+AliFMDInput::ETrees
+AliFMDInput::ParseLoad(const char* what)
+{
+  TString opt(what);
+  opt.ToLower();
+  const ETrees* ptype = fgkAllLoads;
+  do { 
+    ETrees  type = *ptype;
+    if (opt.Contains(TreeName(type,true), TString::kIgnoreCase)) 
+      return type;
+  } while (*ptype++ != kUser);
+  return kUser;
+}
+//____________________________________________________________________
+const char*
+AliFMDInput::LoadedString(Bool_t dataOnly) const
+{
+  static TString ret;
+  if (!ret.IsNull()) return ret.Data();
+
+  const ETrees* ptype = fgkAllLoads;
+  do { 
+    ETrees type = *ptype;
+    if (dataOnly && 
+       (type == kKinematics || 
+        type == kHeader     || 
+        type == kGeometry   || 
+        type == kTrackRefs)) continue;
+    if (!IsLoaded(*ptype)) continue;
+    
+    if (!ret.IsNull()) ret.Append(",");
+    ret.Append(TreeName(type));
+  } while (*ptype++ != kUser);
+  return ret.Data();
+}
+
+//____________________________________________________________________
+const char* 
+AliFMDInput::TreeName(ETrees tree, Bool_t shortest) 
+{
+  if (shortest) {
+    switch (tree) {
+    case kHits:                return "hit";        
+    case kKinematics:  return "kin";
+    case kDigits:      return "dig";     
+    case kSDigits:     return "sdig";    
+    case kHeader:      return "hea";     
+    case kRecPoints:   return "recp";  
+    case kESD:         return "esd";        
+    case kRaw:         return "raw";        
+    case kGeometry:    return "geo";   
+    case kTrackRefs:   return "trackr";  
+    case kRawCalib:    return "rawc";   
+    case kUser:                return "user"; 
+    }
+    return 0;
+  }
+  switch (tree) {
+  case kHits:          return "Hits";        
+  case kKinematics:    return "Kinematics"; 
+  case kDigits:                return "Digits";     
+  case kSDigits:       return "SDigits";    
+  case kHeader:                return "Header";     
+  case kRecPoints:     return "RecPoints";  
+  case kESD:           return "ESD";        
+  case kRaw:           return "Raw";        
+  case kGeometry:      return "Geometry";   
+  case kTrackRefs:     return "TrackRefs";  
+  case kRawCalib:      return "RawCalib";   
+  case kUser:          return "User"; 
+  }
+  return 0;
+}
+
+//____________________________________________________________________
 Int_t
 AliFMDInput::NEvents() const 
 {
   // Get number of events
-  if (TESTBIT(fTreeMask, kRaw)) return fReader->GetNumberOfEvents();
+  if (IsLoaded(kRaw) || 
+      IsLoaded(kRawCalib)) return fReader->GetNumberOfEvents();
+  if (fChainE) return fChainE->GetEntriesFast();
   if (fTreeE) return fTreeE->GetEntries();
   return -1;
 }
@@ -175,63 +305,68 @@ AliFMDInput::Init()
     AliWarning("Already initialized");
     return fIsInit;
   }
-  // Get the run 
-  if (!TESTBIT(fTreeMask, kRaw) && 
-      !TESTBIT(fTreeMask, kESD)) { 
-    if (fGAliceFile.IsNull()) fGAliceFile = "galice.root";
-    // Get the loader
-    fLoader = AliRunLoader::Open(fGAliceFile.Data(), "Alice", "read");
-    if (!fLoader) {
-      AliError(Form("Coulnd't read the file %s", fGAliceFile.Data()));
-      return kFALSE;
-    }
-  
-    if  (fLoader->LoadgAlice()) return kFALSE;
-    fRun = fLoader->GetAliRun();
+  TString what;
+  const ETrees* ptype = fgkAllLoads;
+  do { 
+    ETrees type = *ptype;
+    what.Append(Form("\n\t%-20s: %s", TreeName(type), 
+                    IsLoaded(type) ? "yes" : "no"));
+  } while (*ptype++ != kUser);
   
-    // Get the FMD 
-    fFMD = static_cast<AliFMD*>(fRun->GetDetector("FMD"));
-    if (!fFMD) {
-      AliError("Failed to get detector FMD from loader");
-      return kFALSE;
-    }
-  
-    // Get the FMD loader
-    fFMDLoader = fLoader->GetLoader("FMDLoader");
-    if (!fFMDLoader) {
-      AliError("Failed to get detector FMD loader from loader");
-      return kFALSE;
+  Info("Init","Initialising w/mask 0x%04x%s", fTreeMask, what.Data());
+  // Get the run 
+  if (IsLoaded(kDigits)     ||
+      IsLoaded(kSDigits)    || 
+      IsLoaded(kKinematics) || 
+      IsLoaded(kTrackRefs)  || 
+      IsLoaded(kHeader)) {
+    if (!gSystem->FindFile(".:/", fGAliceFile)) {
+      AliWarning(Form("Cannot find file %s in .:/", fGAliceFile.Data()));
     }
-    if (fLoader->LoadHeader()) { 
-      AliError("Failed to get event header information from loader");
-      return kFALSE;
+    else {
+      fLoader = AliRunLoader::Open(fGAliceFile.Data(), "Alice", "read");
+      if (!fLoader) {
+       AliError(Form("Coulnd't read the file %s", fGAliceFile.Data()));
+       return kFALSE;
+      }
+      AliInfo(Form("Opened GAlice file %s", fGAliceFile.Data()));
+
+      if  (fLoader->LoadgAlice()) return kFALSE;
+      
+      fRun = fLoader->GetAliRun();
+      
+      // Get the FMD 
+      fFMD = static_cast<AliFMD*>(fRun->GetDetector("FMD"));
+      if (!fFMD) {
+       AliError("Failed to get detector FMD from loader");
+       return kFALSE;
+      }
+      
+      // Get the FMD loader
+      fFMDLoader = fLoader->GetLoader("FMDLoader");
+      if (!fFMDLoader) {
+       AliError("Failed to get detector FMD loader from loader");
+       return kFALSE;
+      }
+      if (fLoader->LoadHeader()) { 
+       AliError("Failed to get event header information from loader");
+       return kFALSE;
+      }
+      fTreeE = fLoader->TreeE();
     }
-    fTreeE = fLoader->TreeE();
   }
 
   // Optionally, get the ESD files
-  if (TESTBIT(fTreeMask, kESD)) {
-    fChainE = new TChain("esdTree");
-    TSystemDirectory dir(".",".");
-    TList*           files = dir.GetListOfFiles();
-    TSystemFile*     file = 0;
-    if (!files) {
-      AliError("No files");
-      return kFALSE;
-    }
-    files->Sort();
-    TIter            next(files);
-    while ((file = static_cast<TSystemFile*>(next()))) {
-      TString fname(file->GetName());
-      if (fname.Contains("AliESDs")) fChainE->AddFile(fname.Data());
-    }
+  if (IsLoaded(kESD)) {
+    fChainE = MakeChain("ESD", fInputDir, true);
     fESDEvent = new AliESDEvent();
     fESDEvent->ReadFromTree(fChainE);
     //    fChainE->SetBranchAddress("ESD", &fMainESD);
     
   }
     
-  if (TESTBIT(fTreeMask, kRaw)) {
+  if (IsLoaded(kRaw) || 
+      IsLoaded(kRawCalib)) {
     AliInfo("Getting FMD raw data digits");
     fArrayA = new TClonesArray("AliFMDDigit");
 #if 0
@@ -251,24 +386,22 @@ AliFMDInput::Init()
   }
   
   // Optionally, get the geometry 
-  if (TESTBIT(fTreeMask, kGeometry)) {
+  if (IsLoaded(kGeometry)) {
+    TString fname;
     if (fRun) {
-      TString fname(fRun->GetGeometryFileName());
-      if (fname.IsNull()) {
-       Warning("Init", "No file name for the geometry from AliRun");
-       fname = gSystem->DirName(fGAliceFile);
-       fname.Append("/geometry.root");
-      }
-      fGeoManager = TGeoManager::Import(fname.Data());
-      if (!fGeoManager) {
-       Fatal("Init", "No geometry manager found");
-       return kFALSE;
-      }
-    }
-    else { 
-      AliGeomManager::LoadGeometry();
+      fname = gSystem->DirName(fGAliceFile);
+      fname.Append("/geometry.root");
     }
+    if (!gSystem->AccessPathName(fname.Data())) 
+      fname = "";
     AliCDBManager* cdb   = AliCDBManager::Instance();
+    if (!cdb->IsDefaultStorageSet()) {
+      cdb->SetDefaultStorage("local://$ALICE_ROOT/OCDB");
+      cdb->SetRun(0);
+    }
+
+    AliGeomManager::LoadGeometry(fname.IsNull() ? 0 : fname.Data());
+
     AliCDBEntry*   align = cdb->Get("FMD/Align/Data");
     if (align) {
       AliInfo("Got alignment data from CDB");
@@ -287,6 +420,9 @@ AliFMDInput::Init()
        }
       }
     }
+    AliFMDGeometry* geom = AliFMDGeometry::Instance();
+    geom->Init();
+    geom->InitTransformations();
   }
 
   fEventCount = 0;
@@ -311,17 +447,16 @@ AliFMDInput::Begin(Int_t event)
 
   // Get the event 
   if (fLoader && fLoader->GetEvent(event)) return kFALSE;
-  AliInfo(Form("Now in event %8d/%8d", event, NEvents()));
 
   // Possibly load global kinematics information 
-  if (TESTBIT(fTreeMask, kKinematics) || TESTBIT(fTreeMask, kTracks)) {
+  if (IsLoaded(kKinematics)) {
     // AliInfo("Getting kinematics");
     if (fLoader->LoadKinematics("READ")) return kFALSE;
     fStack = fLoader->Stack();
   }
 
   // Possibly load FMD Hit information 
-  if (TESTBIT(fTreeMask, kHits) || TESTBIT(fTreeMask, kTracks)) {
+  if (IsLoaded(kHits)) {
     // AliInfo("Getting FMD hits");
     if (!fFMDLoader || fFMDLoader->LoadHits("READ")) return kFALSE;
     fTreeH = fFMDLoader->TreeH();
@@ -329,7 +464,7 @@ AliFMDInput::Begin(Int_t event)
   }
   
   // Possibly load FMD TrackReference information 
-  if (TESTBIT(fTreeMask, kTrackRefs) || TESTBIT(fTreeMask, kTracks)) {
+  if (IsLoaded(kTrackRefs)) {
     // AliInfo("Getting FMD hits");
     if (!fLoader || fLoader->LoadTrackRefs("READ")) return kFALSE;
     fTreeTR = fLoader->TreeTR();
@@ -338,14 +473,14 @@ AliFMDInput::Begin(Int_t event)
   }
   
   // Possibly load heaedr information 
-  if (TESTBIT(fTreeMask, kHeader)) {
+  if (IsLoaded(kHeader)) {
     // AliInfo("Getting FMD hits");
     if (!fLoader /* || fLoader->LoadHeader()*/) return kFALSE;
     fHeader = fLoader->GetHeader();
   }
 
   // Possibly load FMD Digit information 
-  if (TESTBIT(fTreeMask, kDigits)) {
+  if (IsLoaded(kDigits)) {
     // AliInfo("Getting FMD digits");
     if (!fFMDLoader || fFMDLoader->LoadDigits("READ")) return kFALSE;
     fTreeD = fFMDLoader->TreeD();
@@ -359,15 +494,18 @@ AliFMDInput::Begin(Int_t event)
   }
 
   // Possibly load FMD Sdigit information 
-  if (TESTBIT(fTreeMask, kSDigits)) {
+  if (IsLoaded(kSDigits)) {
     // AliInfo("Getting FMD summable digits");
-    if (!fFMDLoader || fFMDLoader->LoadSDigits("READ")) return kFALSE;
+    if (!fFMDLoader || fFMDLoader->LoadSDigits("READ")) { 
+      AliWarning("Failed to load SDigits!");
+      return kFALSE;
+    }
     fTreeS = fFMDLoader->TreeS();
     if (!fArrayS) fArrayS = fFMD->SDigits();
   }
 
   // Possibly load FMD RecPoints information 
-  if (TESTBIT(fTreeMask, kRecPoints)) {
+  if (IsLoaded(kRecPoints)) {
     // AliInfo("Getting FMD reconstructed points");
     if (!fFMDLoader || fFMDLoader->LoadRecPoints("READ")) return kFALSE;
     fTreeR = fFMDLoader->TreeR();
@@ -376,30 +514,33 @@ AliFMDInput::Begin(Int_t event)
   }  
 
   // Possibly load FMD ESD information 
-  if (TESTBIT(fTreeMask, kESD)) {
+  if (IsLoaded(kESD)) {
     // AliInfo("Getting FMD event summary data");
     Int_t read = fChainE->GetEntry(event);
     if (read <= 0) return kFALSE;
     fESD = fESDEvent->GetFMDData();
     if (!fESD) return kFALSE;
-#if 0
-    TFile* f = fChainE->GetFile();
-    if (f) {
-      TObject* o = f->GetStreamerInfoList()->FindObject("AliFMDMap");
-      if (o) {
-       TStreamerInfo* info = static_cast<TStreamerInfo*>(o);
-       std::cout << "AliFMDMap class version read is " 
-                 <<  info->GetClassVersion() << std::endl;
-      }
-    }
-    // fESD->CheckNeedUShort(fChainE->GetFile());
-#endif
   }
 
   // Possibly load FMD Digit information 
-  if (TESTBIT(fTreeMask, kRaw)) {
+  if (IsLoaded(kRaw) || IsLoaded(kRawCalib)) {
+    Bool_t mon = fRawFile.Contains("mem://");
     // AliInfo("Getting FMD raw data digits");
-    if (!fReader->NextEvent()) return kFALSE;
+    if (mon) std::cout << "Waiting for event ..." << std::flush;
+    do { 
+      if (!fReader->NextEvent()) { 
+       if (mon) { 
+         gSystem->Sleep(3);
+         continue;
+       }
+       return kFALSE;
+      }
+      UInt_t eventType = fReader->GetType();
+      if(eventType == AliRawEventHeaderBase::kPhysicsEvent ||
+        eventType == AliRawEventHeaderBase::kCalibrationEvent) 
+       break;
+    } while (true);
+    if (mon) std::cout << "got it" << std::endl;
     // AliFMDRawReader r(fReader, 0);
     fArrayA->Clear();
     fFMDReader->ReadAdcs(fArrayA);
@@ -422,22 +563,18 @@ AliFMDInput::Event()
   //   -  ProcessRecPoints  if the reconstructed points are loaded. 
   //   -  ProcessESD        if the event summary data is loaded
   // 
-  if (TESTBIT(fTreeMask, kHits)) 
-    if (!ProcessHits()) return kFALSE; 
-  if (TESTBIT(fTreeMask, kTrackRefs)) 
-    if (!ProcessTrackRefs()) return kFALSE; 
-  if (TESTBIT(fTreeMask, kTracks)) 
-    if (!ProcessTracks()) return kFALSE; 
-  if (TESTBIT(fTreeMask, kDigits)) 
-    if (!ProcessDigits()) return kFALSE;
-  if (TESTBIT(fTreeMask, kSDigits)) 
-    if (!ProcessSDigits()) return kFALSE;
-  if (TESTBIT(fTreeMask, kRaw)) 
-    if (!ProcessRawDigits()) return kFALSE;
-  if (TESTBIT(fTreeMask, kRecPoints)) 
-    if (!ProcessRecPoints()) return kFALSE;
-  if (TESTBIT(fTreeMask, kESD))
-    if (!ProcessESDs()) return kFALSE;
+  if (IsLoaded(kHits))     if (!ProcessHits())      return kFALSE; 
+  if (IsLoaded(kTrackRefs))if (!ProcessTrackRefs()) return kFALSE; 
+  if (IsLoaded(kKinematics) && 
+      IsLoaded(kHits))     if (!ProcessTracks())    return kFALSE; 
+  if (IsLoaded(kKinematics))if (!ProcessStack())     return kFALSE; 
+  if (IsLoaded(kSDigits))  if (!ProcessSDigits())   return kFALSE;
+  if (IsLoaded(kDigits))   if (!ProcessDigits())    return kFALSE;
+  if (IsLoaded(kRaw))      if (!ProcessRawDigits()) return kFALSE;
+  if (IsLoaded(kRawCalib)) if (!ProcessRawCalibDigits())return kFALSE;
+  if (IsLoaded(kRecPoints))if (!ProcessRecPoints()) return kFALSE;
+  if (IsLoaded(kESD))      if (!ProcessESDs())      return kFALSE;
+  if (IsLoaded(kUser))     if (!ProcessUsers())     return kFALSE;
   
   return kTRUE;
 }
@@ -470,7 +607,7 @@ AliFMDInput::ProcessHits()
       if (!hit) continue;
 
       TParticle* track = 0;
-      if (TESTBIT(fTreeMask, kKinematics) && fStack) {
+      if (IsLoaded(kKinematics) && fStack) {
        Int_t trackno = hit->Track();
        track = fStack->Particle(trackno);
       }
@@ -500,11 +637,12 @@ AliFMDInput::ProcessTrackRefs()
     if (trRead <= 0) continue;
     Int_t nTrackRefs = fArrayTR->GetEntries();
     for (Int_t j = 0; j < nTrackRefs; j++) {
-      AliTrackReference* trackRef = static_cast<AliTrackReference*>(fArrayTR->At(j));
+      AliTrackReference* trackRef = 
+       static_cast<AliTrackReference*>(fArrayTR->At(j));
       if (!trackRef) continue;
-      if (trackRef->DetectorId() != AliTrackReference::kFMD) continue;
+      // if (trackRef->DetectorId() != AliTrackReference::kFMD) continue;
       TParticle* track = 0;
-      if (TESTBIT(fTreeMask, kKinematics) && fStack) {
+      if (IsLoaded(kKinematics) && fStack) {
        Int_t trackno = trackRef->GetTrack();
        track = fStack->Particle(trackno);
       }
@@ -556,7 +694,26 @@ AliFMDInput::ProcessTracks()
   }
   return kTRUE;
 }
+//____________________________________________________________________
+Bool_t 
+AliFMDInput::ProcessStack()
+{
+  // Read the hit tree, and pass each hit to the member function
+  // ProcessTrack.
+  if (!fStack) {
+    AliError("No track tree defined");
+    return kFALSE;
+  }
+  Int_t nTracks = fStack->GetNtrack();
+  for (Int_t i = 0; i < nTracks; i++) {
+    Int_t      trackno = nTracks - i - 1;
+    TParticle* track   = fStack->Particle(trackno);
+    if (!track) continue;
 
+    if (!ProcessParticle(trackno, track)) return kFALSE;
+  }
+  return kTRUE;
+}
 //____________________________________________________________________
 Bool_t 
 AliFMDInput::ProcessDigits()
@@ -606,9 +763,13 @@ AliFMDInput::ProcessSDigits()
   Int_t nEv = fTreeS->GetEntries();
   for (Int_t i = 0; i < nEv; i++) {
     Int_t sdigitRead  = fTreeS->GetEntry(i);
-    if (sdigitRead <= 0) continue;
-    Int_t nSdigit = fArrayS->GetEntries();
+    if (sdigitRead <= 0) { 
+      AliInfo(Form("Read nothing from tree"));
+      continue;
+    }
+    Int_t nSdigit = fArrayS->GetEntriesFast();
     AliFMDDebug(0, ("Got %5d digits for this event", nSdigit));
+    AliInfo(Form("Got %5d digits for this event", nSdigit));
     if (nSdigit <= 0) continue;
     for (Int_t j = 0; j < nSdigit; j++) {
       AliFMDSDigit* sdigit = static_cast<AliFMDSDigit*>(fArrayS->At(j));
@@ -644,6 +805,29 @@ AliFMDInput::ProcessRawDigits()
 
 //____________________________________________________________________
 Bool_t 
+AliFMDInput::ProcessRawCalibDigits()
+{
+  // Read the digit tree, and pass each digit to the member function
+  // ProcessDigit.
+  if (!fArrayA) {
+    AliError("No raw digit array defined");
+    return kFALSE;
+  }
+
+  Int_t nDigit = fArrayA->GetEntries();
+  if (nDigit <= 0) return kTRUE;
+  for (Int_t j = 0; j < nDigit; j++) {
+    AliFMDDigit* digit = static_cast<AliFMDDigit*>(fArrayA->At(j));
+    if (!digit) continue;
+    if (AliLog::GetDebugLevel("FMD","") >= 40 && j < 30) 
+      digit->Print();
+    if (!ProcessRawCalibDigit(digit)) return kFALSE;
+  }    
+  return kTRUE;
+}
+
+//____________________________________________________________________
+Bool_t 
 AliFMDInput::ProcessRecPoints()
 {
   // Read the reconstrcted points tree, and pass each reconstruction
@@ -697,6 +881,27 @@ AliFMDInput::ProcessESDs()
 }
 
 //____________________________________________________________________
+Bool_t 
+AliFMDInput::ProcessUsers()
+{
+  // Process event summary data
+  for (UShort_t det = 1; det <= 3; det++) {
+    Char_t rings[] = { 'I', (det == 1 ? '\0' : 'O'), '\0' };
+    for (Char_t* rng = rings; *rng != '\0'; rng++) {
+      UShort_t nsec = (*rng == 'I' ?  20 :  40);
+      UShort_t nstr = (*rng == 'I' ? 512 : 256);
+      for (UShort_t sec = 0; sec < nsec; sec++) {
+       for (UShort_t str = 0; str < nstr; str++) {
+         Float_t v  = GetSignal(det,*rng,sec,str);
+         if (!ProcessUser(det, *rng, sec, str, v)) continue;
+       }
+      }
+    }
+  }
+  return kTRUE;
+}
+
+//____________________________________________________________________
 Bool_t
 AliFMDInput::End()
 {
@@ -711,28 +916,28 @@ AliFMDInput::End()
     return fIsInit;
   }
   // Possibly unload global kinematics information 
-  if (TESTBIT(fTreeMask, kKinematics) || TESTBIT(fTreeMask, kTracks)) {
+  if (IsLoaded(kKinematics)) {
     fLoader->UnloadKinematics();
     // fTreeK = 0;
     fStack = 0;
   }
   // Possibly unload FMD Hit information 
-  if (TESTBIT(fTreeMask, kHits) || TESTBIT(fTreeMask, kTracks)) {
+  if (IsLoaded(kHits)) {
     fFMDLoader->UnloadHits();
     fTreeH = 0;
   }
   // Possibly unload FMD Digit information 
-  if (TESTBIT(fTreeMask, kDigits)) {
+  if (IsLoaded(kDigits)) {
     fFMDLoader->UnloadDigits();
     fTreeD = 0;
   }
   // Possibly unload FMD Sdigit information 
-  if (TESTBIT(fTreeMask, kSDigits)) {
+  if (IsLoaded(kSDigits)) {
     fFMDLoader->UnloadSDigits();
     fTreeS = 0;
   }
   // Possibly unload FMD RecPoints information 
-  if (TESTBIT(fTreeMask, kRecPoints)) {
+  if (IsLoaded(kRecPoints)) {
     fFMDLoader->UnloadRecPoints();
     fTreeR = 0;
   }
@@ -742,19 +947,25 @@ AliFMDInput::End()
 
 //____________________________________________________________________
 Bool_t
-AliFMDInput::Run()
+AliFMDInput::Run(UInt_t maxEvents)
 {
   // Run over all events and files references in galice.root 
 
   Bool_t retval;
   if (!(retval = Init())) return retval;
 
-  Int_t nEvents = NEvents();
-  for (Int_t event = 0; nEvents < 0 || event < nEvents; event++) {
+  fNEvents = NEvents();
+  if (fNEvents < 0)       fNEvents = maxEvents;
+  else if (maxEvents > 0) fNEvents = TMath::Min(fNEvents,Int_t(maxEvents));
+
+  Int_t event = 0;
+  for (; fNEvents < 0 || event < fNEvents; event++) {
+    printf("\rEvent %8d/%8d ...", event, fNEvents);
     if (!(retval = Begin(event))) break;
     if (!(retval = Event())) break;
     if (!(retval = End())) break;
   }
+  printf("Looped over %8d events\n", event+1);
   if (!retval) return retval;
   retval = Finish();
   return retval;
@@ -784,6 +995,84 @@ AliFMDInput::MakeLogScale(Int_t n, Double_t min, Double_t max)
   return bins;
 }
 
+//____________________________________________________________________
+void
+AliFMDInput::ScanDirectory(TSystemDirectory* dir, 
+                          const TString& olddir, 
+                          TChain* chain, 
+                          const char* pattern, bool recursive)
+{
+  // Get list of files, and go back to old working directory
+  TString oldDir(gSystem->WorkingDirectory());
+  TList* files = dir->GetListOfFiles();
+  gSystem->ChangeDirectory(oldDir);
+  
+  // Sort list of files and check if we should add it 
+  if (!files) return;
+  files->Sort();
+  TIter next(files);
+  TSystemFile* file = 0;
+  while ((file = static_cast<TSystemFile*>(next()))) {
+    TString name(file->GetName());
+    
+    // Ignore special links 
+    if (name == "." || name == "..") continue;
+
+    // Check if this is a directory 
+    if (file->IsDirectory()) { 
+      if (recursive) 
+       ScanDirectory(static_cast<TSystemDirectory*>(file),
+                     olddir, chain,
+                     pattern,recursive);
+      continue;
+    }
+    
+    // If this is not a root file, ignore 
+    if (!name.EndsWith(".root")) continue;
+
+    // If this file does not contain the pattern, ignore 
+    if (!name.Contains(pattern)) continue;
+    if (name.Contains("friends")) continue;
+    
+    // Get the path 
+    TString data(Form("%s/%s", file->GetTitle(), name.Data()));
+
+    TFile* test = TFile::Open(data.Data(), "READ");
+    if (!test || test->IsZombie()) { 
+      ::Warning("ScanDirectory", "Failed to open file %s", data.Data());
+      continue;
+    }
+    test->Close();
+    chain->Add(data);
+  }
+}
+
+//____________________________________________________________________
+TChain*
+AliFMDInput::MakeChain(const char* what, const char* datadir, bool recursive)
+{
+  TString w(what);
+  w.ToUpper();
+  const char* treeName = 0;
+  const char* pattern  = 0;
+  if      (w.Contains("ESD")) { treeName = "esdTree"; pattern = "AliESD"; }
+  else if (w.Contains("MC"))  { treeName = "TE";      pattern = "galice"; }
+  else {
+    ::Error("MakeChain", "Unknown mode '%s' (not one of ESD, or MC)", what);
+    return 0;
+  }
+    
+  // --- Our data chain ----------------------------------------------
+  TChain* chain = new TChain(treeName);
+
+  // --- Get list of ESDs --------------------------------------------
+  // Open source directory, and make sure we go back to were we were 
+  TString oldDir(gSystem->WorkingDirectory());
+  TSystemDirectory d(datadir, datadir);
+  ScanDirectory(&d, oldDir, chain, pattern, recursive);
+
+  return chain;
+}
 
 
 //____________________________________________________________________