]> git.uio.no Git - u/mrichter/AliRoot.git/blobdiff - FMD/AliFMDParameters.cxx
restore threshold getters after parameter dynamics update (fw v. >= A012)
[u/mrichter/AliRoot.git] / FMD / AliFMDParameters.cxx
index 22a54aaa17fec7ce8c4cf6ad780c516e56817cb0..7142e26eeb13727c37e4f7754a68298140d35c2e 100644 (file)
@@ -1,4 +1,4 @@
-/**************************************************************************
+/*************************************************************************
  * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
  *                                                                        *
  * Author: The ALICE Off-line Project.                                    *
  * appear in the supporting documentation. The authors make no claims     *
  * about the suitability of this software for any purpose. It is          *
  * provided "as is" without express or implied warranty.                  *
- **************************************************************************/
-
-/* $Id$ */
-
+ *************************************************************************
+ * $Id$ */
+/**
+ * @file    AliFMDParameters.cxx
+ * @author  Christian Holm Christensen <cholm@nbi.dk>
+ * @date    Mon Mar 27 12:44:26 2006
+ * @brief   Manager of FMD parameters     
+ */
 //____________________________________________________________________
 //                                                                          
 // Forward Multiplicity Detector based on Silicon wafers. 
 //
 // This class is a singleton that handles various parameters of
 // the FMD detectors.  
-// Eventually, this class will use the Conditions DB to get the
-// various parameters, which code can then request from here.
+// The manager normally serves the parameters from the Conditions
+// Database (CDB).  These are retrivied by the member function
+// `Init'.  Optionally, the class can serve hard-coded constants, if
+// no CDB is available. 
 //                                                       
-#include "AliLog.h"               // ALILOG_H
+#include "AliFMDDebug.h"                  // ALILOG_H
 #include "AliFMDParameters.h"     // ALIFMDPARAMETERS_H
 #include "AliFMDGeometry.h"       // ALIFMDGEOMETRY_H
 #include "AliFMDRing.h"                   // ALIFMDRING_H
 #include "AliFMDCalibGain.h"       // ALIFMDCALIBGAIN_H
 #include "AliFMDCalibPedestal.h"   // ALIFMDCALIBPEDESTAL_H
-#include "AliFMDCalibSampleRate.h" // ALIFMDCALIBPEDESTAL_H
+#include "AliFMDCalibSampleRate.h" // ALIFMDCALIBSAMPLERATE_H
+#include "AliFMDCalibStripRange.h" // ALIFMDCALIBSTRIPRANGE_H
+#include "AliFMDAltroMapping.h"    // ALIFMDALTROMAPPING_H
+#include <AliCDBManager.h>         // ALICDBMANAGER_H
+#include <AliCDBEntry.h>           // ALICDBMANAGER_H
+#include <AliFMDPreprocessor.h>
+#include <AliLog.h>
 #include <Riostream.h>
+#include <sstream>
+#include <TSystem.h>
+#include <TArrayF.h>
+#include <TH2D.h>
 
 //====================================================================
 ClassImp(AliFMDParameters)
@@ -42,27 +58,61 @@ ClassImp(AliFMDParameters)
 //____________________________________________________________________
 AliFMDParameters* AliFMDParameters::fgInstance = 0;
 
+//____________________________________________________________________
+const char* AliFMDParameters::fgkPulseGain         = "FMD/Calib/PulseGain";
+const char* AliFMDParameters::fgkPedestal          = "FMD/Calib/Pedestal";
+const char* AliFMDParameters::fgkDead              = "FMD/Calib/Dead";
+const char* AliFMDParameters::fgkSampleRate        = "FMD/Calib/SampleRate";
+const char* AliFMDParameters::fgkAltroMap          = "FMD/Calib/AltroMap";
+const char* AliFMDParameters::fgkZeroSuppression    = "FMD/Calib/ZeroSuppression";
+const char* AliFMDParameters::fgkStripRange        = "FMD/Calib/StripRange";
+const char* AliFMDParameters::fkPedestalShuttleID   = "pedestals";
+const char* AliFMDParameters::fkGainShuttleID       = "gains";
+const char* AliFMDParameters::fkConditionsShuttleID = "conditions";
+
 //____________________________________________________________________
 AliFMDParameters* 
 AliFMDParameters::Instance() 
 {
+  // 
   // Get static instance 
+  //
   if (!fgInstance) fgInstance = new AliFMDParameters;
   return fgInstance;
 }
 
 //____________________________________________________________________
 AliFMDParameters::AliFMDParameters() 
-  : fSiDeDxMip(1.664), 
-    fFixedPulseGain(0), 
+  : fIsInit(kFALSE),
+    fkSiDeDxMip(1.664), 
+    fVA1MipRange(0),
+    fAltroChannelSize(0),
+    fChannelsPerAltro(0),
+    fPedestalFactor(0),
+    fZSPre(1),
+    fZSPost(1),
+    fZSPedSubtract(kTRUE),
+    fFixedPedestal(100),
+    fFixedPedestalWidth(2),
+    fFixedZeroSuppression(1),
+    fFixedSampleRate(2),
+    fFixedThreshold(0),
+    fFixedMinStrip(0),
+    fFixedMaxStrip(127),
+    fFixedPulseGain(2), 
     fEdepMip(0),
+    fHasCompleteHeader(kTRUE),
     fZeroSuppression(0), 
     fSampleRate(0), 
     fPedestal(0), 
     fPulseGain(0), 
-    fDeadMap(0)
+    fDeadMap(0), 
+    fAltroMap(0), 
+    fStripRange(0)
 {
+  //
   // Default constructor 
+  //
   SetVA1MipRange();
   SetAltroChannelSize();
   SetChannelsPerAltro();
@@ -72,12 +122,710 @@ AliFMDParameters::AliFMDParameters()
   SetPedestalWidth();
   SetPedestalFactor();
   SetThreshold();
+  SetStripRange();
+  SetGain();
+  fAltroMap = new AliFMDAltroMapping;
+}
+
+//__________________________________________________________________
+void
+AliFMDParameters::Init(Bool_t forceReInit, UInt_t what)
+{
+  // 
+  // Initialize the manager.  This tries to read the parameters from
+  // CDB.  If that fails, the class uses the hard-coded parameters.
+  // 
+  // Parameters:
+  //    forceReInit Force (re-)initalize flag
+  //    what        What to initialize 
+  //
+  if (forceReInit) fIsInit = kFALSE;
+  if (fIsInit) return;
+  if (what & kPulseGain)       InitPulseGain();
+  if (what & kPedestal)        InitPedestal();
+  if (what & kDeadMap)         InitDeadMap();
+  if (what & kSampleRate)      InitSampleRate();
+  if (what & kZeroSuppression) InitZeroSuppression();
+  if (what & kAltroMap)        InitAltroMap();
+  if (what & kStripRange)      InitStripRange();
+  fIsInit = kTRUE;
+}
+//__________________________________________________________________
+void
+AliFMDParameters::Init(AliFMDPreprocessor* pp, Bool_t forceReInit, UInt_t what)
+{
+  // 
+  // Initialize the manager.  This tries to read the parameters from
+  // CDB.  If that fails, the class uses the hard-coded parameters.
+  // 
+  // Parameters:
+  //    pp          Preprocessor 
+  //    forceReInit Force (re-)initalize flag
+  //    what        What to initialize 
+  //
+  if (forceReInit) fIsInit = kFALSE;
+  if (fIsInit) return;
+  if (what & kPulseGain)       InitPulseGain(pp);
+  if (what & kPedestal)        InitPedestal(pp);
+  if (what & kDeadMap)         InitDeadMap(pp);
+  if (what & kSampleRate)      InitSampleRate(pp);
+  if (what & kZeroSuppression) InitZeroSuppression(pp);
+  if (what & kAltroMap)        InitAltroMap(pp);
+  if (what & kStripRange)      InitStripRange(pp);
+  fIsInit = kTRUE;
+}
+
+//__________________________________________________________________
+Bool_t
+AliFMDParameters::CheckFile(const char* prefix, 
+                           const char* path, 
+                           int         number, 
+                           TString&    f) const
+{
+  // 
+  // Check if the file <i>prefix</i><i>number</i> exists in @a path, 
+  // and write the full path to @a f.  
+  // 
+  // Parameters:
+  //    prefix  File prefix (cond, peds, gains, ...)
+  //    path    Path to files
+  //    number  Detector number (1, 2, or 3)
+  //    f       On return full path to file (if found)
+  // 
+  // Return:
+  //    @c true if file exists and is readable, @c false otherwise
+  //
+  f = (Form("%s%d.csv", prefix, number));
+  AliFMDDebug(5, ("Checking if %s exists in %s ...", f.Data(), path));
+  f = gSystem->Which(path, f.Data());
+  AliFMDDebug(5, ("Got back '%s'", f.Data()));
+  return !f.IsNull();
+}
+
+//__________________________________________________________________
+void
+AliFMDParameters::Init(const char* path, Bool_t forceReInit, UInt_t what)
+{
+  // 
+  // Initialize the manager.  This will try to read some calibrations
+  // (sample rate, strip range, gains, pedestals) from local comma
+  // separated value (CSV) files in the directory pointed at by @a
+  // path.  If they are not found, then they will be retrieved from
+  // OCDB as appropriately.   Other calibrations are always read from
+  // OCDB.  
+  // 
+  // The CSV files should be named as 
+  // 
+  // - Pedestals: <tt>peds</tt><i>det_number</i><tt>.csv</tt>
+  // - Gains: <tt>gains</tt><i>det_number</i><tt>.csv</tt>
+  // - Sample Rate: <tt>conditions</tt><i>det_number</i><tt>.csv</tt>
+  // - Strip Range: <tt>conditions</tt><i>det_number</i><tt>.csv</tt>
+  //
+  // where <i>det_number</i> is the detector number (1, 2, or 3). 
+  // 
+  // Parameters:
+  //    path        Where to look for the CSV files
+  //    forceReInit Always reinitialise 
+  //    what        What calibrations to load. 
+  //  
+  if (forceReInit) fIsInit = kFALSE;
+  if (fIsInit) return;
+
+  AliFMDCalibStripRange*  range = 0;
+  AliFMDCalibSampleRate*  rate  = 0;
+  AliFMDCalibPedestal*    peds  = 0;
+  AliFMDCalibGain*        gains = 0;
+
+  for (Int_t i = 1; i <= 3; i++) { 
+    TString f;
+    if (((what & kSampleRate) || (what & kStripRange)) && 
+       CheckFile("conditions", path, i, f)) {
+      if (!rate  && (what & kSampleRate)) rate  = new AliFMDCalibSampleRate;
+      if (!range && (what & kStripRange)) range = new AliFMDCalibStripRange;
+      std::ifstream in(f.Data());
+      if (range) range->ReadFromFile(in);
+      if (rate)  rate->ReadFromFile(in);
+      in.close();
+    }
+    if ((what & kPedestal) && CheckFile("peds", path, i, f)) {
+      if (!peds) peds  = new AliFMDCalibPedestal;
+      std::ifstream in(f.Data());
+      peds->ReadFromFile(in);
+      in.close();
+    }
+    if ((what & kPulseGain) && CheckFile("gains", path, i, f)) { 
+      if (!gains) gains = new AliFMDCalibGain;
+      std::ifstream in(f.Data());
+      gains->ReadFromFile(in);
+      in.close();
+    }
+  }
+
+  if (range) what &= ~kStripRange;
+  if (rate)  what &= ~kSampleRate;
+  if (peds)  what &= ~kPedestal;
+  if (gains) what &= ~kPulseGain;
+
+  Init(kFALSE, what);
+  
+  if (range) SetStripRange(range);
+  if (rate)  SetSampleRate(rate);
+  if (peds)  SetPedestal(peds);
+  if (gains) SetGain(gains);
+
+  fIsInit = kTRUE;
+}
+
+//__________________________________________________________________
+void
+AliFMDParameters::MakeDeadMap(Float_t maxNoise, 
+                             Float_t minGain, 
+                             Float_t maxGain)
+{
+  // 
+  // Automatically generate a dead map from the pedestals and gains.
+  // A channel is marked as dead of the noise is too high (currently
+  // more than 10 ADC counts), or the gain is unreasonable (currently
+  // larger than 10, or smaller than 0.1). 
+  // 
+  // The procedure does not overwrite channels previously marked as
+  // dead - e.g., channels marked as dead in the calibration loaded
+  // from OCDB will continue to be marked as dead.  That is, this
+  // procedure will never make a channel un-dead. 
+  // 
+  // Parameters:
+  //    maxNoise  Maximum noise value before a channel is marked
+  // as dead. 
+  //    minGain   Minimum value of the calibrated gain before a
+  // channel is considered dead. 
+  //    maxGain   Maximum value of the calibrated gain before a
+  // channel is considered dead. 
+  //
+  if (fPedestal)  
+    fDeadMap = fPedestal->MakeDeadMap(maxNoise, fDeadMap);
+  if (fPulseGain) 
+    fDeadMap = fPulseGain->MakeDeadMap(minGain, maxGain, fDeadMap);
+}
+//__________________________________________________________________
+#define DET2IDX(det,ring,sec,str) \
+  (det * 1000 + (ring == 'I' ? 0 : 512) + str)  
+  
+//__________________________________________________________________
+void
+AliFMDParameters::Draw(Option_t* option)
+{
+  // 
+  // Draw parameters. 
+  // 
+  // Parameters:
+  //    option What to draw. Should be one of 
+  // - dead      Dead channels
+  // - threshold Threshold
+  // - gain      Gain
+  // - pedestal  Pedestal
+  // - noise     Noise (or pedestal width)
+  // - zero      Zero suppression
+  // - rate      Sampling rate (VA1 clock / ALTRO clock)
+  // - min       Minimum strip read out
+  // - max       Maximum strip read out
+  // - map       hardware address
+  //
+  TString opt(option);
+  enum {
+    kLocalPulseGain,       // Path to PulseGain calib object
+    kLocalThreshold,       // Path to PulseGain calib object
+    kLocalPedestal,        // Path to Pedestal calib object
+    kLocalPedestalWidth,   // Path to Pedestal calib object
+    kLocalDead,            // Path to Dead calib object
+    kLocalSampleRate,      // Path to SampleRate calib object
+    kLocalAltroMap,        // Path to AltroMap calib object
+    kLocalZeroSuppression, // Path to ZeroSuppression cal object
+    kLocalMinStripRange,   // Path to strip range cal object
+    kLocalMaxStripRange    // Path to strip range cal object
+  } what;
+    
+  if      (opt.Contains("dead", TString::kIgnoreCase)) 
+    what = kLocalDead;
+  else if (opt.Contains("threshold",TString::kIgnoreCase)) 
+    what = kLocalThreshold;
+  else if (opt.Contains("gain",TString::kIgnoreCase)) 
+    what = kLocalPulseGain;
+  else if (opt.Contains("pedestal",TString::kIgnoreCase)) 
+    what = kLocalPedestal;
+  else if (opt.Contains("noise",TString::kIgnoreCase)) 
+    what = kLocalPedestalWidth;
+  else if (opt.Contains("zero",TString::kIgnoreCase)) 
+    what = kLocalZeroSuppression;
+  else if (opt.Contains("rate",TString::kIgnoreCase)) 
+    what = kLocalSampleRate;
+  else if (opt.Contains("min",TString::kIgnoreCase)) 
+    what = kLocalMinStripRange;
+  else if (opt.Contains("max",TString::kIgnoreCase)) 
+    what = kLocalMaxStripRange;
+  else if (opt.Contains("map",TString::kIgnoreCase)) 
+    what = kLocalAltroMap;
+  else {
+    Warning("Draw", "unknown parameter: %s\n\tShould be one of\n\t"
+           "dead, threshold, gain, pedestal, noise, zero, rate, "
+           "min, max, map",  
+           option); 
+    return;
+  }
+
+  TArrayD xbins(3 * 512 + 2 * 256 + 5);
+  Int_t i = 1;
+  Bool_t skip = kTRUE;
+  for (UShort_t det = 1; det <= 3; det++) {
+    UShort_t nRings = (det == 1 ? 1 : 2);
+    for (UShort_t iring = 0; iring < nRings; iring++) {
+      UShort_t nStrip  = (iring == 0 ? 512 : 256);
+      Char_t   ring    = (iring == 0 ? 'I' : 'O');
+      for (UShort_t str = 0; str < nStrip; str++) {
+       // UShort_t nSec    = (iring == 0 ? 20  : 40);
+       // Char_t   ring    = (iring == 0 ? 'I' : 'O');
+       // for (UShort_t sec = 0; sec < nSec; sec++) {
+       Int_t idx = DET2IDX(det, ring, 0, str);
+       // Int_t idx = DET2IDX(det, ring, sec, 0);
+       if (skip) {
+         xbins[i-1] = idx - .5;
+         skip  = kFALSE;
+       }
+       xbins[i] = idx + .5;
+       i++;
+      }
+      skip = kTRUE;
+      i++;
+    }
+  }
+  TArrayD ybins(41);
+  for (/*Int_t*/ i = 0; i < ybins.fN; i++) ybins[i] = Float_t(i - .5);
+  TH2D* hist = new TH2D("calib", Form("Calibration %s", option), 
+                       xbins.fN-1, xbins.fArray,  
+                       ybins.fN-1, ybins.fArray);
+  hist->GetXaxis()->SetTitle("1000 #times detector + 512 #times ring + strip");
+  hist->GetYaxis()->SetTitle("sector");
+  
+  // hist->Draw("Lego");
+  // return;
+  
+  for (UShort_t det = 1; det <= 3; det++) {
+    UShort_t nRings = (det == 1 ? 1 : 2);
+    for (UShort_t iring = 0; iring < nRings; iring++) {
+      UShort_t nSector = (iring == 0 ?  20 : 40);
+      UShort_t nStrip  = (iring == 0 ? 512 : 256);
+      Char_t   ring    = (iring == 0 ? 'I' : 'O');
+      for (UShort_t sec = 0; sec < nSector; sec++) {
+       for (UShort_t str = 0; str < nStrip; str++) {
+         Int_t idx = DET2IDX(det, ring, sec, str);
+         UShort_t ddl, addr, time, sam=0;
+         Double_t val = 0;
+         switch (what) {
+         case kLocalPulseGain:       // Path to PulseGain calib object
+            val = GetPulseGain(det,ring,sec,str); break;
+         case kLocalThreshold:       // Path to PulseGain calib object
+            val = GetThreshold(); break;
+         case kLocalPedestal:        // Path to Pedestal calib object
+            val = GetPedestal(det,ring,sec,str); break;
+         case kLocalPedestalWidth:   // Path to Pedestal calib object
+            val = GetPedestalWidth(det,ring,sec,str); break;
+         case kLocalDead:            // Path to Dead calib object
+            val = IsDead(det,ring,sec,str); break;
+         case kLocalSampleRate:      // Path to SampleRate calib object
+            val = GetSampleRate(det,ring,sec,str); break;
+         case kLocalAltroMap:        // Path to AltroMap calib object
+           Detector2Hardware(det,ring,sec,str,sam,ddl,addr,time); 
+            val = addr; break;
+         case kLocalZeroSuppression: // Path to ZeroSuppression cal object
+            val = GetZeroSuppression(det,ring,sec,str); break;
+         case kLocalMinStripRange:   // Path to strip range cal object
+            val = GetMinStrip(det,ring,sec,str); break;
+         case kLocalMaxStripRange:    // Path to strip range cal object
+            val = GetMaxStrip(det,ring,sec,str); break;
+         }
+         hist->Fill(idx,sec,val);
+         // hist->Fill(idx,str,val);
+       }
+      }
+    }
+  }
+  hist->Draw("lego");
+}
+
+//__________________________________________________________________
+void
+AliFMDParameters::Print(Option_t* option) const
+{
+  // Print information. 
+  // If option contains an 'A' then everything is printed. 
+  // If the option contains the string "FMD" the function will search 
+  // for detector, ring, sector, and strip numbers to print, in the
+  // format 
+  // 
+  //    FMD<detector><ring>[<sector>,<string>] 
+  // 
+  // The wild card '*' means all of <detector>, <ring>, <sector>, or 
+  // <strip>. 
+  TString opt(option);
+  Bool_t showStrips  = opt.Contains("a", TString::kIgnoreCase);
+  UShort_t ds[]      = { 1, 2, 3, 0 };
+  Char_t   rs[]      = { 'I', 'O', '\0' };
+  UShort_t minStrip  = 0;
+  UShort_t maxStrip  = 512;
+  UShort_t minSector = 0;
+  UShort_t maxSector = 40;
+  
+  
+  if (opt.Contains("fmd",TString::kIgnoreCase)) {
+    Int_t   i    = opt.Index("fmd",TString::kIgnoreCase);
+    Int_t   j    = opt.Index("]",TString::kIgnoreCase);
+    if (j != kNPOS)
+      showStrips    = kTRUE;
+    else 
+      j = opt.Length();
+    enum {
+      kReadDet, 
+      kReadRing, 
+      kReadLbrack,
+      kReadSector,
+      kReadComma,
+      kReadStrip,
+      kReadRbrack, 
+      kEnd
+    } state = kReadDet;
+    std::stringstream s(opt(i+4, j-i-3).Data());
+    while (state != kEnd) {
+      Char_t tmp = s.peek();
+      if (tmp == ' ' || tmp == '\t') {
+       s.get();
+       continue;
+      }
+      switch (state) {
+      case kReadDet: { // First, try to kRead the detector 
+       if (tmp == '*') s.get();
+       else { 
+         UShort_t det;
+         s >> det;
+         if (!s.bad()) {
+           ds[0] = det;
+           ds[1] = 0;
+         }
+       }
+       state = (s.bad() ? kEnd : kReadRing);
+      } break;
+      case kReadRing: { // Then try to read the ring;
+       Char_t ring;
+       s >> ring;
+       if (ring != '*' && !s.bad()) {
+         rs[0] = ring;
+         rs[1] = '\0';
+       }
+       state = (s.bad() ? kEnd : kReadLbrack);
+      } break;
+      case kReadLbrack: { // Try to read a left bracket 
+       Char_t lbrack;
+       s >> lbrack;
+       state = (s.bad() ? kEnd : kReadSector);
+      } break;
+      case kReadSector: { // Try to read a sector 
+       if (tmp == '*') s.get();
+       else {
+         UShort_t sec;
+         s >> sec;
+         if (!s.bad()) {
+           minSector = sec;
+           maxSector = sec + 1;
+         }
+       }
+       state = (s.bad() ? kEnd : kReadComma);
+      } break;
+      case kReadComma: { // Try to read a left bracket 
+       Char_t comma;
+       s >> comma;
+       state = (s.bad() ? kEnd : kReadStrip);
+      } break;
+      case kReadStrip: { // Try to read a strip 
+       if (tmp == '*') s.get();
+       else {
+         UShort_t str;
+         s >> str;
+         if (!s.bad()) {
+           minStrip = str;
+           maxStrip = str + 1;
+         }
+       }
+       state = (s.bad() ? kEnd : kReadRbrack);
+      } break;
+      case kReadRbrack: { // Try to read a left bracket 
+       Char_t rbrack;
+       s >> rbrack;
+       state = kEnd;
+      } break;
+      case kEnd: 
+       break;
+      }
+    }
+  }
+  UShort_t* dp = ds;
+  UShort_t  det;
+  while ((det = *(dp++))) {
+
+    Char_t* rp = rs;
+    Char_t  ring;
+    while ((ring = *(rp++))) {
+      if (det == 1 && ring == 'O') continue;
+      UShort_t min  = GetMinStrip(det, ring, 0, 0);
+      UShort_t max  = GetMaxStrip(det, ring, 0, 0);
+      std::cout << "FMD" << det << ring 
+               << "  Strip range: " 
+               << std::setw(3) << min << "," 
+               << std::setw(3) << max << std::endl;
+
+      UShort_t nSec = ( ring == 'I' ? 20  :  40 );
+      UShort_t nStr = ( ring == 'I' ? 512 : 256 );
+      for (UShort_t sec = minSector; sec < maxSector && sec < nSec; sec++) {
+
+       UShort_t rate = GetSampleRate(det, ring, sec, 0);
+       std::cout << "FMD" << det << ring << "[" << std::setw(2) << sec 
+                 << "] sample rate: " << rate << std::endl;
+
+       if (!showStrips) continue;
+       std::cout 
+         << "  Strip |     Pedestal      |    Gain    | ZS thr. | Address\n" 
+         << "--------+-------------------+------------+---------+---------" 
+         << std::endl;
+        for (UShort_t str = minStrip; str < nStr && str < maxStrip; str++) {
+         if (str == minStrip) std::cout << std::setw(3) << sec << ",";
+         else std::cout << "    ";
+         std::cout << std::setw(3) << str << " | ";
+         if (IsDead(det, ring, sec, str)) {
+           std::cout << "dead" << std::endl;
+           continue;
+         }
+         UShort_t ddl, addr, time, sam=0;
+         Detector2Hardware(det, ring, sec, str, sam, ddl, addr, time);
+         std::cout << std::setw(7) << GetPedestal(det, ring, sec, str) 
+                   << "+/-" << std::setw(7) 
+                   << GetPedestalWidth(det, ring, sec, str) 
+                   << " | " << std::setw(10) 
+                   << GetPulseGain(det, ring, sec, str) 
+                   << " | " << std::setw(7) 
+                   << GetZeroSuppression(det, ring, sec, str) 
+                   << " | 0x" << std::hex << std::setw(4) 
+                   << std::setfill('0') << ddl << ",0x" << std::setw(3) 
+                   << addr << std::dec << std::setfill(' ') << std::endl;
+        } // for (strip)
+      } // for (sector)
+      std::cout
+       << "=============================================================" 
+       << std::endl;
+    } // while (ring)
+  } // while (det)
+  
+}
+
+//__________________________________________________________________
+AliCDBEntry*
+AliFMDParameters::GetEntry(const char* path, AliFMDPreprocessor* pp, 
+                          Bool_t fatal) const
+{
+  // 
+  // Get an entry from either global AliCDBManager or passed
+  // AliFMDPreprocessor. 
+  // 
+  // Parameters:
+  //    path  Path to CDB object. 
+  //    pp    AliFMDPreprocessor 
+  //    fatal If true, raise a fatal flag if we didn't get the entry.
+  // Return:
+  //    AliCDBEntry if found 
+  // 
+  AliCDBEntry* entry = 0;
+  if (!pp) {
+    AliCDBManager* cdb = AliCDBManager::Instance();
+    entry              = cdb->Get(path);
+  }
+  else {
+    const char* third  = gSystem->BaseName(path);
+    const char* second = gSystem->BaseName(gSystem->DirName(path));
+    entry              = pp->GetFromCDB(second, third);
+  }
+  if (!entry) { 
+    TString msg(Form("No %s found in CDB, perhaps you need to "
+                    "use AliFMDCalibFaker?", path));
+    if (fatal) { AliFatal(msg.Data()); }
+    else       AliLog::Message(AliLog::kWarning, msg.Data(), "FMD", 
+                              "AliFMDParameters", "GetEntry", __FILE__, 
+                              __LINE__);
+    return 0;
+  }
+  if (entry && AliLog::GetDebugLevel("FMD", "") > 0) { 
+    AliInfoF("Got entry %p for %s", entry, path);
+    entry->PrintId();
+    entry->PrintMetaData();                    
+    entry->Print();
+  }
+  return entry;
+}
+
+    
+//__________________________________________________________________
+void
+AliFMDParameters::InitPulseGain(AliFMDPreprocessor* pp)
+{
+  // 
+  // Initialize gains.  Try to get them from CDB 
+  // 
+  // Parameters:
+  //    pp Pre-processor if called from shuttle
+  //
+  AliCDBEntry*   gain     = GetEntry(fgkPulseGain, pp);
+  if (!gain) return;
+  
+  AliFMDDebug(5, ("Got gain from CDB"));
+  fPulseGain = dynamic_cast<AliFMDCalibGain*>(gain->GetObject());
+  if (!fPulseGain) AliFatal("Invalid pulser gain object from CDB");
+  if (!fPulseGain->Values().Ptr()) 
+    AliFatal("Empty pulser gain object from CDB");
+}
+//__________________________________________________________________
+void
+AliFMDParameters::InitPedestal(AliFMDPreprocessor* pp)
+{
+  //
+  // Initialize pedestals.  Try to get them from CDB
+  // 
+  // Parameters:
+  //    pp Pre-processor if called from shuttle
+  //
+  AliCDBEntry*   pedestal = GetEntry(fgkPedestal, pp);
+  if (!pedestal) return;
+
+  AliFMDDebug(5, ("Got pedestal from CDB"));
+  fPedestal = dynamic_cast<AliFMDCalibPedestal*>(pedestal->GetObject());
+  if (!fPedestal) AliFatal("Invalid pedestal object from CDB");
+  if (!fPedestal->Values().Ptr()) AliFatal("Empty pedestal object from CDB");
+}
+
+//__________________________________________________________________
+void
+AliFMDParameters::InitDeadMap(AliFMDPreprocessor* pp)
+{
+  //
+  // Initialize dead map.  Try to get it from CDB
+  // 
+  // Parameters:
+  //    pp Pre-processor if called from shuttle
+  //
+  AliCDBEntry*   deadMap  = GetEntry(fgkDead, pp);
+  if (!deadMap) return;
+  
+  AliFMDDebug(5, ("Got dead map from CDB"));
+  fDeadMap = dynamic_cast<AliFMDCalibDeadMap*>(deadMap->GetObject());
+  if (!fDeadMap) AliFatal("Invalid dead map object from CDB");
+  if (!fDeadMap->Ptr()) AliFatal("Empty dead map object from CDB");
+}
+
+//__________________________________________________________________
+void
+AliFMDParameters::InitZeroSuppression(AliFMDPreprocessor* pp)
+{
+  //
+  // Initialize zero suppression thresholds.  Try to get them from CDB
+  // 
+  // Parameters:
+  //    pp Pre-processor if called from shuttle
+  //
+  AliCDBEntry*   zeroSup  = GetEntry(fgkZeroSuppression, pp);
+  if (!zeroSup) return;
+  AliFMDDebug(5, ("Got zero suppression from CDB"));
+  fZeroSuppression = 
+    dynamic_cast<AliFMDCalibZeroSuppression*>(zeroSup->GetObject());
+  if (!fZeroSuppression)AliFatal("Invalid zero suppression object from CDB");
+  if (!fZeroSuppression->Ptr()) {
+    AliWarningF("Empty zero suppression object from CDB, assuming %d",
+               fFixedZeroSuppression);
+    AliCDBManager* cdbMan = AliCDBManager::Instance();
+    if(!cdbMan || !cdbMan->GetCacheFlag())
+      delete fZeroSuppression;
+    fZeroSuppression = 0;
+  }
+}
+
+//__________________________________________________________________
+void
+AliFMDParameters::InitSampleRate(AliFMDPreprocessor* pp)
+{
+  //
+  // Initialize sample rates.  Try to get them from CDB
+  // 
+  // Parameters:
+  //    pp Pre-processor if called from shuttle
+  //
+  AliCDBEntry*   sampRat  = GetEntry(fgkSampleRate, pp);
+  if (!sampRat) return;
+  AliFMDDebug(5, ("Got zero suppression from CDB"));
+  fSampleRate = dynamic_cast<AliFMDCalibSampleRate*>(sampRat->GetObject());
+  if (!fSampleRate) AliFatal("Invalid sample rate object from CDB");
+  if (!fSampleRate->Rates().Ptr()) 
+    AliFatal("empty sample rate object from CDB");
+}
+
+//__________________________________________________________________
+void
+AliFMDParameters::InitAltroMap(AliFMDPreprocessor* pp)
+{
+  //
+  // Initialize hardware map.  Try to get it from CDB
+  // 
+  // Parameters:
+  //    pp Pre-processor if called from shuttle
+  //
+  if (fAltroMap) { 
+    delete fAltroMap;
+    fAltroMap = 0;
+  }
+  AliCDBEntry*   hwMap    = GetEntry(fgkAltroMap, pp, kFALSE);       
+  if (!hwMap) return;
+
+  AliFMDDebug(5, ("Got ALTRO map from CDB"));
+  fAltroMap = dynamic_cast<AliFMDAltroMapping*>(hwMap->GetObject());
+  if (!fAltroMap) {
+    AliFatal("Invalid ALTRO map object from CDB");
+    fAltroMap = new AliFMDAltroMapping;
+  }
+}
+
+//__________________________________________________________________
+void
+AliFMDParameters::InitStripRange(AliFMDPreprocessor* pp)
+{
+  //
+  // Initialize strip range.  Try to get it from CDB
+  // 
+  // Parameters:
+  //    pp Pre-processor if called from shuttle
+  //
+  AliCDBEntry*   range    = GetEntry(fgkStripRange, pp);
+  if (!range) return;
+  AliFMDDebug(5, ("Got strip range from CDB"));
+  fStripRange = dynamic_cast<AliFMDCalibStripRange*>(range->GetObject());
+  if (!fStripRange) AliFatal("Invalid strip range object from CDB");
+  if (!fStripRange->Ranges().Ptr()) 
+    AliFatal("Empty strip range object from CDB");
 }
 
+
 //__________________________________________________________________
 Float_t
 AliFMDParameters::GetThreshold() const
 {
+  // 
+  // Get the threshold in the pulser gain 
+  // 
+  // 
+  // Return:
+  //    Threshold from pulser 
+  //
   if (!fPulseGain) return fFixedThreshold;
   return fPulseGain->Threshold();
 }
@@ -87,20 +835,33 @@ Float_t
 AliFMDParameters::GetPulseGain(UShort_t detector, Char_t ring, 
                               UShort_t sector, UShort_t strip) const
 {
-  // Returns the pulser calibrated gain for strip # strip in sector #
-  // sector or ring id ring of detector # detector. 
   // 
-  // For simulation, this is normally set to 
+  // Gain of pre-amp. for strip, sector, ring, detector 
+  //
+  // For simulations this is normally set to 
+  //
+  // @f[ 
+  //  \frac{\mbox{VA1_MIP_Range}{\mbox{ALTRO_channel_size}}\mbox{MIP_Energy_Loss}
+  // @f]
   // 
-  //       VA1_MIP_Range 
-  //    ------------------ * MIP_Energy_Loss
-  //    ALTRO_channel_size
   // 
+  // Parameters:
+  //    detector Detector # (1-3)
+  //    ring     Ring ID ('I' or 'O')
+  //    sector   Sector number (0-39)
+  //    strip    Strip number (0-511)
+  //
+  // Return:
+  //    Gain of pre-amp.  
+  //
   if (!fPulseGain) { 
     if (fFixedPulseGain <= 0)
       fFixedPulseGain = fVA1MipRange * GetEdepMip() / fAltroChannelSize;
     return fFixedPulseGain;
   }  
+  AliFMDDebug(50, ("pulse gain for FMD%d%c[%2d,%3d]=%f",
+                   detector, ring, sector, strip,
+                   fPulseGain->Value(detector, ring, sector, strip)));
   return fPulseGain->Value(detector, ring, sector, strip);
 }
 
@@ -109,7 +870,24 @@ Bool_t
 AliFMDParameters::IsDead(UShort_t detector, Char_t ring, 
                         UShort_t sector, UShort_t strip) const
 {
+  // 
+  // Whether the strip is considered dead
+  // 
+  // Parameters:
+  //    detector Detector # (1-3)
+  //    ring     Ring ID ('I' or 'O')
+  //    sector   Sector number (0-39)
+  //    strip    Strip number (0-511)
+  //
+  // Return:
+  //    @c true if the strip is considered dead, @c false if it's
+  // OK.
+  //
   if (!fDeadMap) return kFALSE;
+  AliFMDDebug(50, ("Dead for FMD%d%c[%2d,%3d]=%s",
+                   detector, ring, sector, strip,
+                   fDeadMap->operator()(detector, ring, sector, strip) ? 
+                   "no" : "yes"));
   return fDeadMap->operator()(detector, ring, sector, strip);
 }
 
@@ -118,18 +896,105 @@ UShort_t
 AliFMDParameters::GetZeroSuppression(UShort_t detector, Char_t ring, 
                                     UShort_t sector, UShort_t strip) const
 {
+  // 
+  // zero suppression threshold (in ADC counts)
+  // 
+  // Parameters:
+  //    detector Detector # (1-3)
+  //    ring     Ring ID ('I' or 'O')
+  //    sector   Sector number (0-39)
+  //    strip    Strip number (0-511)
+  //
+  // Return:
+  //    zero suppression threshold (in ADC counts) 
+  //
   if (!fZeroSuppression) return fFixedZeroSuppression;
+
+  // In case of empty zero suppression objects. 
+  if (!fZeroSuppression->Ptr() || 
+      fZeroSuppression->MaxIndex() <= 0) return fFixedZeroSuppression;
+
   // Need to map strip to ALTRO chip. 
+  AliFMDDebug(50, ("zero sup. for FMD%d%c[%2d,%3d]=%d",
+                   detector, ring, sector, strip,
+                   fZeroSuppression->operator()(detector, ring, 
+                                                sector, strip)));
   return fZeroSuppression->operator()(detector, ring, sector, strip/128);
 }
 
 //__________________________________________________________________
 UShort_t
-AliFMDParameters::GetSampleRate(UShort_t ddl) const
+AliFMDParameters::GetSampleRate(UShort_t det, Char_t ring, UShort_t sector, 
+                               UShort_t str) const
 {
+  // 
+  // Get the sampling rate
+  // 
+  // Parameters:
+  //    detector Detector # (1-3)
+  //    ring     Ring ID ('I' or 'O')
+  //    sector   Sector number (0-39)
+  //    strip    Strip number (0-511)
+  //
+  // Return:
+  //    The sampling rate 
+  //
   if (!fSampleRate) return fFixedSampleRate;
   // Need to map sector to digitizier card. 
-  return fSampleRate->Rate(ddl);
+  UInt_t ret = fSampleRate->Rate(det, ring, sector, str);
+  AliFMDDebug(50, ("Sample rate for FMD%d%c[%2d,%3d]=%d", 
+                   det, ring, sector, str, ret));
+  return ret;
+}
+
+//__________________________________________________________________
+UShort_t
+AliFMDParameters::GetMinStrip(UShort_t det, Char_t ring, UShort_t sector, 
+                             UShort_t str) const
+{
+  // 
+  // Get the minimum strip in the read-out range
+  // 
+  // Parameters:
+  //    detector Detector # (1-3)
+  //    ring     Ring ID ('I' or 'O')
+  //    sector   Sector number (0-39)
+  //    strip    Strip number (0-511)
+  //
+  // Return:
+  //    Minimum strip 
+  //
+  if (!fStripRange) return fFixedMinStrip;
+  // Need to map sector to digitizier card. 
+  UInt_t ret = fStripRange->Min(det, ring, sector, str);
+  AliFMDDebug(50, ("Min strip # for FMD%d%c[%2d,%3d]=%d", 
+                   det, ring, sector, str, ret));
+  return ret;
+}
+
+//__________________________________________________________________
+UShort_t
+AliFMDParameters::GetMaxStrip(UShort_t det, Char_t ring, UShort_t sector, 
+                             UShort_t str) const
+{
+  // 
+  // Get the maximum strip in the read-out range
+  // 
+  // Parameters:
+  //    detector Detector # (1-3)
+  //    ring     Ring ID ('I' or 'O')
+  //    sector   Sector number (0-39)
+  //    strip    Strip number (0-511)
+  //
+  // Return:
+  //    Maximum strip 
+  //
+  if (!fStripRange) return fFixedMaxStrip;
+  // Need to map sector to digitizier card. 
+  UInt_t ret = fStripRange->Max(det, ring, sector, str);
+  AliFMDDebug(50, ("Max strip # for FMD%d%c[%2d,%3d]=%d", 
+                   det, ring, sector, str, ret));
+  return ret;
 }
 
 //__________________________________________________________________
@@ -137,7 +1002,22 @@ Float_t
 AliFMDParameters::GetPedestal(UShort_t detector, Char_t ring, 
                              UShort_t sector, UShort_t strip) const
 {
+  // 
+  // Get mean of pedestal
+  // 
+  // Parameters:
+  //    detector Detector # (1-3)
+  //    ring     Ring ID ('I' or 'O')
+  //    sector   Sector number (0-39)
+  //    strip    Strip number (0-511)
+  //
+  // Return:
+  //    Mean of pedestal 
+  //
   if (!fPedestal) return fFixedPedestal;
+  AliFMDDebug(50, ("pedestal for FMD%d%c[%2d,%3d]=%f",
+                   detector, ring, sector, strip,
+                   fPedestal->Value(detector, ring, sector, strip)));
   return fPedestal->Value(detector, ring, sector, strip);
 }
 
@@ -146,236 +1026,234 @@ Float_t
 AliFMDParameters::GetPedestalWidth(UShort_t detector, Char_t ring, 
                                   UShort_t sector, UShort_t strip) const
 {
+  // 
+  // Width of pedestal
+  // 
+  // Parameters:
+  //    detector Detector # (1-3)
+  //    ring     Ring ID ('I' or 'O')
+  //    sector   Sector number (0-39)
+  //    strip    Strip number (0-511)
+  //
+  // Return:
+  //    Width of pedestal 
+  //
   if (!fPedestal) return fFixedPedestalWidth;
+  AliFMDDebug(50, ("pedetal width for FMD%d%c[%2d,%3d]=%f",
+                   detector, ring, sector, strip,
+                   fPedestal->Width(detector, ring, sector, strip)));
   return fPedestal->Width(detector, ring, sector, strip);
 }
   
-                             
-
 //__________________________________________________________________
-Float_t
-AliFMDParameters::GetEdepMip() const 
-{ 
-  // Get energy deposited by a MIP in the silicon sensors
-  if (fEdepMip <= 0){
-    AliFMDGeometry* fmd = AliFMDGeometry::Instance();
-    fEdepMip = (fSiDeDxMip 
-               * fmd->GetRing('I')->GetSiThickness() 
-               * fmd->GetSiDensity());
-  }
-  return fEdepMip;
+AliFMDAltroMapping*
+AliFMDParameters::GetAltroMap() const
+{
+  // 
+  // Get the map that translates hardware to detector coordinates 
+  //
+  // Return:
+  //    Get the map that translates hardware to detector
+  // coordinates 
+  // 
+  return fAltroMap;
 }
 
-//__________________________________________________________________
-Bool_t
-AliFMDParameters::Hardware2Detector(UInt_t ddl, UInt_t addr, UShort_t& det,
-                                   Char_t& ring, UShort_t& sec, 
-                                   UShort_t& str) const
-{
-  // Translate a hardware address to detector coordinates. 
-  // The detector is simply 
-  // 
-  //    ddl - kBaseDDL + 1
-  // 
-  // The ring number, sector, and strip number is given by the addr
-  // argument.  The address argument, has the following format 
-  // 
-  //   12            7          4          0
-  //   +-------------+----------+----------+
-  //   | Board       | ALTRO    | Channel  |
-  //   +-------------+----------+----------+
-  // 
-  // The board number identifier among other things the ring.  There's
-  // up to 4 boards per DDL, and the two first (0 and 1) corresponds
-  // to the inner rings, while the two last (2 and 3) corresponds to
-  // the outer rings. 
-  // 
-  // The board number and ALTRO number together identifies the sensor,
-  // and hence.  The lower board number (0 or 2) are the first N / 2
-  // sensors (where N is the number of sensors in the ring).  
-  // 
-  // There are 3 ALTRO's per card, and each ALTRO serves up to 4
-  // sensors.  Which of sensor is determined by the channel number.
-  // For the inner rings, the map is
-  // 
-  //    ALTRO 0, Channel  0 to  7   -> Sensor 0 or 5
-  //    ALTRO 0, Channel  8 to 15   -> Sensor 1 or 6
-  //    ALTRO 1, Channel  0 to  7   -> Sensor 2 or 7 
-  //    ALTRO 2, Channel  0 to  7   -> Sensor 3 or 8
-  //    ALTRO 2, Channel  8 to 15   -> Sensor 4 or 9
-  // 
-  // For the outer rings, the map is 
-  // 
-  //    ALTRO 0, Channel  0 to  3   -> Sensor 0 or 10
-  //    ALTRO 0, Channel  4 to  7   -> Sensor 1 or 11
-  //    ALTRO 0, Channel  8 to 11   -> Sensor 2 or 12
-  //    ALTRO 0, Channel 12 to 15   -> Sensor 3 or 13
-  //    ALTRO 1, Channel  0 to  3   -> Sensor 4 or 14
-  //    ALTRO 1, Channel  4 to  7   -> Sensor 5 or 15
-  //    ALTRO 2, Channel  0 to  3   -> Sensor 6 or 16
-  //    ALTRO 2, Channel  4 to  7   -> Sensor 7 or 17
-  //    ALTRO 2, Channel  8 to 11   -> Sensor 8 or 18
-  //    ALTRO 2, Channel 12 to 15   -> Sensor 9 or 19
-  // 
-  // Which divison of the sensor we're in, depends on the channel
-  // number only.  For the inner rings, the map is 
-  // 
-  //    Channel 0                   -> Sector 0, strips   0-127
-  //    Channel 1                   -> Sector 1, strips   0-127
-  //    Channel 3                   -> Sector 0, strips 128-255
-  //    Channel 4                   -> Sector 1, strips 128-255
-  //    Channel 5                   -> Sector 0, strips 256-383
-  //    Channel 6                   -> Sector 1, strips 256-383
-  //    Channel 7                   -> Sector 0, strips 384-511
-  //    Channel 8                   -> Sector 1, strips 384-511 
-  // 
-  // There are only half as many strips in the outer sensors, so there
-  // only 4 channels are used for a full sensor.  The map is 
-  // 
-  //    Channel 0                   -> Sector 0, strips   0-127
-  //    Channel 1                   -> Sector 1, strips   0-127
-  //    Channel 3                   -> Sector 0, strips 128-255
-  //    Channel 4                   -> Sector 1, strips 128-255
-  // 
-  // With this information, we can decode the hardware address to give
-  // us detector coordinates, unique at least up a 128 strips.  We
-  // return the first strip in the given range. 
-  //
-  det          =  (ddl - kBaseDDL) + 1;
-  UInt_t board =  (addr >> 7) & 0x1F;
-  UInt_t altro =  (addr >> 4) & 0x7;
-  UInt_t chan  =  (addr & 0xf);
-  if (board > 3) {
-    AliError(Form("Invalid board address %d for the FMD", board));
+
+//____________________________________________________________________
+Bool_t 
+AliFMDParameters::Hardware2Detector(UShort_t  ddl,       UShort_t addr,
+                                   UShort_t  timebin,   
+                                   UShort_t& det,       Char_t&  ring, 
+                                   UShort_t& sec,       Short_t& str,
+                                   UShort_t& sam) const
+{
+  // 
+  // Map a hardware address into a detector index. 
+  // 
+  // Parameters:
+  //    ddl        Hardware DDL number 
+  //    addr       Hardware address.  
+  //    timebin    Timebin 
+  //    det        On return, the detector #
+  //    ring       On return, the ring ID
+  //    sec        On return, the sector #
+  //    str        On return, the base of strip #
+  //    sam        On return, the sample number for this strip
+  //
+  // Return:
+  //    @c true on success, false otherwise 
+  //
+  if (!fAltroMap) return kFALSE;
+  UShort_t board, chip, chan;
+  fAltroMap->ChannelAddress(addr, board, chip, chan);
+  return Hardware2Detector(ddl,board,chip,chan,timebin,det,ring,sec,str,sam);
+}
+//____________________________________________________________________
+Bool_t 
+AliFMDParameters::Hardware2Detector(UShort_t  ddl,       UShort_t   board,
+                                   UShort_t  chip,      UShort_t   chan,
+                                   UShort_t  timebin,   
+                                   UShort_t& det,       Char_t&   ring, 
+                                   UShort_t& sec,       Short_t& str,
+                                   UShort_t& sam) const
+{
+  // 
+  // Map a hardware address into a detector index. 
+  // 
+  // Parameters:
+  //    ddl        Hardware DDL number 
+  //    board      FEC number
+  //    altro      ALTRO number 
+  //    channel    Channel number 
+  //    timebin    Timebin 
+  //    det        On return, the detector #
+  //    ring       On return, the ring ID
+  //    sec        On return, the sector #
+  //    str        On return, the base of strip #
+  //    sam        On return, the sample number for this strip
+  //
+  // Return:
+  //    @c true on success, false otherwise 
+  //
+  if (!fAltroMap) {
+    AliFMDDebug(1, ("No ALTRO map available"));
+    return kFALSE;
+  }
+  if (fAltroMap->DDL2Detector(ddl) < 0) { 
+    AliFMDDebug(1, ("Invalid DDL number %d", ddl));
     return kFALSE;
   }
-  if (altro > 2) {
-    AliError(Form("Invalid ALTRO address %d for the FMD digitizer %d", 
-                 altro, board));
+  det = fAltroMap->DDL2Detector(ddl);
+  Short_t stripBase = 0;
+  if (!fAltroMap->Channel2StripBase(board,chip,chan, ring, sec, stripBase)) {
+    AliFMDDebug(1, ("Failed to translate  "
+                   "%d/0x%02x/0x%x/0x%x/%04d -> "
+                   "FMD%d%c[%2d,%3d] to detector", 
+                   ddl, board, chip, chan, timebin, 
+                   det, ring, sec, stripBase));
     return kFALSE;
   }
-  ring         =  (board > 1 ? 'O' : 'I');
-  UInt_t nsen  =  (ring == 'I' ? 10 : 20);
-  UInt_t nsa   =  (ring == 'I' ? 2 : 4);   // Sensors per ALTRO
-  UInt_t ncs   =  (ring == 'I' ? 8 : 4);   // Channels per sensor 
-  UInt_t sen   =  (board % 2) * nsen / 2;  // Base for half-ring
-  sen          += chan / ncs + (altro == 0 ? 0   : 
-                               altro == 1 ? nsa : UInt_t(1.5 * nsa));
-  sec          =  2 * sen + (chan % 2);
-  str          =  (chan % ncs) / 2 * 128;
+  UShort_t preSamples = GetPreSamples(det, ring, sec, stripBase);
+  UShort_t sampleRate = GetSampleRate(det, ring, sec, stripBase);
+  Short_t stripOff = 0;
+  fAltroMap->Timebin2Strip(sec, timebin, preSamples, sampleRate, stripOff, sam);
+  str = stripBase + stripOff;
+  AliFMDDebug(50, ("%d/0x%02x/0x%x/0x%x/%04d -> FMD%d%c[%02d,%03d]-%d"
+                 " (pre=%2d, rate=%d)", 
+                  ddl, board, chip, chan, timebin, 
+                  det, ring, sec, str, sam, preSamples, sampleRate));
   return kTRUE;
 }
 
-//__________________________________________________________________
-Bool_t
-AliFMDParameters::Detector2Hardware(UShort_t det, Char_t ring, UShort_t sec, 
-                                   UShort_t str, UInt_t& ddl, UInt_t& addr) 
-  const
-{
-  // Translate detector coordinates to a hardware address.
-  // The ddl is simply 
-  // 
-  //    kBaseDDL + (det - 1)
-  // 
-  // The ring number, sector, and strip number must be encoded into a
-  // hardware address.  The address argument, will have the following
-  // format on output
-  // 
-  //   12            7          4          0
-  //   +-------------+----------+----------+
-  //   | Board       | ALTRO    | Channel  |
-  //   +-------------+----------+----------+
-  // 
-  // The board number is given by the ring and sector.  The inner
-  // rings board 0 and 1, while the outer are 2 and 3.  Which of these
-  // depends on the sector.  The map is 
-  // 
-  //    Ring I, sector  0- 9       ->   board 0 
-  //    Ring I, sector 10-19       ->   board 1
-  //    Ring O, sector  0-19       ->   board 2 
-  //    Ring O, sector 20-39       ->   board 3
-  // 
-  // There are 3 ALTRO's per board.  The ALTRO number is given by the
-  // sector number.  For the inner rings, these are given by
-  // 
-  //    Sector  0- 3  or  10-13    ->   ALTRO 0 
-  //    Sector  4- 5  or  14-15    ->   ALTRO 1 
-  //    Sector  6- 9  or  16-19    ->   ALTRO 2 
-  // 
-  // For the outers, it's given by 
-  // 
-  //    Sector  0- 7  or  20-27    ->   ALTRO 0 
-  //    Sector  8-11  or  28-31    ->   ALTRO 1 
-  //    Sector 12-19  or  32-39    ->   ALTRO 2 
-  //
-  // The channel number is given by the sector and strip number.  For
-  // the inners, the map is 
-  // 
-  //    Sector  0, strips   0-127  ->   Channel  0
-  //    Sector  0, strips 128-255  ->   Channel  2
-  //    Sector  0, strips 256-383  ->   Channel  4
-  //    Sector  0, strips 384-511  ->   Channel  6
-  //    Sector  1, strips   0-127  ->   Channel  1
-  //    Sector  1, strips 128-255  ->   Channel  3
-  //    Sector  1, strips 256-383  ->   Channel  5
-  //    Sector  1, strips 384-511  ->   Channel  7
-  //    Sector  2, strips   0-127  ->   Channel  8
-  //    Sector  2, strips 128-255  ->   Channel 10
-  //    Sector  2, strips 256-383  ->   Channel 12
-  //    Sector  2, strips 384-511  ->   Channel 14
-  //    Sector  3, strips   0-127  ->   Channel  9
-  //    Sector  3, strips 128-255  ->   Channel 11
-  //    Sector  3, strips 256-383  ->   Channel 13
-  //    Sector  3, strips 384-511  ->   Channel 15
-  // 
-  // and so on, up to sector 19.  For the outer, the map is 
-  // 
-  //    Sector  0, strips   0-127  ->   Channel  0
-  //    Sector  0, strips 128-255  ->   Channel  2
-  //    Sector  1, strips   0-127  ->   Channel  1
-  //    Sector  1, strips 128-255  ->   Channel  3
-  //    Sector  2, strips   0-127  ->   Channel  4
-  //    Sector  2, strips 128-255  ->   Channel  6
-  //    Sector  3, strips   0-127  ->   Channel  5
-  //    Sector  3, strips 128-255  ->   Channel  7
-  //    Sector  4, strips   0-127  ->   Channel  8
-  //    Sector  4, strips 128-255  ->   Channel 10
-  //    Sector  5, strips   0-127  ->   Channel  9
-  //    Sector  5, strips 128-255  ->   Channel 11
-  //    Sector  6, strips   0-127  ->   Channel 12
-  //    Sector  6, strips 128-255  ->   Channel 14
-  //    Sector  7, strips   0-127  ->   Channel 13
-  //    Sector  7, strips 128-255  ->   Channel 15
-  // 
-  // and so on upto sector 40. 
-  // 
-  // With this information, we can decode the detector coordinates to
-  // give us a unique hardware address 
-  //
-  ddl          =  kBaseDDL + (det - 1);
-  UInt_t nsen  =  (ring == 'I' ? 10 : 20);
-  UInt_t nsa   =  (ring == 'I' ? 2 : 4);   // Sensors per ALTRO
-  UInt_t ncs   =  (ring == 'I' ? 8 : 4);   // Channels per sensor 
-  UInt_t bbase =  (ring == 'I' ? 0 : 2);
-  UInt_t board =  bbase + sec / nsen;
-  UInt_t lsen  =  (sec - (board - bbase) * nsen);
-  UInt_t altro =  (lsen < 2 * nsa ? 0 : (lsen < 3 * nsa ? 1 : 2));
-  UInt_t sbase =  (lsen < 2 * nsa ? 0 : (lsen < 3 * nsa ? 2*nsa : 3*nsa));
-  UInt_t chan  =  (sec % 2) + (lsen-sbase) / 2 * ncs + 2 * str / 128;
-  AliDebug(40, Form("\n"
-                   "  chan = (%d %% 2) + (%d-%d) / %d * %d + 2 * %d / 128\n"
-                   "       = %d + %d + %d = %d", 
-                   sec, lsen, sbase, 2, ncs, str, 
-                   (sec % 2), (lsen - sbase) / 2 * ncs, 
-                   2 * str / 128, chan));
-  addr         =  chan + (altro << 4) + (board << 7);
-  
-  return kTRUE;
+
+//____________________________________________________________________
+Bool_t 
+AliFMDParameters::Detector2Hardware(UShort_t  det,        Char_t    ring, 
+                                   UShort_t  sec,        UShort_t  str,
+                                   UShort_t  sam, 
+                                   UShort_t& ddl,        UShort_t& board, 
+                                   UShort_t& altro,      UShort_t& channel, 
+                                   UShort_t& timebin) const
+{
+  // 
+  // Map a detector index into a hardware address. 
+  // 
+  // Parameters:
+  //    det         The detector #
+  //    ring        The ring ID
+  //    sec         The sector #
+  //    str         The strip #
+  //    sam         The sample number 
+  //    ddl         On return, hardware DDL number 
+  //    board       On return, the FEC board address (local to DDL)
+  //    altro       On return, the ALTRO number (local to FEC)
+  //    channel     On return, the channel number (local to ALTRO)
+  //    timebin     On return, the timebin number (local to ALTRO)
+  //
+  // Return:
+  //    @c true on success, false otherwise 
+  //
+  if (!fAltroMap) { 
+    AliFMDDebug(1, ("No ALTRO map available"));
+    return kFALSE;
+  }
+  UShort_t preSamples = GetPreSamples(det, ring, sec, str);
+  UShort_t sampleRate = GetSampleRate(det, ring, sec, str);
+  UShort_t strip      = str - GetMinStrip(det,ring,sec,str);
+  return fAltroMap->Detector2Hardware(det, ring, sec, strip, sam,
+                                     preSamples, sampleRate,
+                                     ddl, board, altro, channel, timebin);
 }
 
   
+
+//____________________________________________________________________
+Bool_t 
+AliFMDParameters::Detector2Hardware(UShort_t  det,        Char_t    ring, 
+                                   UShort_t  sec,        UShort_t  str,
+                                   UShort_t  sam, 
+                                   UShort_t&   ddl,        UShort_t&   addr,
+                                   UShort_t& timebin) const
+{
+  // 
+  // Map a detector index into a hardware address. 
+  // 
+  // Parameters:
+  //    det         The detector #
+  //    ring        The ring ID
+  //    sec         The sector #
+  //    str         The strip #
+  //    sam         The sample number 
+  //    ddl         On return, hardware DDL number 
+  //    addr      On return, hardware address.  
+  //    timebin     On return, the timebin number (local to ALTRO)
+  //
+  // Return:
+  //    @c true on success, false otherwise 
+  //
+  if (!fAltroMap) return kFALSE;
+  UShort_t preSamples = GetPreSamples(det, ring, sec, str);
+  UShort_t sampleRate = GetSampleRate(det, ring, sec, str);
+  UShort_t strip      = str - GetMinStrip(det,ring,sec,str);
+  return fAltroMap->Detector2Hardware(det, ring, sec, strip, sam,
+                                     preSamples, sampleRate,
+                                     ddl, addr, timebin);
+}
+
+
+//__________________________________________________________________
+Float_t
+AliFMDParameters::GetEdepMip() const 
+{ 
+  // 
+  // Return:
+  //    The average energy deposited by one MIP 
+  //
+  if (fEdepMip <= 0){
+    AliFMDGeometry* fmd = AliFMDGeometry::Instance();
+    fEdepMip = (fkSiDeDxMip 
+               * fmd->GetRing('I')->GetSiThickness() 
+               * fmd->GetSiDensity());
+  }
+  return fEdepMip;
+}
+//____________________________________________________________________
+Float_t  
+AliFMDParameters::GetDACPerMIP() const
+{
+  // 
+  // This is the conversion from Digital-to-Analog-Converter setting
+  // to the number of MIPs. The number was measured in the NBI lab during
+  // August 2008.
+  //
+  // Return:
+  //    The conversion factor from DAC to ADC 
+  //
+  return 29.67;
   
-  
+}
 //____________________________________________________________________
 //
 // EOF