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