/**************************************************************************
-* Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
-* *
-* Author: The ALICE Off-line Project. *
-* Contributors are mentioned in the code where appropriate. *
-* *
-* Permission to use, copy, modify and distribute this software and its *
-* documentation strictly for non-commercial purposes is hereby granted *
-* without fee, provided that the above copyright notice appears in all *
-* copies and that both the copyright notice and this permission notice *
-* appear in the supporting documentation. The authors make no claims *
-* about the suitability of this software for any purpose. It is *
-* provided "as is" without express or implied warranty. *
-**************************************************************************/
+ * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
+ * *
+ * Author: The ALICE Off-line Project. *
+ * Contributors are mentioned in the code where appropriate. *
+ * *
+ * Permission to use, copy, modify and distribute this software and its *
+ * documentation strictly for non-commercial purposes is hereby granted *
+ * without fee, provided that the above copyright notice appears in all *
+ * copies and that both the copyright notice and this permission notice *
+ * appear in the supporting documentation. The authors make no claims *
+ * about the suitability of this software for any purpose. It is *
+ * provided "as is" without express or implied warranty. *
+ **************************************************************************/
// $Id$
#include "AliMUONDigitCalibrator.h"
+#include "AliCDBEntry.h"
+#include "AliCDBManager.h"
#include "AliLog.h"
#include "AliMUONCalibrationData.h"
+#include "AliMUONConstants.h"
#include "AliMUONLogger.h"
#include "AliMUONPadStatusMaker.h"
#include "AliMUONPadStatusMapMaker.h"
+#include "AliMUONRecoParam.h"
#include "AliMUONVCalibParam.h"
#include "AliMUONVDigit.h"
#include "AliMUONVDigitStore.h"
#include "AliMUONVStore.h"
#include "AliMpBusPatch.h"
#include "AliMpConstants.h"
+#include "AliMpCDB.h"
#include "AliMpDDLStore.h"
#include "AliMpDEIterator.h"
#include "AliMpDetElement.h"
+#include "AliMpManuStore.h"
//-----------------------------------------------------------------------------
/// \class AliMUONDigitCalibrator
const Int_t AliMUONDigitCalibrator::fgkNoGain(0);
const Int_t AliMUONDigitCalibrator::fgkGainConstantCapa(1);
const Int_t AliMUONDigitCalibrator::fgkGain(2);
+const Int_t AliMUONDigitCalibrator::fgkInjectionGain(3);
+
+//_____________________________________________________________________________
+AliMUONDigitCalibrator::AliMUONDigitCalibrator(Int_t runNumber, 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),
+fMask(0)
+{
+ /// ctor
+
+ AliMUONRecoParam* recoParam(0x0);
+
+ AliCDBEntry* e = AliCDBManager::Instance()->Get("MUON/Calib/RecoParam",runNumber);
+ if (e)
+ {
+ TObject* o = e->GetObject();
+ if ( o->IsA() == TObjArray::Class() )
+ {
+ TObjArray* a = static_cast<TObjArray*>(o);
+ TIter next(a);
+ AliMUONRecoParam* p;
+ while ( ( p = static_cast<AliMUONRecoParam*>(next()) ))
+ {
+ if ( p->IsDefault()) recoParam = p;
+ }
+ }
+ else
+ {
+ recoParam = static_cast<AliMUONRecoParam*>(o);
+ }
+ }
+ if (!recoParam)
+ {
+ AliError("Cannot get the recoParam. Failing");
+ return;
+ }
+
+ // OK. Now get all we need and work...
+
+ AliMUONCalibrationData calib(runNumber);
+
+ Ctor(calibMode,calib,recoParam,kFALSE);
+}
+
+//_____________________________________________________________________________
+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),
+fMask(0)
+{
+ /// ctor
+
+ Ctor(calibMode,calib,recoParams);
+}
//_____________________________________________________________________________
AliMUONDigitCalibrator::AliMUONDigitCalibrator(const AliMUONCalibrationData& calib,
fGains(0x0),
fApplyGains(0),
fCapacitances(0x0),
-fNofChannelsPerDE(new TExMap)
+fNumberOfBadPads(0),
+fNumberOfPads(0),
+fChargeSigmaCut(0),
+fMask(0)
{
/// ctor
+ Ctor(calibMode,calib,0x0);
+}
+
+//_____________________________________________________________________________
+void
+AliMUONDigitCalibrator::Ctor(const char* calibMode,
+ const AliMUONCalibrationData& calib,
+ const AliMUONRecoParam* recoParams,
+ Bool_t deferredInitialization)
+{
+ /// designated ctor
+
TString cMode(calibMode);
cMode.ToUpper();
fApplyGains = fgkGain;
AliInfo("Will apply gain correction, with measured capacitances");
}
+ else if ( cMode == "INJECTIONGAIN")
+ {
+ fApplyGains = fgkInjectionGain;
+ AliInfo("Will apply injection gain correction, with EMELEC factory gains");
+ }
else
{
AliError(Form("Invalid calib mode = %s. Will use NOGAIN instead",calibMode));
fApplyGains = fgkNoGain;
}
-
- fStatusMaker = new AliMUONPadStatusMaker(calib);
- // 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...
- fStatusMaker->SetHVSt12Limits(1300,1600);
- fStatusMaker->SetHVSt345Limits(1500,2000);
- fStatusMaker->SetPedMeanLimits(50,200);
- fStatusMaker->SetPedSigmaLimits(0.1,3);
+ // Load mapping manu store
+ if ( ! AliMpCDB::LoadManuStore() ) {
+ AliFatal("Could not access manu store from OCDB !");
+ }
- 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 ;-)
+ fStatusMaker = new AliMUONPadStatusMaker(calib);
- Bool_t deferredInitialization = kTRUE;
+ // Set default values, as loose as reasonable
- fStatusMapMaker = new AliMUONPadStatusMapMaker(*fStatusMaker,mask,deferredInitialization);
+ fChargeSigmaCut = 3.0;
- fPedestals = calib.Pedestals();
-
- fGains = calib.Gains(); // we get gains whatever the calibMode is, in order
- // to get the saturation value...
-
- if ( fApplyGains == fgkGain )
+ fMask = 0x8080; // reject pads where ped *or* hv are missing
+
+ if ( recoParams )
+ {
+ // if we have reco params, we use limits and cuts from there :
+
+ fStatusMaker->SetLimits(*recoParams);
+
+ fMask = recoParams->PadGoodnessMask();
+ //WARNING : getting this mask wrong is a very effective way of getting
+ //no digits at all out of this class ;-)
+
+ fChargeSigmaCut = recoParams->ChargeSigmaCut();
+ }
+ else
{
- fCapacitances = calib.Capacitances();
+ fLogger->Log("No RecoParam available");
+ fLogger->Log(Form("SigmaCut=%e",fChargeSigmaCut));
}
- // FIXME: get the nof of channels per de directly within AliMpDetElement ?
- // or use the AliMUONTrackerData class for that ?
+ fStatusMapMaker = new AliMUONPadStatusMapMaker(*fStatusMaker,fMask,deferredInitialization);
- AliMpDEIterator it;
+ fPedestals = calib.Pedestals();
- it.First();
+ fGains = calib.Gains(); // we get gains whatever the calibMode is, in order
+ // to get the saturation value...
- while ( !it.IsDone() )
+ if ( fApplyGains == fgkGain || fApplyGains == fgkInjectionGain )
{
-
- AliMpDetElement* det = it.CurrentDE();
- Int_t detElemId = det->GetId();
- Int_t nchannels(0);
-
- for ( Int_t i = 0; i < det->GetNofBusPatches(); ++i )
- {
- Int_t busPatchId = det->GetBusPatchId(i);
- AliMpBusPatch* bp = AliMpDDLStore::Instance()->GetBusPatch(busPatchId);
- for ( Int_t j = 0; j < bp->GetNofManus(); ++j )
- {
- Int_t manuId = bp->GetManuId(j);
- nchannels += det->NofChannelsInManu(manuId);
- }
- }
-
- it.Next();
-
- fNofChannelsPerDE->Add((Long_t)detElemId,(Long_t)nchannels);
+ fCapacitances = calib.Capacitances();
}
}
AliMUONDigitCalibrator::~AliMUONDigitCalibrator()
{
/// dtor.
- delete fStatusMaker;
- delete fStatusMapMaker;
- AliInfo("Summary of messages:");
- fLogger->Print();
+ if ( fNumberOfPads > 0 )
+ {
+ if ( fStatusMaker )
+ {
+ fStatusMaker->Report(fMask);
+ }
+
+ 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 fStatusMaker;
+ delete fStatusMapMaker;
delete fLogger;
- delete fNofChannelsPerDE;
}
//_____________________________________________________________________________
/// Calibrate the digits contained in digitStore
TIter next(digitStore.CreateTrackerIterator());
AliMUONVDigit* digit;
- Int_t detElemId(-1);
- Double_t nsigmas(3.0);
+
+ fStatusMapMaker->RefreshRejectProbabilities(); // this will do something only for simulations
+ // (and only for those simulations where the reject list contain probabilities which are
+ // different from zero or one)
AliDebug(1,Form("# of digits = %d",digitStore.GetSize()));
while ( ( digit = static_cast<AliMUONVDigit*>(next() ) ) )
{
- if ( digit->DetElemId() != detElemId )
+ if ( digit->IsCalibrated() )
{
- // Find out occupancy of that DE
- detElemId = digit->DetElemId();
- Double_t nchannels = fNofChannelsPerDE->GetValue(detElemId);
- 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 = 3.0;
- }
+ fLogger->Log("ERROR : trying to calibrate a digit twice");
+ return;
}
-
- CalibrateDigit(*digit,nsigmas);
+
+ digit->Calibrated(kTRUE);
+
+ Float_t charge(0.0);
+ Int_t statusMap;
+ Bool_t isSaturated(kFALSE);
+
+ ++fNumberOfPads;
+
+ Bool_t ok = IsValidDigit(digit->DetElemId(),digit->ManuId(),digit->ManuChannel(),&statusMap);
+
+ digit->SetStatusMap(statusMap);
+
+ if (ok)
+ {
+ charge = CalibrateDigit(digit->DetElemId(),digit->ManuId(),digit->ManuChannel(),
+ digit->ADC(),fChargeSigmaCut,&isSaturated);
+ }
+ else
+ {
+ ++fNumberOfBadPads;
+ }
+
+ digit->SetCharge(charge);
+ digit->Saturated(isSaturated);
}
}
//_____________________________________________________________________________
-void
-AliMUONDigitCalibrator::CalibrateDigit(AliMUONVDigit& digit, Double_t nsigmas)
+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
+ /// Return the digit charge, in fC
- if ( digit.IsCalibrated() )
+ if ( nsigmas < 0 )
{
- fLogger->Log("ERROR : trying to calibrate a digit twice");
- return;
+ nsigmas = fChargeSigmaCut;
}
-
- Int_t statusMap = fStatusMapMaker->StatusMap(digit.DetElemId(),
- digit.ManuId(),
- digit.ManuChannel());
- digit.SetStatusMap(statusMap);
- digit.Calibrated(kTRUE);
+ fLogger->Log(Form("ChargeSigmaCut used = %e",nsigmas));
+
+ AliMUONVCalibParam* pedestal = static_cast<AliMUONVCalibParam*>
+ (fPedestals->FindObject(detElemId,manuId));
- if ( ( statusMap & AliMUONPadStatusMapMaker::SelfDeadMask() ) != 0 )
+ 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*>
- (fPedestals->FindObject(digit.DetElemId(),digit.ManuId()));
-
- if (!pedestal)
+ if ( fApplyGains != fgkNoGain )
{
- // no pedestal -> no charge
- digit.SetCharge(0);
-
- fLogger->Log(Form("Got a null pedestal object for DE,manu=%d,%d",
- digit.DetElemId(),digit.ManuId()));
- return;
+ // 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);
+
+ // Gain (mV/fC) = 1/(a0*capa) with a0~1.25 and capa~0.2
+ Float_t charge(0);
+ Float_t capa(AliMUONConstants::DefaultCapa()); // capa = 0.2 and a0 = 1.25
+ Float_t a0(AliMUONConstants::DefaultA0()); // is equivalent to gain = 4 mV/fC
+ Float_t a1(0);
+ Float_t adc2mv(AliMUONConstants::DefaultADC2MV()); // 1 ADC channel = 0.61 mV
+ Float_t injGain(4); // By default the gain is set to 4 mV/fC
+ //
+ // Note that the ChargeMax (for one pad) is roughly 4096 * 0.61 mV/channel / 4 mV/fC = 625 fC
+
+ if ( fApplyGains == fgkGain || fApplyGains == fgkInjectionGain )
+ {
+ Int_t serialNumber
+ = AliMpManuStore::Instance()->GetManuSerial(detElemId, manuId);
+ AliMUONVCalibParam* param = static_cast<AliMUONVCalibParam*>(fCapacitances->FindObject(serialNumber));
- AliMUONVCalibParam* gain = static_cast<AliMUONVCalibParam*>
- (fGains->FindObject(digit.DetElemId(),digit.ManuId()));
-
- if (!gain)
+ if ( param )
{
- if ( fApplyGains != fgkNoGain )
+ capa = param->ValueAsFloat(manuChannel,0);
+ injGain = param->ValueAsFloat(manuChannel,1);
+ if ( injGain < 0 )
{
- // no gain -> no charge
- digit.SetCharge(0);
-
- fLogger->Log(Form("Got a null gain object for DE,manu=%d,%d",
- digit.DetElemId(),digit.ManuId()));
- return;
+ fLogger->Log(Form("injGain is %e < 0 for serialNumber=%d",injGain,serialNumber));
+ return 0.0;
}
}
-
- Int_t manuChannel = digit.ManuChannel();
- Float_t adc = digit.ADC();
- Float_t padc = adc-pedestal->ValueAsFloat(manuChannel,0);
- Float_t charge(0);
- Float_t capa(1.0);
-
- if ( fApplyGains == fgkGainConstantCapa )
+ else
{
- capa = 0.2; // pF
+ // If capa not found in the OCDB we exit
+ fLogger->Log(Form("No capa (injGain) found for serialNumber=%d",serialNumber));
+ return 0.0;
}
- else if ( fApplyGains == fgkGain )
+ }
+
+ if ( padc > nsigmas*pedestal->ValueAsFloat(manuChannel,1) )
+ {
+ if ( fApplyGains == fgkGain || fApplyGains == fgkGainConstantCapa )
{
- AliMpDetElement* de = AliMpDDLStore::Instance()->GetDetElement(digit.DetElemId());
-
- Int_t serialNumber = de->GetManuSerialFromId(digit.ManuId());
-
- AliMUONVCalibParam* param = static_cast<AliMUONVCalibParam*>(fCapacitances->FindObject(serialNumber));
-
- if ( param )
+ a0 = gain->ValueAsFloat(manuChannel,0);
+ a1 = gain->ValueAsFloat(manuChannel,1);
+ Int_t thres = gain->ValueAsInt(manuChannel,2);
+ if ( padc < thres )
{
- capa = param->ValueAsFloat(digit.ManuChannel());
+ charge = a0*padc;
}
else
{
- fLogger->Log(Form("No capa found for serialNumber=%d",serialNumber));
- capa = 0.0;
+ charge = a0*thres + a0*(padc-thres) + a1*(padc-thres)*(padc-thres);
}
+ charge *= capa*adc2mv;
}
-
- if ( padc > nsigmas*pedestal->ValueAsFloat(manuChannel,1) )
+ else if ( fApplyGains == fgkInjectionGain )
{
- if ( fApplyGains != fgkNoGain )
- {
- 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);
- }
- }
- else
- {
- charge = padc;
- }
+
+ charge = padc*adc2mv/injGain;
}
-
- charge *= capa;
- digit.SetCharge(charge);
-
+ else
+ {
+ charge = a0*padc*capa*adc2mv;
+ }
+ }
+
+ if ( isSaturated )
+ {
Int_t saturation(3000);
- if ( gain )
+ if ( gain && ( fApplyGains != fgkNoGain ) )
{
saturation = gain->ValueAsInt(manuChannel,4);
}
if ( padc >= saturation )
{
- digit.Saturated(kTRUE);
+ *isSaturated = kTRUE;
+ }
+ else
+ {
+ *isSaturated = kFALSE;
}
}
+
+ return ( charge > 0.0 ? charge : 0.0 );
}
+
+//_____________________________________________________________________________
+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);
+
+}
+