1 /**************************************************************************
2 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
4 * Author: The ALICE Off-line Project. *
5 * Contributors are mentioned in the code where appropriate. *
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 **************************************************************************/
18 #include "AliMUONDigitCalibrator.h"
20 #include "AliCDBEntry.h"
21 #include "AliCDBManager.h"
23 #include "AliMUONCalibrationData.h"
24 #include "AliMUONLogger.h"
25 #include "AliMUONPadStatusMaker.h"
26 #include "AliMUONPadStatusMapMaker.h"
27 #include "AliMUONRecoParam.h"
28 #include "AliMUONVCalibParam.h"
29 #include "AliMUONVDigit.h"
30 #include "AliMUONVDigitStore.h"
31 #include "AliMUONVStore.h"
32 #include "AliMpBusPatch.h"
33 #include "AliMpConstants.h"
35 #include "AliMpDDLStore.h"
36 #include "AliMpDEIterator.h"
37 #include "AliMpDetElement.h"
38 #include "AliMpManuStore.h"
40 //-----------------------------------------------------------------------------
41 /// \class AliMUONDigitCalibrator
42 /// Class used to calibrate digits (either real or simulated ones).
44 /// The calibration consists of subtracting the pedestal
45 /// and multiplying by a gain, so that
46 /// Signal = (ADC-pedestal)*gain
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
56 /// \author Laurent Aphecetche
57 //-----------------------------------------------------------------------------
61 ClassImp(AliMUONDigitCalibrator)
64 const Int_t AliMUONDigitCalibrator::fgkNoGain(0);
65 const Int_t AliMUONDigitCalibrator::fgkGainConstantCapa(1);
66 const Int_t AliMUONDigitCalibrator::fgkGain(2);
67 const Int_t AliMUONDigitCalibrator::fgkInjectionGain(3);
69 //_____________________________________________________________________________
70 AliMUONDigitCalibrator::AliMUONDigitCalibrator(Int_t runNumber, const char* calibMode)
72 fLogger(new AliMUONLogger(20000)),
86 AliMUONRecoParam* recoParam(0x0);
88 AliCDBEntry* e = AliCDBManager::Instance()->Get("MUON/Calib/RecoParam",runNumber);
91 TObject* o = e->GetObject();
92 if ( o->IsA() == TObjArray::Class() )
94 TObjArray* a = static_cast<TObjArray*>(o);
97 while ( ( p = static_cast<AliMUONRecoParam*>(next()) ))
99 if ( p->IsDefault()) recoParam = p;
104 recoParam = static_cast<AliMUONRecoParam*>(o);
109 AliError("Cannot get the recoParam. Failing");
113 // OK. Now get all we need and work...
115 AliMUONCalibrationData calib(runNumber);
117 Ctor(calibMode,calib,recoParam,kFALSE);
120 //_____________________________________________________________________________
121 AliMUONDigitCalibrator::AliMUONDigitCalibrator(const AliMUONCalibrationData& calib,
122 const AliMUONRecoParam* recoParams,
123 const char* calibMode)
125 fLogger(new AliMUONLogger(20000)),
127 fStatusMapMaker(0x0),
139 Ctor(calibMode,calib,recoParams);
142 //_____________________________________________________________________________
143 AliMUONDigitCalibrator::AliMUONDigitCalibrator(const AliMUONCalibrationData& calib,
144 const char* calibMode)
146 fLogger(new AliMUONLogger(20000)),
148 fStatusMapMaker(0x0),
160 Ctor(calibMode,calib,0x0);
163 //_____________________________________________________________________________
165 AliMUONDigitCalibrator::Ctor(const char* calibMode,
166 const AliMUONCalibrationData& calib,
167 const AliMUONRecoParam* recoParams,
168 Bool_t deferredInitialization)
172 TString cMode(calibMode);
175 if ( cMode == "NOGAIN" )
177 fApplyGains = fgkNoGain;
178 AliInfo("Will NOT apply gain correction");
180 else if ( cMode == "GAINCONSTANTCAPA" )
182 fApplyGains = fgkGainConstantCapa;
183 AliInfo("Will apply gain correction, but with constant capacitance");
185 else if ( cMode == "GAIN" )
187 fApplyGains = fgkGain;
188 AliInfo("Will apply gain correction, with measured capacitances");
190 else if ( cMode == "INJECTIONGAIN")
192 fApplyGains = fgkInjectionGain;
193 AliInfo("Will apply injection gain correction, with EMELEC factory gains");
197 AliError(Form("Invalid calib mode = %s. Will use NOGAIN instead",calibMode));
198 fApplyGains = fgkNoGain;
201 // Load mapping manu store
202 if ( ! AliMpCDB::LoadManuStore() ) {
203 AliFatal("Could not access manu store from OCDB !");
206 fStatusMaker = new AliMUONPadStatusMaker(calib);
208 // Set default values, as loose as reasonable
210 fChargeSigmaCut = 3.0;
212 fMask = 0x8080; // reject pads where ped *or* hv are missing
216 // if we have reco params, we use limits and cuts from there :
218 fStatusMaker->SetLimits(*recoParams);
220 fMask = recoParams->PadGoodnessMask();
221 //WARNING : getting this mask wrong is a very effective way of getting
222 //no digits at all out of this class ;-)
224 fChargeSigmaCut = recoParams->ChargeSigmaCut();
228 fLogger->Log("No RecoParam available");
229 fLogger->Log(Form("SigmaCut=%e",fChargeSigmaCut));
232 fStatusMapMaker = new AliMUONPadStatusMapMaker(*fStatusMaker,fMask,deferredInitialization);
234 fPedestals = calib.Pedestals();
236 fGains = calib.Gains(); // we get gains whatever the calibMode is, in order
237 // to get the saturation value...
239 if ( fApplyGains == fgkGain || fApplyGains == fgkInjectionGain )
241 fCapacitances = calib.Capacitances();
245 //_____________________________________________________________________________
246 AliMUONDigitCalibrator::~AliMUONDigitCalibrator()
250 if ( fNumberOfPads > 0 )
254 fStatusMaker->Report(fMask);
257 AliInfo("Summary of messages:");
261 AliInfo(Form("We have seen %g pads, and rejected %g (%7.2f %%)",
262 fNumberOfPads,fNumberOfBadPads,
263 ( fNumberOfPads > 0 ) ? fNumberOfBadPads*100.0/fNumberOfPads : 0 ));
267 delete fStatusMapMaker;
271 //_____________________________________________________________________________
273 AliMUONDigitCalibrator::Calibrate(AliMUONVDigitStore& digitStore)
275 /// Calibrate the digits contained in digitStore
276 TIter next(digitStore.CreateTrackerIterator());
277 AliMUONVDigit* digit;
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)
283 AliDebug(1,Form("# of digits = %d",digitStore.GetSize()));
285 while ( ( digit = static_cast<AliMUONVDigit*>(next() ) ) )
287 if ( digit->IsCalibrated() )
289 fLogger->Log("ERROR : trying to calibrate a digit twice");
293 digit->Calibrated(kTRUE);
297 Bool_t isSaturated(kFALSE);
301 Bool_t ok = IsValidDigit(digit->DetElemId(),digit->ManuId(),digit->ManuChannel(),&statusMap);
303 digit->SetStatusMap(statusMap);
307 charge = CalibrateDigit(digit->DetElemId(),digit->ManuId(),digit->ManuChannel(),
308 digit->ADC(),fChargeSigmaCut,&isSaturated);
315 digit->SetCharge(charge);
316 digit->Saturated(isSaturated);
320 //_____________________________________________________________________________
322 AliMUONDigitCalibrator::CalibrateDigit(Int_t detElemId, Int_t manuId, Int_t manuChannel,
323 Float_t adc, Float_t nsigmas,
324 Bool_t* isSaturated) const
327 /// Calibrate one digit
328 /// Return the digit charge, in fC
332 nsigmas = fChargeSigmaCut;
335 fLogger->Log(Form("ChargeSigmaCut used = %e",nsigmas));
337 AliMUONVCalibParam* pedestal = static_cast<AliMUONVCalibParam*>
338 (fPedestals->FindObject(detElemId,manuId));
342 // no pedestal -> no charge
343 fLogger->Log(Form("Got a null pedestal object for DE,manu=%d,%d",detElemId,manuId));
348 AliMUONVCalibParam* gain = static_cast<AliMUONVCalibParam*>
349 (fGains->FindObject(detElemId,manuId));
353 if ( fApplyGains != fgkNoGain )
355 // no gain -> no charge
356 fLogger->Log(Form("Got a null gain object for DE,manu=%d,%d",
362 Float_t padc = adc-pedestal->ValueAsFloat(manuChannel,0);
364 // Gain (mV/fC) = 1/(a0*capa) with a0~1.25 and capa~0.2
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
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
372 // Note that the ChargeMax (for one pad) is roughly 4096 * 0.61 mV/channel / 4 mV/fC = 625 fC
374 if ( fApplyGains == fgkGain || fApplyGains == fgkInjectionGain )
377 = AliMpManuStore::Instance()->GetManuSerial(detElemId, manuId);
379 AliMUONVCalibParam* param = static_cast<AliMUONVCalibParam*>(fCapacitances->FindObject(serialNumber));
383 capa = param->ValueAsFloat(manuChannel,0);
384 injGain = param->ValueAsFloat(manuChannel,1);
387 fLogger->Log(Form("injGain is %e < 0 for serialNumber=%d",injGain,serialNumber));
393 // If capa not found in the OCDB we exit
394 fLogger->Log(Form("No capa (injGain) found for serialNumber=%d",serialNumber));
399 if ( padc > nsigmas*pedestal->ValueAsFloat(manuChannel,1) )
401 if ( fApplyGains == fgkGain || fApplyGains == fgkGainConstantCapa )
403 a0 = gain->ValueAsFloat(manuChannel,0);
404 a1 = gain->ValueAsFloat(manuChannel,1);
405 Int_t thres = gain->ValueAsInt(manuChannel,2);
412 charge = a0*thres + a0*(padc-thres) + a1*(padc-thres)*(padc-thres);
414 charge *= capa*adc2mv;
416 else if ( fApplyGains == fgkInjectionGain )
419 charge = padc*adc2mv/injGain;
423 charge = a0*padc*capa*adc2mv;
429 Int_t saturation(3000);
431 if ( gain && ( fApplyGains != fgkNoGain ) )
433 saturation = gain->ValueAsInt(manuChannel,4);
436 if ( padc >= saturation )
438 *isSaturated = kTRUE;
442 *isSaturated = kFALSE;
446 return ( charge > 0.0 ? charge : 0.0 );
449 //_____________________________________________________________________________
451 AliMUONDigitCalibrator::IsValidDigit(Int_t detElemId, Int_t manuId, Int_t manuChannel,
452 Int_t* statusMap) const
455 /// Check if a given pad is ok or not.
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))
462 // non-existing (might happen when we get parity errors in read-out
463 // that spoils the manuId
466 if (!de->IsConnectedChannel(manuId,manuChannel))
468 // existing (in read-out), but not connected channel
472 // ok, now we have a valid channel number, so let's see if that pad
473 // behaves or not ;-)
475 Int_t sm = fStatusMapMaker->StatusMap(detElemId,manuId,manuChannel);
477 if (statusMap) *statusMap = sm;
479 if ( ( sm & AliMUONPadStatusMapMaker::SelfDeadMask() ) != 0 )
481 // pad itself is bad (not testing its neighbours at this stage)
488 //_____________________________________________________________________________
490 AliMUONDigitCalibrator::PadStatus(Int_t detElemId, Int_t manuId, Int_t manuChannel) const
492 /// Return the status of the given pad
493 return fStatusMaker->PadStatus(detElemId,manuId,manuChannel);
496 //_____________________________________________________________________________
498 AliMUONDigitCalibrator::StatusMap(Int_t detElemId, Int_t manuId, Int_t manuChannel) const
500 /// Return the status map of the given pad
501 return fStatusMapMaker->StatusMap(detElemId,manuId,manuChannel);