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