]> git.uio.no Git - u/mrichter/AliRoot.git/blobdiff - MUON/AliMUONTrackerData.cxx
- Implementing the possibility to histogram the raw adc values when reading
[u/mrichter/AliRoot.git] / MUON / AliMUONTrackerData.cxx
index 898ae37e301381a2b4035097791b61aa97f3f802..dbf97858fde738e0269080c248d419f64a4b0be0 100644 (file)
 
 #include "AliMUONTrackerData.h"
 
+#include "AliCodeTimer.h"
+#include "AliLog.h"
+#include "AliMUON1DArray.h"
+#include "AliMUON1DMap.h"
+#include "AliMUON2DMap.h"
 #include "AliMUONCalibParamND.h"
+#include "AliMUONSparseHisto.h"
 #include "AliMUONVStore.h"
 #include "AliMpBusPatch.h"
+#include "AliMpConstants.h"
 #include "AliMpDDLStore.h"
-#include "AliMpDEManager.h"
 #include "AliMpDEIterator.h"
+#include "AliMpDEManager.h"
 #include "AliMpDetElement.h"
 #include "AliMpHVNamer.h"
-#include "AliCodeTimer.h"
-#include "AliLog.h"
+#include "AliMpManuIterator.h"
 #include <Riostream.h>
+#include <TH1.h>
 #include <TMath.h>
 #include <TObjArray.h>
 #include <TObjString.h>
@@ -62,10 +69,15 @@ fPCBValues(0x0),
 fDimension(dimension*2+fgkExtraDimension),
 fNevents(0x0),
 fDimensionNames(new TObjArray(fDimension+fgkVirtualExtraDimension)),
+fExternalDimensionNames(new TObjArray(dimension)),
 fExternalDimension(dimension),
-fIsRunnable(runnable)
+fIsRunnable(runnable),
+fHistogramming(new Int_t[fExternalDimension]),
+fChannelHistos(0x0)
 {  
   /// ctor
+  memset(fHistogramming,0,sizeof(Int_t)); // histogramming is off by default. Use SetHistogramDimension to turn it on.
+  fExternalDimensionNames->SetOwner(kTRUE);
   fDimensionNames->SetOwner(kTRUE);  
   fDimensionNames->AddAt(new TObjString("occ"),IndexOfOccupancyDimension());
   fDimensionNames->AddAt(new TObjString("N"),IndexOfNumberDimension());
@@ -84,78 +96,128 @@ AliMUONTrackerData::~AliMUONTrackerData()
   delete fChamberValues;
   delete fPCBValues;
   delete fDimensionNames;
+  delete fExternalDimensionNames;
+  delete[] fHistogramming;
+  delete fChannelHistos;
 }
 
 //_____________________________________________________________________________
 Bool_t
 AliMUONTrackerData::Add(const AliMUONVStore& store)
 {
-  /// We first convert the external store to a temporary internal store
-  /// with more dimension (2*store's dimension)
+  /// Add the given external store to our internal store
   
-  AliCodeTimerAuto(GetName())
-  
-  Int_t ndim(NumberOfDimensions()-fgkExtraDimension-fgkVirtualExtraDimension); 
+  AliCodeTimerAuto(GetName());
+    
+  ++fNevents;
+  NumberOfEventsChanged();
   
-  AliMUONVStore* istore = store.Create();
+  if (!fChannelValues)
+  {
+    fChannelValues = store.Create();
+    fManuValues = store.Create();
+    fPCBValues = store.Create();
+    fBusPatchValues = new AliMUON1DMap;
+    fDEValues = new AliMUON1DMap;
+    fChamberValues = new AliMUON1DArray;
+  }
   
   TIter next(store.CreateIterator());
   AliMUONVCalibParam* external;
   
-  AliCodeTimerStart("from external to internal store");
-  
   while ( ( external = static_cast<AliMUONVCalibParam*>(next()) ) )
   {
-    Int_t detElemId = external->ID0();
-    Int_t manuId = external->ID1();
+    if ( external->Dimension() != ExternalDimension() )
+    {
+      AliError(Form("Incompatible dimensions %d vs %d",
+                    external->Dimension(),ExternalDimension()));
+      return kFALSE;
+    }
     
-    AliMpDetElement* de = AliMpDDLStore::Instance()->GetDetElement(detElemId);
+
+    AliMUONVCalibParam* chamber, *de, *busPatch, *pcb, *manu, *channel;
+    AliMpDetElement* mpde;
     
-    AliMUONVCalibParam* internal = static_cast<AliMUONVCalibParam*>
-      (istore->FindObject(detElemId,manuId));
+    Int_t manuId = GetParts(external,chamber,de,busPatch,pcb,manu,channel,mpde);
     
-    if (!internal)
-    {
-      internal = new AliMUONCalibParamND(ndim,external->Size(),
-                                         detElemId, manuId, 
-                                         0.0);
-      istore->Add(internal);
-    }
+    Int_t detElemId = mpde->GetId();
+    
+    Double_t value[] = { 0.0, 0.0 };
+    
+    Int_t nch = mpde->NofChannelsInManu(manuId);
     
     for ( Int_t i = 0; i < external->Size(); ++i ) 
     {
-      Bool_t connectPad = de->IsConnectedChannel(manuId,i);
-      
-      if (!connectPad) continue;
+      Bool_t existingChannel =  ( nch == AliMpConstants::ManuNofChannels() ? kTRUE
+                                                                           : mpde->IsConnectedChannel(manuId,i));
+      // note we only use IsConnectedChannel method when really needed, as
+      // it costs (some) CPU time...
       
-      for ( Int_t j = 0; j < external->Dimension(); ++j )
+      if ( existingChannel ) 
       {
-        Int_t ix = External2Internal(j);
-        
-        Double_t vext = external->IsDoublePrecision() ? 
-          external->ValueAsDouble(i,j) :
-          external->ValueAsFloat(i,j);
+        Bool_t validChannel(kFALSE);
         
-        Double_t sumw = internal->ValueAsDouble(i,ix) + vext;
-        Double_t sumw2 = internal->ValueAsDouble(i,ix+1) + vext*vext;
+        for ( Int_t j = 0; j < external->Dimension(); ++j )
+        {
+          Double_t vext = external->IsDoublePrecision() ? 
+            external->ValueAsDoubleFast(i,j) :
+            external->ValueAsFloatFast(i,j);
+          
+          if ( vext >= AliMUONVCalibParam::InvalidFloatValue() ) continue;
+          
+          validChannel = kTRUE;
+                    
+          Int_t ix = External2Internal(j);
+          
+          value[0] = vext;
+          value[1] = vext*vext;
+          
+          if ( IsHistogrammed(j) )
+          {
+            FillChannel(detElemId,manuId,i,j,vext);
+          }
+          
+          for ( Int_t k = 0; k < 2; ++k ) 
+          {
+            channel->SetValueAsDoubleFast(i,ix+k,channel->ValueAsDoubleFast(i,ix+k)+value[k]);
+
+            manu->SetValueAsDoubleFast(0,ix+k,manu->ValueAsDoubleFast(0,ix+k)+value[k]);            
+            
+            busPatch->SetValueAsDoubleFast(0,ix+k,busPatch->ValueAsDoubleFast(0,ix+k)+value[k]);
+          
+            de->SetValueAsDoubleFast(0,ix+k,de->ValueAsDoubleFast(0,ix+k)+value[k]);
+          
+            chamber->SetValueAsDoubleFast(0,ix+k,chamber->ValueAsDoubleFast(0,ix+k)+value[k]);
+          
+            if ( pcb ) 
+            {
+              pcb->SetValueAsDoubleFast(0,ix+k,pcb->ValueAsDoubleFast(0,ix+k)+value[k]);
+            }
+          }
+        }
         
-        internal->SetValueAsFloat(i,ix,sumw);
-        internal->SetValueAsFloat(i,ix+1,sumw2);
+        if ( validChannel )
+        {
+          channel->SetValueAsDoubleFast(i,IndexOfOccupancyDimension(),
+                                        channel->ValueAsDoubleFast(i,IndexOfOccupancyDimension())+1.0);
+          manu->SetValueAsDoubleFast(0,IndexOfOccupancyDimension(),
+                                                 manu->ValueAsDoubleFast(0,IndexOfOccupancyDimension())+1.0);        
+          busPatch->SetValueAsDoubleFast(0,IndexOfOccupancyDimension(),
+                                                         busPatch->ValueAsDoubleFast(0,IndexOfOccupancyDimension())+1.0);        
+          de->SetValueAsDoubleFast(0,IndexOfOccupancyDimension(),
+                                             de->ValueAsDoubleFast(0,IndexOfOccupancyDimension())+1.0);        
+          chamber->SetValueAsDoubleFast(0,IndexOfOccupancyDimension(),
+                                                       chamber->ValueAsDoubleFast(0,IndexOfOccupancyDimension())+1.0); 
+          if ( pcb ) 
+          {
+            pcb->SetValueAsDoubleFast(0,IndexOfOccupancyDimension(),
+                                      pcb->ValueAsDoubleFast(0,IndexOfOccupancyDimension())+1.0);        
+          }
+        }
       }
     }
   }
   
-  AliCodeTimerStop("from external to internal store");
-  
-  /// and we add this internal store to what we already have
-  
-  InternalAdd(*istore);
-  
-  /// delete the temporary internal store.
-  AliCodeTimerStart("delete");
-  delete istore;
-  AliCodeTimerStop("delete");
-  
   return kTRUE;
 }
 
@@ -171,11 +233,57 @@ AliMUONTrackerData::BusPatch(Int_t busPatchId, Int_t dim) const
 
 //_____________________________________________________________________________
 AliMUONVCalibParam* 
-AliMUONTrackerData::BusPatchParam(Int_t busPatchId) const
+AliMUONTrackerData::BusPatchParam(Int_t busPatchId, Bool_t create) const
 {
   /// Return (if it exist), the VCalibParam for a given busPatch
-  return fBusPatchValues ? static_cast<AliMUONVCalibParam*>
-  (fBusPatchValues->FindObject(busPatchId)) : 0x0;
+  
+  AliMUONVCalibParam* busPatch = fBusPatchValues ? static_cast<AliMUONVCalibParam*>
+    (fBusPatchValues->FindObject(busPatchId)) : 0x0;
+  
+  if (!busPatch && create && fBusPatchValues)
+  {
+    busPatch = CreateBusPatchParam(busPatchId);
+    fBusPatchValues->Add(busPatch);
+  }
+  
+  return busPatch;
+}
+
+//_____________________________________________________________________________
+AliMUONVCalibParam* 
+AliMUONTrackerData::CreateBusPatchParam(Int_t busPatchId) const
+{
+  /// Create storage for one bus patch
+  
+  AliCodeTimerAuto("");
+  
+  AliMpBusPatch* bp = AliMpDDLStore::Instance()->GetBusPatch(busPatchId);
+  
+  if (!bp)
+  {
+    AliError(Form("Got an invalid buspatchId = %d",busPatchId));
+    return 0x0;
+  }
+  
+  AliMUONVCalibParam* busPatch = new AliMUONCalibParamND(Dimension(),1,busPatchId,0,0.0);
+  
+  // set the number of channels in that buspatch
+  
+  Int_t nchannels(0);
+  
+  Int_t detElemId = AliMpDDLStore::Instance()->GetDEfromBus(busPatchId);
+  
+  AliMpDetElement* de = AliMpDDLStore::Instance()->GetDetElement(detElemId);
+  
+  for ( Int_t i = 0; i < bp->GetNofManus(); ++i ) 
+  {
+    Int_t manuId = bp->GetManuId(i);
+    nchannels += de->NofChannelsInManu(manuId);
+  }
+  
+  busPatch->SetValueAsDouble(0,IndexOfNumberDimension(),nchannels);
+  
+  return busPatch;
 }
 
 //_____________________________________________________________________________
@@ -190,11 +298,61 @@ AliMUONTrackerData::Chamber(Int_t chamberId, Int_t dim) const
 
 //_____________________________________________________________________________
 AliMUONVCalibParam* 
-AliMUONTrackerData::ChamberParam(Int_t chamberId) const
+AliMUONTrackerData::ChamberParam(Int_t chamberId, Bool_t create) const
 {
   /// Return (if it exist) the VCalibParam for a given chamber
-  return fChamberValues ? static_cast<AliMUONVCalibParam*>
+  
+  AliMUONVCalibParam* chamber =  fChamberValues ? static_cast<AliMUONVCalibParam*>
   (fChamberValues->FindObject(chamberId)) : 0x0;
+  
+  if (!chamber && create && fChamberValues)
+  {
+    chamber = CreateChamberParam(chamberId);
+    fChamberValues->Add(chamber);
+  }
+    
+  return chamber;
+}
+
+//_____________________________________________________________________________
+AliMUONVCalibParam* 
+AliMUONTrackerData::CreateChamberParam(Int_t chamberId) const
+{
+  /// Create storage for one chamber
+  
+  AliCodeTimerAuto("");
+  
+  AliMUONVCalibParam* chamber = new AliMUONCalibParamND(Dimension(),1,chamberId,0,0.0);
+  
+  // set the number of channels in that chamber
+  
+  Int_t nchannels(0);
+  
+  AliMpDEIterator it;
+  
+  it.First(chamberId);
+  
+  while ( !it.IsDone() )
+  {        
+    AliMpDetElement* det = it.CurrentDE();
+    
+    for ( Int_t i = 0; i < det->GetNofBusPatches(); ++i ) 
+    {
+      Int_t busPatchId = det->GetBusPatchId(i);
+      AliMpBusPatch* bp = AliMpDDLStore::Instance()->GetBusPatch(busPatchId);
+      for ( Int_t j = 0; j < bp->GetNofManus(); ++j ) 
+      {
+        Int_t manuId = bp->GetManuId(j);
+        nchannels += det->NofChannelsInManu(manuId);
+      }        
+    }
+    
+    it.Next();
+  }
+  
+  chamber->SetValueAsDouble(0,IndexOfNumberDimension(),nchannels);
+  
+  return chamber;
 }
 
 //_____________________________________________________________________________
@@ -211,14 +369,23 @@ AliMUONTrackerData::Channel(Int_t detElemId, Int_t manuId,
 
 //_____________________________________________________________________________
 AliMUONVCalibParam* 
-AliMUONTrackerData::ChannelParam(Int_t detElemId, Int_t manuId) const
+AliMUONTrackerData::ChannelParam(Int_t detElemId, Int_t manuId,
+                                 AliMUONVCalibParam* external) const
 {
   /// Return (if it exist) the VCalibParam for a given manu
-  return fChannelValues ? static_cast<AliMUONVCalibParam*>
-  (fChannelValues->FindObject(detElemId,manuId)) : 0x0 ;
+  
+  AliMUONVCalibParam* param = fChannelValues ? static_cast<AliMUONVCalibParam*>
+    (fChannelValues->FindObject(detElemId,manuId)) : 0x0 ;
+  
+  if (!param && external && fChannelValues)
+  {
+    param = CreateDouble(*external);
+    fChannelValues->Add(param);
+  }
+  
+  return param;
 }
 
-
 //_____________________________________________________________________________
 void 
 AliMUONTrackerData::Clear(Option_t*)
@@ -229,7 +396,8 @@ AliMUONTrackerData::Clear(Option_t*)
   if ( fBusPatchValues) fBusPatchValues->Clear();
   if ( fPCBValues ) fPCBValues->Clear();
   if ( fDEValues) fDEValues->Clear();
-  if ( fChamberValues) fChamberValues->Clear();
+  if ( fChamberValues ) fChamberValues->Clear();
+  if ( fChannelHistos ) fChannelHistos->Clear();
   fNevents = 0;
   NumberOfEventsChanged();
 }
@@ -240,12 +408,8 @@ AliMUONTrackerData::Count(Int_t detElemId, Int_t manuId,
                           Int_t manuChannel) const
 {
   /// Return the number of times a given channel had data
-  AliMUONVCalibParam* param = static_cast<AliMUONVCalibParam*>
-  (fChannelValues->FindObject(detElemId,manuId));
-  
-  if ( !param ) return 0.0;
   
-  return param->ValueAsDouble(manuChannel,IndexOfOccupancyDimension());
+  return Channel(detElemId,manuId,manuChannel,IndexOfNumberDimension());
 }
 
 //_____________________________________________________________________________
@@ -253,11 +417,14 @@ AliMUONVCalibParam*
 AliMUONTrackerData::CreateDouble(const AliMUONVCalibParam& param) const
 {
   /// Create a double version of VCalibParam, for internal use
-  AliMUONVCalibParam* c = new AliMUONCalibParamND(param.Dimension()+fgkExtraDimension,
-                                 param.Size(),
-                                 param.ID0(),
-                                 param.ID1(),
-                                 0.0);
+  
+  AliCodeTimerAuto("");
+  
+  AliMUONVCalibParam* c = new AliMUONCalibParamND(Dimension(),
+                                                  param.Size(),
+                                                  param.ID0(),
+                                                  param.ID1(),
+                                                  0.0);
   
   for ( Int_t i = 0; i < c->Size(); ++i ) 
   {
@@ -279,11 +446,50 @@ AliMUONTrackerData::DetectionElement(Int_t detElemId, Int_t dim) const
 
 //_____________________________________________________________________________
 AliMUONVCalibParam* 
-AliMUONTrackerData::DetectionElementParam(Int_t detElemId) const
+AliMUONTrackerData::DetectionElementParam(Int_t detElemId, Bool_t create) const
 {
   /// Return (if it exist) the VCalibParam for a given detection element
-  return fDEValues ? static_cast<AliMUONVCalibParam*>
-  (fDEValues->FindObject(detElemId)) : 0x0 ;
+  
+  AliMUONVCalibParam* de = fDEValues ? static_cast<AliMUONVCalibParam*>
+    (fDEValues->FindObject(detElemId)) : 0x0 ;
+  
+  if (!de && create && fDEValues)
+  {
+    de = CreateDetectionElementParam(detElemId);
+    fDEValues->Add(de);
+  }
+  
+  return de;
+  
+}
+
+//_____________________________________________________________________________
+AliMUONVCalibParam* 
+AliMUONTrackerData::CreateDetectionElementParam(Int_t detElemId) const
+{
+  /// Create storage for one detection element
+  
+  AliCodeTimerAuto("");
+  
+  AliMUONVCalibParam*  de = new AliMUONCalibParamND(Dimension(),1,detElemId,0,0.0);
+  
+  AliMpDetElement* det = AliMpDDLStore::Instance()->GetDetElement(detElemId);
+  Int_t nchannels(0);
+  
+  for ( Int_t i = 0; i < det->GetNofBusPatches(); ++i ) 
+  {
+    Int_t busPatchId = det->GetBusPatchId(i);
+    AliMpBusPatch* bp = AliMpDDLStore::Instance()->GetBusPatch(busPatchId);
+    for ( Int_t j = 0; j < bp->GetNofManus(); ++j ) 
+    {
+      Int_t manuId = bp->GetManuId(j);
+      nchannels += det->NofChannelsInManu(manuId);
+    }        
+  }
+  
+  de->SetValueAsDouble(0,IndexOfNumberDimension(),nchannels);
+  
+  return de;
 }
 
 //_____________________________________________________________________________
@@ -303,304 +509,405 @@ AliMUONTrackerData::DimensionName(Int_t dim) const
 }
 
 //_____________________________________________________________________________
-Bool_t 
-AliMUONTrackerData::HasBusPatch(Int_t busPatchId) const
+TString 
+AliMUONTrackerData::ExternalDimensionName(Int_t dim) const
 {
-  /// Whether we have data for a given buspatch
-  return ( BusPatchParam(busPatchId) != 0 );
+  /// Get the name of a given external dimension
+  
+  TObjString* value = static_cast<TObjString*>(fExternalDimensionNames->At(dim));
+  if ( value ) 
+  {
+    return value->String();
+  }
+  else
+  {
+    return TString("Invalid");
+  }  
 }
 
 //_____________________________________________________________________________
-Bool_t 
-AliMUONTrackerData::HasChamber(Int_t chamberId) const
+void
+AliMUONTrackerData::FillChannel(Int_t detElemId, Int_t manuId, Int_t manuChannel,
+                                Int_t dim, Double_t value)
 {
-  /// Whether we have data for a given chamber
-  return ( ChamberParam(chamberId) != 0 );
+  /// Fill histogram of a given channel
+  
+  AliMUONSparseHisto* h = GetChannelHisto(detElemId, manuId, manuChannel,dim);
+  h->Fill(static_cast<Int_t>(TMath::Nint(value)));
 }
 
 //_____________________________________________________________________________
-Bool_t 
-AliMUONTrackerData::HasDetectionElement(Int_t detElemId) const
+TH1*
+AliMUONTrackerData::CreateChannelHisto(Int_t detElemId, Int_t manuId, 
+                                       Int_t manuChannel, Int_t dim)
 {
-  /// Whether we have data for a given detection element
-  return ( DetectionElementParam(detElemId) != 0 );
+  /// Create histogram of a given channel. Note that in order
+  /// to keep memory footprint as low as possible, you should delete
+  /// the returned pointer as soon as possible...
+
+  if ( HasChannel(detElemId, manuId, manuChannel) && IsHistogrammed(dim) )
+  {
+    AliMUONSparseHisto* sh = GetChannelHisto(detElemId,manuId,manuChannel,dim);
+  
+    if ( sh ) 
+    {
+      TH1* h = new TH1I(Form("DE%04dMANU%04dCH%02d_%d",detElemId,manuId,manuChannel,dim),
+                        Form("Data=%s Dim=%s",GetName(),ExternalDimensionName(dim).Data()),
+                        4096,-0.5,4095.5);
+      
+      Add(*h,*sh);
+      return h;
+    }
+  }
+  return 0x0;
 }
 
 //_____________________________________________________________________________
-Bool_t
-AliMUONTrackerData::HasManu(Int_t detElemId, Int_t manuId) const
+void
+AliMUONTrackerData::Add(TH1& h, const AliMUONSparseHisto& sh)
 {
-  /// Whether we have data for a given manu
-  return ( ManuParam(detElemId,manuId) != 0 ); 
+  /// Add sparse histo content to histogram.
+  
+  Double_t entries(h.GetEntries());
+  
+  for ( Int_t i = 0; i < sh.GetNbins(); ++i ) 
+  {
+    Int_t x = sh.GetBinContent(i);
+    Int_t adc, count;
+    sh.Decode(x,adc,count);
+    h.Fill(adc,count);
+    entries += count;
+  }
+  
+  h.SetEntries(entries);
 }
 
 //_____________________________________________________________________________
-Bool_t
-AliMUONTrackerData::HasPCB(Int_t detElemId, Int_t pcbIndex) const
+TH1*
+AliMUONTrackerData::CreateHisto(const char* name, Int_t dim) const
 {
-  /// Whether we have data for a given pcb
-  return ( PCBParam(detElemId,pcbIndex) != 0 ); 
+  /// Create a single histogram
+  return new TH1I(name,Form("Data=%s Dim=%s",GetName(),ExternalDimensionName(dim).Data()),
+                  4096,-0.5,4095.5);
 }
 
 //_____________________________________________________________________________
-Bool_t 
-AliMUONTrackerData::InternalAdd(const AliMUONVStore& store)
+TH1*
+AliMUONTrackerData::CreateBusPatchHisto(Int_t busPatchId, Int_t dim)
 {
-  /// Add the given store to our internal store
-  /// Store must be of dimension = fDimension-1
+  /// Create histogram of a given bus patch. Note that in order
+  /// to keep memory footprint as low as possible, you should delete
+  /// the returned pointer as soon as possible...
   
-  AliCodeTimerAuto(GetName());
+  TH1* h(0x0);
   
-  AliMpDDLStore* ddlStore = AliMpDDLStore::Instance();
-  
-  ++fNevents;
-  NumberOfEventsChanged();
-  
-  if (!fChannelValues)
+  if ( HasBusPatch(busPatchId) && IsHistogrammed(dim)) 
   {
-    fChannelValues = store.Create();
-    fManuValues = store.Create();
-    fBusPatchValues = store.Create();
-    fDEValues = store.Create();
-    fChamberValues = store.Create();
-    fPCBValues = store.Create();
+    h = CreateHisto(Form("BP%04d_%d",busPatchId,dim),dim);
+    AddBusPatchHisto(*h,busPatchId,dim);
   }
   
-  TIter next(store.CreateIterator());
-  AliMUONVCalibParam* external;
-  
-  AliMpHVNamer namer;
-  
-  while ( ( external = static_cast<AliMUONVCalibParam*>(next()) ) )
+  return h;
+}  
+//_____________________________________________________________________________
+void
+AliMUONTrackerData::AddBusPatchHisto(TH1& h, Int_t busPatchId, Int_t dim)
+{
+  /// Add data from one bus patch to the histogram
+      
+  if ( HasBusPatch(busPatchId ) )
   {
-    if ( external->Dimension() != fDimension-fgkExtraDimension ) 
+    AliMpBusPatch* busPatch = AliMpDDLStore::Instance()->GetBusPatch(busPatchId);
+    for ( Int_t i = 0; i < busPatch->GetNofManus(); ++i ) 
     {
-      AliError(Form("Incompatible dimensions %d vs %d",
-                    external->Dimension(),fDimension-fgkExtraDimension));
-      return kFALSE;
+      Int_t manuId = busPatch->GetManuId(i);
+      AddManuHisto(h,busPatch->GetDEId(),manuId,dim);
     }
-    
-    Int_t detElemId = external->ID0();
-    
-    AliMp::StationType stationType = AliMpDEManager::GetStationType(detElemId);
-    
-    Int_t chamberId = AliMpDEManager::GetChamberId(detElemId);
-    
-    Int_t manuId = external->ID1();
-    
-    AliMpDetElement* mpde = ddlStore->GetDetElement(detElemId);
+  }
+}
 
-    Int_t busPatchId = ddlStore->GetBusPatchId(detElemId,manuId);
-    
-    Int_t pcbIndex = -1;
-    
-    if ( stationType == AliMp::kStation345 ) 
-    {
-      pcbIndex = namer.ManuId2PCBIndex(detElemId,manuId);
-    }
 
-    AliMUONVCalibParam* channel = ChannelParam(detElemId,manuId);
-    if (!channel)
-    {
-      channel = CreateDouble(*external);
-      fChannelValues->Add(channel);
-    }
+//_____________________________________________________________________________
+TH1*
+AliMUONTrackerData::CreateDEHisto(Int_t detElemId, Int_t dim)
+{
+  /// Create histogram of a given detection element. Note that in order
+  /// to keep memory footprint as low as possible, you should delete
+  /// the returned pointer as soon as possible...
+  
+  TH1* h(0x0);
+  
+  if ( HasDetectionElement(detElemId) && IsHistogrammed(dim) ) 
+  {
+    h = CreateHisto(Form("DE%04d-%d",detElemId,dim),dim);
+    AddDEHisto(*h,detElemId,dim);
+  }
+  
+  return h;
+}
 
-    AliMUONVCalibParam* manu = ManuParam(detElemId,manuId);
-    if (!manu)
+//_____________________________________________________________________________
+void
+AliMUONTrackerData::AddDEHisto(TH1& h, Int_t detElemId, Int_t dim)
+{
+  /// Add data from one detection element to the histogram
+  
+  if ( HasDetectionElement(detElemId) )
+  {
+    AliMpDetElement* de = AliMpDDLStore::Instance()->GetDetElement(detElemId);
+    for ( Int_t i = 0; i < de->GetNofBusPatches(); ++ i ) 
     {
-      manu = new AliMUONCalibParamND(external->Dimension()+fgkExtraDimension,
-                                     1,
-                                     detElemId,
-                                     manuId,
-                                     0.0);
-      
-      // set the number of channels in that manu
-      
-      AliMpDetElement* de = AliMpDDLStore::Instance()->GetDetElement(detElemId);
-      
-      manu->SetValueAsDouble(0,IndexOfNumberDimension(),de->NofChannelsInManu(manuId));
-      
-      fManuValues->Add(manu);
+      Int_t busPatchId = de->GetBusPatchId(i);
+      AddBusPatchHisto(h,busPatchId,dim);
     }
-    
-    AliMUONVCalibParam* busPatch = BusPatchParam(busPatchId);
-    if (!busPatch)
-    {
-      AliMpBusPatch* bp = AliMpDDLStore::Instance()->GetBusPatch(busPatchId);
-
-      if (!bp)
-      {
-        AliError(Form("Got an invalid buspatchId = %d",busPatchId));
-        continue;
-      }
-      
-      busPatch = new AliMUONCalibParamND(external->Dimension()+fgkExtraDimension,
-                                         1,
-                                         busPatchId,
-                                         0,
-                                         0.0);
-      
-      // set the number of channels in that buspatch
-
-      Int_t nchannels(0);
-      
-      AliMpDetElement* de = AliMpDDLStore::Instance()->GetDetElement(detElemId);
-
-      for ( Int_t i = 0; i < bp->GetNofManus(); ++i ) 
-      {
-        Int_t manuId = bp->GetManuId(i);
-        nchannels += de->NofChannelsInManu(manuId);
-      }
+  }
+}
 
-      busPatch->SetValueAsDouble(0,IndexOfNumberDimension(),nchannels);
-      
-      fBusPatchValues->Add(busPatch);
-    }
+//_____________________________________________________________________________
+TH1*
+AliMUONTrackerData::CreateManuHisto(Int_t detElemId, Int_t manuId, Int_t dim)
+{
+  /// Create histogram of a given manu. Note that in order
+  /// to keep memory footprint as low as possible, you should delete
+  /// the returned pointer as soon as possible...
+  
+  TH1* h(0x0);
+  
+  if ( HasManu(detElemId, manuId) && IsHistogrammed(dim) ) 
+  {
+    h = CreateHisto(Form("DE%04dMANU%04d_%d",detElemId,manuId,dim),dim);
+    AddManuHisto(*h,detElemId,manuId,dim);
+  }
+  
+  return h;
+}
 
-    AliMUONVCalibParam* de = DetectionElementParam(detElemId);
-    if (!de)
+//_____________________________________________________________________________
+void
+AliMUONTrackerData::AddManuHisto(TH1& h, Int_t detElemId, Int_t manuId, Int_t dim)
+{
+  /// Add data from a given manu to histogram
+  
+  if ( HasManu(detElemId,manuId) )
+  {
+    for ( Int_t i = 0; i < AliMpConstants::ManuNofChannels(); ++i ) 
     {
-      de = new AliMUONCalibParamND(external->Dimension()+fgkExtraDimension,
-                                         1,
-                                         detElemId,
-                                         0,
-                                         0.0);
-      
-      AliMpDetElement* det = AliMpDDLStore::Instance()->GetDetElement(detElemId);
-      Int_t nchannels(0);
-      
-      for ( Int_t i = 0; i < det->GetNofBusPatches(); ++i ) 
+      if ( HasChannel(detElemId,manuId,i) )
       {
-        Int_t busPatchId = det->GetBusPatchId(i);
-        AliMpBusPatch* bp = AliMpDDLStore::Instance()->GetBusPatch(busPatchId);
-        for ( Int_t j = 0; j < bp->GetNofManus(); ++j ) 
-        {
-          Int_t manuId = bp->GetManuId(j);
-          nchannels += det->NofChannelsInManu(manuId);
-        }        
-      }
-      
-      de->SetValueAsDouble(0,IndexOfNumberDimension(),nchannels);
-      
-      fDEValues->Add(de);
-    }
-
-    AliMUONVCalibParam* chamber = ChamberParam(chamberId);
-    if (!chamber)
-    {
-      chamber = new AliMUONCalibParamND(external->Dimension()+fgkExtraDimension,
-                                   1,
-                                   chamberId,
-                                   0,
-                                   0.0);
-
-      // set the number of channels in that chamber
-      
-      Int_t nchannels(0);
-      
-      AliMpDEIterator it;
-      
-      it.First(chamberId);
-      
-      while ( !it.IsDone() )
-      {        
-        AliMpDetElement* det = it.CurrentDE();
+        AliMUONSparseHisto* sh = GetChannelHisto(detElemId,manuId,i,dim);
       
-        for ( Int_t i = 0; i < det->GetNofBusPatches(); ++i ) 
-        {
-          Int_t busPatchId = det->GetBusPatchId(i);
-          AliMpBusPatch* bp = AliMpDDLStore::Instance()->GetBusPatch(busPatchId);
-          for ( Int_t j = 0; j < bp->GetNofManus(); ++j ) 
-          {
-            Int_t manuId = bp->GetManuId(j);
-            nchannels += det->NofChannelsInManu(manuId);
-          }        
+        if ( sh ) 
+        {      
+          Add(h,*sh);
         }
-        
-        it.Next();
       }
-      
-      chamber->SetValueAsDouble(0,IndexOfNumberDimension(),nchannels);
-      
-      fChamberValues->Add(chamber);
     }
+  }
+}
 
-    AliMUONVCalibParam* pcb = 0x0;
-    
-    if ( pcbIndex >= 0 ) 
+//_____________________________________________________________________________
+TH1*
+AliMUONTrackerData::CreatePCBHisto(Int_t /*detElemId*/, Int_t /*pcbIndex*/, Int_t /*dim*/)
+{
+  /// Create histogram of a given PCB. Note that in order
+  /// to keep memory footprint as low as possible, you should delete
+  /// the returned pointer as soon as possible...
+  
+ // TH1* h(0x0);
+//  
+//  if ( HasPCB(detElemId, pcbIndex) && IsHistogrammed(dim)) 
+//  {
+//    h = CreateHisto(Form("DE%04dPCB1d_%d",detElemId,pcbIndex,dim),dim);
+//  }
+//  
+//  return h;
+
+  AliWarning("Not implemented (is it needed ?)");
+  return 0x0;
+}
+
+//_____________________________________________________________________________
+TH1*
+AliMUONTrackerData::CreateChamberHisto(Int_t chamberId, Int_t dim)
+{
+  /// Create histogram of a given chamber. Note that in order
+  /// to keep memory footprint as low as possible, you should delete
+  /// the returned pointer as soon as possible...
+  
+  TH1* h(0x0);
+  
+  if ( HasChamber(chamberId) && IsHistogrammed(dim))
+  {
+    h = CreateHisto(Form("CHAMBER%02d_%d",chamberId,dim),dim);
+    AliMpDEIterator it;
+    it.First(chamberId);
+    while ( !it.IsDone() )
     {
-      pcb = PCBParam(detElemId,pcbIndex);
-      if (!pcb)
-      {
-        pcb = new AliMUONCalibParamND(external->Dimension()+fgkExtraDimension,
-                                        namer.NumberOfPCBs(detElemId),
-                                        detElemId,
-                                        pcbIndex,
-                                        0.0);
-        fPCBValues->Add(pcb);
-      }
+      Int_t detElemId = it.CurrentDEId();
+      AddDEHisto(*h,detElemId,dim);
+      it.Next();
     }
-    
-    for ( Int_t i = 0; i < external->Size(); ++i ) 
-    {
-      Bool_t existingChannel = mpde->IsConnectedChannel(manuId,i);
-      
-      if ( existingChannel ) 
-      {
-        Bool_t validChannel(kFALSE);
-        
-        for ( Int_t j = 0; j < external->Dimension(); ++j )
-        {
-          if ( external->ValueAsFloat(i,j) >= AliMUONVCalibParam::InvalidFloatValue() ) continue;
-          
-          validChannel = kTRUE;
-          
-          Double_t vext = external->IsDoublePrecision() ? 
-            external->ValueAsDouble(i,j) :
-            external->ValueAsFloat(i,j);
-          
-          Double_t value = channel->ValueAsDouble(i,j) + vext;
-          
-          channel->SetValueAsDouble(i,j,value);
-          
-          manu->SetValueAsDouble(0,j,manu->ValueAsDouble(0,j)+vext);  
-          
-          busPatch->SetValueAsDouble(0,j,busPatch->ValueAsDouble(0,j)+vext);
+  }
+  
+  return h;
+}
 
-          de->SetValueAsDouble(0,j,de->ValueAsDouble(0,j)+vext);
+//_____________________________________________________________________________
+AliMUONSparseHisto*
+AliMUONTrackerData::GetChannelHisto(Int_t detElemId, Int_t manuId, 
+                                    Int_t manuChannel, Int_t dim)
+{
+  /// Get histogram of a given channel
+  
+  if (!fChannelHistos) fChannelHistos = new AliMUON2DMap(kTRUE);
+  
+  TObjArray* dimArray = static_cast<TObjArray*>(fChannelHistos->FindObject(detElemId,manuId));
+  if (!dimArray)
+  {
+    dimArray = new TObjArray(fExternalDimension);
+    dimArray->SetUniqueID( ( manuId << 16 ) | detElemId );
+    fChannelHistos->Add(dimArray);
+  }
+  
+  TObjArray* channels = static_cast<TObjArray*>(dimArray->UncheckedAt(dim));
+  if (!channels)
+  {
+    channels = new TObjArray(AliMpConstants::ManuNofChannels());
+    dimArray->AddAt(channels,dim);
+  }
+  
+  AliMUONSparseHisto* h = static_cast<AliMUONSparseHisto*>(channels->UncheckedAt(manuChannel));
+  if (!h)
+  {
+    h = new AliMUONSparseHisto;
+    h->SetUniqueID(( manuChannel << 16 ) | dim);
+    channels->AddAt(h,manuChannel);
+  }
+  
+  return h;
+// below is an alternate implementation, using a 1DMap, which *seems* to be
+// slightly SLOWER.
+//
+//  AliMUON1DMap* m = static_cast<AliMUON1DMap*>(fChannelHistos->FindObject(detElemId,manuId));
+//  if (!m)
+//  {
+//    m = new AliMUON1DMap(kFALSE);
+//    m->SetUniqueID( ( manuId << 16 ) | detElemId );
+//    fChannelHistos->Add(m);
+//  }
+//  
+//  UInt_t uid = ( manuChannel << 16 ) | dim;
+//  
+//  AliMUONSparseHisto* h = static_cast<AliMUONSparseHisto*>(m->FindObject(uid));
+//  if (!h)
+//  {
+//    h = new AliMUONSparseHisto;
+//    
+//    h->SetUniqueID(uid);
+//    
+//    m->Add(h);
+//  }
 
-          chamber->SetValueAsDouble(0,j,chamber->ValueAsDouble(0,j)+vext);
+  return h;
+}
 
-          if ( pcb ) 
-          {
-            pcb->SetValueAsDouble(pcbIndex,j,pcb->ValueAsDouble(pcbIndex,j)+vext);
-          }
-        }
-        
-        if ( validChannel )
-        {
-          channel->SetValueAsDouble(i,IndexOfOccupancyDimension(),
-                                  channel->ValueAsDouble(i,IndexOfOccupancyDimension())+1.0);
-          manu->SetValueAsDouble(0,IndexOfOccupancyDimension(),
-                               manu->ValueAsDouble(0,IndexOfOccupancyDimension())+1.0);        
-          busPatch->SetValueAsDouble(0,IndexOfOccupancyDimension(),
-                                 busPatch->ValueAsDouble(0,IndexOfOccupancyDimension())+1.0);        
-          de->SetValueAsDouble(0,IndexOfOccupancyDimension(),
-                                     de->ValueAsDouble(0,IndexOfOccupancyDimension())+1.0);        
-          chamber->SetValueAsDouble(0,IndexOfOccupancyDimension(),
-                               chamber->ValueAsDouble(0,IndexOfOccupancyDimension())+1.0); 
-          if ( pcb ) 
-          {
-            pcb->SetValueAsDouble(pcbIndex,IndexOfOccupancyDimension(),
-                                    pcb->ValueAsDouble(pcbIndex,IndexOfOccupancyDimension())+1.0);        
-          }
-        }
-      }
-    }
+//_____________________________________________________________________________
+Int_t
+AliMUONTrackerData::GetParts(AliMUONVCalibParam* external,
+                             AliMUONVCalibParam*& chamber,
+                             AliMUONVCalibParam*& de,
+                             AliMUONVCalibParam*& busPatch,
+                             AliMUONVCalibParam*& pcb,
+                             AliMUONVCalibParam*& manu,
+                             AliMUONVCalibParam*& channel,
+                             AliMpDetElement*& mpde)
+{
+  /// Get containers at all levels
+  AliMpDDLStore* ddlStore = AliMpDDLStore::Instance();
+  
+  Int_t detElemId = external->ID0();
+  
+  Int_t chamberId = AliMpDEManager::GetChamberId(detElemId);
+  
+  Int_t manuId = external->ID1();
+  
+  mpde = ddlStore->GetDetElement(detElemId);
+  
+  Int_t busPatchId = ddlStore->GetBusPatchId(detElemId,manuId);
+  
+  Int_t pcbIndex = -1;
+  
+  AliMp::StationType stationType = mpde->GetStationType();
+  
+  if ( stationType == AliMp::kStation345 ) 
+  {
+    AliMpHVNamer namer;
+    pcbIndex = namer.ManuId2PCBIndex(detElemId,manuId);
+  }
+  
+  channel = ChannelParam(detElemId,manuId,external);
+  
+  manu = ManuParam(detElemId,manuId,kTRUE);
+  
+  busPatch = BusPatchParam(busPatchId,kTRUE);
+  
+  de = DetectionElementParam(detElemId,kTRUE);
+  
+  chamber = ChamberParam(chamberId,kTRUE);
+  
+  pcb = 0x0;
+  
+  if ( pcbIndex >= 0 ) 
+  {
+    pcb = PCBParam(detElemId,pcbIndex,kTRUE);
   }
+  
+  return manuId;
+}
 
-  return kTRUE;
+//_____________________________________________________________________________
+Bool_t 
+AliMUONTrackerData::HasBusPatch(Int_t busPatchId) const
+{
+  /// Whether we have data for a given buspatch
+  return ( BusPatchParam(busPatchId) != 0 );
+}
+
+//_____________________________________________________________________________
+Bool_t 
+AliMUONTrackerData::HasChamber(Int_t chamberId) const
+{
+  /// Whether we have data for a given chamber
+  return ( ChamberParam(chamberId) != 0 );
+}
+
+//_____________________________________________________________________________
+Bool_t 
+AliMUONTrackerData::HasDetectionElement(Int_t detElemId) const
+{
+  /// Whether we have data for a given detection element
+  return ( DetectionElementParam(detElemId) != 0 );
+}
+
+//_____________________________________________________________________________
+Bool_t
+AliMUONTrackerData::HasManu(Int_t detElemId, Int_t manuId) const
+{
+  /// Whether we have data for a given manu
+  return ( ManuParam(detElemId,manuId) != 0 ); 
+}
+
+//_____________________________________________________________________________
+Bool_t
+AliMUONTrackerData::HasPCB(Int_t detElemId, Int_t pcbIndex) const
+{
+  /// Whether we have data for a given pcb
+  return ( PCBParam(detElemId,pcbIndex) != 0 ); 
 }
 
 //_____________________________________________________________________________
@@ -615,11 +922,39 @@ AliMUONTrackerData::Manu(Int_t detElemId, Int_t manuId, Int_t dim) const
 
 //_____________________________________________________________________________
 AliMUONVCalibParam* 
-AliMUONTrackerData::ManuParam(Int_t detElemId, Int_t manuId) const
+AliMUONTrackerData::ManuParam(Int_t detElemId, Int_t manuId, Bool_t create) const
 {
   /// Get the VCalibParam for a given manu
-  return fManuValues ? static_cast<AliMUONVCalibParam*>
-  (fManuValues->FindObject(detElemId,manuId)) : 0x0 ;
+  
+  AliMUONVCalibParam* manu = fManuValues ? static_cast<AliMUONVCalibParam*>
+    (fManuValues->FindObject(detElemId,manuId)) : 0x0 ;
+  
+  if (!manu && create && fManuValues)
+  {
+    manu = CreateManuParam(detElemId,manuId);
+    fManuValues->Add(manu);
+  }
+  
+  return manu;
+}
+
+//_____________________________________________________________________________
+AliMUONVCalibParam* 
+AliMUONTrackerData::CreateManuParam(Int_t detElemId, Int_t manuId) const
+{
+  /// Create storage for one manu
+  
+  AliCodeTimerAuto("");
+  
+  AliMUONVCalibParam* manu = new AliMUONCalibParamND(Dimension(),1,detElemId,manuId,0.0);
+  
+  // set the number of channels in that manu
+  
+  AliMpDetElement* de = AliMpDDLStore::Instance()->GetDetElement(detElemId);
+  
+  manu->SetValueAsDouble(0,IndexOfNumberDimension(),de->NofChannelsInManu(manuId));
+  
+  return manu;
 }
 
 //_____________________________________________________________________________
@@ -644,11 +979,38 @@ AliMUONTrackerData::PCB(Int_t detElemId, Int_t pcbIndex, Int_t dim) const
 
 //_____________________________________________________________________________
 AliMUONVCalibParam* 
-AliMUONTrackerData::PCBParam(Int_t detElemId, Int_t pcbIndex) const
+AliMUONTrackerData::PCBParam(Int_t detElemId, Int_t pcbIndex, Bool_t create) const
 {
   /// Return (if it exist) the VCalibParam for a given pcb
-  return fPCBValues ? static_cast<AliMUONVCalibParam*>
-  (fPCBValues->FindObject(detElemId,pcbIndex)) : 0x0 ;
+
+  AliMUONVCalibParam* pcb =  fPCBValues ? static_cast<AliMUONVCalibParam*>
+    (fPCBValues->FindObject(detElemId,pcbIndex)) : 0x0 ;
+  
+  if (create && fPCBValues && !pcb)
+  {
+    pcb = CreatePCBParam(detElemId,pcbIndex);
+    fPCBValues->Add(pcb);
+  }
+  
+  return pcb;
+}
+
+//_____________________________________________________________________________
+AliMUONVCalibParam* 
+AliMUONTrackerData::CreatePCBParam(Int_t detElemId, Int_t pcbIndex) const
+{
+  /// Create storage for one PCB (station345 only)
+  
+  AliCodeTimerAuto("");
+  
+  AliMpHVNamer namer;
+  
+  AliMUONVCalibParam* pcb = new AliMUONCalibParamND(Dimension(),
+                                                    namer.NumberOfPCBs(detElemId),
+                                                    detElemId,
+                                                    pcbIndex,
+                                                    0.0);
+  return pcb;
 }
 
 //_____________________________________________________________________________
@@ -663,16 +1025,22 @@ AliMUONTrackerData::Print(Option_t* wildcard, Option_t* opt) const
   {
     cout << " Nevents=" << fNevents << endl;
   }
+
+  for ( Int_t i = 0; i <= fExternalDimensionNames->GetLast(); ++i ) 
+  {
+    TObjString* name = static_cast<TObjString*>(fExternalDimensionNames->At(i));
+    cout << Form("External Dimension %2d Name %s %s",i,
+                 ( name ? name->String().Data() : "null"),
+                 ( IsHistogrammed(i) ? "(histogrammed)" : "")) << endl;
+  }
   
   for ( Int_t i = 0; i <= fDimensionNames->GetLast(); ++i ) 
   {
     TObjString* name = static_cast<TObjString*>(fDimensionNames->At(i));
-    cout << Form("Dimension %2d Name %s",i,
+    cout << Form("Internal Dimension %2d Name %s",i,
                  ( name ? name->String().Data() : "null")) << endl;
   }
-  
-  cout << Form("External Dimensions = %d",fExternalDimension) << endl;  
-
+    
   TString sopt(opt);
   sopt.ToUpper();
   
@@ -725,6 +1093,22 @@ AliMUONTrackerData::SetDimensionName(Int_t index, const char* name)
     
     SetInternalDimensionName(j,Form("%s of %s",prefix[i],name));
   }
+  
+  SetExternalDimensionName(index,name);
+}
+
+//_____________________________________________________________________________
+void 
+AliMUONTrackerData::SetHistogramDimension(Int_t index, Bool_t value)
+{
+  /// decide to make histos for a given dimension
+  if ( index >= ExternalDimension() ) 
+  {
+    AliError(Form("Index out of bounds : %d / %d",index,ExternalDimension()));
+    return;
+  }
+  
+  fHistogramming[index] = value;
 }
 
 //_____________________________________________________________________________
@@ -748,6 +1132,27 @@ AliMUONTrackerData::SetInternalDimensionName(Int_t index, const char* value)
   fDimensionNames->AddAt(new TObjString(value),index);
 }
 
+//_____________________________________________________________________________
+void 
+AliMUONTrackerData::SetExternalDimensionName(Int_t index, const char* value)
+{
+  /// Set the name of a given external dimension
+  if ( index >= fExternalDimension ) 
+  {
+    AliError(Form("Index out of bounds : %d / %d",index,fExternalDimension));
+    return;
+  }
+  
+  TObjString* ovalue = static_cast<TObjString*>(fExternalDimensionNames->At(index));
+  
+  if ( ovalue ) 
+  {
+    fExternalDimensionNames->Remove(ovalue);
+    delete ovalue;
+  }
+  fExternalDimensionNames->AddAt(new TObjString(value),index);
+}
+
 //_____________________________________________________________________________
 Double_t 
 AliMUONTrackerData::Value(const AliMUONVCalibParam& param, Int_t i, Int_t dim) const