]> git.uio.no Git - u/mrichter/AliRoot.git/blobdiff - FMD/AliFMDReconstructor.cxx
Complete rewrite of the FMD code.
[u/mrichter/AliRoot.git] / FMD / AliFMDReconstructor.cxx
index 69cb4ddd228ed9e3c481c48d51db4dfede690922..0587d5207bb43fb7e9c98e1ae00d941e3bb360d7 100644 (file)
  * provided "as is" without express or implied warranty.                  *
  **************************************************************************/
 
-//_________________________________________________________________________
-// This is a class that constructs ReconstParticles (reconstructed particles) 
-// out of Digits
+//____________________________________________________________________
+// This is a class that constructs ReconstParticles (reconstructed
+// particles) out of Digits
+//
+//
+// This class reads either digits from a TClonesArray or raw data from
+// a DDL file (or similar), and stores the read ADC counts in an
+// internal cache (fAdcs). 
+//
+// From the cached values it then calculates the number of particles
+// that hit a region of the FMDs, as specified by the user. 
+//
+// The reconstruction can be done in two ways: Either via counting the
+// number of empty strips (Poisson method), or by converting the ADC
+// signal to an energy deposition, and then dividing by the typical
+// energy loss of a particle.
+// 
+// Currently, this class only reads the digits from a TClonesArray,
+// and the Poission method for reconstruction. 
+//
 // 
 //-- Authors: Evgeny Karpechev(INR) and Alla Maevsksia
-//////////////////////////////////////////////////////////////////////////////
+//  Latest changes by Christian Holm Christensen <cholm@nbi.dk>
+//
+//
+//____________________________________________________________________
 
-// --- ROOT system ---
-#include "TTask.h"
-#include "TTree.h"
-#include "TSystem.h"
-#include "TFile.h"
-#include "TROOT.h"
-#include "TFolder.h"
-#include "TH2F.h"
-#include "TRandom.h"
+#ifndef ALIFMD_H
+# include "AliFMD.h"
+#endif
+#ifndef ALIFMDDIGIT_H
+# include "AliFMDDigit.h"
+#endif
+#ifndef ALIFMDPARTICLES_H
+# include "AliFMDParticles.h"
+#endif
+#ifndef ALIFMDRECONSTRUCTOR_H
+# include "AliFMDReconstructor.h"
+#endif
+#ifndef ALIALTROBUFFER_H
+# include "AliAltroBuffer.h"
+#endif
+#ifndef ALILOG_H
+# include "AliLog.h"
+#endif
+#ifndef ALIRUN_H
+# include "AliRun.h"
+#endif
+#ifndef ALIRUNLOADER_H
+# include "AliRunLoader.h"
+#endif
+#ifndef ALILOADER_H
+# include "AliLoader.h"
+#endif
+#ifndef ALIHEADER_H
+# include "AliHeader.h"
+#endif
+#ifndef ALIGENEVENTHEADER_H
+# include "AliGenEventHeader.h"
+#endif
+#ifndef ALIRAWREADERFILE_H
+# include "AliRawReaderFile.h"
+#endif
+#ifndef ALIFMDRAWSTREAM_H
+# include "AliFMDRawStream.h"
+#endif
+
+//____________________________________________________________________
+ClassImp(AliFMDReconstructor);
 
-// --- Standard library ---
-#include <stdlib.h>
-#include <Riostream.h>
+//____________________________________________________________________
+AliFMDReconstructor::AliFMDReconstructor() 
+  : AliReconstructor(),
+    fAdcs(kMaxDetectors, kMaxRings, kMaxSectors, kMaxStrips),
+    fDeltaEta(0), 
+    fDeltaPhi(0), 
+    fThreshold(0),
+    fPedestal(0), 
+    fPedestalWidth(0)
+{
+  SetDeltaEta();
+  SetDeltaPhi();
+  SetThreshold();
+  SetPedestal();
+
+  fParticles = new TClonesArray("AliFMDParticles", 1000);
+  fFMDLoader = 0;
+  fRunLoader = 0;
+  fFMD       = 0;
+}
+  
+//____________________________________________________________________
+void 
+AliFMDReconstructor::SetPedestal(Float_t mean, Float_t width) 
+{
+  // Set the pedestal, and pedestal width 
+  fPedestal      = mean;
+  fPedestalWidth = width;
+}
+
+//____________________________________________________________________
+void 
+AliFMDReconstructor::Reconstruct(AliRunLoader* runLoader, 
+                                AliRawReader* rawReader) const
+{ 
+  // Collects all digits in the same active volume into number of
+  // particles
+  //
+  // Reconstruct number of particles in given group of pads for given
+  // FMDvolume determined by numberOfVolume,
+  // numberOfMinSector, numberOfMaxSector, numberOfMinRing,
+  // numberOgMaxRing 
+  //
+  // The reconstruction method is choosen based on the number of empty
+  // strips. 
+  fParticles->Clear();
+  if (!runLoader) {
+    Error("Exec","Run Loader loader is NULL - Session not opened");
+    return;
+  }
+  fRunLoader = runLoader;
+  fFMDLoader = runLoader->GetLoader("FMDLoader");
+  if (!fFMDLoader) 
+    Fatal("AliFMDReconstructor","Can not find FMD (loader) "
+         "in specified event");
 
-// --- AliRoot header files ---
+  // Get the AliRun object
+  if (!fRunLoader->GetAliRun()) fRunLoader->LoadgAlice();
+  
+  // Get the AliFMD object
+  fFMD = static_cast<AliFMD*>(fRunLoader->GetAliRun()->GetDetector("FMD"));
+  if (!fFMD) {
+    AliError("Can not get FMD from gAlice");
+    return;
+  }
+  fFMDLoader->LoadRecPoints("RECREATE");
 
-#include "AliRunLoader.h"
-#include "AliLoader.h"
+  if (!fRunLoader->TreeE())     fRunLoader->LoadHeader();
 
-#include "AliFMDdigit.h"
-#include "AliFMDReconstParticles.h"
-#include "AliFMDReconstructor.h"
-#include "AliRun.h"
-#include "AliConfig.h"
-#include "AliHeader.h"
-#include "AliGenEventHeader.h"
+  TClonesArray* digits = fFMD->Digits();
+  if (rawReader) {
+    Int_t event = 0;
+    while (rawReader->NextEvent()) {
+      ProcessEvent(event, rawReader, digits);
+      event++;
+    }
+  }
+  else {
+    Int_t nEvents= Int_t(fRunLoader->TreeE()->GetEntries()); 
+    for(Int_t event = 0; event < nEvents; event++) 
+      ProcessEvent(event, 0, digits);
+  }
 
-ClassImp(AliFMDReconstructor)
 
-        
-//____________________________________________________________________________
+  fFMDLoader->UnloadRecPoints();
+  fFMDLoader = 0;
+  fRunLoader = 0;
+  fFMD       = 0;
+}
 
-void AliFMDReconstructor::Reconstruct(AliRunLoader* runLoader) const
+//____________________________________________________________________
+void 
+AliFMDReconstructor::Reconstruct(AliRunLoader* runLoader) const
 { 
- //Collects all digits in the same active volume into number of particles
-  /*
-    Reconstruct number of particles 
-    in given group of pads for given FMDvolume
-    determine by numberOfVolume , 
-    numberOfMinSector,numberOfMaxSector,
-    numberOfMinRing, numberOgMaxRing
-    Reconstructor method choose dependence on number of empty pads  
-  */
-
-
-#ifdef DEBUG
-  Info("Exec ","Start");
-#endif
+  // Collects all digits in the same active volume into number of
+  // particles
+  //
+  // Reconstruct number of particles in given group of pads for given
+  // FMDvolume determined by numberOfVolume,
+  // numberOfMinSector, numberOfMaxSector, numberOfMinRing,
+  // numberOgMaxRing 
+  //
+  // The reconstruction method is choosen based on the number of empty
+  // strips. 
+  Reconstruct(runLoader, 0);
+}
+
+
+//____________________________________________________________________
+void 
+AliFMDReconstructor::ProcessEvent(Int_t event, 
+                                 AliRawReader* reader, 
+                                 TClonesArray* digits) const
+{
+  fRunLoader->GetEvent(event) ;
+  //event z-vertex for correction eta-rad dependence      
+  AliHeader *header            = fRunLoader->GetHeader();
+  if (!header) 
+    Warning("ProcessEvent", "no AliHeader found!");
+  AliGenEventHeader* genHeader = (header ? header->GenEventHeader() : 0);
 
-  Int_t const knumVolumes=5;
-  Int_t padADC;
-  Float_t eta, etain,etaout,rad,theta;
-  Int_t ivol, iSector, iRing;
-  Float_t rin[5]={4.2,15.4,4.2,15.4,4.2};
-  Float_t rout[5]={17.4,28.4,17.4,28.4,17.4};
-  Float_t z[5]={-62.8, -75.2, 83.4, 75.2, 340.};
-  Int_t numberOfRings[5]={512,256,512,256,512};
-  Int_t numberOfSectors[5]=  {20,40,20,40,20};
-  Int_t numberOfEtaIntervals[5];
-  // number of ring for boundary 0.1 eta
+  // Get the Z--coordinate from the event header 
+  TArrayF o(3); 
+  if (genHeader) genHeader->PrimaryVertex(o);
+  Float_t zVertex = o.At(2);
 
+  // If the recontruction tree isn't loaded, load it
+  if(fFMDLoader->TreeR()==0) fFMDLoader->MakeTree("R");
   
-  if (runLoader == 0x0)
-   {
-    Error("Exec","Run Loader loader is NULL - Session not opened");
-    return;
-   }
-
-  AliLoader* plFMD = runLoader->GetLoader("FMDLoader");
-  if (plFMD == 0x0)
-   {
-     Fatal("AliFMDReconstructor","Can not find FMD (loader) in specified event");
-     return;//never reached
-   }
-   
-  if (!runLoader->GetAliRun()) runLoader->LoadgAlice();
-  if (!runLoader->TreeE()) runLoader->LoadHeader();
-
-  TDirectory* cwd = gDirectory;
-  gDirectory = 0x0;
-  Text_t buf1[20];
-  TH2F* hTotal[10];
-  for (Int_t j=1; j<=5; j++){
-    sprintf(buf1,"hTotal%d",j);
+  //Make branches to hold the reconstructed particles 
+  const Int_t kBufferSize = 16000;
+  fFMDLoader->TreeR()->Branch("FMD", &fParticles, kBufferSize);
+
+  // Load or recreate the digits 
+  if (fFMDLoader->LoadDigits((reader ? "UPDATE" : "READ"))) {
+    if (!reader) {
+      Error("Exec","Error occured while loading digits. Exiting.");
+      return;
+    }
     
-    hTotal[j] = new TH2F(buf1," Number of primary particles ",
-                        numberOfSectors[j-1],1,numberOfSectors[j-1],
-                        numberOfRings[j-1],1,numberOfRings[j-1]);
-  }   
-  gDirectory = cwd;
-  plFMD->LoadRecPoints("RECREATE");
-  TClonesArray* reconParticles = new TClonesArray("AliFMDReconstParticles"); 
-  TClonesArray* digits = new TClonesArray("AliFMDdigit");
-  Int_t retval=0;     
-  Int_t nevents=Int_t (runLoader->TreeE()->GetEntries()); 
-#ifdef DEBUG
-  cout<<" nevents "<<nevents<<endl;
-#endif
-   for(Int_t ievent=0;ievent<nevents;ievent++)
-    { 
-#ifdef DEBUG
-      cout<<" *** event "<<ievent<<endl; 
-#endif
-      runLoader->GetEvent(ievent) ;
-      //event z-vertex for correction eta-rad dependence      
-      AliHeader *header = runLoader->GetHeader();
-      AliGenEventHeader* genHeader = header->GenEventHeader();
-      TArrayF *o = new TArrayF(3); 
-      if (genHeader) genHeader->PrimaryVertex(*o);
-      Float_t zVertex=o->At(2);
-
-      for (Int_t i=0; i<5; i++)
-        hTotal[i+1]->Reset();
-      
-      retval = plFMD->LoadDigits("READ"); 
-      if (retval)
-       {
-         Error("Exec","Error occured while loading digits. Exiting.");
-         return;
+  }
+  // Get the digits tree 
+  TTree* digitTree = fFMDLoader->TreeD();
+  if (!digitTree) { 
+    if (!reader) {
+      Error("Exec","Can not get Tree with Digits. "
+           "Nothing to reconstruct - Exiting");
+      return;
+    }
+    fFMDLoader->MakeTree("D");
+    digitTree = fFMDLoader->TreeD();
+    
+  }
+  // Get the FMD branch holding the digits. 
+  TBranch *digitBranch = digitTree->GetBranch("FMD");
+  if (!digitBranch) {
+    if (!reader) {
+      Error("Exec", "No digit branch for the FMD found");
+      return;
+    }
+    fFMD->MakeBranchInTree(digitTree, fFMD->GetName(), &(digits), 4000, 0);
+  }
+  if (!reader) digitBranch->SetAddress(&digits);
+
+  fEmptyStrips = 0;
+  fTotalStrips = 0;
+  Bool_t ok = kFALSE;
+  if      (reader) ok = ReadAdcs(reader);
+  else if (digits) ok = ReadAdcs(digits);
+  if (!ok) return;
+  
+  ReconstructFromCache(zVertex);
+
+  if (reader) {
+    digitTree->Fill();
+    fFMDLoader->WriteDigits("OVERWRITE");
+  }
+  fFMDLoader->UnloadDigits();
+  fFMDLoader->TreeR()->Reset();
+  fFMDLoader->TreeR()->Fill(); 
+  fFMDLoader->WriteRecPoints("OVERWRITE");
+}
+
+//____________________________________________________________________
+Bool_t
+AliFMDReconstructor::ReadAdcs(TClonesArray* digits) const
+{
+  AliDebug(10, "Reading ADCs from Digits array");
+  // read Digits, and reconstruct the particles
+  if (!fFMDLoader->TreeD()->GetEvent(0)) return kFALSE;
+
+  // Reads the digits from the array, and fills up the cache (fAdcs) 
+  fAdcs.Clear();
+  Int_t nDigits = digits->GetEntries();
+  for (Int_t digit = 0; digit < nDigits; digit++) {
+    AliFMDDigit* fmdDigit = 
+      static_cast<AliFMDDigit*>(digits->UncheckedAt(digit));    
+    
+    ProcessDigit(fmdDigit);
+  } //digit loop
+  return kTRUE;
+}
+
+//____________________________________________________________________
+Bool_t
+AliFMDReconstructor::ReadAdcs(AliRawReader* reader) const
+{
+  AliDebug(10, "Reading ADCs from RawReader");
+  // Reads the digits from a RAW data 
+  fAdcs.Clear();
+  // reader->Reset();
+
+  if (!reader->ReadHeader()) {
+    Error("ReadAdcs", "Couldn't read header");
+    return kFALSE;
+  }
+
+  // Use AliAltroRawStream to read the ALTRO format.  No need to
+  // reinvent the wheel :-) 
+  AliFMDRawStream input(reader);
+  // Select FMD DDL's 
+  reader->Select(AliFMD::kBaseDDL >> 8);
+  
+  Int_t    oldDDL      = -1;
+  Int_t    count       = 0;
+  UShort_t detector    = 1; // Must be one here
+  UShort_t oldDetector = 0;
+  // Loop over data in file 
+  Bool_t   next       = kTRUE;
+
+  // local Cache 
+  TArrayI counts(10);
+  counts.Reset(-1);
+  Int_t offset = 0;
+  
+  while (next) {
+    next = input.Next();
+
+
+    count++; 
+    Int_t ddl = reader->GetDDLID();
+    if (ddl != oldDDL 
+       || input.IsNewStrip()
+       || !next) {
+      // Make a new digit, if we have some data! 
+      if (counts[0] >= 0) {
+       // Got a new strip. 
+       AliDebug(10, Form("Add a new strip: FMD%d%c[%2d,%3d] "
+                         "(current: FMD%d%c[%2d,%3d])", 
+                         oldDetector, input.PrevRing(), 
+                         input.PrevSector() , input.PrevStrip(),
+                         detector , input.Ring(), input.Sector(), 
+                         input.Strip()));
+       fFMD->AddDigit(oldDetector, 
+                      input.PrevRing(), 
+                      input.PrevSector(), 
+                      input.PrevStrip(), 
+                      counts[0], counts[1], counts[2]);
+       AliFMDDigit* digit = 
+         static_cast<AliFMDDigit*>(fFMD->Digits()->
+                                   UncheckedAt(fFMD->GetNdigits()-1));
+       ProcessDigit(digit);
+      }
+       
+      if (!next) { 
+       AliDebug(10, Form("Read %d channels for FMD%d", 
+                         count + 1, detector));
+       break;
+      }
+    
+    
+      // If we got a new DDL, it means we have a new detector. 
+      if (ddl != oldDDL) {
+       if (detector != 0) 
+         AliDebug(10, Form("Read %d channels for FMD%d", 
+                           count + 1, detector));
+       // Reset counts, and update the DDL cache 
+       count       = 0;
+       oldDDL      = ddl;
+       // Check that we're processing a FMD detector 
+       Int_t detId = reader->GetDetectorID();
+       if (detId != (AliFMD::kBaseDDL >> 8)) {
+         Error("ReadAdcs", "Detector ID %d != %d",
+               detId, (AliFMD::kBaseDDL >> 8));
+         break;
        }
-      
-      TTree* treeD = plFMD->TreeD();
-      if (treeD == 0x0)
-       {
-         Error("Exec","Can not get Tree with Digits. Nothing to reconstruct - Exiting");
-         return;
+       // Figure out what detector we're deling with 
+       oldDetector = detector;
+       switch (ddl) {
+       case 0: detector = 1; break;
+       case 1: detector = 2; break;
+       case 2: detector = 3; break;
+       default:
+         Error("ReadAdcs", "Unknown DDL 0x%x for FMD", ddl);
+         return kFALSE;
        }
-      
-      TBranch *brDigits=0;
-           
-      brDigits=treeD->GetBranch("FMD");
-
-      if (brDigits) {
-       brDigits->SetAddress(&digits);
-      }else{
-       cerr<<"EXEC Branch FMD digits not found"<<endl;
-       return;
-      } 
-         
-      if(plFMD->TreeR()==0) plFMD->MakeTree("R");
+       AliDebug(10, Form("Reading ADCs for 0x%x  - That is FMD%d",
+                         reader->GetEquipmentId(), detector));
+      }
+      counts.Reset(-1);
+      offset = 0;
+    }
+    
+    counts[offset] = input.Count();
+    offset++;
+    
+    AliDebug(10, Form("ADC of FMD%d%c[%2d,%3d] += %d",
+                     detector, input.Ring(), input.Sector(), 
+                     input.Strip(), input.Count()));
+    oldDetector = detector;
+  }
+  return kTRUE;
+}
 
-      //Make branches
-      const Int_t kBufferSize = 16000;
-      plFMD->TreeR()->Branch("FMD", &reconParticles, kBufferSize);
+//____________________________________________________________________
+void
+AliFMDReconstructor::ProcessDigit(AliFMDDigit* digit) const
+{
+  // Process a digit.  Derived classes can overload this member
+  // function to do stuff to the digit.  However, it should write the
+  // ADC count to the internal cache 
+  //
+  //    fAdcs(detector - 1, ring, sector, strip) = counts;
+  //
+  // In this implementation, we count the number of strips below
+  // threshold.   This we do to later choose what kind of
+  // reconstruction algorithm we'd like to use. 
+  // 
+  UShort_t detector = digit->Detector();
+  Char_t   ring     = digit->Ring();
+  UShort_t sector   = digit->Sector();
+  UShort_t strip    = digit->Strip();    
+  
+  UShort_t counts  = SubtractPedestal(digit);
+  
+  fAdcs(detector - 1, ring, sector, strip) = counts;
+  if (counts < fThreshold) fEmptyStrips++;
+  fTotalStrips++;
+}
 
-      
-      Int_t zeroADC=6;
-      // read Digits 
-      AliFMDdigit  *fmdDigit;
-       if (plFMD->TreeD()->GetEvent(0))
-       {                 
-         Int_t nDigits=digits->GetEntries();
-         Int_t recParticles[6];
-         Int_t nRecPart=0 ;
-         Int_t zeroPads=0;
-         Int_t numberOfPads=0;
-         Int_t pedestal;
-         Float_t channelWidth=(22400*50)/1024;
-         for (Int_t digit=0;digit<nDigits;digit++) 
-           {
-             fmdDigit=(AliFMDdigit*)digits->UncheckedAt(digit);    
-             ivol=fmdDigit->Volume();
-             iSector=fmdDigit->NumberOfSector();
-             iRing=fmdDigit->NumberOfRing();
-             pedestal=Int_t(gRandom->Gaus(500,250));
-             padADC= fmdDigit->ADCsignal()
-               -Int_t(Float_t(pedestal)/channelWidth);
-             if (padADC<0) padADC=0;
-              hTotal[ivol]->Fill(iSector,iRing,padADC);
-           } //digit loop
-
-         //reconstruct multiplicity in 0.1 eta according Poisson distribution 
-
-         Int_t rmin=0; Int_t rmax=0; 
-         Int_t smin=0; Int_t smax=0; 
-         for (ivol=0; ivol<knumVolumes; ivol++)
-           {
-             Float_t ring2number=Float_t (numberOfRings[ivol])/
-               (rout[ivol]-rin[ivol]);
-             Float_t realZ=zVertex+z[ivol];
-             theta=TMath::ATan(rout[ivol]/TMath::Abs(realZ));
-             etain = - TMath::Log( TMath::Tan(theta/2.));
-             theta=TMath::ATan(rin[ivol]/TMath::Abs(realZ));
-             etaout=- TMath::Log( TMath::Tan(theta/2.));
-             numberOfEtaIntervals[ivol]=Int_t((etaout-etain)*10)-1;
-             eta=etain;
-             for (Int_t e1=0;e1<=numberOfEtaIntervals[ivol];e1++) 
-               {
-                 theta = 2.*TMath::ATan (TMath::Exp (-eta));
-                 Float_t radmin = TMath::Abs(realZ) * (TMath::Tan (theta));
-                 rmax= Int_t ( (radmin-rin[ivol])*ring2number+0.5);
-                 eta=eta+0.1;
-                 theta = 2.*TMath::ATan (TMath::Exp (-eta));
-                 rad = TMath::Abs(realZ) * (TMath::Tan (theta));
-                 rmin=Int_t( (rad-rin[ivol])*ring2number+0.5);
-                 
-                 zeroPads=0;
-                 smin=0;
-                 smax=numberOfSectors[ivol]; 
-                 numberOfPads=(rmax-rmin)*(smax-smin);
-                 for (Int_t iring=rmin; iring<rmax; iring++) 
-                   {
-                     for 
-                       (Int_t isector=0;
-                        isector<numberOfSectors[ivol]; 
-                        isector++) 
-                       {
-                         if(hTotal[ivol+1]->GetBinContent(isector+1,iring+1)
-                            <zeroADC) zeroPads++;}
-                     
-                   } //ring
-                 Float_t numberOfPads=Float_t(smax-smin)*Float_t(rmax-rmin);
-
-                 Double_t lambda=-TMath::Log(Double_t(zeroPads)/numberOfPads);
-                 Int_t fRecon=Int_t (lambda*numberOfPads+0.5);
-                 recParticles[0]=ivol+1;
-                 recParticles[1]=smin;
-                 recParticles[2]=smax;
-                 recParticles[3]=rmin;
-                 recParticles[4]=rmax;
-                 recParticles[5]= fRecon;
-                 new((*reconParticles)[nRecPart++])   AliFMDReconstParticles(recParticles);             
-                 
-
-                } // eta
-            } // volume
-          
-       }//if (plFMD->TreeD()->GetEvent(0))
-       plFMD->TreeR()->Reset();
-       plFMD->TreeR()->Fill(); 
-       plFMD->WriteRecPoints("OVERWRITE");
-       plFMD->UnloadDigits();
-    } //event loop
-  plFMD->UnloadRecPoints();
-#ifdef DEBUG
-  Info(" Exec"," finished");
-#endif
-  //  delete hTotal[10]; 
+//____________________________________________________________________
+UShort_t
+AliFMDReconstructor::SubtractPedestal(AliFMDDigit* digit) const
+{
+  // Member function to subtract the pedestal from a digit
+  // This implementation does nothing, but a derived class could over
+  // load this to subtract a pedestal that was given in a database or
+  // something like that. 
 
+  Int_t counts = 
+    TMath::Max(Int_t(digit->Count1() - fPedestal - 3 * fPedestalWidth), 0);
+  if (digit->Count2() >= 0) 
+    counts += 
+      TMath::Max(Int_t(digit->Count2() - fPedestal - 3 * fPedestalWidth), 0);
+  if (digit->Count3() >= 0) 
+    counts += 
+      TMath::Max(Int_t(digit->Count3() - fPedestal - 3 * fPedestalWidth), 0);
+      
+  if (counts < 0) counts = 0;
+  return  UShort_t(counts);
 }
 
+//____________________________________________________________________
+void
+AliFMDReconstructor::ReconstructFromCache(Float_t zVertex) const
+{
+  // Based on the information in the cache, do the reconstruction. 
+  Int_t nRecon = 0;
+  // Loop over the detectors 
+  for (Int_t i = 1; i <= 3; i++) {
+    AliFMDSubDetector* sub = 0;
+    switch (i) {
+    case 1: sub = fFMD->GetFMD1(); break;
+    case 2: sub = fFMD->GetFMD2(); break;
+    case 3: sub = fFMD->GetFMD3(); break;
+    }
+    if (!sub) continue;
+       
+    // Loop over the rings in the detector
+    for (Int_t j = 0; j < 2; j++) {
+      Float_t     rZ = 0;
+      AliFMDRing* r  = 0;
+      switch (j) {
+      case 0: r  = sub->GetInner(); rZ = sub->GetInnerZ(); break;
+      case 1: r  = sub->GetOuter(); rZ = sub->GetOuterZ(); break;
+      }
+      if (!r) continue;
+      
+      // Calculate low/high theta and eta 
+      // FIXME: Is this right? 
+      Float_t realZ    = zVertex + rZ;
+      Float_t thetaOut = TMath::ATan2(r->GetHighR(), realZ);
+      Float_t thetaIn  = TMath::ATan2(r->GetLowR(), realZ);
+      Float_t etaOut   = - TMath::Log(TMath::Tan(thetaOut / 2));
+      Float_t etaIn    = - TMath::Log(TMath::Tan(thetaIn / 2));
+      if (TMath::Abs(etaOut) > TMath::Abs(etaIn)) {
+       Float_t tmp = etaIn;
+       etaIn       = etaOut;
+       etaOut      = tmp;
+      }
+
+      //-------------------------------------------------------------
+      //
+      // Here starts poisson method 
+      //
+      // Calculate eta step per strip, number of eta steps, number of
+      // phi steps, and check the sign of the eta increment 
+      Float_t stripEta = (Float_t(r->GetNStrips()) / (etaIn - etaOut));
+      Int_t   nEta     = Int_t(TMath::Abs(etaIn - etaOut) / fDeltaEta); 
+      Int_t   nPhi     = Int_t(360. / fDeltaPhi);
+      Float_t sign     = TMath::Sign(Float_t(1.), etaIn);
 
-//_____________________________________________________________________________
-void AliFMDReconstructor::FillESD(AliRunLoader* /*runLoader*/, 
-                                 AliESD* /*esd*/) const
+      AliDebug(10, Form("FMD%d%c Eta range: %f, %f %d Phi steps",
+                       sub->GetId(), r->GetId(), etaOut, etaIn, nPhi));
+
+      // Loop over relevant phi values 
+      for (Int_t p = 0; p < nPhi; p++) {
+       Float_t  minPhi    = p * fDeltaPhi;
+       Float_t  maxPhi    = minPhi + fDeltaPhi;
+       UShort_t minSector = UShort_t(minPhi / 360) * r->GetNSectors();
+       UShort_t maxSector = UShort_t(maxPhi / 360) * r->GetNSectors();
+       
+       AliDebug(10, Form(" Now in phi range %f, %f (sectors %d,%d)",
+                         minPhi, maxPhi, minSector, maxSector));
+       // Loop over relevant eta values 
+       for (Int_t e = nEta; e >= 0; --e) {
+         Float_t  maxEta   = etaIn  - sign * e * fDeltaEta;
+         Float_t  minEta   = maxEta - sign * fDeltaEta;
+         if (sign > 0)  minEta = TMath::Max(minEta, etaOut);
+         else           minEta = TMath::Min(minEta, etaOut);
+         Float_t  theta1   = 2 * TMath::ATan(TMath::Exp(-minEta));
+         Float_t  theta2   = 2 * TMath::ATan(TMath::Exp(-maxEta));
+         Float_t  minR     = TMath::Abs(realZ * TMath::Tan(theta2));
+         Float_t  maxR     = TMath::Abs(realZ * TMath::Tan(theta1));
+         UShort_t minStrip = UShort_t((etaIn - maxEta) * stripEta + 0.5);
+         UShort_t maxStrip = UShort_t((etaIn - minEta) * stripEta + 0.5);
+
+         AliDebug(10, Form("  Now in eta range %f, %f (strips %d, %d)\n"
+                           "    [radii %f, %f, thetas %f, %f, sign %d]", 
+                           minEta, maxEta, minStrip, maxStrip, 
+                           minR, maxR, theta1, theta2, sign));
+
+         // Count number of empty strips
+         Int_t   emptyStrips = 0;
+         for (Int_t sector = minSector; sector < maxSector; sector++) 
+           for (Int_t strip = minStrip; strip < maxStrip; strip++) 
+             if (fAdcs(sub->GetId() - 1, r->GetId(), sector, strip) 
+                 < fThreshold) emptyStrips++;
+         
+         // The total number of strips 
+         Float_t nTotal = (maxSector - minSector) * (maxStrip - minStrip);
+         
+         // Log ratio of empty to total number of strips 
+         AliDebug(10, Form("Lambda= %d / %d = %f", 
+                           emptyStrips, nTotal, 
+                           Float_t(emptyStrips) / nTotal));
+         
+         Double_t lambda = (emptyStrips > 0 ? 
+                            - TMath::Log(Double_t(emptyStrips) / nTotal) :
+                            1);
+
+         // The reconstructed number of particles is then given by 
+         Int_t reconstructed = Int_t(lambda * nTotal + 0.5);
+           
+         // Add a AliFMDParticles to the reconstruction tree. 
+         new((*fParticles)[nRecon])   
+           AliFMDParticles(sub->GetId(), r->GetId(),
+                           minSector, maxSector, minStrip, maxStrip,
+                           minEta, maxEta, minPhi, maxPhi,
+                           reconstructed, AliFMDParticles::kPoission);
+         nRecon++;
+       } // phi 
+      } // eta
+    } // ring 
+  } // detector 
+}
+
+//____________________________________________________________________
+void 
+AliFMDReconstructor::FillESD(AliRunLoader* /*fRunLoader*/, 
+                            AliESD* /*esd*/) const
 {
 // nothing to be done