- Added handling of tracks and file mask (used when merging different files).
[u/mrichter/AliRoot.git] / MUON / AliMUONDigitizerV3.cxx
1 /**************************************************************************
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 **************************************************************************/
15
16 // $Id$
17
18 #include "AliMUONDigitizerV3.h"
19
20 #include "AliLog.h"
21 #include "AliMUONCalibrationData.h"
22 #include "AliMUONChamber.h"
23 #include "AliMUONConstants.h"
24 #include "AliMUONData.h"
25 #include "AliMUONDigit.h"
26 #include "AliMUONTriggerDecisionV1.h"
27 #include "AliMUONTriggerElectronics.h"
28 #include "AliMUONVCalibParam.h"
29 #include "AliMpDEManager.h"
30 #include "AliMpStationType.h"
31 #include "AliRun.h"
32 #include "AliRunDigitizer.h"
33 #include "AliRunLoader.h"
34 #include "Riostream.h"
35 #include "TRandom.h"
36 #include "TString.h"
37
38 ClassImp(AliMUONDigitizerV3)
39
40 //_____________________________________________________________________________
41 AliMUONDigitizerV3::AliMUONDigitizerV3(AliRunDigitizer* manager, 
42                                        ETriggerCodeVersion triggerCodeVersion)
43 : AliDigitizer(manager),
44 fIsInitialized(kFALSE),
45 fOutputData(0x0),
46 fCalibrationData(0x0),
47 fTriggerProcessor(0x0),
48 fTriggerCodeVersion(triggerCodeVersion)
49 {
50   //
51   // Ctor.
52   //
53   AliDebug(1,Form("AliRunDigitizer=%p",fManager));
54 }
55
56 //_____________________________________________________________________________
57 AliMUONDigitizerV3::~AliMUONDigitizerV3()
58 {
59   //
60   // Dtor. Note we're the owner of some pointers.
61   // 
62   AliDebug(1,"dtor");
63   delete fOutputData;
64   delete fCalibrationData;
65   delete fTriggerProcessor;
66 }
67
68 //_____________________________________________________________________________
69 void 
70 AliMUONDigitizerV3::ApplyResponseToDigit(AliMUONDigit& digit)
71 {
72   // For trigger digits, simply does nothing.
73   //
74   // For tracking digits, starting from an ideal digit's charge, we :
75   //
76   // - add some noise (thus leading to a realistic charge)
77   // - divide by a gain (thus decalibrating the digit)
78   // - add a pedestal (thus decalibrating the digit)
79   // - sets the signal to zero if below 3*sigma of the noise
80   //
81   
82   static const Int_t MAXADC = (1<<12)-1; // We code the charge on a 12 bits ADC.
83   
84   Int_t detElemId = digit.DetElemId();
85   AliMpStationType stationType = AliMpDEManager::GetStationType(detElemId);
86   if ( stationType == kStationTrigger )
87   {
88     return;    
89   }
90   
91   // The following is for tracking digits only.
92   
93   Int_t manuId = digit.ManuId();
94   Int_t manuChannel = digit.ManuChannel();
95   
96   AliMUONVCalibParam* pedestal = fCalibrationData->Pedestal(detElemId,manuId);
97   if (!pedestal)
98   {
99     AliFatal(Form("Could not get pedestal for DE=%d manuId=%d",
100                   detElemId,manuId));    
101   }
102   Float_t pedestalMean = pedestal->ValueAsFloat(manuChannel,0);
103   Float_t pedestalSigma = pedestal->ValueAsFloat(manuChannel,1);
104   
105   Float_t adc_noise = gRandom->Gaus(0.0,pedestalSigma);
106   
107   AliMUONVCalibParam* gain = fCalibrationData->Gain(detElemId,manuId);
108   if (!gain)
109   {
110     AliFatal(Form("Could not get gain for DE=%d manuId=%d",
111                   detElemId,manuId));    
112   }
113   
114   Float_t gainMean = gain->ValueAsFloat(manuChannel,0);
115   Float_t signal_noise = adc_noise*gainMean;
116   
117   Float_t signal = digit.Signal() + signal_noise;
118   Int_t adc;
119   
120   if ( gainMean < 1E-6 )
121   {
122     AliError(Form("Got a too small gain %e for DE=%d manuId=%d manuChannel=%d. "
123                   "Setting signal to 0.",
124                   gainMean,detElemId,manuId,manuChannel));
125     adc = 0;
126   }
127   else
128   {
129     adc = TMath::Nint( signal / gainMean + pedestalMean );
130     
131     if ( adc <= pedestalMean + 3.0*pedestalSigma ) 
132     {
133       adc = 0;
134     }
135   }
136   // be sure we stick to 12 bits.
137   if ( adc > MAXADC )
138   {
139     adc = MAXADC;
140   }
141   digit.SetPhysicsSignal(TMath::Nint(signal));
142   digit.SetSignal(adc);
143   digit.SetADC(adc);
144 }
145
146 //_____________________________________________________________________________
147 void
148 AliMUONDigitizerV3::ApplyResponse()
149 {
150   //
151   // Loop over all chamber digits, and apply the response to them
152   // Note that this method may remove digits.
153   //
154   for ( Int_t ich = 0; ich < AliMUONConstants::NCh(); ++ich )
155         {
156     TClonesArray* digits = fOutputData->Digits(ich);
157     Int_t n = digits->GetEntriesFast();
158     for ( Int_t i = 0; i < n; ++i )
159     {
160       AliMUONDigit* d = static_cast<AliMUONDigit*>(digits->UncheckedAt(i));
161       ApplyResponseToDigit(*d);
162       if ( d->Signal() <= 0 )
163       {
164         digits->RemoveAt(i);
165       }
166     }
167     digits->Compress();
168   }    
169 }
170
171 //_____________________________________________________________________________
172 void
173 AliMUONDigitizerV3::AddOrUpdateDigit(TClonesArray& array, 
174                                      const AliMUONDigit& digit)
175 {
176   //
177   // Add or update a digit, depending on whether there's already a digit
178   // for the corresponding channel.
179   //
180   Int_t ix = FindDigitIndex(array,digit);
181   
182   if (ix>=0)
183   {
184     AliMUONDigit* d = static_cast<AliMUONDigit*>(array.UncheckedAt(ix));
185     Bool_t ok = MergeDigits(digit,*d);
186     if (!ok)
187     {
188       AliError("Digits are not mergeable !");
189     }
190   }
191   else
192   {
193     ix = array.GetLast() + 1;
194     new(array[ix]) AliMUONDigit(digit);
195   }
196   
197 }
198
199 //_____________________________________________________________________________
200 void
201 AliMUONDigitizerV3::Exec(Option_t*)
202 {
203   //
204   // Main method.
205   // We first loop over input files, and merge the sdigits we found there.
206   // We then digitize all the resulting sdigits
207   // And we finally generate the trigger outputs.
208   //
209   AliDebug(1, "Running digitizer.");
210   
211   if ( fManager->GetNinputs() == 0 )
212   {
213     AliWarning("No input set. Nothing to do.");
214     return;
215   }
216   
217   if ( !fIsInitialized )
218   {
219     AliError("Not initialized. Cannot perform the work. Sorry");
220     return;
221   }
222   
223   Int_t nInputFiles = fManager->GetNinputs();
224   
225   if ( fOutputData->TreeD() == 0x0 )
226   {
227     AliDebug(1,"Calling MakeDigitsContainer");
228     fOutputData->GetLoader()->MakeDigitsContainer();
229   }
230   fOutputData->MakeBranch("D,GLT");
231   fOutputData->SetTreeAddress("D,GLT");
232   
233   // Loop over all the input files, and merge the sdigits found in those
234   // files.
235   for ( Int_t iFile = 0; iFile < nInputFiles; ++iFile )
236   {    
237     AliMUONData* inputData = GetDataAccess(fManager->GetInputFolderName(iFile));
238     if (!inputData)
239     {
240       AliFatal(Form("Could not get access to input file #%d",iFile));
241     }
242
243     inputData->GetLoader()->LoadSDigits("READ");
244     inputData->SetTreeAddress("S");
245     inputData->GetSDigits();
246
247     MergeWithSDigits(*fOutputData,*inputData,fManager->GetMask(iFile));
248     
249     inputData->ResetSDigits();
250     inputData->GetLoader()->UnloadSDigits();
251     delete inputData;
252   }
253   
254   // At this point, we do have digit arrays (one per chamber) which contains 
255   // the merging of all the sdigits of the input file(s).
256   // We now massage them to apply the detector response, i.e. this
257   // is here that we do the "digitization" work.
258   
259   ApplyResponse();
260
261   // We generate the global and local trigger decisions.
262   fTriggerProcessor->ExecuteTask();
263   
264   // Fill the output treeD
265   fOutputData->Fill("D,GLT");
266   
267   // Write to the output tree(D).
268   // Please note that as GlobalTrigger, LocalTrigger and Digits are in the same
269   // tree (=TreeD) in different branches, this WriteDigits in fact writes all of 
270   // the 3 branches.
271   fOutputData->GetLoader()->WriteDigits("OVERWRITE");
272   
273   // Finally, we clean up after ourselves.
274   fOutputData->ResetDigits();
275   fOutputData->ResetTrigger();
276   fOutputData->GetLoader()->UnloadDigits();
277 }
278
279 //_____________________________________________________________________________
280 Int_t
281 AliMUONDigitizerV3::FindDigitIndex(TClonesArray& array, const AliMUONDigit& digit)
282 {
283   // 
284   // Return the index of digit within array, if that digit is there, 
285   // otherwise returns -1
286   //
287   // FIXME: this is of course not the best implementation you can think of.
288   // Reconsider the use of hit/digit map... ? (but be sure it's needed!)
289   //
290   Int_t n = array.GetEntriesFast();
291   for ( Int_t i = 0; i < n; ++i )
292   {
293     AliMUONDigit* d = static_cast<AliMUONDigit*>(array.UncheckedAt(i));
294     if ( d->DetElemId() == digit.DetElemId() &&
295          d->PadX() == digit.PadX() &&
296          d->PadY() == digit.PadY() && 
297          d->Cathode() == digit.Cathode() )
298     {
299       return i;
300     }
301   }
302   return -1;
303 }
304
305 //_____________________________________________________________________________
306 AliMUONData* 
307 AliMUONDigitizerV3::GetDataAccess(const TString& folderName)
308 {
309   //
310   // Create an AliMUONData to deal with data found in folderName.
311   //
312   AliDebug(1,Form("Getting access to folder %s",folderName.Data()));
313   AliRunLoader* runLoader = AliRunLoader::GetRunLoader(folderName);
314   if (!runLoader)
315   {
316     AliError(Form("Could not get RunLoader from folder %s",folderName.Data()));
317     return 0x0;
318   }
319   AliLoader* loader = static_cast<AliLoader*>(runLoader->GetLoader("MUONLoader"));
320   if (!loader)
321   {
322     AliError(Form("Could not get MuonLoader from folder %s",folderName.Data()));
323     return 0x0;
324   }
325   AliMUONData* data = new AliMUONData(loader,"MUON","MUONDataForDigitOutput");
326   AliDebug(1,Form("AliMUONData=%p loader=%p",data,loader));
327   return data;
328 }
329
330 //_____________________________________________________________________________
331 Bool_t
332 AliMUONDigitizerV3::Init()
333 {
334   //
335   // Initialization of the TTask :
336   // a) set the outputData pointer
337   // b) create the calibrationData, according to run number
338   // c) create the trigger processing task
339   //
340   AliDebug(1,"");
341   
342   if ( fIsInitialized )
343   {
344     AliError("Object already initialized.");
345     return kFALSE;
346   }
347   
348   if (!fManager)
349   {
350     AliError("fManager is null !");
351     return kFALSE;
352   }
353   
354   fOutputData = GetDataAccess(fManager->GetOutputFolderName());
355   if (!fOutputData)
356   {
357     AliError("Can not perform digitization. I'm sorry");
358     return kFALSE;
359   }
360   AliDebug(1,Form("fOutputData=%p",fOutputData));
361   
362   AliRunLoader* runLoader = fOutputData->GetLoader()->GetRunLoader();
363   AliRun* galice = runLoader->GetAliRun();  
364   Int_t runnumber = galice->GetRunNumber();
365   
366   fCalibrationData = new AliMUONCalibrationData(runnumber);
367   
368   switch (fTriggerCodeVersion)
369   {
370     case kTriggerDecision:
371       fTriggerProcessor = new AliMUONTriggerDecisionV1(fOutputData);
372       break;
373     case kTriggerElectronics:
374       fTriggerProcessor = new AliMUONTriggerElectronics(fOutputData);
375       break;
376     default:
377       AliFatal("Unknown trigger processor type");
378       break;
379   }
380   AliDebug(1,Form("Using the following trigger code %s - %s",
381                   fTriggerProcessor->GetName(),fTriggerProcessor->GetTitle()));
382   fIsInitialized = kTRUE;
383   return kTRUE;
384 }
385
386 //_____________________________________________________________________________
387 Bool_t
388 AliMUONDigitizerV3::MergeDigits(const AliMUONDigit& src, 
389                                 AliMUONDigit& srcAndDest)
390 {
391   //
392   // Merge 2 digits (src and srcAndDest) into srcAndDest.
393   //
394   AliDebug(1,"Merging the following digits:");
395   StdoutToAliDebug(1,src.Print("tracks"););
396   StdoutToAliDebug(1,srcAndDest.Print("tracks"););
397   
398   Bool_t check = ( src.DetElemId() == srcAndDest.DetElemId() &&
399                    src.PadX() == srcAndDest.PadX() &&
400                    src.PadY() == srcAndDest.PadY() &&
401                    src.Cathode() == srcAndDest.Cathode() );
402   if (!check)
403   {
404     return kFALSE;
405   }
406   
407   srcAndDest.AddSignal(src.Signal());
408   srcAndDest.AddPhysicsSignal(src.Physics());
409   for ( Int_t i = 0; i < src.Ntracks(); ++i )
410   {
411     srcAndDest.AddTrack(src.Track(i),src.TrackCharge(i));
412   }
413   StdoutToAliDebug(1,cout << "result:"; srcAndDest.Print("tracks"););
414   return kTRUE;
415 }
416
417 //_____________________________________________________________________________
418 void 
419 AliMUONDigitizerV3::MergeWithSDigits(AliMUONData& outputData, 
420                                      const AliMUONData& inputData, Int_t mask)
421 {
422   //
423   // Merge the sdigits in inputData with the digits already present in outputData
424   //
425   AliDebug(1,"");
426   
427         for ( Int_t ich = 0; ich < AliMUONConstants::NCh(); ++ich )
428         {
429     TClonesArray* iDigits = inputData.SDigits(ich); 
430     TClonesArray* oDigits = outputData.Digits(ich);
431     if (!iDigits)
432     {
433       AliError(Form("Could not get sdigits for ich=%d",ich));
434       return;
435     }
436     Int_t nSDigits = iDigits->GetEntriesFast();
437     for ( Int_t k = 0; k < nSDigits; ++k )
438                 {
439                         AliMUONDigit* sdigit = static_cast<AliMUONDigit*>(iDigits->UncheckedAt(k));
440       if (!sdigit)
441       {
442         AliError(Form("Could not get sdigit for ich=%d and k=%d",ich,k));
443       }
444       else
445       {
446         // Update the track references using the mask.
447         // FIXME: this is dirty, for backward compatibility only.
448         // Should re-design all this way of keeping track of MC information...
449         if ( mask ) sdigit->PatchTracks(mask);
450         // Then add or update the digit to the output.
451         AddOrUpdateDigit(*oDigits,*sdigit);
452       }
453                 }   
454   }
455 }