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