2 /**************************************************************************
3 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
5 * Author: The ALICE Off-line Project. *
6 * Contributors are mentioned in the code where appropriate. *
8 * Permission to use, copy, modify and distribute this software and its *
9 * documentation strictly for non-commercial purposes is hereby granted *
10 * without fee, provided that the above copyright notice appears in all *
11 * copies and that both the copyright notice and this permission notice *
12 * appear in the supporting documentation. The authors make no claims *
13 * about the suitability of this software for any purpose. It is *
14 * provided "as is" without express or implied warranty. *
15 **************************************************************************/
20 //_________________________________________________________________________
21 // Utility Class for handling Raw data
22 // Does all transitions from Digits to Raw and vice versa,
23 // for simu and reconstruction
25 // Note: the current version is still simplified. Only
26 // one raw signal per digit is generated; either high-gain or low-gain
27 // Need to add concurrent high and low-gain info in the future
28 // No pedestal is added to the raw signal.
29 //*-- Author: Marco van Leeuwen (LBL)
32 #include "AliEMCALRawUtils.h"
37 #include "AliRunLoader.h"
38 #include "AliAltroBuffer.h"
39 #include "AliRawReader.h"
40 #include "AliCaloRawStreamV3.h"
42 #include "AliEMCALRecParam.h"
43 #include "AliEMCALLoader.h"
44 #include "AliEMCALGeometry.h"
45 #include "AliEMCALDigit.h"
46 #include "AliEMCALRawDigit.h"
48 #include "AliCaloCalibPedestal.h"
49 #include "AliCaloBunchInfo.h"
50 #include "AliCaloFitResults.h"
51 #include "AliEMCALTriggerRawDigitMaker.h"
52 #include "AliEMCALTriggerSTURawStream.h"
53 #include "AliEMCALTriggerData.h"
54 #include "AliCaloConstants.h"
55 #include "AliCaloRawAnalyzer.h"
56 #include "AliCaloRawAnalyzerFactory.h"
59 using namespace EMCAL;
61 Double_t AliEMCALRawUtils::fgTimeTrigger = 600E-9 ; // the time of the trigger as approximately seen in the data
62 Int_t AliEMCALRawUtils::fgThreshold = 1;
63 Int_t AliEMCALRawUtils::fgPedestalValue = 0; // pedestal value for digits2raw, default generate ZS data
64 Double_t AliEMCALRawUtils::fgFEENoise = 3.; // 3 ADC channels of noise (sampled)
66 ClassImp(AliEMCALRawUtils)
69 AliEMCALRawUtils::AliEMCALRawUtils( Algo::fitAlgorithm fitAlgo) : fNoiseThreshold(3),
73 fRemoveBadChannels(kFALSE),
79 fTriggerRawDigitMaker(0x0)
81 SetFittingAlgorithm(fitAlgo);
82 // SetFittingAlgorithm( Algo::kLMSOffline);
84 //Get Mapping RCU files from the AliEMCALRecParam
85 const TObjArray* maps = AliEMCALRecParam::GetMappings();
86 if(!maps) AliFatal("Cannot retrieve ALTRO mappings!!");
88 for(Int_t i = 0; i < 4; i++) {
89 fMapping[i] = (AliAltroMapping*)maps->At(i);
92 //To make sure we match with the geometry in a simulation file,
93 //let's try to get it first. If not, take the default geometry
94 AliRunLoader *rl = AliRunLoader::Instance();
95 if (rl && rl->GetAliRun()) {
96 AliEMCAL * emcal = dynamic_cast<AliEMCAL*>(rl->GetAliRun()->GetDetector("EMCAL"));
97 if(emcal)fGeom = emcal->GetGeometry();
99 AliDebug(1, Form("Using default geometry in raw reco"));
100 fGeom = AliEMCALGeometry::GetInstance(AliEMCALGeometry::GetDefaultGeometryName());
104 AliDebug(1, Form("Using default geometry in raw reco"));
105 fGeom = AliEMCALGeometry::GetInstance(AliEMCALGeometry::GetDefaultGeometryName());
108 if(!fGeom) AliFatal(Form("Could not get geometry!"));
110 fTriggerRawDigitMaker = new AliEMCALTriggerRawDigitMaker();
115 //____________________________________________________________________________
116 AliEMCALRawUtils::AliEMCALRawUtils(AliEMCALGeometry *pGeometry, Algo::fitAlgorithm fitAlgo) : //fHighLowGainFactor(16.),
123 fRemoveBadChannels(kFALSE),fFittingAlgorithm(0),
124 fTimeMin(-1.),fTimeMax(1.),
125 fUseFALTRO(kTRUE),fRawAnalyzer(0),
126 fTriggerRawDigitMaker(0x0)
130 // Initialize with the given geometry - constructor required by HLT
131 // HLT does not use/support AliRunLoader(s) instances
132 // This is a minimum intervention solution
133 // Comment by MPloskon@lbl.gov
134 SetFittingAlgorithm(fitAlgo);
135 // SetFittingAlgorithm( Algo::kLMSOffline);
136 //Get Mapping RCU files from the AliEMCALRecParam
137 const TObjArray* maps = AliEMCALRecParam::GetMappings();
138 if(!maps) AliFatal("Cannot retrieve ALTRO mappings!!");
140 for(Int_t i = 0; i < 4; i++)
142 fMapping[i] = (AliAltroMapping*)maps->At(i);
145 if(!fGeom) AliFatal(Form("Could not get geometry!"));
146 fTriggerRawDigitMaker = new AliEMCALTriggerRawDigitMaker();
150 //____________________________________________________________________________
151 AliEMCALRawUtils::~AliEMCALRawUtils()
157 //____________________________________________________________________________
158 void AliEMCALRawUtils::Digits2Raw()
160 // convert digits of the current event to raw data
161 AliRunLoader *rl = AliRunLoader::Instance();
162 AliEMCALLoader *loader = dynamic_cast<AliEMCALLoader*>(rl->GetDetectorLoader("EMCAL"));
165 loader->LoadDigits("EMCAL");
167 TClonesArray* digits = loader->Digits() ;
170 Warning("Digits2Raw", "no digits found !");
174 static const Int_t nDDL = 12*2; // 12 SM hardcoded for now. Buffers allocated dynamically, when needed, so just need an upper limit here
175 AliAltroBuffer* buffers[nDDL];
176 for (Int_t i=0; i < nDDL; i++)
179 TArrayI adcValuesLow( TIMEBINS );
180 TArrayI adcValuesHigh( TIMEBINS );
182 // loop over digits (assume ordered digits)
183 for (Int_t iDigit = 0; iDigit < digits->GetEntries(); iDigit++)
185 AliEMCALDigit* digit = dynamic_cast<AliEMCALDigit *>(digits->At(iDigit)) ;
188 AliFatal("NULL Digit");
192 if (digit->GetAmplitude() < fgThreshold)
203 fGeom->GetCellIndex(digit->GetId(), nSM, nModule, nIphi, nIeta);
204 fGeom->GetCellPhiEtaIndexInSModule(nSM, nModule, nIphi, nIeta,iphi, ieta) ;
206 //Check which is the RCU, 0 or 1, of the cell.
209 if (0<=iphi&&iphi<8) iRCU=0; // first cable row
210 else if (8<=iphi&&iphi<16 && 0<=ieta&&ieta<24) iRCU=0; // first half;
213 else if(8<=iphi&&iphi<16 && 24<=ieta&&ieta<48) iRCU=1; // second half;
215 else if(16<=iphi&&iphi<24) iRCU=1; // third cable row
217 if (nSM%2==1) iRCU = 1 - iRCU; // swap for odd=C side, to allow us to cable both sides the same
220 Fatal("Digits2Raw()","Non-existent RCU number: %d", iRCU);
223 Int_t iDDL = NRCUSPERMODULE*nSM + iRCU;
224 if (iDDL < 0 || iDDL >= nDDL){
225 Fatal("Digits2Raw()","Non-existent DDL board number: %d", iDDL);
228 if (buffers[iDDL] == 0) {
229 // open new file and write dummy header
230 TString fileName = AliDAQ::DdlFileName("EMCAL",iDDL);
231 //Select mapping file RCU0A, RCU0C, RCU1A, RCU1C
232 Int_t iRCUside=iRCU+(nSM%2)*2;
233 //iRCU=0 and even (0) SM -> RCU0A.data 0
234 //iRCU=1 and even (0) SM -> RCU1A.data 1
235 //iRCU=0 and odd (1) SM -> RCU0C.data 2
236 //iRCU=1 and odd (1) SM -> RCU1C.data 3
237 //cout<<" nSM "<<nSM<<"; iRCU "<<iRCU<<"; iRCUside "<<iRCUside<<endl;
238 buffers[iDDL] = new AliAltroBuffer(fileName.Data(),fMapping[iRCUside]);
239 buffers[iDDL]->WriteDataHeader(kTRUE, kFALSE); //Dummy;
242 // out of time range signal (?)
243 if (digit->GetTimeR() > TIMEBINMAX ) {
244 AliInfo("Signal is out of time range.\n");
245 buffers[iDDL]->FillBuffer((Int_t)digit->GetAmplitude());
246 buffers[iDDL]->FillBuffer( TIMEBINS ); // time bin
247 buffers[iDDL]->FillBuffer(3); // bunch length
248 buffers[iDDL]->WriteTrailer(3, ieta, iphi, nSM); // trailer
249 // calculate the time response function
251 Bool_t lowgain = RawSampledResponse(digit->GetTimeR(), digit->GetAmplitude(), adcValuesHigh.GetArray(), adcValuesLow.GetArray()) ;
253 buffers[iDDL]->WriteChannel(ieta, iphi, 0, TIMEBINS, adcValuesLow.GetArray(), fgThreshold);
255 buffers[iDDL]->WriteChannel(ieta,iphi, 1, TIMEBINS, adcValuesHigh.GetArray(), fgThreshold);
257 }// iDDL under the limits
261 // write headers and close files
262 for (Int_t i=0; i < nDDL; i++) {
265 buffers[i]->WriteDataHeader(kFALSE, kFALSE);
270 loader->UnloadDigits();
274 //____________________________________________________________________________
275 void AliEMCALRawUtils::AddDigit(TClonesArray *digitsArr, Int_t id, Int_t lowGain, Float_t amp, Float_t time, Float_t chi2, Int_t ndf)
277 AliEMCALDigit *digit = 0, *tmpdigit = 0;
278 TIter nextdigit(digitsArr);
280 while (digit == 0 && (tmpdigit = (AliEMCALDigit*) nextdigit()))
282 if (tmpdigit->GetId() == id) digit = tmpdigit;
285 if (!digit) { // no digit existed for this tower; create one
286 Int_t type = AliEMCALDigit::kHG; // use enum in AliEMCALDigit
290 type = AliEMCALDigit::kLGnoHG;
293 Int_t idigit = digitsArr->GetEntries();
294 new((*digitsArr)[idigit]) AliEMCALDigit( -1, -1, id, amp, time, type, idigit, chi2, ndf);
295 AliDebug(2,Form("Add digit Id %d for the first time, type %d", id, type));
296 }//digit added first time
298 { // a digit already exists, check range
299 // (use high gain if signal < cut value, otherwise low gain)
301 { // new digit is low gain
302 if (digit->GetAmplitude() > OVERFLOWCUT )
303 { // use if previously stored (HG) digit is out of range
304 digit->SetAmplitude( HGLGFACTOR * amp);
305 digit->SetTime(time);
306 digit->SetType(AliEMCALDigit::kLG);
307 AliDebug(2,Form("Add LG digit ID %d for the second time, type %d", digit->GetId(), digit->GetType()));
309 }//new low gain digit
310 else { // new digit is high gain
312 if (amp < OVERFLOWCUT )
313 { // new digit is high gain; use if not out of range
314 digit->SetAmplitude(amp);
315 digit->SetTime(time);
316 digit->SetType(AliEMCALDigit::kHG);
317 AliDebug(2,Form("Add HG digit ID %d for the second time, type %d", digit->GetId(), digit->GetType()));
320 { // HG out of range, just change flag value to show that HG did exist
321 digit->SetType(AliEMCALDigit::kLG);
322 AliDebug(2,Form("Change LG digit to HG, ID %d, type %d", digit->GetId(), digit->GetType()));
324 }//new high gain digit
325 }//digit existed replace it
329 //____________________________________________________________________________
330 void AliEMCALRawUtils::Raw2Digits(AliRawReader* reader,TClonesArray *digitsArr, const AliCaloCalibPedestal* pedbadmap, TClonesArray *digitsTRG, AliEMCALTriggerData* trgData)
333 if(digitsArr) digitsArr->Clear("C");
334 if (!digitsArr) { Error("Raw2Digits", "no digits found !");return;}
335 if (!reader) {Error("Raw2Digits", "no raw reader found !");return;}
336 AliEMCALTriggerSTURawStream inSTU(reader);
337 AliCaloRawStreamV3 in(reader,"EMCAL",fMapping);
338 reader->Select("EMCAL",0,43); // 43 = AliEMCALGeoParams::fgkLastAltroDDL
339 fTriggerRawDigitMaker->Reset();
340 fTriggerRawDigitMaker->SetIO(reader, in, inSTU, digitsTRG, trgData);
341 fRawAnalyzer->SetIsZeroSuppressed(true); // TMP - should use stream->IsZeroSuppressed(), or altro cfg registers later
344 Int_t caloFlag = 0; // low, high gain, or TRU, or LED ref.
348 // fprintf(fp," TP1\n");
349 while (in.NextChannel())
351 // fprintf(fp," TP2\n");
352 caloFlag = in.GetCaloFlag();
353 if (caloFlag > 2) continue; // Work with ALTRO and FALTRO
354 if(caloFlag < 2 && fRemoveBadChannels && pedbadmap->IsBadChannel(in.GetModule(),in.GetColumn(),in.GetRow()))
358 vector<AliCaloBunchInfo> bunchlist;
359 while (in.NextBunch())
361 bunchlist.push_back( AliCaloBunchInfo(in.GetStartTimeBin(), in.GetBunchLength(), in.GetSignals() ) );
363 if (bunchlist.size() == 0) continue;
366 Int_t id = fGeom->GetAbsCellIdFromCellIndexes(in.GetModule(), in.GetRow(), in.GetColumn()) ;
367 lowGain = in.IsLowGain();
368 fRawAnalyzer->SetL1Phase( in.GetL1Phase() );
369 AliCaloFitResults res = fRawAnalyzer->Evaluate( bunchlist, in.GetAltroCFG1(), in.GetAltroCFG2());
370 if(res.GetAmp() >= fNoiseThreshold )
372 AddDigit(digitsArr, id, lowGain, res.GetAmp(), res.GetTime(), res.GetChi2(), res.GetNdf() );
377 fTriggerRawDigitMaker->Add( bunchlist );
379 } // end while over channel
380 } //end while over DDL's, of input stream
381 fTriggerRawDigitMaker->PostProcess();
382 TrimDigits(digitsArr);
386 void AliEMCALRawUtils::TrimDigits(TClonesArray *digitsArr)
388 AliEMCALDigit *digit = 0;
390 Int_t nDigits = digitsArr->GetEntriesFast();
391 TIter nextdigit(digitsArr);
392 while ((digit = (AliEMCALDigit*) nextdigit())) {
393 if (digit->GetType() == AliEMCALDigit::kLGnoHG) {
394 AliDebug(1,Form("Remove digit with id %d, LGnoHG",digit->GetId()));
395 digitsArr->Remove(digit);
397 else if(fTimeMin > digit->GetTime() || fTimeMax < digit->GetTime()) {
398 digitsArr->Remove(digit);
399 AliDebug(1,Form("Remove digit with id %d, Bad Time %e",digit->GetId(), digit->GetTime()));
401 else if (0 > digit->GetChi2()) {
402 digitsArr->Remove(digit);
403 AliDebug(1,Form("Remove digit with id %d, Bad Chi2 %e",digit->GetId(), digit->GetChi2()));
406 digit->SetIndexInList(n);
411 digitsArr->Compress();
412 AliDebug(1,Form("N Digits before trimming : %d; after array compression %d",nDigits,digitsArr->GetEntriesFast()));
417 AliEMCALRawUtils::RawResponseFunction(Double_t *x, Double_t *par)
419 Double_t signal = 0.;
420 Double_t tau = par[2];
422 Double_t ped = par[4];
423 Double_t xx = ( x[0] - par[1] + tau ) / tau ;
428 signal = ped + par[0] * TMath::Power(xx , n) * TMath::Exp(n * (1 - xx )) ;
434 Bool_t AliEMCALRawUtils::RawSampledResponse(const Double_t dtime, const Double_t damp, Int_t * adcH,
435 Int_t * adcL, const Int_t keyErr) const
437 Bool_t lowGain = kFALSE ;
438 TF1 signalF("signal", RawResponseFunction, 0, TIMEBINS, 5);
439 signalF.SetParameter(0, damp) ;
440 signalF.SetParameter(1, (dtime + fgTimeTrigger)/ TIMEBINWITH) ;
441 signalF.SetParameter(2, TAU) ;
442 signalF.SetParameter(3, ORDER);
443 signalF.SetParameter(4, fgPedestalValue);
445 Double_t signal=0.0, noise=0.0;
446 for (Int_t iTime = 0; iTime < TIMEBINS; iTime++) {
447 signal = signalF.Eval(iTime) ;
450 noise = gRandom->Gaus(0.,fgFEENoise);
454 adcH[iTime] = static_cast<Int_t>(signal + 0.5) ;
455 if ( adcH[iTime] > MAXBINVALUE ){ // larger than 10 bits
456 adcH[iTime] = MAXBINVALUE ;
459 signal /= HGLGFACTOR;
460 adcL[iTime] = static_cast<Int_t>(signal + 0.5) ;
461 if ( adcL[iTime] > MAXBINVALUE ) // larger than 10 bits
462 adcL[iTime] = MAXBINVALUE ;
468 //__________________________________________________________________
469 Double_t AliEMCALRawUtils::RawResponseFunctionLog(Double_t *x, Double_t *par)
471 Double_t signal = 0. ;
472 Double_t tau = par[2];
474 Double_t xx = ( x[0] - par[1] + tau ) / tau ;
478 signal = par[0] - n*TMath::Log(TMath::Abs(xx)) + n * (1 - xx ) ;
482 signal = par[0] + n*TMath::Log(xx) + n * (1 - xx ) ;
489 //__________________________________________________________________
490 void AliEMCALRawUtils::SetFittingAlgorithm(Int_t fitAlgo)
492 // fRawAnalyzer = AliCaloRawAnalyzerFactory::CreateAnalyzer( Algo::kStandard );
493 fRawAnalyzer = AliCaloRawAnalyzerFactory::CreateAnalyzer( fitAlgo );
495 //fRawAnalyzer = AliCaloRawAnalyzerFactory::CreateAnalyzer( kStandard );
497 fRawAnalyzer->SetNsampleCut(5); // requirement for fits to be done, for the new methods
498 fRawAnalyzer->SetOverflowCut ( OVERFLOWCUT );
499 fRawAnalyzer->SetAmpCut(fNoiseThreshold);
500 fRawAnalyzer->SetFitArrayCut(fNoiseThreshold);