AliMUONDigitCalibrator.cxx
[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 "AliMUONCalibrationData.h"
21 #include "AliMUONVDigit.h"
22 #include "AliMUONVDigitStore.h"
23 #include "AliMUONLogger.h"
24 #include "AliMUONPadStatusMaker.h"
25 #include "AliMUONPadStatusMapMaker.h"
26 #include "AliMUONVStore.h"
27 #include "AliMUONVCalibParam.h"
28 #include "AliMpConstants.h"
29 #include "AliMpDetElement.h"
30 #include "AliMpDDLStore.h"
31 #include "AliLog.h"
32
33 //-----------------------------------------------------------------------------
34 /// \class AliMUONDigitCalibrator
35 /// Class used to calibrate digits (either real or simulated ones).
36 ///
37 /// The calibration consists of subtracting the pedestal
38 /// and multiplying by a gain, so that
39 /// Signal = (ADC-pedestal)*gain
40 ///
41 /// Please note also that for the moment, if a digit lies on a dead channel
42 /// we remove this digit from the list of digits.
43 /// FIXME: this has to be revisited. By using the AliMUONDigit::fFlags we
44 /// should in principle flag a digit as bad w/o removing it, but this 
45 /// then requires some changes in the cluster finder to deal with this extra
46 /// information correctly (e.g. to set a quality for the cluster if it contains
47 /// bad digits).
48 ///
49 /// \author Laurent Aphecetche
50 //-----------------------------------------------------------------------------
51
52
53 /// \cond CLASSIMP
54 ClassImp(AliMUONDigitCalibrator)
55 /// \endcond
56
57 const Int_t AliMUONDigitCalibrator::fgkNoGain(0);
58 const Int_t AliMUONDigitCalibrator::fgkGainConstantCapa(1);
59 const Int_t AliMUONDigitCalibrator::fgkGain(2);
60
61 //_____________________________________________________________________________
62 AliMUONDigitCalibrator::AliMUONDigitCalibrator(const AliMUONCalibrationData& calib,
63                                                const char* calibMode)
64 : TObject(),
65 fLogger(new AliMUONLogger(20000)),
66 fStatusMaker(0x0),
67 fStatusMapMaker(0x0),
68 fPedestals(0x0),
69 fGains(0x0),
70 fApplyGains(0),
71 fCapacitances(0x0)
72 {
73   /// ctor
74   
75   TString cMode(calibMode);
76   cMode.ToUpper();
77   
78   if ( cMode == "NOGAIN" ) 
79   {
80     fApplyGains = fgkNoGain;
81     AliInfo("Will NOT apply gain correction");
82   }
83   else if ( cMode == "GAINCONSTANTCAPA" ) 
84   {
85     fApplyGains = fgkGainConstantCapa;
86     AliInfo("Will apply gain correction, but with constant capacitance");
87   }
88   else if ( cMode == "GAIN" ) 
89   {
90     fApplyGains = fgkGain;
91     AliInfo("Will apply gain correction, with measured capacitances");
92   }
93   else
94   {
95     AliError(Form("Invalid calib mode = %s. Will use NOGAIN instead",calibMode));
96     fApplyGains = fgkNoGain;
97   }
98        
99   fStatusMaker = new AliMUONPadStatusMaker(calib);
100   
101   // this is here that we decide on our "goodness" policy, i.e.
102   // what do we call an invalid pad (a pad maybe bad because its HV
103   // was too low, or its pedestals too high, etc..)
104   // FIXME: find a way not to hard-code the goodness policy (i.e. the limits)
105   // here...
106   fStatusMaker->SetHVSt12Limits(1300,1600);
107   fStatusMaker->SetHVSt345Limits(1500,2000);
108   fStatusMaker->SetPedMeanLimits(50,200);
109   fStatusMaker->SetPedSigmaLimits(0.1,3);
110   
111   Int_t mask(0x8080); 
112   //FIXME: kind of fake one for the moment, we consider dead only 
113   // if ped and/or hv value missing.
114   //WARNING : getting this mask wrong is a very effective way of getting
115   //no digits at all out of this class ;-)
116   
117   Bool_t deferredInitialization = kTRUE;
118   
119   fStatusMapMaker = new AliMUONPadStatusMapMaker(*fStatusMaker,mask,deferredInitialization);
120   
121   fPedestals = calib.Pedestals();
122
123   fGains = calib.Gains(); // we get gains whatever the calibMode is, in order
124   // to get the saturation value...
125
126   if ( fApplyGains == fgkGain ) 
127   {
128     fCapacitances = calib.Capacitances();
129   }
130 }
131
132 //_____________________________________________________________________________
133 AliMUONDigitCalibrator::~AliMUONDigitCalibrator()
134 {
135   /// dtor.
136   delete fStatusMaker;
137   delete fStatusMapMaker;
138   
139   AliInfo("Summary of messages:");
140   fLogger->Print();
141
142   delete fLogger;
143 }
144
145 //_____________________________________________________________________________
146 void
147 AliMUONDigitCalibrator::Calibrate(AliMUONVDigitStore& digitStore)
148 {
149   /// Calibrate the digits contained in digitStore  
150   TIter next(digitStore.CreateTrackerIterator());
151   AliMUONVDigit* digit;
152   
153   while ( ( digit = static_cast<AliMUONVDigit*>(next() ) ) )
154   {
155     CalibrateDigit(*digit);
156   }
157 }
158
159 //_____________________________________________________________________________
160 void
161 AliMUONDigitCalibrator::CalibrateDigit(AliMUONVDigit& digit)
162 {
163   /// Calibrate one digit
164   
165   if ( digit.IsCalibrated() ) 
166   {
167     fLogger->Log("ERROR : trying to calibrate a digit twice");
168     return;
169   }
170   
171   Int_t statusMap = fStatusMapMaker->StatusMap(digit.DetElemId(),
172                                                digit.ManuId(),
173                                                digit.ManuChannel());
174
175   digit.SetStatusMap(statusMap);
176   digit.Calibrated(kTRUE);
177   
178   if ( ( statusMap & AliMUONPadStatusMapMaker::SelfDeadMask() ) != 0 ) 
179   {
180     // pad itself is bad (not testing its neighbours at this stage)
181     digit.SetCharge(0);
182     fLogger->Log(Form("%s:%d:Channel detElemId %d manuId %d "
183                     "manuChannel %d is bad %x",__FILE__,__LINE__,
184                     digit.DetElemId(),digit.ManuId(),
185                     digit.ManuChannel(),digit.StatusMap()));
186   }
187   else
188   {
189     // If the channel is good, go on with the calibration itself.
190
191     AliMUONVCalibParam* pedestal = static_cast<AliMUONVCalibParam*>
192     (fPedestals->FindObject(digit.DetElemId(),digit.ManuId()));
193
194     if (!pedestal)
195     {
196       // no pedestal -> no charge
197       digit.SetCharge(0);
198       
199       fLogger->Log(Form("Got a null pedestal object for DE,manu=%d,%d",
200                         digit.DetElemId(),digit.ManuId()));        
201       return;
202     }
203     
204     
205     AliMUONVCalibParam* gain = static_cast<AliMUONVCalibParam*>
206         (fGains->FindObject(digit.DetElemId(),digit.ManuId()));
207
208     if (!gain)
209     {
210       if ( fApplyGains != fgkNoGain )
211       {
212         // no gain -> no charge
213         digit.SetCharge(0);
214
215         fLogger->Log(Form("Got a null gain object for DE,manu=%d,%d",
216                           digit.DetElemId(),digit.ManuId())); 
217         return;
218       }
219     }
220
221     Int_t manuChannel = digit.ManuChannel();
222     Float_t adc = digit.ADC();
223     Float_t padc = adc-pedestal->ValueAsFloat(manuChannel,0);
224     Float_t charge(0);
225     Float_t capa(1.0);
226     
227     if ( fApplyGains == fgkGainConstantCapa ) 
228     {
229       capa = 0.2; // pF
230     }
231     else if ( fApplyGains == fgkGain ) 
232     {
233       AliMpDetElement* de = AliMpDDLStore::Instance()->GetDetElement(digit.DetElemId());
234       
235       Int_t serialNumber = de->GetManuSerialFromId(digit.ManuId());
236
237       AliMUONVCalibParam* param = static_cast<AliMUONVCalibParam*>(fCapacitances->FindObject(serialNumber));
238       
239       if ( param )
240       {
241         capa = param->ValueAsFloat(digit.ManuChannel());
242       }
243       else
244       {
245         fLogger->Log(Form("No capa found for serialNumber=%d",serialNumber));
246         capa = 0.0;
247       }
248     }
249     
250     if ( padc > 3.0*pedestal->ValueAsFloat(manuChannel,1) ) 
251     {
252       if ( fApplyGains != fgkNoGain ) 
253       {
254         Float_t a0 = gain->ValueAsFloat(manuChannel,0);
255         Float_t a1 = gain->ValueAsFloat(manuChannel,1);
256         Int_t thres = gain->ValueAsInt(manuChannel,2);
257         if ( padc < thres ) 
258         {
259           charge = a0*padc;
260         }
261         else
262         {
263           charge = a0*thres + a0*(padc-thres) + a1*(padc-thres)*(padc-thres);
264         }
265       }
266       else
267       {
268         charge = padc;
269       }
270     }
271     
272     charge *= capa;
273     digit.SetCharge(charge);
274     
275     Int_t saturation(3000);
276     
277     if ( gain )
278     {
279       saturation = gain->ValueAsInt(manuChannel,4);
280     }
281     
282     if ( padc >= saturation )
283     {
284       digit.Saturated(kTRUE);
285     }
286   }
287 }