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