In AliMUONTriggerQADataMakerRec:
[u/mrichter/AliRoot.git] / MUON / AliMUONDigitCalibrator.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$
17
18 #include "AliMUONDigitCalibrator.h"
19
20 #include "AliCDBEntry.h"
21 #include "AliCDBManager.h"
22 #include "AliLog.h"
23 #include "AliMUONCalibrationData.h"
24 #include "AliMUONLogger.h"
25 #include "AliMUONPadStatusMaker.h"
26 #include "AliMUONPadStatusMapMaker.h"
27 #include "AliMUONRecoParam.h"
28 #include "AliMUONVCalibParam.h"
29 #include "AliMUONVDigit.h"
30 #include "AliMUONVDigitStore.h"
31 #include "AliMUONVStore.h"
32 #include "AliMpBusPatch.h"
33 #include "AliMpConstants.h"
34 #include "AliMpCDB.h"
35 #include "AliMpDDLStore.h"
36 #include "AliMpDEIterator.h"
37 #include "AliMpDetElement.h"
38 #include "AliMpManuStore.h"
39
40 //-----------------------------------------------------------------------------
41 /// \class AliMUONDigitCalibrator
42 /// Class used to calibrate digits (either real or simulated ones).
43 ///
44 /// The calibration consists of subtracting the pedestal
45 /// and multiplying by a gain, so that
46 /// Signal = (ADC-pedestal)*gain
47 ///
48 /// Please note also that for the moment, if a digit lies on a dead channel
49 /// we remove this digit from the list of digits.
50 /// FIXME: this has to be revisited. By using the AliMUONDigit::fFlags we
51 /// should in principle flag a digit as bad w/o removing it, but this 
52 /// then requires some changes in the cluster finder to deal with this extra
53 /// information correctly (e.g. to set a quality for the cluster if it contains
54 /// bad digits).
55 ///
56 /// \author Laurent Aphecetche
57 //-----------------------------------------------------------------------------
58
59
60 /// \cond CLASSIMP
61 ClassImp(AliMUONDigitCalibrator)
62 /// \endcond
63
64 const Int_t AliMUONDigitCalibrator::fgkNoGain(0);
65 const Int_t AliMUONDigitCalibrator::fgkGainConstantCapa(1);
66 const Int_t AliMUONDigitCalibrator::fgkGain(2);
67 const Int_t AliMUONDigitCalibrator::fgkInjectionGain(3);
68
69 //_____________________________________________________________________________
70 AliMUONDigitCalibrator::AliMUONDigitCalibrator(Int_t runNumber, const char* calibMode)
71 : TObject(),
72 fLogger(new AliMUONLogger(20000)),
73 fStatusMaker(0x0),
74 fStatusMapMaker(0x0),
75 fPedestals(0x0),
76 fGains(0x0),
77 fApplyGains(0),
78 fCapacitances(0x0),
79 fNumberOfBadPads(0),
80 fNumberOfPads(0),
81 fChargeSigmaCut(0),
82 fMask(0)
83 {
84   /// ctor
85   
86   AliMUONRecoParam* recoParam(0x0);
87   
88   AliCDBEntry* e = AliCDBManager::Instance()->Get("MUON/Calib/RecoParam",runNumber);
89   if (e)
90   {
91     TObject* o = e->GetObject();
92     if ( o->IsA() == TObjArray::Class() )
93     {
94       TObjArray* a = static_cast<TObjArray*>(o);
95       TIter next(a);
96       AliMUONRecoParam* p;
97       while ( ( p = static_cast<AliMUONRecoParam*>(next()) ))
98       {
99         if ( p->IsDefault()) recoParam = p;
100       }
101     }
102     else
103     {
104       recoParam = static_cast<AliMUONRecoParam*>(o);
105     }
106   }
107   if (!recoParam)
108   {
109     AliError("Cannot get the recoParam. Failing");
110     return;
111   }
112   
113   // OK. Now get all we need and work...
114   
115   AliMUONCalibrationData calib(runNumber);
116   
117   Ctor(calibMode,calib,recoParam,kFALSE);
118 }
119
120 //_____________________________________________________________________________
121 AliMUONDigitCalibrator::AliMUONDigitCalibrator(const AliMUONCalibrationData& calib,
122                                                const AliMUONRecoParam* recoParams,
123                                                const char* calibMode)
124 : TObject(),
125 fLogger(new AliMUONLogger(20000)),
126 fStatusMaker(0x0),
127 fStatusMapMaker(0x0),
128 fPedestals(0x0),
129 fGains(0x0),
130 fApplyGains(0),
131 fCapacitances(0x0),
132 fNumberOfBadPads(0),
133 fNumberOfPads(0),
134 fChargeSigmaCut(0),
135 fMask(0)
136 {
137   /// ctor
138   
139   Ctor(calibMode,calib,recoParams);
140 }
141
142 //_____________________________________________________________________________
143 AliMUONDigitCalibrator::AliMUONDigitCalibrator(const AliMUONCalibrationData& calib,
144                                                const char* calibMode)
145 : TObject(),
146 fLogger(new AliMUONLogger(20000)),
147 fStatusMaker(0x0),
148 fStatusMapMaker(0x0),
149 fPedestals(0x0),
150 fGains(0x0),
151 fApplyGains(0),
152 fCapacitances(0x0),
153 fNumberOfBadPads(0),
154 fNumberOfPads(0),
155 fChargeSigmaCut(0),
156 fMask(0)
157 {
158   /// ctor
159   
160   Ctor(calibMode,calib,0x0);
161 }
162
163 //_____________________________________________________________________________
164 void
165 AliMUONDigitCalibrator::Ctor(const char* calibMode,
166                              const AliMUONCalibrationData& calib,
167                              const AliMUONRecoParam* recoParams,
168                              Bool_t deferredInitialization)
169 {
170   /// designated ctor
171   
172   TString cMode(calibMode);
173   cMode.ToUpper();
174   
175   if ( cMode == "NOGAIN" ) 
176   {
177     fApplyGains = fgkNoGain;
178     AliInfo("Will NOT apply gain correction");
179   }
180   else if ( cMode == "GAINCONSTANTCAPA" ) 
181   {
182     fApplyGains = fgkGainConstantCapa;
183     AliInfo("Will apply gain correction, but with constant capacitance");
184   }
185   else if ( cMode == "GAIN" ) 
186   {
187     fApplyGains = fgkGain;
188     AliInfo("Will apply gain correction, with measured capacitances");
189   }
190   else if ( cMode == "INJECTIONGAIN")
191         {
192                 fApplyGains = fgkInjectionGain;
193     AliInfo("Will apply injection gain correction, with EMELEC factory gains");
194         }  
195   else
196   {
197     AliError(Form("Invalid calib mode = %s. Will use NOGAIN instead",calibMode));
198     fApplyGains = fgkNoGain;
199   }
200   
201   // Load mapping manu store
202   if ( ! AliMpCDB::LoadManuStore() ) {
203     AliFatal("Could not access manu store from OCDB !");
204   }
205   
206   fStatusMaker = new AliMUONPadStatusMaker(calib);
207   
208   // Set default values, as loose as reasonable
209   
210   fChargeSigmaCut = 3.0;
211   
212         fMask = 0x8080; // reject pads where ped *or* hv are missing
213         
214         if ( recoParams )
215         {
216     // if we have reco params, we use limits and cuts from there :
217     
218     fStatusMaker->SetLimits(*recoParams);
219     
220     fMask = recoParams->PadGoodnessMask();
221                 //WARNING : getting this mask wrong is a very effective way of getting
222                 //no digits at all out of this class ;-)
223     
224     fChargeSigmaCut = recoParams->ChargeSigmaCut();
225         }
226   else
227   {
228     fLogger->Log("No RecoParam available");
229     fLogger->Log(Form("SigmaCut=%e",fChargeSigmaCut));
230   }
231   
232   fStatusMapMaker = new AliMUONPadStatusMapMaker(*fStatusMaker,fMask,deferredInitialization);
233   
234   fPedestals = calib.Pedestals();
235   
236   fGains = calib.Gains(); // we get gains whatever the calibMode is, in order
237   // to get the saturation value...
238   
239   if ( fApplyGains == fgkGain || fApplyGains == fgkInjectionGain ) 
240   {
241     fCapacitances = calib.Capacitances();
242   }
243 }
244
245 //_____________________________________________________________________________
246 AliMUONDigitCalibrator::~AliMUONDigitCalibrator()
247 {
248   /// dtor.
249   
250   if ( fNumberOfPads > 0 ) 
251   {
252     if ( fStatusMaker ) 
253     {
254       fStatusMaker->Report(fMask);
255     }
256     
257     AliInfo("Summary of messages:");
258
259     fLogger->Print();
260     
261     AliInfo(Form("We have seen %g pads, and rejected %g (%7.2f %%)",
262                  fNumberOfPads,fNumberOfBadPads,
263                  ( fNumberOfPads > 0 ) ? fNumberOfBadPads*100.0/fNumberOfPads : 0 ));
264         }
265
266   delete fStatusMaker;
267   delete fStatusMapMaker;
268   delete fLogger;
269 }
270
271 //_____________________________________________________________________________
272 void
273 AliMUONDigitCalibrator::Calibrate(AliMUONVDigitStore& digitStore)
274 {
275   /// Calibrate the digits contained in digitStore  
276   TIter next(digitStore.CreateTrackerIterator());
277   AliMUONVDigit* digit;
278   
279   fStatusMapMaker->RefreshRejectProbabilities(); // this will do something only for simulations
280   // (and only for those simulations where the reject list contain probabilities which are
281   // different from zero or one)
282   
283   AliDebug(1,Form("# of digits = %d",digitStore.GetSize()));
284   
285   while ( ( digit = static_cast<AliMUONVDigit*>(next() ) ) )
286   {
287     if ( digit->IsCalibrated() ) 
288     {
289       fLogger->Log("ERROR : trying to calibrate a digit twice");
290       return;
291     }
292     
293     digit->Calibrated(kTRUE);
294     
295     Float_t charge(0.0);
296     Int_t statusMap;
297     Bool_t isSaturated(kFALSE);
298     
299     ++fNumberOfPads;
300     
301     Bool_t ok = IsValidDigit(digit->DetElemId(),digit->ManuId(),digit->ManuChannel(),&statusMap);
302     
303     digit->SetStatusMap(statusMap);
304     
305     if (ok)
306     {
307       charge = CalibrateDigit(digit->DetElemId(),digit->ManuId(),digit->ManuChannel(),
308                               digit->ADC(),fChargeSigmaCut,&isSaturated);
309     }
310     else
311     {
312       ++fNumberOfBadPads;      
313     }
314     
315     digit->SetCharge(charge);
316     digit->Saturated(isSaturated);
317   }
318 }
319
320 //_____________________________________________________________________________
321 Float_t
322 AliMUONDigitCalibrator::CalibrateDigit(Int_t detElemId, Int_t manuId, Int_t manuChannel,
323                                        Float_t adc, Float_t nsigmas, 
324                                        Bool_t* isSaturated) const
325
326 {
327   /// Calibrate one digit
328   /// Return the digit charge, in fC
329   
330   if ( nsigmas < 0 ) 
331   {
332     nsigmas = fChargeSigmaCut;
333   }
334
335   fLogger->Log(Form("ChargeSigmaCut used = %e",nsigmas));
336
337   AliMUONVCalibParam* pedestal = static_cast<AliMUONVCalibParam*>
338   (fPedestals->FindObject(detElemId,manuId));
339   
340   if (!pedestal)
341   {
342     // no pedestal -> no charge    
343     fLogger->Log(Form("Got a null pedestal object for DE,manu=%d,%d",detElemId,manuId));        
344     return 0.0;
345   }
346   
347   
348   AliMUONVCalibParam* gain = static_cast<AliMUONVCalibParam*>
349   (fGains->FindObject(detElemId,manuId));
350   
351   if (!gain)
352   {
353     if ( fApplyGains != fgkNoGain )
354     {
355       // no gain -> no charge
356       fLogger->Log(Form("Got a null gain object for DE,manu=%d,%d",
357                         detElemId,manuId)); 
358       return 0.0;
359     }
360   }
361   
362   Float_t padc = adc-pedestal->ValueAsFloat(manuChannel,0);
363   
364         // Gain (mV/fC) = 1/(a0*capa) with a0~1.25 and capa~0.2 
365   Float_t charge(0);
366   Float_t capa(0.2); // capa = 0.2 and a0 = 1.25
367         Float_t a0(1.25);  // is equivalent to gain = 4 mV/fC
368         Float_t a1(0);
369         Float_t adc2mv(0.61); // 1 ADC channel = 0.61 mV
370         Float_t injGain(4); // By default the gain is set to 4 mV/fC
371   //
372   // Note that the ChargeMax (for one pad) is roughly 4096 * 0.61 mV/channel / 4 mV/fC = 625 fC
373
374   if ( fApplyGains == fgkGain || fApplyGains == fgkInjectionGain ) 
375   {
376     Int_t serialNumber 
377     = AliMpManuStore::Instance()->GetManuSerial(detElemId, manuId);
378     
379     AliMUONVCalibParam* param = static_cast<AliMUONVCalibParam*>(fCapacitances->FindObject(serialNumber));
380     
381     if ( param )
382     {
383       capa = param->ValueAsFloat(manuChannel,0);
384                         injGain = param->ValueAsFloat(manuChannel,1);
385       if ( injGain < 0 ) 
386       {
387         fLogger->Log(Form("injGain is %e < 0 for serialNumber=%d",injGain,serialNumber));
388         return 0.0;
389       }
390     }
391     else
392     {
393       // If capa not found in the OCDB we exit
394             fLogger->Log(Form("No capa (injGain) found for serialNumber=%d",serialNumber));
395                         return 0.0;
396     }
397   }
398   
399   if ( padc > nsigmas*pedestal->ValueAsFloat(manuChannel,1) ) 
400   {
401     if ( fApplyGains == fgkGain || fApplyGains == fgkGainConstantCapa ) 
402     {
403       a0 = gain->ValueAsFloat(manuChannel,0);
404       a1 = gain->ValueAsFloat(manuChannel,1);
405       Int_t thres = gain->ValueAsInt(manuChannel,2);
406       if ( padc < thres ) 
407       {
408         charge = a0*padc;
409       }
410       else
411       {
412         charge = a0*thres + a0*(padc-thres) + a1*(padc-thres)*(padc-thres);
413       }
414                         charge *= capa*adc2mv;
415     }
416     else if ( fApplyGains == fgkInjectionGain ) 
417     {
418                         
419       charge = padc*adc2mv/injGain;
420     }
421                 else
422                 {
423                         charge = a0*padc*capa*adc2mv;
424                 }
425   }
426   
427   if ( isSaturated ) 
428   {
429     Int_t saturation(3000);
430     
431     if ( gain && ( fApplyGains != fgkNoGain ) )
432     {
433       saturation = gain->ValueAsInt(manuChannel,4);
434     }
435     
436     if ( padc >= saturation )
437     {
438       *isSaturated = kTRUE;
439     }
440     else
441     {
442       *isSaturated = kFALSE;
443     }
444   }
445   
446   return ( charge > 0.0 ? charge : 0.0 );
447 }
448
449 //_____________________________________________________________________________
450 Bool_t 
451 AliMUONDigitCalibrator::IsValidDigit(Int_t detElemId, Int_t manuId, Int_t manuChannel,
452                                      Int_t* statusMap) const
453
454 {
455   /// Check if a given pad is ok or not.
456   
457   // First a protection against bad input parameters
458   AliMpDetElement* de = AliMpDDLStore::Instance()->GetDetElement(detElemId);
459   if (!de) return kFALSE; // not existing DE
460   if (!de->IsExistingChannel(manuId,manuChannel))
461   {
462     // non-existing (might happen when we get parity errors in read-out
463     // that spoils the manuId
464     return kFALSE;
465   }
466   if (!de->IsConnectedChannel(manuId,manuChannel))
467   {
468     // existing (in read-out), but not connected channel
469     return kFALSE;
470   }
471   
472   // ok, now we have a valid channel number, so let's see if that pad
473   // behaves or not ;-)
474   
475   Int_t sm = fStatusMapMaker->StatusMap(detElemId,manuId,manuChannel);
476   
477   if (statusMap) *statusMap = sm;
478   
479   if ( ( sm & AliMUONPadStatusMapMaker::SelfDeadMask() ) != 0 ) 
480   {
481     // pad itself is bad (not testing its neighbours at this stage)
482     return kFALSE;
483   }
484   
485   return kTRUE;
486 }
487
488 //_____________________________________________________________________________
489 Int_t 
490 AliMUONDigitCalibrator::PadStatus(Int_t detElemId, Int_t manuId, Int_t manuChannel) const
491 {
492   /// Return the status of the given pad
493   return fStatusMaker->PadStatus(detElemId,manuId,manuChannel);
494 }
495
496 //_____________________________________________________________________________
497 Int_t 
498 AliMUONDigitCalibrator::StatusMap(Int_t detElemId, Int_t manuId, Int_t manuChannel) const
499 {
500   /// Return the status map of the given pad
501   return fStatusMapMaker->StatusMap(detElemId,manuId,manuChannel);
502   
503 }
504