fix finding of pad neighbours; remove methods to write them in OCDB
[u/mrichter/AliRoot.git] / MUON / AliMUONCalibrationData.cxx
1 /**************************************************************************
2 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
3 *                                                                        *
4 * Author: The ALICE Off-line Project.                                    *
5 * Contributors are mentioned in the code where appropriate.              *
6 *                                                                        *
7 * Permission to use, copy, modify and distribute this software and its   *
8 * documentation strictly for non-commercial purposes is hereby granted   *
9 * without fee, provided that the above copyright notice appears in all   *
10 * copies and that both the copyright notice and this permission notice   *
11 * appear in the supporting documentation. The authors make no claims     *
12 * about the suitability of this software for any purpose. It is          *
13 * provided "as is" without express or implied warranty.                  *
14 **************************************************************************/
15
16 // $Id: AliMUONCalibrationData.cxx 59486 2012-11-07 22:06:24Z laphecet $
17
18 #include "AliMUONCalibrationData.h"
19
20 #include "AliCDBEntry.h"
21 #include "AliCDBManager.h"
22 #include "AliCodeTimer.h"
23 #include "AliDCSValue.h"
24 #include "AliLog.h"
25 #include "AliMpDCSNamer.h"
26 #include "AliMpIntPair.h"
27 #include "AliMUONGlobalCrateConfig.h"
28 #include "AliMUONRegionalTriggerConfig.h"
29 #include "AliMUONRejectList.h"
30 #include "AliMUONTriggerEfficiencyCells.h"
31 #include "AliMUONTriggerLut.h"
32 #include "AliMUONVCalibParam.h"
33 #include "AliMUONVStore.h"
34 #include "AliMUONVStore.h"
35
36 #include <Riostream.h>
37 #include <TClass.h>
38 #include <TMap.h>
39 #include <TMath.h>
40
41 //-----------------------------------------------------------------------------
42 /// \class AliMUONCalibrationData
43 ///
44 /// For the moment, this class stores pedestals, gains, hv (for tracker)
45 /// and lut, masks and efficiencies (for trigger) that are fetched from the CDB.
46 ///
47 /// This class is to be considered as a convenience class.
48 /// Its aim is to ease retrieval of calibration data from the 
49 /// condition database.
50 ///
51 /// It acts as a "facade" to a bunch of underlying 
52 /// containers/calibration classes.
53 ///
54 /// \author Laurent Aphecetche
55 //-----------------------------------------------------------------------------
56
57 using std::cout;
58 using std::endl;
59 /// \cond CLASSIMP
60 ClassImp(AliMUONCalibrationData)
61 /// \endcond
62
63 AliMUONVStore* AliMUONCalibrationData::fgBypassPedestals(0x0);
64 AliMUONVStore* AliMUONCalibrationData::fgBypassGains(0x0);
65
66 UInt_t AliMUONCalibrationData::fgkDCSSt1Flag(42);
67
68 namespace
69 {
70   void MarkForDeletion(Int_t* indices, Int_t first, Int_t last)
71   {
72     for ( Int_t i = first; i <= last; ++i ) 
73     {
74       indices[i] = 1;
75     }
76   }
77 }
78
79 //_____________________________________________________________________________
80 AliMUONCalibrationData::AliMUONCalibrationData(Int_t runNumber, 
81                                                Bool_t deferredInitialization) 
82 : TObject(), 
83 fIsValid(kTRUE),
84 fRunNumber(runNumber), 
85 fGains(0x0), 
86 fPedestals(0x0),
87 fHV(0x0),
88 fTriggerDCS(0x0),
89 fLocalTriggerBoardMasks(0x0),
90 fRegionalTriggerConfig(0x0),
91 fGlobalTriggerCrateConfig(0x0),
92 fTriggerLut(0x0),
93 fTriggerEfficiency(0x0),
94 fCapacitances(0x0),
95 fNeighbours(0x0),
96 fOccupancyMap(0x0),
97 fRejectList(0x0),
98 fConfig(0x0)
99 {
100 /// Default ctor.
101
102   // If deferredInitialization is false, we read *all* calibrations
103   // at once.
104   // So when using this class to access only one kind of calibrations (e.g.
105   // only pedestals), you should put deferredInitialization to kTRUE, which
106   // will instruct this object to fetch the data only when neeeded.
107
108   if ( deferredInitialization == kFALSE )
109   {
110     Gains();
111     Pedestals();
112     OccupancyMap();
113     RejectList();
114     HV();
115     TriggerDCS();
116     LocalTriggerBoardMasks(0);
117     RegionalTriggerConfig();
118     GlobalTriggerCrateConfig();
119     TriggerLut();
120     TriggerEfficiency();
121     Capacitances();
122     Neighbours();
123     Config();
124   }
125 }
126
127 //_____________________________________________________________________________
128 AliMUONCalibrationData::~AliMUONCalibrationData()
129 {
130   /// Destructor. Note that we're the owner of our pointers if the OCDB cache
131   /// is not set. Otherwise the cache is supposed to take care of them...
132   if (!(AliCDBManager::Instance()->GetCacheFlag())) Reset();
133 }
134
135 //_____________________________________________________________________________
136 AliMUONVStore*
137 AliMUONCalibrationData::Capacitances() const
138 {
139   /// Create (if needed) and return the internal store for capacitances.
140   
141   if (!fCapacitances)
142   {
143     fCapacitances = CreateCapacitances(fRunNumber);
144   }
145   return fCapacitances;
146 }
147
148 //_____________________________________________________________________________
149 AliMUONVStore*
150 AliMUONCalibrationData::CreateCapacitances(Int_t runNumber, Int_t* startOfValidity)
151 {
152   /// Create capa store from OCDB for a given run
153   
154   return dynamic_cast<AliMUONVStore*>(CreateObject(runNumber,"MUON/Calib/Capacitances",startOfValidity));
155 }
156
157 //_____________________________________________________________________________
158 AliMUONVStore*
159 AliMUONCalibrationData::CreateGains(Int_t runNumber, Int_t* startOfValidity)
160 {
161   /// Create a new gain store from the OCDB for a given run
162   return dynamic_cast<AliMUONVStore*>(CreateObject(runNumber,"MUON/Calib/Gains",startOfValidity));
163 }
164
165 //_____________________________________________________________________________
166 AliMUONGlobalCrateConfig*
167 AliMUONCalibrationData::CreateGlobalTriggerCrateConfig(Int_t runNumber, Int_t* startOfValidity)
168 {
169   /// Create the internal store for GlobalTriggerCrateConfig from OCDB
170   
171   return dynamic_cast<AliMUONGlobalCrateConfig*>(CreateObject(runNumber,"MUON/Calib/GlobalTriggerCrateConfig",startOfValidity));
172 }
173
174
175 //______________________________________________________________________________
176 Bool_t AliMUONCalibrationData::CheckHVGroup(TObjArray& values, Int_t first, Int_t last, Double_t& value, Int_t& slope, TString* msg)
177 {
178   // Get the HV of the values between first and last indices
179   // return the HV slope  (in Volt per second) and a message
180   // Return kFALSE if we must discard the group
181   //
182   
183   if (msg) *msg="";
184   
185   if ( last < first ) return kFALSE;
186   if ( last - first < 2 ) return kFALSE;
187   
188   Double_t a(0.0);
189   Double_t b(0.0);
190
191   Float_t HVSAME(1); // 1 volts
192
193   AliDCSValue* vfirst = static_cast<AliDCSValue*>(values.UncheckedAt(first));
194   AliDCSValue* vlast = static_cast<AliDCSValue*>(values.UncheckedAt(last));
195
196   Int_t deltaHV = TMath::Nint(TMath::Abs(vfirst->GetFloat()-vlast->GetFloat()));
197   
198   if ( deltaHV < HVSAME ) return kFALSE;
199
200   for ( Int_t i = first; i <= last; ++i )
201   {
202     AliDCSValue* v = static_cast<AliDCSValue*>(values.UncheckedAt(i));
203
204     Double_t y = v->GetFloat() - vfirst->GetFloat();
205     Double_t x = v->GetTimeStamp() - vfirst->GetTimeStamp();
206   
207     a += x*y;
208     b += x*x;
209   }
210   
211   value = a/b;
212   slope = value > 0 ? 1 : -1;
213   value = TMath::Abs(value);
214   
215   UInt_t deltaTime = vlast->GetTimeStamp() - vfirst->GetTimeStamp();
216   
217   if (msg)
218   {
219     if (slope>0) (*msg) = Form("RU%d[%d:%d](%d)",TMath::Nint(value),first,last,deltaTime);
220     if (slope<0) (*msg) = Form("RD%d[%d:%d](%d)",TMath::Nint(value),first,last,deltaTime);
221     
222     if ( TMath::Nint(value) == 0 )
223     {
224       // this is to protect for the few cases 
225       // (see e.g. MchHvLvLeft/Chamber00Left/Quad2Sect0.actual.vMon in run 134497)
226       // where we can have *lots* of values (2483 in this example) but that
227       // are more or less constant...
228       //
229       // or simply to remove small ramps
230       //
231       slope = 0;
232       value = (vfirst->GetFloat()+vlast->GetFloat())/2.0;
233       *msg = Form("FLUCT%d[%d:%d]",TMath::Nint(value),first,last);
234     }
235   }
236   
237   return kTRUE;
238 }
239
240 //______________________________________________________________________________
241 Bool_t AliMUONCalibrationData::PatchHVValues(TObjArray& values,
242                                              TString* msg,
243                                              Bool_t dryRun)
244 {
245   /// We do here a little bit of massaging of the HV values, if needed.
246   ///
247   /// The main point is to "gather" values that are within a given small amount
248   /// of time (typically 60 seconds) and infer a slope from those values
249   /// slope > 0 means it is a ramp-up, slope < 0 that's a ramp-down
250   ///
251   /// This is to avoid both the "ramp-down-before-end-of-run" and the
252   /// "ramp-up-after-start-of-run" syndroms...
253   ///
254   /// Use dryRun = kTRUE to fill the messages *without* altering the values
255   ///
256   /// Return kFALSE is the kind of HV (trouble) case we have here
257   /// has not been identified...
258   ///
259   
260   UInt_t DELTATIME(60); // in seconds
261   Int_t IENDRU(60); // in seconds
262   
263   // Start by finding groups of values which are not separated (each) by more than
264   // deltaTime
265   
266   Bool_t gather(kFALSE);
267   Int_t ifirst(0);
268   Int_t ilast(0);
269   TObjArray groups;
270   groups.SetOwner(kTRUE);
271   
272   for ( Int_t i = values.GetLast(); i > 0; --i ) 
273   {
274     AliDCSValue* vi = static_cast<AliDCSValue*>(values.UncheckedAt(i));
275     AliDCSValue* vj = static_cast<AliDCSValue*>(values.UncheckedAt(i-1));
276
277     if ( vi->GetTimeStamp() - vj->GetTimeStamp() < DELTATIME )
278     {
279       if ( !gather ) 
280       {
281         gather = kTRUE;
282         ifirst = i;    
283       }
284       ilast=i;
285     }
286     else
287     {
288       if ( gather ) 
289       {
290         ilast=i;
291         
292         groups.Add(new AliMpIntPair(ilast,ifirst));
293       }
294       gather = kFALSE;
295     }
296   }
297   
298   if (gather)
299   {
300     groups.Add(new AliMpIntPair(0,ifirst));
301   }
302                  
303   TIter nextGroup(&groups,kIterBackward);
304   AliMpIntPair* p;
305   TString internalMsg;
306   Int_t ngroups(0);
307
308   Int_t nRU(0);
309   Int_t nRD(0);
310   Int_t nStartRU(0);
311   Int_t nEndAndShortRU(0);
312   Int_t nEndRD(0);
313   Int_t nTripRD(0);
314   Int_t nFluct(0);
315   TObjArray trips;
316   trips.SetOwner(kTRUE);
317   
318   while ( ( p = static_cast<AliMpIntPair*>(nextGroup()) ) )
319   {
320     Double_t value;
321     Int_t slope;
322     
323     TString groupMsg;
324     
325     AliDebugClass(1,Form("group %d:%d",p->GetFirst(),p->GetSecond()));
326     
327     Bool_t ok = CheckHVGroup(values,p->GetFirst(),p->GetSecond(),value,slope,&groupMsg);
328     
329     if (!ok) continue;
330     
331     ++ngroups;
332     
333     if ( slope > 0 )
334     {
335       if ( p->GetFirst() == 0 ) 
336       {
337         // start with a ramp-up
338         ++nStartRU;
339       }
340       else if ( p->GetSecond() == values.GetLast() && TMath::Nint(value) < IENDRU )
341       {
342         ++nEndAndShortRU;
343       }
344       else
345       {
346         // ramp-up in the middle of nowhere...
347         ++nRU;
348       }
349     }
350     else if ( slope < 0 )
351     {
352       if ( p->GetSecond() == values.GetLast() ) 
353       {
354         // end with a ramp-down
355         ++nEndRD;
356       }
357       else
358       {
359         // ramp-down in the middle of nowhere
360         ++nRD;
361       }
362
363       AliDCSValue* d = static_cast<AliDCSValue*>(values.At(p->GetSecond()));
364       
365       if ( d->GetFloat() < AliMpDCSNamer::TrackerHVOFF() )
366       {
367         ++nTripRD;
368         AliDCSValue* tripStart = static_cast<AliDCSValue*>(values.At(p->GetFirst()));        
369         trips.Add(new AliMpIntPair(tripStart->GetTimeStamp(),TMath::Nint(tripStart->GetFloat())));
370       }
371     }
372     else
373     {
374       ++nFluct;
375     }
376     
377     internalMsg += groupMsg;
378     internalMsg += " ";    
379   }
380   
381   /*
382    
383    Once we have "decoded" the groups we try to find out which of 
384    the following cases we're facing :
385   
386    case A = -------- = OK(1)
387   
388    case B = ----
389                 \
390                 \   = OK, once we have removed the ramp-down (2)
391   
392    case C =    ----- 
393               /
394              /       = OK, once we have removed the ramp-up (3)
395   
396    case D =    ----- 
397               /     \
398              /       \ = OK, once we have removed the ramp-down (2) and the ramp-up (3)
399   
400    case E = ----
401                 \
402                  \____ = TRIP = BAD (here the ramp-down slope should be bigger than in case C)
403   
404    case F = ----         
405                 \      ----- = BAD (trip + ramp-up at end of run)
406                  \____/   
407   
408    case G = fluctuations (within a range defined in CheckHVGroup...)
409    
410    case H =            
411                    /
412                   /   = ramp-up right at the end-of-run = OK (4)
413             ------
414    
415    (1) OK means the group is identified correctly, still the value can be below ready...
416    (2) ramp-down values will be removed if the ramp is indeed the last values in the serie
417        i.e. it's really an end-of-run problem (otherwise it's not case B)
418    (3) ramp-up values will be removed if the ramp is indeed the first values in the serie
419        i.e. it's really a start-of-run problem (otherwise it's not case C)
420    (4) OK if short enough...
421    
422    Any other case is unknown and we'll :
423    a) return kFALSE
424    b) assume the channel is OFF.
425   
426   
427   */
428   
429   AliDebugClass(1,Form("msg=%s ngroupds=%d",internalMsg.Data(),ngroups));
430   AliDebugClass(1,Form("nRU %d nRD %d nStartRU %d nEndRD %d nTripRD %d nFluct %d",
431                        nRU,nRD,nStartRU,nEndRD,nTripRD,nFluct));
432   
433   TString hvCase("OTHER");
434   int dummy(0),a(-1),b(-1);
435   char r[81];
436   Int_t nvalues = values.GetSize();  
437   Int_t* indices = new Int_t[nvalues];
438   memset(indices,0,nvalues*sizeof(Int_t));
439          
440   AliDCSValue* vfirst = static_cast<AliDCSValue*>(values.UncheckedAt(0));
441   AliDCSValue* vlast = static_cast<AliDCSValue*>(values.UncheckedAt(values.GetLast()));
442
443   UInt_t meanTimeStamp = ( vfirst->GetTimeStamp() + vlast->GetTimeStamp() ) / 2;
444   
445   if ( ngroups == 0 ) 
446   {
447     hvCase = "A"; 
448   }
449   else if ( nTripRD > 0 )
450   {
451     const Double_t HVLOWTRIP(600); // a trip below this value is considered a "low trip"
452     // i.e. one starting for a non-operational voltage
453     
454     internalMsg += Form("NT:%d ",nTripRD);
455     
456     if ( nRU > 0 && nRD > 0 )
457     {
458       hvCase = "F";
459     }
460     else
461     {
462       hvCase = "E";
463     }
464     
465     for ( Int_t iTrip = 0; iTrip <= trips.GetLast(); ++iTrip )
466     {
467       AliMpIntPair* tripPair = static_cast<AliMpIntPair*>(trips.At(iTrip));
468       TString tripType("TRIP");
469       if ( tripPair->GetSecond() < HVLOWTRIP)
470       {
471         tripType = "LOWTRIP";
472       }
473
474       internalMsg += Form("%s SV:%d TS:%d ",tripType.Data(),tripPair->GetSecond(),tripPair->GetFirst());
475     }
476     
477     // we put here the TRIP value as SV:value
478     // for cases where there's a drop in voltage but the starting point was
479     // below operational voltage, so strictly speaking it's *not* a trip, but
480     // more a big fluctuation
481     if ( !dryRun )
482     {
483       MarkForDeletion(indices,0,values.GetLast());
484       values.Add(new AliDCSValue(static_cast<Float_t>(0),meanTimeStamp));
485     }
486   }
487   else if ( nStartRU > 0 && nRU == 0 && nRD == 0 && nEndRD == 0 )
488   {
489     hvCase = "C";
490     if (!dryRun)
491     {
492       sscanf(internalMsg.Data(),"RU%10d[%10d:%10d]%80s",&dummy,&a,&b,r);
493       MarkForDeletion(indices,a,b);
494     }
495   }
496   else if ( nStartRU > 0 && nEndRD > 0 && nRD == 0 && nRU == 0 )
497   {
498     hvCase = "D";
499     if (!dryRun)
500     {
501       sscanf(internalMsg.Data(),"RU%10d[%10d:%10d]%80s",&dummy,&a,&b,r);
502       MarkForDeletion(indices,a,b-1);
503       Int_t i = internalMsg.Index("RD",strlen("RD"),0,TString::kExact);
504       sscanf(internalMsg(i,internalMsg.Length()-i).Data(),
505              "RD%10d[%10d:%10d]%80s",&dummy,&a,&b,r);
506       MarkForDeletion(indices,a+1,b);
507     }
508   }
509   else if ( nEndRD > 0 && nStartRU == 0 && nRU == 0 && nRD == 0 )
510   {
511     hvCase = "B";
512     if  (!dryRun)
513     {
514       Int_t i = internalMsg.Index("RD",strlen("RD"),0,TString::kExact);
515       sscanf(internalMsg(i,internalMsg.Length()-i).Data(),
516              "RD%10d[%10d:%10d]%80s",&dummy,&a,&b,r);
517       MarkForDeletion(indices,a,b);
518     }
519   }
520   else if ( nFluct > 0 )
521   {
522     hvCase = "G";
523     if (!dryRun)
524     {
525       TObjArray* af = internalMsg.Tokenize(" ");
526       TIter next(af);
527       TObjString* str;
528       while ( ( str = static_cast<TObjString*>(next()) ) )
529       {
530         TString s(str->String());
531         if ( s.BeginsWith("FLUCT") )
532         {
533           sscanf(s.Data(),"FLUCT%d[%d:%d]",&dummy,&a,&b);
534           MarkForDeletion(indices,a,b);
535         }
536       }
537       delete af;
538     }
539   }
540   else if ( nEndAndShortRU > 0 && nStartRU == 0 && nRU == 0 && nRD == 0 && nEndRD == 0 )
541   {
542     hvCase = "H";
543     if (!dryRun)
544     {
545       sscanf(internalMsg.Data(),"RU%10d[%10d:%10d]%80s",&dummy,&a,&b,r);
546       MarkForDeletion(indices,a,b);
547     }
548   }
549   else
550   {
551     // last chance... 
552     // here we know it's not a trip, so let's assume everything is OK
553     // if first and last value are in the same ballpark
554
555     const Double_t HVFLUCT(20); // volts
556     
557     if ( TMath::Abs(vfirst->GetFloat() - vlast->GetFloat()) < HVFLUCT )
558     {
559       hvCase = "Z";
560     }
561     if (!dryRun)
562     {
563       MarkForDeletion(indices,1,nvalues-1);
564     }
565   }
566   
567   if (!dryRun)
568   {
569     for ( Int_t i = 0; i < nvalues; ++i )
570     {
571       if ( indices[i] )
572       {
573         values.RemoveAt(i);
574       }
575     }
576   
577     values.Compress();
578   }
579   
580   delete[] indices;
581   
582   if ( !values.GetEntries() )
583   {
584     AliErrorClass(Form("No value left after patch... Check that !!! initial # of values=%d msg=%s",
585                        nvalues,internalMsg.Data()));
586     hvCase = "OTHER";
587   }
588
589   if (!dryRun)
590   {
591     // take the max of the remaining values
592     TIter nextA(&values);
593     AliDCSValue* val;
594     Float_t maxval(-9999);
595   
596     while ( ( val = static_cast<AliDCSValue*>(nextA()) ) )
597     {
598       if ( val->GetFloat() > maxval )
599       {
600         maxval = val->GetFloat();
601       }
602     }
603   
604     values.Clear();
605   
606     values.Add(new AliDCSValue(maxval,meanTimeStamp));
607   }
608   
609   // once the case is inferred, add a "CASE:%10d",hvCase.Data()
610   // to the msg
611   // so we can them sum up for all channels and get a summary per run...
612   
613   internalMsg += Form("CASE:%s",hvCase.Data());
614  
615   if (msg) *msg = internalMsg.Data();
616   
617   return hvCase=="OTHER" ? kFALSE : kTRUE;
618 }
619
620 //_____________________________________________________________________________
621 void AliMUONCalibrationData::AddToMap(const TMap& sourceMap,
622                                       TMap& destMap,
623                                       const TString& key,
624                                       const char* source,
625                                       const char* dest)
626 {
627   /// Remap
628   
629   TString newkey(key);
630   
631   newkey.ReplaceAll(source,dest);
632
633   TPair* pair = static_cast<TPair*>(sourceMap.FindObject(key.Data()));
634
635   destMap.Add(new TObjString(newkey.Data()),pair->Value());
636 }
637
638 //_____________________________________________________________________________
639 void AliMUONCalibrationData::PatchSt1DCSAliases(TMap& hvMap)
640 {
641   /// It was discovered (in sept. 2013) that the DCS aliases for St1 was
642   /// wrongly assigned (in the hardware), so the correspondence between DCS channels
643   /// and actual HV channels is wrong for St1 in the DCS (and thus in the DCS archive,
644   /// and so in the OCDB HV object).
645   ///
646   /// It affects all the OCDB object written in 2010-2013.
647   ///
648   /// This method fixes that.
649   
650   if ( hvMap.GetUniqueID() == fgkDCSSt1Flag )
651   {
652     // already clean object. Do nothing
653     return;
654   }
655
656   TIter next(&hvMap);
657   TObjString* hvChannelName;
658   
659   TMap newmap;
660   newmap.SetOwnerKeyValue(kTRUE,kFALSE);
661   
662   while ( ( hvChannelName = static_cast<TObjString*>(next()) ) )
663   {
664     TString name(hvChannelName->String());
665     TString newname(name);
666     
667     // the problem is limited to St1 = ch1+ch2 (or, in DCS parlance, ch0+ch1)
668     // do it "by hand" as we "only" have 8 names to change
669     
670     if ( name.Contains("Chamber00Left") )
671     {
672       if (name.Contains("Quad1Sect0")) AddToMap(hvMap,newmap,name,"Quad1Sect0","Quad2Sect0"); // channel 0 of Board00 (alidcscae020)
673       
674       if (name.Contains("Quad1Sect1")) AddToMap(hvMap,newmap,name,"Quad1Sect1","Quad2Sect1"); // channel 1
675       if (name.Contains("Quad1Sect2")) AddToMap(hvMap,newmap,name,"Quad1Sect2","Quad2Sect2"); // channel 2
676       
677       if (name.Contains("Quad2Sect2")) AddToMap(hvMap,newmap,name,"Quad2Sect2","Quad1Sect0"); // channel 3
678       if (name.Contains("Quad2Sect1")) AddToMap(hvMap,newmap,name,"Quad2Sect1","Quad1Sect1"); // channel 4
679       if (name.Contains("Quad2Sect0")) AddToMap(hvMap,newmap,name,"Quad2Sect0","Quad1Sect2"); // channel 5
680     }
681     else if ( name.Contains("Chamber01Left"))
682     {
683       if (name.Contains("Quad2Sect2")) AddToMap(hvMap,newmap,name,"Quad2Sect2","Quad2Sect0"); // channel 9 of Board00 (alidcscae020)
684       if (name.Contains("Quad2Sect0")) AddToMap(hvMap,newmap,name,"Quad2Sect0","Quad2Sect2"); // channel 11
685     }
686     else
687     {
688       AddToMap(hvMap,newmap,name,name,name);
689     }
690   }
691   
692   // copy newmap to hvMap
693   
694   TIter nextNewMap(&newmap);
695   while ( ( hvChannelName = static_cast<TObjString*>(nextNewMap()) ) )
696   {
697     TPair* oldPair = static_cast<TPair*>(hvMap.FindObject(hvChannelName->String().Data()));
698     TPair* newPair = static_cast<TPair*>(newmap.FindObject(hvChannelName->String().Data()));
699       
700     TObjArray* newValues = static_cast<TObjArray*>(newPair->Value());
701       
702     oldPair->SetValue(newValues);
703   }
704 }
705
706 //_____________________________________________________________________________
707 TMap*
708 AliMUONCalibrationData::CreateHV(Int_t runNumber, 
709                                  Int_t* startOfValidity, 
710                                  Bool_t patched,
711                                  TList* messages,
712                                  Bool_t dryRun)
713 {
714   /// Create a new HV map from the OCDB for a given run
715   ///
716   /// dryRun is only usefull with patched=kTRUE and non-empty messages) :
717   /// it allow to get the list of messages without altering the values at all
718   /// (A patch without a patch, so to speak...)
719   ///
720   
721   TMap* hvMap = dynamic_cast<TMap*>(CreateObject(runNumber,"MUON/Calib/HV",startOfValidity));
722
723   if (!hvMap) return 0x0;
724
725   PatchSt1DCSAliases(*hvMap);
726   
727   if (patched)
728   {
729     TIter next(hvMap);
730     TObjString* hvChannelName;
731     
732     while ( ( hvChannelName = static_cast<TObjString*>(next()) ) )
733     {
734       TString name(hvChannelName->String());
735       
736       if ( name.Contains("sw") ) continue; // skip switches
737
738       if ( name.Contains("iMon") ) continue; // skip HV currents
739
740       TPair* hvPair = static_cast<TPair*>(hvMap->FindObject(name.Data()));
741       TObjArray* values = static_cast<TObjArray*>(hvPair->Value());
742       if (!values)
743       {
744         AliErrorClass(Form("Could not get values for alias %s",name.Data()));
745       }
746       else
747       {
748         TString msg;
749         
750         AliDebugClass(1,Form("channel %s",name.Data()));
751         Bool_t ok = PatchHVValues(*values,&msg,dryRun);
752         
753         if ( messages ) 
754         {
755           messages->Add(new TObjString(Form("%s %s",hvChannelName->String().Data(),msg.Data())));
756         }
757         
758         if (!ok)
759         {
760           AliErrorClass(Form("PatchHVValue was not successfull ! This is serious ! "
761                              "You'll have to check the logic for channel %s in run %09d",
762                              name.Data(),runNumber));
763         }
764       }
765     }
766     
767   }
768   
769   if ( messages ) 
770   {
771     Int_t a(0),b(0),c(0),d(0),e(0),f(0),g(0),h(0),u(0),z(0);
772     TIter next(messages);
773     TObjString* msg;
774     char hvCase('u');
775     
776     while ( ( msg = static_cast<TObjString*>(next()) ) )
777     {
778       Int_t i = msg->String().Index("CASE",strlen("CASE"),0,TString::kExact);
779       
780       if ( i >= 0 )
781       {
782         sscanf(msg->String()(i,msg->String().Length()-i).Data(),"CASE:%10c",&hvCase);
783       }
784
785       switch (hvCase)
786       {
787         case 'A': ++a; break;
788         case 'B': ++b; break;
789         case 'C': ++c; break;
790         case 'D': ++d; break;
791         case 'E': ++e; break;
792         case 'F': ++f; break;
793         case 'G': ++g; break;
794         case 'H': ++h; break;
795         case 'Z': ++z; break;
796         default: ++u; break;
797       }
798     }
799     
800     messages->Add(new TObjString(Form("SUMMARY : # of cases A(%3d) B(%3d) C(%3d) D(%3d) E(%3d) F(%3d) G(%3d) H(%3d) Z(%3d) OTHER(%3d)",
801                                       a,b,c,d,e,f,g,h,z,u)));
802   }
803   
804   return hvMap;
805 }
806
807 //_____________________________________________________________________________
808 TMap*
809 AliMUONCalibrationData::CreateTriggerDCS(Int_t runNumber, Int_t* startOfValidity)
810 {
811   /// Create a new Trigger HV and curent map from the OCDB for a given run
812   return dynamic_cast<TMap*>(CreateObject(runNumber,"MUON/Calib/TriggerDCS",startOfValidity));
813 }
814
815 //_____________________________________________________________________________
816 AliMUONVStore*
817 AliMUONCalibrationData::CreateLocalTriggerBoardMasks(Int_t runNumber, Int_t* startOfValidity)
818 {
819   /// Get the internal store for LocalTriggerBoardMasks from OCDB
820   
821   return dynamic_cast<AliMUONVStore*>(CreateObject(runNumber,"MUON/Calib/LocalTriggerBoardMasks",startOfValidity));
822 }
823
824 //_____________________________________________________________________________
825 AliMUONVStore*
826 AliMUONCalibrationData::CreateNeighbours(Int_t runNumber, Int_t* startOfValidity)
827 {
828   /// Create a neighbour store from the OCDB for a given run
829   return dynamic_cast<AliMUONVStore*>(CreateObject(runNumber,"MUON/Calib/Neighbours",startOfValidity));
830 }
831
832 //_____________________________________________________________________________
833 TObject*
834 AliMUONCalibrationData::CreateObject(Int_t runNumber, const char* path, Int_t* startOfValidity)
835 {
836   /// Access the CDB for a given path (e.g. MUON/Calib/Pedestals),
837   /// and return the corresponding TObject.
838   
839   AliCodeTimerAutoClass(Form("%09d : %s",runNumber,path),0);
840   
841   AliCDBManager* man = AliCDBManager::Instance();
842   
843   AliCDBEntry* entry =  man->Get(path,runNumber);
844   
845   if (entry)
846   {
847                 if ( startOfValidity ) *startOfValidity = entry->GetId().GetFirstRun();
848                 
849     TObject* object = entry->GetObject();
850     if (!(man->GetCacheFlag()))
851     {
852       entry->SetOwner(kFALSE);
853       delete entry;      
854     }
855 //    else
856 //    {
857 //      entry->SetOwner(kTRUE); //FIXME : this should be done but is causing problems with RecoParams at the end of the reco : investigate why...
858 //    }
859     return object;
860   }
861         else
862         {
863                 if ( startOfValidity )  *startOfValidity = AliCDBRunRange::Infinity();
864   }
865         
866   {
867     
868     AliCodeTimerAutoClass(Form("Failed to get %s for run %09d",path,runNumber),1);
869
870   }
871   
872   return 0x0;
873 }
874
875 //_____________________________________________________________________________
876 AliMUONVStore*
877 AliMUONCalibrationData::CreateOccupancyMap(Int_t runNumber, Int_t* startOfValidity)
878 {
879   /// Create a new occupancy map store from the OCDB for a given run
880   return dynamic_cast<AliMUONVStore*>(CreateObject(runNumber,"MUON/Calib/OccupancyMap",startOfValidity));
881 }
882
883 //_____________________________________________________________________________
884 AliMUONRejectList*
885 AliMUONCalibrationData::CreateRejectList(Int_t runNumber, Int_t* startOfValidity)
886 {
887   /// Create a new rejectlist store from the OCDB for a given run
888   return dynamic_cast<AliMUONRejectList*>(CreateObject(runNumber,"MUON/Calib/RejectList",startOfValidity));
889 }
890
891 //_____________________________________________________________________________
892 AliMUONVStore*
893 AliMUONCalibrationData::CreatePedestals(Int_t runNumber, Int_t* startOfValidity)
894 {
895   /// Create a new pedestal store from the OCDB for a given run
896   return dynamic_cast<AliMUONVStore*>(CreateObject(runNumber,"MUON/Calib/Pedestals",startOfValidity));
897 }
898
899 //_____________________________________________________________________________
900 AliMUONVStore*
901 AliMUONCalibrationData::CreateConfig(Int_t runNumber, Int_t* startOfValidity)
902 {
903   /// Create a new config store from the OCDB for a given run
904   return dynamic_cast<AliMUONVStore*>(CreateObject(runNumber,"MUON/Calib/Config",startOfValidity));
905 }
906
907
908 //_____________________________________________________________________________
909 AliMUONRegionalTriggerConfig*
910 AliMUONCalibrationData::CreateRegionalTriggerConfig(Int_t runNumber, Int_t* startOfValidity)
911 {
912   /// Create the internal store for RegionalTriggerConfig from OCDB
913   
914   return dynamic_cast<AliMUONRegionalTriggerConfig*>(CreateObject(runNumber,"MUON/Calib/RegionalTriggerConfig",startOfValidity));
915 }
916
917 //_____________________________________________________________________________
918 AliMUONTriggerEfficiencyCells* 
919 AliMUONCalibrationData::CreateTriggerEfficiency(Int_t runNumber, Int_t* startOfValidity)
920 {
921   /// Create trigger efficiency object from OCBD
922   
923   return dynamic_cast<AliMUONTriggerEfficiencyCells*>(CreateObject(runNumber,"MUON/Calib/TriggerEfficiency",startOfValidity));
924 }
925
926 //_____________________________________________________________________________
927 AliMUONTriggerLut* 
928 AliMUONCalibrationData::CreateTriggerLut(Int_t runNumber, Int_t* startOfValidity)
929 {
930   /// Create trigger LUT from OCDB
931   
932   return dynamic_cast<AliMUONTriggerLut*>(CreateObject(runNumber,"MUON/Calib/TriggerLut",startOfValidity));
933 }
934
935 //_____________________________________________________________________________
936 AliMUONVStore*
937 AliMUONCalibrationData::Gains() const
938 {
939   /// Create (if needed) and return the internal store for gains.
940   if (fgBypassGains) return fgBypassGains;
941   
942   if (!fGains)
943   {
944     fGains = CreateGains(fRunNumber);
945   }
946   return fGains;
947 }
948  
949 //_____________________________________________________________________________
950 AliMUONVCalibParam*
951 AliMUONCalibrationData::Gains(Int_t detElemId, Int_t manuId) const
952 {
953 /// Return the gains for a given (detElemId, manuId) pair
954 /// Note that, unlike the DeadChannel case, if the result is 0x0, that's an
955 /// error (meaning that we should get gains for all channels).
956
957   AliMUONVStore* gains = Gains();
958   if (!gains)
959   {
960     return 0x0;
961   }
962   
963   return static_cast<AliMUONVCalibParam*>(gains->FindObject(detElemId,manuId));
964 }
965
966 //_____________________________________________________________________________
967 AliMUONGlobalCrateConfig* 
968 AliMUONCalibrationData::GlobalTriggerCrateConfig() const
969 {
970   /// Return the config for the global trigger board.
971   
972   if (!fGlobalTriggerCrateConfig)
973   {
974     fGlobalTriggerCrateConfig = CreateGlobalTriggerCrateConfig(fRunNumber);
975   }
976   return fGlobalTriggerCrateConfig;
977 }
978
979
980 //_____________________________________________________________________________
981 TMap*
982 AliMUONCalibrationData::HV(Bool_t patched) const
983 {
984   /// Return the calibration for a given (detElemId, manuId) pair
985   
986   if (!fHV)
987   {
988     fHV = CreateHV(fRunNumber,0,patched);
989   }
990   return fHV;
991 }
992
993 //_____________________________________________________________________________
994 TMap*
995 AliMUONCalibrationData::TriggerDCS() const
996 {
997   /// Return the calibration for a given (detElemId, manuId) pair
998   
999   if (!fTriggerDCS)
1000   {
1001     fTriggerDCS = CreateTriggerDCS(fRunNumber);
1002   }
1003   return fTriggerDCS;
1004 }
1005
1006 //_____________________________________________________________________________
1007 AliMUONVStore*
1008 AliMUONCalibrationData::Neighbours() const
1009 {
1010   /// Create (if needed) and return the internal store for neighbours.
1011   if (!fNeighbours)
1012   {
1013     fNeighbours = CreateNeighbours(fRunNumber);
1014   }
1015   return fNeighbours;
1016 }
1017
1018 //_____________________________________________________________________________
1019 AliMUONVCalibParam* 
1020 AliMUONCalibrationData::LocalTriggerBoardMasks(Int_t localBoardNumber) const
1021 {
1022 /// Return the masks for a given trigger local board.
1023
1024   if (!fLocalTriggerBoardMasks)
1025   {
1026     fLocalTriggerBoardMasks = CreateLocalTriggerBoardMasks(fRunNumber);
1027   }
1028
1029   if ( fLocalTriggerBoardMasks ) 
1030   {
1031     AliMUONVCalibParam* ltbm = 
1032       static_cast<AliMUONVCalibParam*>(fLocalTriggerBoardMasks->FindObject(localBoardNumber));
1033     if (!ltbm)
1034     {
1035       AliError(Form("Could not get mask for localBoardNumber=%d",localBoardNumber));
1036     }
1037     return ltbm;  
1038   }
1039   return 0x0;
1040 }
1041
1042 //_____________________________________________________________________________
1043 AliMUONVStore*
1044 AliMUONCalibrationData::OccupancyMap() const
1045 {
1046   /// Get occupancy map
1047   if (!fOccupancyMap)
1048   {
1049     fOccupancyMap = CreateOccupancyMap(fRunNumber);
1050   }
1051   return fOccupancyMap;
1052 }
1053
1054 //_____________________________________________________________________________
1055 AliMUONRejectList*
1056 AliMUONCalibrationData::RejectList() const
1057 {
1058   /// Get reject list
1059   if (!fRejectList)
1060   {
1061     fRejectList = CreateRejectList(fRunNumber);
1062   }
1063   return fRejectList;
1064 }
1065
1066 //_____________________________________________________________________________
1067 void
1068 AliMUONCalibrationData::BypassStores(AliMUONVStore* ped, AliMUONVStore* gain)
1069 {
1070   /// Force the use of those pedestals and gains
1071   fgBypassPedestals = ped;
1072   fgBypassGains = gain;
1073   
1074 }
1075
1076 //_____________________________________________________________________________
1077 AliMUONVStore*
1078 AliMUONCalibrationData::Pedestals() const
1079 {
1080   /// Return pedestals
1081   
1082   if (fgBypassPedestals) return fgBypassPedestals;
1083   
1084   if (!fPedestals)
1085   {
1086     fPedestals = CreatePedestals(fRunNumber);
1087   }
1088   return fPedestals;
1089 }
1090
1091 //_____________________________________________________________________________
1092 AliMUONVStore*
1093 AliMUONCalibrationData::Config() const
1094 {
1095   /// Return config
1096   
1097   if (!fConfig)
1098   {
1099     fConfig = CreateConfig(fRunNumber);
1100   }
1101   return fConfig;
1102 }
1103
1104 //_____________________________________________________________________________
1105 AliMUONVCalibParam*
1106 AliMUONCalibrationData::Pedestals(Int_t detElemId, Int_t manuId) const
1107 {
1108   /// Return the pedestals for a given (detElemId, manuId) pair.
1109   /// A return value of 0x0 is considered an error, meaning we should get
1110   /// pedestals for all channels.
1111   
1112   AliMUONVStore* pedestals = Pedestals();
1113   if (!pedestals) 
1114   {
1115     return 0x0;
1116   }
1117   
1118   return static_cast<AliMUONVCalibParam*>(pedestals->FindObject(detElemId,manuId));
1119 }
1120
1121 //_____________________________________________________________________________
1122 void
1123 AliMUONCalibrationData::Print(Option_t*) const
1124 {
1125   /// A very basic dump of our guts.
1126
1127   cout << "RunNumber " << RunNumber()
1128   << " fGains=" << fGains
1129   << " fPedestals=" << fPedestals
1130   << " fConfig=" << fConfig
1131   << " fHV=" << fHV
1132   << " fTriggerDCS=" << fTriggerDCS
1133   << " fLocalTriggerBoardMasks=" << fLocalTriggerBoardMasks
1134   << " fRegionalTriggerConfig=" << fRegionalTriggerConfig
1135   << " fGlobalTriggerCrateConfig=" << fGlobalTriggerCrateConfig
1136   << " fTriggerLut=" << fTriggerLut
1137   << endl;
1138 }
1139
1140
1141 //_____________________________________________________________________________
1142 AliMUONRegionalTriggerConfig* 
1143 AliMUONCalibrationData::RegionalTriggerConfig() const
1144 {
1145   /// Return the config for the regional trigger board.
1146   
1147   if (!fRegionalTriggerConfig)
1148   {
1149     fRegionalTriggerConfig = CreateRegionalTriggerConfig(fRunNumber);
1150     }
1151   return fRegionalTriggerConfig;
1152 }
1153
1154
1155 //_____________________________________________________________________________
1156 AliMUONTriggerEfficiencyCells*
1157 AliMUONCalibrationData::TriggerEfficiency() const
1158 {
1159 /// Return the trigger efficiency.
1160
1161   if (!fTriggerEfficiency)
1162   {
1163     fTriggerEfficiency = CreateTriggerEfficiency(fRunNumber);
1164   }
1165   return fTriggerEfficiency;
1166 }
1167
1168
1169 //_____________________________________________________________________________
1170 AliMUONTriggerLut*
1171 AliMUONCalibrationData::TriggerLut() const
1172 {
1173 /// Return the trigger look up table.
1174
1175   if (!fTriggerLut)
1176   {
1177     fTriggerLut = CreateTriggerLut(fRunNumber);
1178   }
1179   return fTriggerLut;
1180 }
1181
1182 //_____________________________________________________________________________
1183 void
1184 AliMUONCalibrationData::Reset()
1185 {
1186 /// Reset all data
1187
1188   AliCodeTimerAuto("",0);
1189   
1190   delete fConfig;
1191   fConfig = 0x0;
1192   delete fPedestals;
1193   fPedestals = 0x0;
1194   delete fGains;
1195   fGains = 0x0;
1196   delete fHV;
1197   fHV = 0x0;
1198   delete fTriggerDCS;
1199   fTriggerDCS = 0x0;
1200   delete fLocalTriggerBoardMasks;
1201   fLocalTriggerBoardMasks = 0x0;
1202   delete fRegionalTriggerConfig;
1203   fRegionalTriggerConfig = 0x0;
1204   delete fGlobalTriggerCrateConfig;
1205   fGlobalTriggerCrateConfig = 0x0;
1206   
1207   delete fTriggerLut;
1208   fTriggerLut = 0x0;
1209   delete fTriggerEfficiency;
1210   fTriggerEfficiency = 0x0;
1211   delete fCapacitances;
1212   fCapacitances = 0x0;
1213   delete fNeighbours;
1214   fNeighbours = 0x0;
1215 }
1216
1217 //_____________________________________________________________________________
1218 void
1219 AliMUONCalibrationData::Check(Int_t runNumber)
1220 {
1221   /// Self-check to see if we can read all data for a given run 
1222   /// from the current OCDB...
1223   
1224   if ( ! CreateCapacitances(runNumber) )
1225   {
1226     AliErrorClass("Could not read capacitances");
1227   }
1228   else
1229   {
1230     AliInfoClass("Capacitances read OK");
1231   }
1232
1233   if ( ! CreateGains(runNumber) ) 
1234   {
1235     AliErrorClass("Could not read gains");
1236   }
1237   else
1238   {
1239     AliInfoClass("Gains read OK");
1240   }
1241
1242   if ( ! CreateGlobalTriggerCrateConfig(runNumber) ) 
1243   {
1244     AliErrorClass("Could not read Trigger Crate Config");
1245   }
1246   else
1247   {
1248     AliInfoClass("TriggerBoardMasks read OK");
1249   }
1250
1251   if ( !  CreateHV(runNumber) )
1252   {
1253     AliErrorClass("Could not read HV");
1254   }
1255   else
1256   {
1257     AliInfoClass("HV read OK");
1258   }
1259
1260   if ( !  CreateTriggerDCS(runNumber) )
1261   {
1262     AliErrorClass("Could not read Trigger HV and Currents");
1263   }
1264   else
1265   {
1266     AliInfoClass("Trigger HV and Currents read OK");
1267   }
1268
1269   if ( ! CreateNeighbours(runNumber) )
1270   {
1271     AliErrorClass("Could not read Neighbours");
1272   }
1273   else
1274   {
1275     AliInfoClass("Neighbours read OK");
1276   }
1277
1278   if ( !  CreateLocalTriggerBoardMasks(runNumber) )
1279   {
1280     AliErrorClass("Could not read LocalTriggerBoardMasks");
1281   }
1282   else
1283   {
1284     AliInfoClass("LocalTriggerBoardMasks read OK");
1285   }
1286   
1287   if ( ! CreatePedestals(runNumber) )
1288   {
1289     AliErrorClass("Could not read pedestals");
1290   }
1291   else
1292   {
1293     AliInfoClass("Pedestals read OK");
1294   }
1295
1296   if ( ! CreateConfig(runNumber) )
1297   {
1298     AliErrorClass("Could not read config");
1299   }
1300   else
1301   {
1302     AliInfoClass("Config read OK");
1303   }
1304   
1305   if ( ! CreateRegionalTriggerConfig(runNumber) )
1306   {
1307     AliErrorClass("Could not read RegionalTriggerConfig");
1308   }
1309   else
1310   {
1311     AliInfoClass("RegionalTriggerBoardMasks read OK");
1312   }
1313   
1314   if ( ! CreateTriggerLut(runNumber) )
1315   {
1316     AliErrorClass("Could not read TriggerLut");
1317   }
1318   else
1319   {
1320     AliInfoClass("TriggerLut read OK");
1321   }
1322
1323   if ( ! CreateTriggerEfficiency(runNumber) )
1324   {
1325     AliErrorClass("Could not read TriggerEfficiency");
1326   }
1327   else    
1328   {
1329     AliInfoClass("TriggerEfficiency read OK");
1330   }
1331 }