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