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