a/ AliTRDCalibTask.cxx .h: one histo more to quantify the event selection if any...
[u/mrichter/AliRoot.git] / MUON / AliMUONDigitCalibrator.cxx
CommitLineData
d99769c3 1/**************************************************************************
66cdf5b3 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 **************************************************************************/
d99769c3 15
16// $Id$
17
18#include "AliMUONDigitCalibrator.h"
19
b9bd355c 20#include "AliCDBEntry.h"
21#include "AliCDBManager.h"
861d6ce8 22#include "AliLog.h"
d99769c3 23#include "AliMUONCalibrationData.h"
fe6ed686 24#include "AliMUONLogger.h"
d1c20d08 25#include "AliMUONPadStatusMaker.h"
26#include "AliMUONPadStatusMapMaker.h"
de487b6e 27#include "AliMUONRecoParam.h"
c795d086 28#include "AliMUONVCalibParam.h"
861d6ce8 29#include "AliMUONVDigit.h"
30#include "AliMUONVDigitStore.h"
31#include "AliMUONVStore.h"
32#include "AliMpBusPatch.h"
de98fdc9 33#include "AliMpConstants.h"
ab167304 34#include "AliMpCDB.h"
de98fdc9 35#include "AliMpDDLStore.h"
861d6ce8 36#include "AliMpDEIterator.h"
37#include "AliMpDetElement.h"
ab167304 38#include "AliMpManuStore.h"
d99769c3 39
3d1463c8 40//-----------------------------------------------------------------------------
7945aae7 41/// \class AliMUONDigitCalibrator
1171bb0a 42/// Class used to calibrate digits (either real or simulated ones).
43///
44/// The calibration consists of subtracting the pedestal
45/// and multiplying by a gain, so that
46/// Signal = (ADC-pedestal)*gain
47///
48/// Please note also that for the moment, if a digit lies on a dead channel
49/// we remove this digit from the list of digits.
50/// FIXME: this has to be revisited. By using the AliMUONDigit::fFlags we
51/// should in principle flag a digit as bad w/o removing it, but this
52/// then requires some changes in the cluster finder to deal with this extra
53/// information correctly (e.g. to set a quality for the cluster if it contains
54/// bad digits).
55///
7945aae7 56/// \author Laurent Aphecetche
3d1463c8 57//-----------------------------------------------------------------------------
7945aae7 58
1171bb0a 59
7945aae7 60/// \cond CLASSIMP
d99769c3 61ClassImp(AliMUONDigitCalibrator)
7945aae7 62/// \endcond
d99769c3 63
de98fdc9 64const Int_t AliMUONDigitCalibrator::fgkNoGain(0);
65const Int_t AliMUONDigitCalibrator::fgkGainConstantCapa(1);
66const Int_t AliMUONDigitCalibrator::fgkGain(2);
66cdf5b3 67const Int_t AliMUONDigitCalibrator::fgkInjectionGain(3);
de98fdc9 68
d99769c3 69//_____________________________________________________________________________
b9bd355c 70AliMUONDigitCalibrator::AliMUONDigitCalibrator(Int_t runNumber, const char* calibMode)
71: TObject(),
72fLogger(new AliMUONLogger(20000)),
73fStatusMaker(0x0),
74fStatusMapMaker(0x0),
75fPedestals(0x0),
76fGains(0x0),
77fApplyGains(0),
78fCapacitances(0x0),
79fNumberOfBadPads(0),
80fNumberOfPads(0),
81fChargeSigmaCut(0),
82fMask(0)
83{
84 /// ctor
85
86 AliMUONRecoParam* recoParam(0x0);
87
88 AliCDBEntry* e = AliCDBManager::Instance()->Get("MUON/Calib/RecoParam",runNumber);
89 if (e)
90 {
91 TObject* o = e->GetObject();
92 if ( o->IsA() == TObjArray::Class() )
93 {
94 TObjArray* a = static_cast<TObjArray*>(o);
95 TIter next(a);
96 AliMUONRecoParam* p;
97 while ( ( p = static_cast<AliMUONRecoParam*>(next()) ))
98 {
99 if ( p->IsDefault()) recoParam = p;
100 }
101 }
102 else
103 {
104 recoParam = static_cast<AliMUONRecoParam*>(o);
105 }
106 }
107 if (!recoParam)
108 {
109 AliError("Cannot get the recoParam. Failing");
110 return;
111 }
112
113 // OK. Now get all we need and work...
114
115 AliMUONCalibrationData calib(runNumber);
116
117 Ctor(calibMode,calib,recoParam,kFALSE);
118}
119
120//_____________________________________________________________________________
de98fdc9 121AliMUONDigitCalibrator::AliMUONDigitCalibrator(const AliMUONCalibrationData& calib,
ab167304 122 const AliMUONRecoParam* recoParams,
de98fdc9 123 const char* calibMode)
42825ed9 124: TObject(),
3b6f7dce 125fLogger(new AliMUONLogger(20000)),
49e396d9 126fStatusMaker(0x0),
127fStatusMapMaker(0x0),
128fPedestals(0x0),
de98fdc9 129fGains(0x0),
130fApplyGains(0),
de487b6e 131fCapacitances(0x0),
132fNumberOfBadPads(0),
170f4046 133fNumberOfPads(0),
411a502a 134fChargeSigmaCut(0),
135fMask(0)
d99769c3 136{
42825ed9 137 /// ctor
de98fdc9 138
de487b6e 139 Ctor(calibMode,calib,recoParams);
140}
141
142//_____________________________________________________________________________
143AliMUONDigitCalibrator::AliMUONDigitCalibrator(const AliMUONCalibrationData& calib,
144 const char* calibMode)
145: TObject(),
146fLogger(new AliMUONLogger(20000)),
147fStatusMaker(0x0),
148fStatusMapMaker(0x0),
149fPedestals(0x0),
150fGains(0x0),
151fApplyGains(0),
152fCapacitances(0x0),
153fNumberOfBadPads(0),
170f4046 154fNumberOfPads(0),
411a502a 155fChargeSigmaCut(0),
156fMask(0)
de487b6e 157{
158 /// ctor
159
160 Ctor(calibMode,calib,0x0);
161}
162
163//_____________________________________________________________________________
164void
165AliMUONDigitCalibrator::Ctor(const char* calibMode,
166 const AliMUONCalibrationData& calib,
b9bd355c 167 const AliMUONRecoParam* recoParams,
168 Bool_t deferredInitialization)
de487b6e 169{
170 /// designated ctor
171
de98fdc9 172 TString cMode(calibMode);
173 cMode.ToUpper();
174
175 if ( cMode == "NOGAIN" )
176 {
177 fApplyGains = fgkNoGain;
178 AliInfo("Will NOT apply gain correction");
179 }
3b6f7dce 180 else if ( cMode == "GAINCONSTANTCAPA" )
de98fdc9 181 {
182 fApplyGains = fgkGainConstantCapa;
183 AliInfo("Will apply gain correction, but with constant capacitance");
184 }
185 else if ( cMode == "GAIN" )
186 {
187 fApplyGains = fgkGain;
188 AliInfo("Will apply gain correction, with measured capacitances");
189 }
66cdf5b3 190 else if ( cMode == "INJECTIONGAIN")
191 {
192 fApplyGains = fgkInjectionGain;
193 AliInfo("Will apply injection gain correction, with EMELEC factory gains");
194 }
de98fdc9 195 else
196 {
197 AliError(Form("Invalid calib mode = %s. Will use NOGAIN instead",calibMode));
198 fApplyGains = fgkNoGain;
199 }
66cdf5b3 200
ab167304 201 // Load mapping manu store
202 if ( ! AliMpCDB::LoadManuStore() ) {
203 AliFatal("Could not access manu store from OCDB !");
204 }
66cdf5b3 205
49e396d9 206 fStatusMaker = new AliMUONPadStatusMaker(calib);
207
170f4046 208 // Set default values, as loose as reasonable
66cdf5b3 209
170f4046 210 fChargeSigmaCut = 3.0;
211
411a502a 212 fMask = 0x8080; // reject pads where ped *or* hv are missing
de487b6e 213
de487b6e 214 if ( recoParams )
215 {
170f4046 216 // if we have reco params, we use limits and cuts from there :
217
411a502a 218 fStatusMaker->SetLimits(*recoParams);
219
220 fMask = recoParams->PadGoodnessMask();
de487b6e 221 //WARNING : getting this mask wrong is a very effective way of getting
222 //no digits at all out of this class ;-)
170f4046 223
224 fChargeSigmaCut = recoParams->ChargeSigmaCut();
de487b6e 225 }
8f29b706 226 else
227 {
228 fLogger->Log("No RecoParam available");
229 fLogger->Log(Form("SigmaCut=%e",fChargeSigmaCut));
230 }
49e396d9 231
411a502a 232 fStatusMapMaker = new AliMUONPadStatusMapMaker(*fStatusMaker,fMask,deferredInitialization);
49e396d9 233
234 fPedestals = calib.Pedestals();
66cdf5b3 235
de98fdc9 236 fGains = calib.Gains(); // we get gains whatever the calibMode is, in order
237 // to get the saturation value...
66cdf5b3 238
6b31d882 239 if ( fApplyGains == fgkGain || fApplyGains == fgkInjectionGain )
de98fdc9 240 {
241 fCapacitances = calib.Capacitances();
242 }
d99769c3 243}
244
1171bb0a 245//_____________________________________________________________________________
d99769c3 246AliMUONDigitCalibrator::~AliMUONDigitCalibrator()
247{
d1c20d08 248 /// dtor.
411a502a 249
250 if ( fNumberOfPads > 0 )
251 {
252 if ( fStatusMaker )
253 {
254 fStatusMaker->Report(fMask);
255 }
256
257 AliInfo("Summary of messages:");
258
259 fLogger->Print();
260
261 AliInfo(Form("We have seen %g pads, and rejected %g (%7.2f %%)",
262 fNumberOfPads,fNumberOfBadPads,
263 ( fNumberOfPads > 0 ) ? fNumberOfBadPads*100.0/fNumberOfPads : 0 ));
264 }
265
49e396d9 266 delete fStatusMaker;
267 delete fStatusMapMaker;
fe6ed686 268 delete fLogger;
d99769c3 269}
270
271//_____________________________________________________________________________
272void
42825ed9 273AliMUONDigitCalibrator::Calibrate(AliMUONVDigitStore& digitStore)
d99769c3 274{
42825ed9 275 /// Calibrate the digits contained in digitStore
276 TIter next(digitStore.CreateTrackerIterator());
277 AliMUONVDigit* digit;
66cdf5b3 278
0045b488 279 fStatusMapMaker->RefreshRejectProbabilities(); // this will do something only for simulations
280 // (and only for those simulations where the reject list contain probabilities which are
281 // different from zero or one)
861d6ce8 282
283 AliDebug(1,Form("# of digits = %d",digitStore.GetSize()));
c795d086 284
42825ed9 285 while ( ( digit = static_cast<AliMUONVDigit*>(next() ) ) )
d99769c3 286 {
de487b6e 287 if ( digit->IsCalibrated() )
288 {
289 fLogger->Log("ERROR : trying to calibrate a digit twice");
290 return;
291 }
292
293 digit->Calibrated(kTRUE);
294
de487b6e 295 Float_t charge(0.0);
296 Int_t statusMap;
297 Bool_t isSaturated(kFALSE);
66cdf5b3 298
8bf22fd6 299 ++fNumberOfPads;
66cdf5b3 300
de487b6e 301 Bool_t ok = IsValidDigit(digit->DetElemId(),digit->ManuId(),digit->ManuChannel(),&statusMap);
66cdf5b3 302
de487b6e 303 digit->SetStatusMap(statusMap);
304
305 if (ok)
306 {
de487b6e 307 charge = CalibrateDigit(digit->DetElemId(),digit->ManuId(),digit->ManuChannel(),
0045b488 308 digit->ADC(),fChargeSigmaCut,&isSaturated);
de487b6e 309 }
310 else
311 {
411a502a 312 ++fNumberOfBadPads;
de487b6e 313 }
314
315 digit->SetCharge(charge);
316 digit->Saturated(isSaturated);
42825ed9 317 }
318}
319
320//_____________________________________________________________________________
de487b6e 321Float_t
322AliMUONDigitCalibrator::CalibrateDigit(Int_t detElemId, Int_t manuId, Int_t manuChannel,
323 Float_t adc, Float_t nsigmas,
324 Bool_t* isSaturated) const
325
42825ed9 326{
327 /// Calibrate one digit
db068204 328 /// Return the digit charge, in fC
cf27231a 329
8f29b706 330 if ( nsigmas < 0 )
331 {
332 nsigmas = fChargeSigmaCut;
333 }
334
335 fLogger->Log(Form("ChargeSigmaCut used = %e",nsigmas));
336
de487b6e 337 AliMUONVCalibParam* pedestal = static_cast<AliMUONVCalibParam*>
338 (fPedestals->FindObject(detElemId,manuId));
49e396d9 339
de487b6e 340 if (!pedestal)
42825ed9 341 {
de487b6e 342 // no pedestal -> no charge
343 fLogger->Log(Form("Got a null pedestal object for DE,manu=%d,%d",detElemId,manuId));
344 return 0.0;
42825ed9 345 }
de487b6e 346
347
348 AliMUONVCalibParam* gain = static_cast<AliMUONVCalibParam*>
349 (fGains->FindObject(detElemId,manuId));
350
351 if (!gain)
42825ed9 352 {
de487b6e 353 if ( fApplyGains != fgkNoGain )
d99769c3 354 {
de487b6e 355 // no gain -> no charge
356 fLogger->Log(Form("Got a null gain object for DE,manu=%d,%d",
357 detElemId,manuId));
358 return 0.0;
42825ed9 359 }
de487b6e 360 }
361
362 Float_t padc = adc-pedestal->ValueAsFloat(manuChannel,0);
de487b6e 363
66cdf5b3 364 // Gain (mV/fC) = 1/(a0*capa) with a0~1.25 and capa~0.2
365 Float_t charge(0);
366 Float_t capa(0.2); // capa = 0.2 and a0 = 1.25
367 Float_t a0(1.25); // is equivalent to gain = 4 mV/fC
368 Float_t a1(0);
369 Float_t adc2mv(0.61); // 1 ADC channel = 0.61 mV
370 Float_t injGain(4); // By default the gain is set to 4 mV/fC
db068204 371 //
372 // Note that the ChargeMax (for one pad) is roughly 4096 * 0.61 mV/channel / 4 mV/fC = 625 fC
373
66cdf5b3 374 if ( fApplyGains == fgkGain || fApplyGains == fgkInjectionGain )
de487b6e 375 {
ab167304 376 Int_t serialNumber
66cdf5b3 377 = AliMpManuStore::Instance()->GetManuSerial(detElemId, manuId);
3b6f7dce 378
de487b6e 379 AliMUONVCalibParam* param = static_cast<AliMUONVCalibParam*>(fCapacitances->FindObject(serialNumber));
380
381 if ( param )
42825ed9 382 {
66cdf5b3 383 capa = param->ValueAsFloat(manuChannel,0);
384 injGain = param->ValueAsFloat(manuChannel,1);
db068204 385 if ( injGain < 0 )
386 {
387 fLogger->Log(Form("injGain is %e < 0 for serialNumber=%d",injGain,serialNumber));
388 return 0.0;
389 }
42825ed9 390 }
de487b6e 391 else
de98fdc9 392 {
db068204 393 // If capa not found in the OCDB we exit
66cdf5b3 394 fLogger->Log(Form("No capa (injGain) found for serialNumber=%d",serialNumber));
395 return 0.0;
de98fdc9 396 }
de487b6e 397 }
398
399 if ( padc > nsigmas*pedestal->ValueAsFloat(manuChannel,1) )
400 {
66cdf5b3 401 if ( fApplyGains == fgkGain || fApplyGains == fgkGainConstantCapa )
de98fdc9 402 {
66cdf5b3 403 a0 = gain->ValueAsFloat(manuChannel,0);
404 a1 = gain->ValueAsFloat(manuChannel,1);
de487b6e 405 Int_t thres = gain->ValueAsInt(manuChannel,2);
406 if ( padc < thres )
3b6f7dce 407 {
de487b6e 408 charge = a0*padc;
3b6f7dce 409 }
410 else
411 {
de487b6e 412 charge = a0*thres + a0*(padc-thres) + a1*(padc-thres)*(padc-thres);
3b6f7dce 413 }
66cdf5b3 414 charge *= capa*adc2mv;
de98fdc9 415 }
66cdf5b3 416 else if ( fApplyGains == fgkInjectionGain )
42825ed9 417 {
66cdf5b3 418
419 charge = padc*adc2mv/injGain;
42825ed9 420 }
66cdf5b3 421 else
422 {
423 charge = a0*padc*capa*adc2mv;
424 }
de487b6e 425 }
426
de487b6e 427 if ( isSaturated )
428 {
3b6f7dce 429 Int_t saturation(3000);
66cdf5b3 430
6b191dea 431 if ( gain && ( fApplyGains != fgkNoGain ) )
3b6f7dce 432 {
433 saturation = gain->ValueAsInt(manuChannel,4);
434 }
66cdf5b3 435
de98fdc9 436 if ( padc >= saturation )
42825ed9 437 {
de487b6e 438 *isSaturated = kTRUE;
439 }
440 else
441 {
ada26c2d 442 *isSaturated = kFALSE;
d99769c3 443 }
444 }
de487b6e 445
58e1d4ed 446 return ( charge > 0.0 ? charge : 0.0 );
d99769c3 447}
de487b6e 448
449//_____________________________________________________________________________
450Bool_t
451AliMUONDigitCalibrator::IsValidDigit(Int_t detElemId, Int_t manuId, Int_t manuChannel,
452 Int_t* statusMap) const
453
454{
455 /// Check if a given pad is ok or not.
456
457 // First a protection against bad input parameters
458 AliMpDetElement* de = AliMpDDLStore::Instance()->GetDetElement(detElemId);
459 if (!de) return kFALSE; // not existing DE
460 if (!de->IsExistingChannel(manuId,manuChannel))
461 {
462 // non-existing (might happen when we get parity errors in read-out
463 // that spoils the manuId
464 return kFALSE;
465 }
466 if (!de->IsConnectedChannel(manuId,manuChannel))
467 {
468 // existing (in read-out), but not connected channel
469 return kFALSE;
470 }
471
472 // ok, now we have a valid channel number, so let's see if that pad
473 // behaves or not ;-)
474
475 Int_t sm = fStatusMapMaker->StatusMap(detElemId,manuId,manuChannel);
476
477 if (statusMap) *statusMap = sm;
478
479 if ( ( sm & AliMUONPadStatusMapMaker::SelfDeadMask() ) != 0 )
480 {
481 // pad itself is bad (not testing its neighbours at this stage)
482 return kFALSE;
483 }
484
485 return kTRUE;
486}
487
488//_____________________________________________________________________________
489Int_t
490AliMUONDigitCalibrator::PadStatus(Int_t detElemId, Int_t manuId, Int_t manuChannel) const
491{
492 /// Return the status of the given pad
493 return fStatusMaker->PadStatus(detElemId,manuId,manuChannel);
494}
495
496//_____________________________________________________________________________
497Int_t
498AliMUONDigitCalibrator::StatusMap(Int_t detElemId, Int_t manuId, Int_t manuChannel) const
499{
500 /// Return the status map of the given pad
501 return fStatusMapMaker->StatusMap(detElemId,manuId,manuChannel);
502
503}
504