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