Correct the message about rejected pads, by not mixing good pads with total number...
[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
66 //_____________________________________________________________________________
67 AliMUONDigitCalibrator::AliMUONDigitCalibrator(const AliMUONCalibrationData& calib,
68                                                const AliMUONRecoParam* recoParams,
69                                                const char* calibMode)
70 : TObject(),
71 fLogger(new AliMUONLogger(20000)),
72 fStatusMaker(0x0),
73 fStatusMapMaker(0x0),
74 fPedestals(0x0),
75 fGains(0x0),
76 fApplyGains(0),
77 fCapacitances(0x0),
78 fNumberOfBadPads(0),
79 fNumberOfPads(0),
80 fChargeSigmaCut(0)
81 {
82   /// ctor
83   
84   Ctor(calibMode,calib,recoParams);
85 }
86
87 //_____________________________________________________________________________
88 AliMUONDigitCalibrator::AliMUONDigitCalibrator(const AliMUONCalibrationData& calib,
89                                                const char* calibMode)
90 : TObject(),
91 fLogger(new AliMUONLogger(20000)),
92 fStatusMaker(0x0),
93 fStatusMapMaker(0x0),
94 fPedestals(0x0),
95 fGains(0x0),
96 fApplyGains(0),
97 fCapacitances(0x0),
98 fNumberOfBadPads(0),
99 fNumberOfPads(0),
100 fChargeSigmaCut(0)
101 {
102   /// ctor
103   
104   Ctor(calibMode,calib,0x0);
105 }
106
107 //_____________________________________________________________________________
108 void
109 AliMUONDigitCalibrator::Ctor(const char* calibMode,
110                              const AliMUONCalibrationData& calib,
111                              const AliMUONRecoParam* recoParams)
112 {
113   /// designated ctor
114   
115   TString cMode(calibMode);
116   cMode.ToUpper();
117   
118   if ( cMode == "NOGAIN" ) 
119   {
120     fApplyGains = fgkNoGain;
121     AliInfo("Will NOT apply gain correction");
122   }
123   else if ( cMode == "GAINCONSTANTCAPA" ) 
124   {
125     fApplyGains = fgkGainConstantCapa;
126     AliInfo("Will apply gain correction, but with constant capacitance");
127   }
128   else if ( cMode == "GAIN" ) 
129   {
130     fApplyGains = fgkGain;
131     AliInfo("Will apply gain correction, with measured capacitances");
132   }
133   else
134   {
135     AliError(Form("Invalid calib mode = %s. Will use NOGAIN instead",calibMode));
136     fApplyGains = fgkNoGain;
137   }
138        
139   // Load mapping manu store
140   if ( ! AliMpCDB::LoadManuStore() ) {
141     AliFatal("Could not access manu store from OCDB !");
142   }
143
144   fStatusMaker = new AliMUONPadStatusMaker(calib);
145   
146   // Set default values, as loose as reasonable
147
148   fChargeSigmaCut = 3.0;
149   
150         Int_t mask(0x8080); // reject pads where ped *or* hv are missing
151         
152         if ( recoParams )
153         {
154     // if we have reco params, we use limits and cuts from there :
155     
156                 fStatusMaker->SetHVSt12Limits(recoParams->HVSt12LowLimit(),recoParams->HVSt12HighLimit());
157                 fStatusMaker->SetHVSt345Limits(recoParams->HVSt345LowLimit(),recoParams->HVSt345HighLimit());
158                 fStatusMaker->SetPedMeanLimits(recoParams->PedMeanLowLimit(),recoParams->PedMeanHighLimit());
159                 fStatusMaker->SetPedSigmaLimits(recoParams->PedSigmaLowLimit(),recoParams->PedSigmaHighLimit());
160                 fStatusMaker->SetGainA1Limits(recoParams->GainA1LowLimit(),recoParams->GainA1HighLimit());
161                 fStatusMaker->SetGainA2Limits(recoParams->GainA2LowLimit(),recoParams->GainA2HighLimit());
162                 fStatusMaker->SetGainThresLimits(recoParams->GainThresLowLimit(),recoParams->GainThresHighLimit());
163                 
164     mask = recoParams->PadGoodnessMask();
165                 //WARNING : getting this mask wrong is a very effective way of getting
166                 //no digits at all out of this class ;-)
167     
168     fChargeSigmaCut = recoParams->ChargeSigmaCut();
169         }
170   
171   Bool_t deferredInitialization = kTRUE;
172   
173   fStatusMapMaker = new AliMUONPadStatusMapMaker(*fStatusMaker,mask,deferredInitialization);
174   
175   fPedestals = calib.Pedestals();
176
177   fGains = calib.Gains(); // we get gains whatever the calibMode is, in order
178   // to get the saturation value...
179
180   if ( fApplyGains == fgkGain ) 
181   {
182     fCapacitances = calib.Capacitances();
183   }
184 }
185
186 //_____________________________________________________________________________
187 AliMUONDigitCalibrator::~AliMUONDigitCalibrator()
188 {
189   /// dtor.
190   delete fStatusMaker;
191   delete fStatusMapMaker;
192   
193   AliInfo("Summary of messages:");
194   fLogger->Print();
195
196         AliInfo(Form("We have seen %g pads, and rejected %g (%7.2f %%)",
197                                                          fNumberOfPads,fNumberOfBadPads,
198                                                          ( fNumberOfPads > 0 ) ? fNumberOfBadPads*100.0/fNumberOfPads : 0 ));
199         
200   delete fLogger;
201 }
202
203 //_____________________________________________________________________________
204 void
205 AliMUONDigitCalibrator::Calibrate(AliMUONVDigitStore& digitStore)
206 {
207   /// Calibrate the digits contained in digitStore  
208   TIter next(digitStore.CreateTrackerIterator());
209   AliMUONVDigit* digit;
210   Int_t detElemId(-1);
211   Double_t nsigmas = fChargeSigmaCut;
212   
213   AliDebug(1,Form("# of digits = %d",digitStore.GetSize()));
214   
215   while ( ( digit = static_cast<AliMUONVDigit*>(next() ) ) )
216   {
217     if ( digit->IsCalibrated() ) 
218     {
219       fLogger->Log("ERROR : trying to calibrate a digit twice");
220       return;
221     }
222     
223     digit->Calibrated(kTRUE);
224     
225     if ( digit->DetElemId() != detElemId ) 
226     {
227       // Find out occupancy of that DE
228       detElemId = digit->DetElemId();
229       AliMpDetElement* de = AliMpDDLStore::Instance()->GetDetElement(detElemId);
230       Double_t nchannels = de->NofChannels();
231       Double_t occ = digitStore.GetSize(detElemId)/nchannels;
232       if ( occ > 0.05 ) 
233       {
234         nsigmas = 10.0; // enlarge (a lot) sigma cut if occupancy is high
235         // (which probably means zero suppression was not exactly OK).
236         fLogger->Log(Form("Will use %5.0f*sigma cut for DE %04d "
237                           "due to high occupancy",nsigmas,detElemId));
238       }
239       else
240       {
241         nsigmas = fChargeSigmaCut;
242       }
243     }
244
245     Float_t charge(0.0);
246     Int_t statusMap;
247     Bool_t isSaturated(kFALSE);
248
249     ++fNumberOfPads;
250
251     Bool_t ok = IsValidDigit(digit->DetElemId(),digit->ManuId(),digit->ManuChannel(),&statusMap);
252
253     digit->SetStatusMap(statusMap);
254     
255     if (ok)
256     {
257       charge = CalibrateDigit(digit->DetElemId(),digit->ManuId(),digit->ManuChannel(),
258                               digit->ADC(),nsigmas,&isSaturated);
259     }
260     else
261     {
262       ++fNumberOfBadPads;
263     }
264     
265     digit->SetCharge(charge);
266     digit->Saturated(isSaturated);
267   }
268 }
269
270 //_____________________________________________________________________________
271 Float_t
272 AliMUONDigitCalibrator::CalibrateDigit(Int_t detElemId, Int_t manuId, Int_t manuChannel,
273                                        Float_t adc, Float_t nsigmas, 
274                                        Bool_t* isSaturated) const
275
276 {
277   /// Calibrate one digit
278   
279   
280   AliMUONVCalibParam* pedestal = static_cast<AliMUONVCalibParam*>
281   (fPedestals->FindObject(detElemId,manuId));
282   
283   if (!pedestal)
284   {
285     // no pedestal -> no charge    
286     fLogger->Log(Form("Got a null pedestal object for DE,manu=%d,%d",detElemId,manuId));        
287     return 0.0;
288   }
289   
290   
291   AliMUONVCalibParam* gain = static_cast<AliMUONVCalibParam*>
292   (fGains->FindObject(detElemId,manuId));
293   
294   if (!gain)
295   {
296     if ( fApplyGains != fgkNoGain )
297     {
298       // no gain -> no charge
299       fLogger->Log(Form("Got a null gain object for DE,manu=%d,%d",
300                         detElemId,manuId)); 
301       return 0.0;
302     }
303   }
304   
305   Float_t padc = adc-pedestal->ValueAsFloat(manuChannel,0);
306   Float_t charge(0);
307   Float_t capa(1.0);
308   
309   if ( fApplyGains == fgkGainConstantCapa ) 
310   {
311     capa = 0.2; // pF
312   }
313   else if ( fApplyGains == fgkGain ) 
314   {
315     
316
317     Int_t serialNumber 
318       = AliMpManuStore::Instance()->GetManuSerial(detElemId, manuId);
319     
320     AliMUONVCalibParam* param = static_cast<AliMUONVCalibParam*>(fCapacitances->FindObject(serialNumber));
321     
322     if ( param )
323     {
324       capa = param->ValueAsFloat(manuChannel);
325     }
326     else
327     {
328       fLogger->Log(Form("No capa found for serialNumber=%d",serialNumber));
329       capa = 0.0;
330     }
331   }
332   
333   if ( padc > nsigmas*pedestal->ValueAsFloat(manuChannel,1) ) 
334   {
335     if ( fApplyGains != fgkNoGain ) 
336     {
337       Float_t a0 = gain->ValueAsFloat(manuChannel,0);
338       Float_t a1 = gain->ValueAsFloat(manuChannel,1);
339       Int_t thres = gain->ValueAsInt(manuChannel,2);
340       if ( padc < thres ) 
341       {
342         charge = a0*padc;
343       }
344       else
345       {
346         charge = a0*thres + a0*(padc-thres) + a1*(padc-thres)*(padc-thres);
347       }
348     }
349     else
350     {
351       charge = padc;
352     }
353   }
354   
355   charge *= capa;
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