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