#include "AliMUONDigitCalibrator.h"
#include "AliLog.h"
-#include "AliMpConstants.h"
#include "AliMUONCalibrationData.h"
-#include "AliMUONVDigit.h"
-#include "AliMUONVDigitStore.h"
#include "AliMUONLogger.h"
#include "AliMUONPadStatusMaker.h"
#include "AliMUONPadStatusMapMaker.h"
-#include "AliMUONVStore.h"
+#include "AliMUONRecoParam.h"
#include "AliMUONVCalibParam.h"
+#include "AliMUONVDigit.h"
+#include "AliMUONVDigitStore.h"
+#include "AliMUONVStore.h"
+#include "AliMpBusPatch.h"
+#include "AliMpConstants.h"
+#include "AliMpDDLStore.h"
+#include "AliMpDEIterator.h"
+#include "AliMpDetElement.h"
+//-----------------------------------------------------------------------------
/// \class AliMUONDigitCalibrator
/// Class used to calibrate digits (either real or simulated ones).
///
/// bad digits).
///
/// \author Laurent Aphecetche
+//-----------------------------------------------------------------------------
/// \cond CLASSIMP
ClassImp(AliMUONDigitCalibrator)
/// \endcond
+const Int_t AliMUONDigitCalibrator::fgkNoGain(0);
+const Int_t AliMUONDigitCalibrator::fgkGainConstantCapa(1);
+const Int_t AliMUONDigitCalibrator::fgkGain(2);
+
+//_____________________________________________________________________________
+AliMUONDigitCalibrator::AliMUONDigitCalibrator(const AliMUONCalibrationData& calib,
+ const AliMUONRecoParam* recoParams,
+ const char* calibMode)
+: TObject(),
+fLogger(new AliMUONLogger(20000)),
+fStatusMaker(0x0),
+fStatusMapMaker(0x0),
+fPedestals(0x0),
+fGains(0x0),
+fApplyGains(0),
+fCapacitances(0x0),
+fNumberOfBadPads(0),
+fNumberOfPads(0),
+fChargeSigmaCut(0)
+{
+ /// ctor
+
+ Ctor(calibMode,calib,recoParams);
+}
+
//_____________________________________________________________________________
AliMUONDigitCalibrator::AliMUONDigitCalibrator(const AliMUONCalibrationData& calib,
- Bool_t createAndUseStatusMap)
+ const char* calibMode)
: TObject(),
-fCalibrationData(calib),
-fStatusMap(0x0),
-fLogger(new AliMUONLogger(1000))
+fLogger(new AliMUONLogger(20000)),
+fStatusMaker(0x0),
+fStatusMapMaker(0x0),
+fPedestals(0x0),
+fGains(0x0),
+fApplyGains(0),
+fCapacitances(0x0),
+fNumberOfBadPads(0),
+fNumberOfPads(0),
+fChargeSigmaCut(0)
{
/// ctor
- if (createAndUseStatusMap)
+
+ Ctor(calibMode,calib,0x0);
+}
+
+//_____________________________________________________________________________
+void
+AliMUONDigitCalibrator::Ctor(const char* calibMode,
+ const AliMUONCalibrationData& calib,
+ const AliMUONRecoParam* recoParams)
+{
+ /// designated ctor
+
+ TString cMode(calibMode);
+ cMode.ToUpper();
+
+ if ( cMode == "NOGAIN" )
{
- AliMUONPadStatusMaker maker(fCalibrationData);
-
- // this is here that we decide on our "goodness" policy, i.e.
- // what do we call an invalid pad (a pad maybe bad because its HV
- // was too low, or its pedestals too high, etc..)
- // FIXME: find a way not to hard-code the goodness policy (i.e. the limits)
- // here...
- maker.SetHVSt12Limits(1300,1600);
- maker.SetHVSt345Limits(1500,2000);
- maker.SetPedMeanLimits(50,200);
- maker.SetPedSigmaLimits(0.1,3);
-
- // From this set of limits, compute the status of all tracker pads.
- AliMUONVStore* status = maker.MakeStatus();
- // we do not check that status is != 0x0, as this is supposed to be
- // the responsability of the padStatusMaker.
-
- AliMUONPadStatusMapMaker mapMaker(fCalibrationData);
-
- Int_t mask(0x8080);
- //FIXME: kind of fake one for the moment, we consider dead only
- // if ped and/or hv value missing.
- //WARNING : getting this mask wrong is a very effective way of getting
- //no digits at all out of this class ;-)
+ fApplyGains = fgkNoGain;
+ AliInfo("Will NOT apply gain correction");
+ }
+ else if ( cMode == "GAINCONSTANTCAPA" )
+ {
+ fApplyGains = fgkGainConstantCapa;
+ AliInfo("Will apply gain correction, but with constant capacitance");
+ }
+ else if ( cMode == "GAIN" )
+ {
+ fApplyGains = fgkGain;
+ AliInfo("Will apply gain correction, with measured capacitances");
+ }
+ else
+ {
+ AliError(Form("Invalid calib mode = %s. Will use NOGAIN instead",calibMode));
+ fApplyGains = fgkNoGain;
+ }
+
+ fStatusMaker = new AliMUONPadStatusMaker(calib);
+
+ // Set default values, as loose as reasonable
+
+ fChargeSigmaCut = 3.0;
+
+ Int_t mask(0x8080); // reject pads where ped *or* hv are missing
+
+ if ( recoParams )
+ {
+ // if we have reco params, we use limits and cuts from there :
- fStatusMap = mapMaker.MakePadStatusMap(*status,mask);
+ fStatusMaker->SetHVSt12Limits(recoParams->HVSt12LowLimit(),recoParams->HVSt12HighLimit());
+ fStatusMaker->SetHVSt345Limits(recoParams->HVSt345LowLimit(),recoParams->HVSt345HighLimit());
+ fStatusMaker->SetPedMeanLimits(recoParams->PedMeanLowLimit(),recoParams->PedMeanHighLimit());
+ fStatusMaker->SetPedSigmaLimits(recoParams->PedSigmaLowLimit(),recoParams->PedSigmaHighLimit());
+ fStatusMaker->SetGainA1Limits(recoParams->GainA1LowLimit(),recoParams->GainA1HighLimit());
+ fStatusMaker->SetGainA2Limits(recoParams->GainA2LowLimit(),recoParams->GainA2HighLimit());
+ fStatusMaker->SetGainThresLimits(recoParams->GainThresLowLimit(),recoParams->GainThresHighLimit());
+
+ mask = recoParams->PadGoodnessMask();
+ //WARNING : getting this mask wrong is a very effective way of getting
+ //no digits at all out of this class ;-)
- delete status;
- }
- else
+ fChargeSigmaCut = recoParams->ChargeSigmaCut();
+ }
+
+ Bool_t deferredInitialization = kTRUE;
+
+ fStatusMapMaker = new AliMUONPadStatusMapMaker(*fStatusMaker,mask,deferredInitialization);
+
+ fPedestals = calib.Pedestals();
+
+ fGains = calib.Gains(); // we get gains whatever the calibMode is, in order
+ // to get the saturation value...
+
+ if ( fApplyGains == fgkGain )
{
- // make a fake (empty) status map
- fStatusMap = AliMUONPadStatusMapMaker::MakeEmptyPadStatusMap();
+ fCapacitances = calib.Capacitances();
}
}
AliMUONDigitCalibrator::~AliMUONDigitCalibrator()
{
/// dtor.
- delete fStatusMap;
+ delete fStatusMaker;
+ delete fStatusMapMaker;
AliInfo("Summary of messages:");
fLogger->Print();
+ AliInfo(Form("We have seen %g pads, and rejected %g (%7.2f %%)",
+ fNumberOfPads,fNumberOfBadPads,
+ ( fNumberOfPads > 0 ) ? fNumberOfBadPads*100.0/fNumberOfPads : 0 ));
+
delete fLogger;
}
/// Calibrate the digits contained in digitStore
TIter next(digitStore.CreateTrackerIterator());
AliMUONVDigit* digit;
+ Int_t detElemId(-1);
+ Double_t nsigmas = fChargeSigmaCut;
+
+ AliDebug(1,Form("# of digits = %d",digitStore.GetSize()));
while ( ( digit = static_cast<AliMUONVDigit*>(next() ) ) )
{
- CalibrateDigit(*digit);
+ if ( digit->IsCalibrated() )
+ {
+ fLogger->Log("ERROR : trying to calibrate a digit twice");
+ return;
+ }
+
+ digit->Calibrated(kTRUE);
+
+ if ( digit->DetElemId() != detElemId )
+ {
+ // Find out occupancy of that DE
+ detElemId = digit->DetElemId();
+ AliMpDetElement* de = AliMpDDLStore::Instance()->GetDetElement(detElemId);
+ Double_t nchannels = de->NofChannels();
+ Double_t occ = digitStore.GetSize(detElemId)/nchannels;
+ if ( occ > 0.05 )
+ {
+ nsigmas = 10.0; // enlarge (a lot) sigma cut if occupancy is high
+ // (which probably means zero suppression was not exactly OK).
+ fLogger->Log(Form("Will use %5.0f*sigma cut for DE %04d "
+ "due to high occupancy",nsigmas,detElemId));
+ }
+ else
+ {
+ nsigmas = fChargeSigmaCut;
+ }
+ }
+
+ Float_t charge(0.0);
+ Int_t statusMap;
+ Bool_t isSaturated(kFALSE);
+
+ Bool_t ok = IsValidDigit(digit->DetElemId(),digit->ManuId(),digit->ManuChannel(),&statusMap);
+
+ digit->SetStatusMap(statusMap);
+
+ if (ok)
+ {
+ ++fNumberOfPads;
+ charge = CalibrateDigit(digit->DetElemId(),digit->ManuId(),digit->ManuChannel(),
+ digit->ADC(),nsigmas,&isSaturated);
+ }
+ else
+ {
+ ++fNumberOfBadPads;
+ }
+
+ digit->SetCharge(charge);
+ digit->Saturated(isSaturated);
}
}
//_____________________________________________________________________________
-void
-AliMUONDigitCalibrator::CalibrateDigit(AliMUONVDigit& digit)
+Float_t
+AliMUONDigitCalibrator::CalibrateDigit(Int_t detElemId, Int_t manuId, Int_t manuChannel,
+ Float_t adc, Float_t nsigmas,
+ Bool_t* isSaturated) const
+
{
/// Calibrate one digit
- AliMUONVCalibParam* deadmap = static_cast<AliMUONVCalibParam*>
- (fStatusMap->FindObject(digit.DetElemId(),digit.ManuId()));
- Int_t statusMap = deadmap->ValueAsInt(digit.ManuChannel());
- digit.SetStatusMap(statusMap);
- digit.Calibrated(kTRUE);
- if ( ( statusMap & AliMUONPadStatusMapMaker::SelfDeadMask() ) != 0 )
+
+ AliMUONVCalibParam* pedestal = static_cast<AliMUONVCalibParam*>
+ (fPedestals->FindObject(detElemId,manuId));
+
+ if (!pedestal)
{
- // pad itself is bad (not testing its neighbours at this stage)
- digit.SetCharge(0);
- fLogger->Log(Form("%s:%d:Channel detElemId %d manuId %d "
- "manuChannel %d is bad %x",__FILE__,__LINE__,
- digit.DetElemId(),digit.ManuId(),
- digit.ManuChannel(),digit.StatusMap()));
+ // no pedestal -> no charge
+ fLogger->Log(Form("Got a null pedestal object for DE,manu=%d,%d",detElemId,manuId));
+ return 0.0;
}
- else
+
+
+ AliMUONVCalibParam* gain = static_cast<AliMUONVCalibParam*>
+ (fGains->FindObject(detElemId,manuId));
+
+ if (!gain)
{
- // If the channel is good, go on with the calibration itself.
-
- AliMUONVCalibParam* pedestal = static_cast<AliMUONVCalibParam*>
- (fCalibrationData.Pedestals(digit.DetElemId(),digit.ManuId()));
+ if ( fApplyGains != fgkNoGain )
+ {
+ // no gain -> no charge
+ fLogger->Log(Form("Got a null gain object for DE,manu=%d,%d",
+ detElemId,manuId));
+ return 0.0;
+ }
+ }
+
+ Float_t padc = adc-pedestal->ValueAsFloat(manuChannel,0);
+ Float_t charge(0);
+ Float_t capa(1.0);
+
+ if ( fApplyGains == fgkGainConstantCapa )
+ {
+ capa = 0.2; // pF
+ }
+ else if ( fApplyGains == fgkGain )
+ {
+ AliMpDetElement* de = AliMpDDLStore::Instance()->GetDetElement(detElemId);
+
+ Int_t serialNumber = de->GetManuSerialFromId(manuId);
- AliMUONVCalibParam* gain = static_cast<AliMUONVCalibParam*>
- (fCalibrationData.Gains(digit.DetElemId(),digit.ManuId()));
+ AliMUONVCalibParam* param = static_cast<AliMUONVCalibParam*>(fCapacitances->FindObject(serialNumber));
- if (!pedestal)
+ if ( param )
{
- AliFatal(Form("Got a null ped object for DE,manu=%d,%d",
- digit.DetElemId(),digit.ManuId()));
-
+ capa = param->ValueAsFloat(manuChannel);
}
- if (!gain)
+ else
{
- AliFatal(Form("Got a null gain object for DE,manu=%d,%d",
- digit.DetElemId(),digit.ManuId()));
+ fLogger->Log(Form("No capa found for serialNumber=%d",serialNumber));
+ capa = 0.0;
}
-
- Int_t manuChannel = digit.ManuChannel();
- Float_t adc = digit.ADC();
- Float_t padc = adc-pedestal->ValueAsFloat(manuChannel,0);
- if ( padc < 3.0*pedestal->ValueAsFloat(manuChannel,1) )
+ }
+
+ if ( padc > nsigmas*pedestal->ValueAsFloat(manuChannel,1) )
+ {
+ if ( fApplyGains != fgkNoGain )
{
- padc = 0.0;
+ Float_t a0 = gain->ValueAsFloat(manuChannel,0);
+ Float_t a1 = gain->ValueAsFloat(manuChannel,1);
+ Int_t thres = gain->ValueAsInt(manuChannel,2);
+ if ( padc < thres )
+ {
+ charge = a0*padc;
+ }
+ else
+ {
+ charge = a0*thres + a0*(padc-thres) + a1*(padc-thres)*(padc-thres);
+ }
}
- Float_t charge = padc*gain->ValueAsFloat(manuChannel,0);
- digit.SetCharge(charge);
- Int_t saturation = gain->ValueAsInt(manuChannel,1);
- if ( charge >= saturation )
+ else
{
- digit.Saturated(kTRUE);
+ charge = padc;
}
}
+
+ charge *= capa;
+
+ if ( isSaturated )
+ {
+ Int_t saturation(3000);
+
+ if ( gain )
+ {
+ saturation = gain->ValueAsInt(manuChannel,4);
+ }
+
+ if ( padc >= saturation )
+ {
+ *isSaturated = kTRUE;
+ }
+ else
+ {
+ *isSaturated = kFALSE;
+ }
+ }
+
+ return charge;
}
+
+//_____________________________________________________________________________
+Bool_t
+AliMUONDigitCalibrator::IsValidDigit(Int_t detElemId, Int_t manuId, Int_t manuChannel,
+ Int_t* statusMap) const
+
+{
+ /// Check if a given pad is ok or not.
+
+ // First a protection against bad input parameters
+ AliMpDetElement* de = AliMpDDLStore::Instance()->GetDetElement(detElemId);
+ if (!de) return kFALSE; // not existing DE
+ if (!de->IsExistingChannel(manuId,manuChannel))
+ {
+ // non-existing (might happen when we get parity errors in read-out
+ // that spoils the manuId
+ return kFALSE;
+ }
+ if (!de->IsConnectedChannel(manuId,manuChannel))
+ {
+ // existing (in read-out), but not connected channel
+ return kFALSE;
+ }
+
+ // ok, now we have a valid channel number, so let's see if that pad
+ // behaves or not ;-)
+
+ Int_t sm = fStatusMapMaker->StatusMap(detElemId,manuId,manuChannel);
+
+ if (statusMap) *statusMap = sm;
+
+ if ( ( sm & AliMUONPadStatusMapMaker::SelfDeadMask() ) != 0 )
+ {
+ // pad itself is bad (not testing its neighbours at this stage)
+ return kFALSE;
+ }
+
+ return kTRUE;
+}
+
+//_____________________________________________________________________________
+Int_t
+AliMUONDigitCalibrator::PadStatus(Int_t detElemId, Int_t manuId, Int_t manuChannel) const
+{
+ /// Return the status of the given pad
+ return fStatusMaker->PadStatus(detElemId,manuId,manuChannel);
+}
+
+//_____________________________________________________________________________
+Int_t
+AliMUONDigitCalibrator::StatusMap(Int_t detElemId, Int_t manuId, Int_t manuChannel) const
+{
+ /// Return the status map of the given pad
+ return fStatusMapMaker->StatusMap(detElemId,manuId,manuChannel);
+
+}
+