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