]> git.uio.no Git - u/mrichter/AliRoot.git/blob - MUON/AliMUONDigitCalibrator.cxx
AMORE & QA fixes.
[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 fMask(0)
83 {
84   /// ctor
85   
86   Ctor(calibMode,calib,recoParams);
87 }
88
89 //_____________________________________________________________________________
90 AliMUONDigitCalibrator::AliMUONDigitCalibrator(const AliMUONCalibrationData& calib,
91                                                const char* calibMode)
92 : TObject(),
93 fLogger(new AliMUONLogger(20000)),
94 fStatusMaker(0x0),
95 fStatusMapMaker(0x0),
96 fPedestals(0x0),
97 fGains(0x0),
98 fApplyGains(0),
99 fCapacitances(0x0),
100 fNumberOfBadPads(0),
101 fNumberOfPads(0),
102 fChargeSigmaCut(0),
103 fMask(0)
104 {
105   /// ctor
106   
107   Ctor(calibMode,calib,0x0);
108 }
109
110 //_____________________________________________________________________________
111 void
112 AliMUONDigitCalibrator::Ctor(const char* calibMode,
113                              const AliMUONCalibrationData& calib,
114                              const AliMUONRecoParam* recoParams)
115 {
116   /// designated ctor
117   
118   TString cMode(calibMode);
119   cMode.ToUpper();
120   
121   if ( cMode == "NOGAIN" ) 
122   {
123     fApplyGains = fgkNoGain;
124     AliInfo("Will NOT apply gain correction");
125   }
126   else if ( cMode == "GAINCONSTANTCAPA" ) 
127   {
128     fApplyGains = fgkGainConstantCapa;
129     AliInfo("Will apply gain correction, but with constant capacitance");
130   }
131   else if ( cMode == "GAIN" ) 
132   {
133     fApplyGains = fgkGain;
134     AliInfo("Will apply gain correction, with measured capacitances");
135   }
136   else if ( cMode == "INJECTIONGAIN")
137         {
138                 fApplyGains = fgkInjectionGain;
139     AliInfo("Will apply injection gain correction, with EMELEC factory gains");
140         }  
141   else
142   {
143     AliError(Form("Invalid calib mode = %s. Will use NOGAIN instead",calibMode));
144     fApplyGains = fgkNoGain;
145   }
146   
147   // Load mapping manu store
148   if ( ! AliMpCDB::LoadManuStore() ) {
149     AliFatal("Could not access manu store from OCDB !");
150   }
151   
152   fStatusMaker = new AliMUONPadStatusMaker(calib);
153   
154   // Set default values, as loose as reasonable
155   
156   fChargeSigmaCut = 3.0;
157   
158         fMask = 0x8080; // reject pads where ped *or* hv are missing
159         
160         if ( recoParams )
161         {
162     // if we have reco params, we use limits and cuts from there :
163     
164     fStatusMaker->SetLimits(*recoParams);
165     
166     fMask = recoParams->PadGoodnessMask();
167                 //WARNING : getting this mask wrong is a very effective way of getting
168                 //no digits at all out of this class ;-)
169     
170     fChargeSigmaCut = recoParams->ChargeSigmaCut();
171         }
172   else
173   {
174     fLogger->Log("No RecoParam available");
175     fLogger->Log(Form("SigmaCut=%e",fChargeSigmaCut));
176   }
177   
178   Bool_t deferredInitialization = kTRUE;
179   
180   fStatusMapMaker = new AliMUONPadStatusMapMaker(*fStatusMaker,fMask,deferredInitialization);
181   
182   fPedestals = calib.Pedestals();
183   
184   fGains = calib.Gains(); // we get gains whatever the calibMode is, in order
185   // to get the saturation value...
186   
187   if ( fApplyGains == fgkGain || fApplyGains == fgkInjectionGain ) 
188   {
189     fCapacitances = calib.Capacitances();
190   }
191 }
192
193 //_____________________________________________________________________________
194 AliMUONDigitCalibrator::~AliMUONDigitCalibrator()
195 {
196   /// dtor.
197   
198   if ( fNumberOfPads > 0 ) 
199   {
200     if ( fStatusMaker ) 
201     {
202       fStatusMaker->Report(fMask);
203     }
204     
205     AliInfo("Summary of messages:");
206
207     fLogger->Print();
208     
209     AliInfo(Form("We have seen %g pads, and rejected %g (%7.2f %%)",
210                  fNumberOfPads,fNumberOfBadPads,
211                  ( fNumberOfPads > 0 ) ? fNumberOfBadPads*100.0/fNumberOfPads : 0 ));
212         }
213
214   delete fStatusMaker;
215   delete fStatusMapMaker;
216   delete fLogger;
217 }
218
219 //_____________________________________________________________________________
220 void
221 AliMUONDigitCalibrator::Calibrate(AliMUONVDigitStore& digitStore)
222 {
223   /// Calibrate the digits contained in digitStore  
224   TIter next(digitStore.CreateTrackerIterator());
225   AliMUONVDigit* digit;
226   
227   fStatusMapMaker->RefreshRejectProbabilities(); // this will do something only for simulations
228   // (and only for those simulations where the reject list contain probabilities which are
229   // different from zero or one)
230   
231   AliDebug(1,Form("# of digits = %d",digitStore.GetSize()));
232   
233   while ( ( digit = static_cast<AliMUONVDigit*>(next() ) ) )
234   {
235     if ( digit->IsCalibrated() ) 
236     {
237       fLogger->Log("ERROR : trying to calibrate a digit twice");
238       return;
239     }
240     
241     digit->Calibrated(kTRUE);
242     
243     Float_t charge(0.0);
244     Int_t statusMap;
245     Bool_t isSaturated(kFALSE);
246     
247     ++fNumberOfPads;
248     
249     Bool_t ok = IsValidDigit(digit->DetElemId(),digit->ManuId(),digit->ManuChannel(),&statusMap);
250     
251     digit->SetStatusMap(statusMap);
252     
253     if (ok)
254     {
255       charge = CalibrateDigit(digit->DetElemId(),digit->ManuId(),digit->ManuChannel(),
256                               digit->ADC(),fChargeSigmaCut,&isSaturated);
257     }
258     else
259     {
260       ++fNumberOfBadPads;      
261     }
262     
263     digit->SetCharge(charge);
264     digit->Saturated(isSaturated);
265   }
266 }
267
268 //_____________________________________________________________________________
269 Float_t
270 AliMUONDigitCalibrator::CalibrateDigit(Int_t detElemId, Int_t manuId, Int_t manuChannel,
271                                        Float_t adc, Float_t nsigmas, 
272                                        Bool_t* isSaturated) const
273
274 {
275   /// Calibrate one digit
276   /// Return the digit charge, in fC
277   
278   if ( nsigmas < 0 ) 
279   {
280     nsigmas = fChargeSigmaCut;
281   }
282
283   fLogger->Log(Form("ChargeSigmaCut used = %e",nsigmas));
284
285   AliMUONVCalibParam* pedestal = static_cast<AliMUONVCalibParam*>
286   (fPedestals->FindObject(detElemId,manuId));
287   
288   if (!pedestal)
289   {
290     // no pedestal -> no charge    
291     fLogger->Log(Form("Got a null pedestal object for DE,manu=%d,%d",detElemId,manuId));        
292     return 0.0;
293   }
294   
295   
296   AliMUONVCalibParam* gain = static_cast<AliMUONVCalibParam*>
297   (fGains->FindObject(detElemId,manuId));
298   
299   if (!gain)
300   {
301     if ( fApplyGains != fgkNoGain )
302     {
303       // no gain -> no charge
304       fLogger->Log(Form("Got a null gain object for DE,manu=%d,%d",
305                         detElemId,manuId)); 
306       return 0.0;
307     }
308   }
309   
310   Float_t padc = adc-pedestal->ValueAsFloat(manuChannel,0);
311   
312         // Gain (mV/fC) = 1/(a0*capa) with a0~1.25 and capa~0.2 
313   Float_t charge(0);
314   Float_t capa(0.2); // capa = 0.2 and a0 = 1.25
315         Float_t a0(1.25);  // is equivalent to gain = 4 mV/fC
316         Float_t a1(0);
317         Float_t adc2mv(0.61); // 1 ADC channel = 0.61 mV
318         Float_t injGain(4); // By default the gain is set to 4 mV/fC
319   //
320   // Note that the ChargeMax (for one pad) is roughly 4096 * 0.61 mV/channel / 4 mV/fC = 625 fC
321
322   if ( fApplyGains == fgkGain || fApplyGains == fgkInjectionGain ) 
323   {
324     Int_t serialNumber 
325     = AliMpManuStore::Instance()->GetManuSerial(detElemId, manuId);
326     
327     AliMUONVCalibParam* param = static_cast<AliMUONVCalibParam*>(fCapacitances->FindObject(serialNumber));
328     
329     if ( param )
330     {
331       capa = param->ValueAsFloat(manuChannel,0);
332                         injGain = param->ValueAsFloat(manuChannel,1);
333       if ( injGain < 0 ) 
334       {
335         fLogger->Log(Form("injGain is %e < 0 for serialNumber=%d",injGain,serialNumber));
336         return 0.0;
337       }
338     }
339     else
340     {
341       // If capa not found in the OCDB we exit
342             fLogger->Log(Form("No capa (injGain) found for serialNumber=%d",serialNumber));
343                         return 0.0;
344     }
345   }
346   
347   if ( padc > nsigmas*pedestal->ValueAsFloat(manuChannel,1) ) 
348   {
349     if ( fApplyGains == fgkGain || fApplyGains == fgkGainConstantCapa ) 
350     {
351       a0 = gain->ValueAsFloat(manuChannel,0);
352       a1 = gain->ValueAsFloat(manuChannel,1);
353       Int_t thres = gain->ValueAsInt(manuChannel,2);
354       if ( padc < thres ) 
355       {
356         charge = a0*padc;
357       }
358       else
359       {
360         charge = a0*thres + a0*(padc-thres) + a1*(padc-thres)*(padc-thres);
361       }
362                         charge *= capa*adc2mv;
363     }
364     else if ( fApplyGains == fgkInjectionGain ) 
365     {
366                         
367       charge = padc*adc2mv/injGain;
368     }
369                 else
370                 {
371                         charge = a0*padc*capa*adc2mv;
372                 }
373   }
374   
375   if ( isSaturated ) 
376   {
377     Int_t saturation(3000);
378     
379     if ( gain && ( fApplyGains != fgkNoGain ) )
380     {
381       saturation = gain->ValueAsInt(manuChannel,4);
382     }
383     
384     if ( padc >= saturation )
385     {
386       *isSaturated = kTRUE;
387     }
388     else
389     {
390       *isSaturated = kFALSE;
391     }
392   }
393   
394   return ( charge > 0.0 ? charge : 0.0 );
395 }
396
397 //_____________________________________________________________________________
398 Bool_t 
399 AliMUONDigitCalibrator::IsValidDigit(Int_t detElemId, Int_t manuId, Int_t manuChannel,
400                                      Int_t* statusMap) const
401
402 {
403   /// Check if a given pad is ok or not.
404   
405   // First a protection against bad input parameters
406   AliMpDetElement* de = AliMpDDLStore::Instance()->GetDetElement(detElemId);
407   if (!de) return kFALSE; // not existing DE
408   if (!de->IsExistingChannel(manuId,manuChannel))
409   {
410     // non-existing (might happen when we get parity errors in read-out
411     // that spoils the manuId
412     return kFALSE;
413   }
414   if (!de->IsConnectedChannel(manuId,manuChannel))
415   {
416     // existing (in read-out), but not connected channel
417     return kFALSE;
418   }
419   
420   // ok, now we have a valid channel number, so let's see if that pad
421   // behaves or not ;-)
422   
423   Int_t sm = fStatusMapMaker->StatusMap(detElemId,manuId,manuChannel);
424   
425   if (statusMap) *statusMap = sm;
426   
427   if ( ( sm & AliMUONPadStatusMapMaker::SelfDeadMask() ) != 0 ) 
428   {
429     // pad itself is bad (not testing its neighbours at this stage)
430     return kFALSE;
431   }
432   
433   return kTRUE;
434 }
435
436 //_____________________________________________________________________________
437 Int_t 
438 AliMUONDigitCalibrator::PadStatus(Int_t detElemId, Int_t manuId, Int_t manuChannel) const
439 {
440   /// Return the status of the given pad
441   return fStatusMaker->PadStatus(detElemId,manuId,manuChannel);
442 }
443
444 //_____________________________________________________________________________
445 Int_t 
446 AliMUONDigitCalibrator::StatusMap(Int_t detElemId, Int_t manuId, Int_t manuChannel) const
447 {
448   /// Return the status map of the given pad
449   return fStatusMapMaker->StatusMap(detElemId,manuId,manuChannel);
450   
451 }
452