]> git.uio.no Git - u/mrichter/AliRoot.git/blob - MUON/AliMUONDigitizerV3.cxx
Adding mask handling
[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 "AliMUON.h"
22 #include "AliMUONCalibrationData.h"
23 #include "AliMUONConstants.h"
24 #include "AliMUONData.h"
25 #include "AliMUONDataIterator.h"
26 #include "AliMUONDigit.h"
27 #include "AliMUONSegmentation.h"
28 #include "AliMUONTriggerDecisionV1.h"
29 #include "AliMUONTriggerEfficiencyCells.h"
30 #include "AliMUONTriggerElectronics.h"
31 #include "AliMUONVCalibParam.h"
32 #include "AliMpDEIterator.h"
33 #include "AliMpDEManager.h"
34 #include "AliMpIntPair.h"
35 #include "AliMpPad.h"
36 #include "AliMpStationType.h"
37 #include "AliMpVSegmentation.h"
38 #include "AliRun.h"
39 #include "AliRunDigitizer.h"
40 #include "AliRunLoader.h"
41 #include "Riostream.h"
42 #include "TF1.h"
43 #include "TRandom.h"
44 #include "TString.h"
45
46 ///
47 /// The digitizer is performing the transformation to go from SDigits (digits
48 /// w/o any electronic noise) to Digits (w/ electronic noise, and decalibration)
49 /// 
50 /// The decalibration is performed by doing the reverse operation of the
51 /// calibration, that is we do (Signal+pedestal)/gain -> ADC
52 ///
53 /// Note also that the digitizer takes care of merging sdigits that belongs
54 /// to the same pad, either because we're merging several input sdigit files
55 /// or with a single file because the sdigitizer does not merge sdigits itself
56 /// (for performance reason mainly, and because anyway we know we have to do it
57 /// here, at the digitization level).
58 ///
59
60 namespace
61 {
62   AliMUON* muon()
63   {
64     return static_cast<AliMUON*>(gAlice->GetModule("MUON"));
65   }
66
67   AliMUONSegmentation* Segmentation()
68   {
69     static AliMUONSegmentation* segmentation = muon()->GetSegmentation();
70     return segmentation;
71   }
72 }
73
74 const Double_t AliMUONDigitizerV3::fgkNSigmas=3;
75
76 ClassImp(AliMUONDigitizerV3)
77
78 //_____________________________________________________________________________
79 AliMUONDigitizerV3::AliMUONDigitizerV3(AliRunDigitizer* manager, 
80                                        ETriggerCodeVersion triggerCodeVersion,
81                                        Bool_t useTriggerEfficiency,
82                                        Bool_t generateNoisyDigits)
83 : AliDigitizer(manager),
84 fIsInitialized(kFALSE),
85 fOutputData(0x0),
86 fCalibrationData(0x0),
87 fTriggerProcessor(0x0),
88 fTriggerCodeVersion(triggerCodeVersion),
89 fUseTriggerEfficiency(useTriggerEfficiency),
90 fTriggerEfficiency(0x0),
91 fNoiseFunction(0x0),
92 fGenerateNoisyDigits(generateNoisyDigits)
93 {
94   //
95   // Ctor.
96   //
97   AliDebug(1,Form("AliRunDigitizer=%p",fManager));
98   fGenerateNoisyDigitsTimer.Start(kTRUE); fGenerateNoisyDigitsTimer.Stop();
99   fExecTimer.Start(kTRUE); fExecTimer.Stop();
100   fFindDigitIndexTimer.Start(kTRUE); fFindDigitIndexTimer.Stop();
101 }
102
103 //______________________________________________________________________________
104 AliMUONDigitizerV3::AliMUONDigitizerV3(const AliMUONDigitizerV3& right) 
105   : AliDigitizer(right) 
106 {  
107 /// Protected copy constructor (not implemented)
108
109   AliFatal("Copy constructor not provided.");
110 }
111
112 //_____________________________________________________________________________
113 AliMUONDigitizerV3::~AliMUONDigitizerV3()
114 {
115   //
116   // Dtor. Note we're the owner of some pointers.
117   // 
118   AliDebug(1,"dtor");
119
120   delete fOutputData;
121   delete fCalibrationData;
122   delete fTriggerProcessor;
123   delete fNoiseFunction;
124   
125   AliInfo(Form("Execution time for FindDigitIndex() : R:%.2fs C:%.2fs",
126                fFindDigitIndexTimer.RealTime(),fFindDigitIndexTimer.CpuTime()));
127   if ( fGenerateNoisyDigits )
128   {
129     AliInfo(Form("Execution time for GenerateNoisyDigits() : R:%.2fs C:%.2fs",
130                  fGenerateNoisyDigitsTimer.RealTime(),
131                  fGenerateNoisyDigitsTimer.CpuTime()));
132   }
133   AliInfo(Form("Execution time for Exec() : R:%.2fs C:%.2fs",
134                fExecTimer.RealTime(),fExecTimer.CpuTime()));
135   
136 }
137
138 //______________________________________________________________________________
139 AliMUONDigitizerV3& 
140 AliMUONDigitizerV3::operator=(const AliMUONDigitizerV3& right)
141 {
142 /// Protected assignement operator (not implemented)
143
144   // check assignement to self
145   if (this == &right) return *this;
146
147   AliFatal("Assignement operator not provided.");
148     
149   return *this;  
150 }    
151
152 //_____________________________________________________________________________
153 void 
154 AliMUONDigitizerV3::ApplyResponseToTrackerDigit(AliMUONDigit& digit, Bool_t addNoise)
155 {
156   // For tracking digits, starting from an ideal digit's charge, we :
157   //
158   // - add some noise (thus leading to a realistic charge), if requested to do so
159   // - divide by a gain (thus decalibrating the digit)
160   // - add a pedestal (thus decalibrating the digit)
161   // - sets the signal to zero if below 3*sigma of the noise
162   //
163   
164   static const Int_t kMaxADC = (1<<12)-1; // We code the charge on a 12 bits ADC.
165   
166   Float_t signal = digit.Signal();
167   
168   Int_t detElemId = digit.DetElemId();
169   
170   Int_t manuId = digit.ManuId();
171   Int_t manuChannel = digit.ManuChannel();
172   
173   AliMUONVCalibParam* pedestal = fCalibrationData->Pedestals(detElemId,manuId);
174   if (!pedestal)
175   {
176     AliFatal(Form("Could not get pedestal for DE=%d manuId=%d",
177                   detElemId,manuId));    
178   }
179   Float_t pedestalMean = pedestal->ValueAsFloat(manuChannel,0);
180   Float_t pedestalSigma = pedestal->ValueAsFloat(manuChannel,1);
181
182   AliMUONVCalibParam* gain = fCalibrationData->Gains(detElemId,manuId);
183   if (!gain)
184   {
185     AliFatal(Form("Could not get gain for DE=%d manuId=%d",
186                   detElemId,manuId));    
187   }    
188   Float_t gainMean = gain->ValueAsFloat(manuChannel,0);
189
190   if ( addNoise )
191   {
192     Float_t adcNoise = gRandom->Gaus(0.0,pedestalSigma);
193   
194     signal += adcNoise*gainMean;
195   }
196   
197   Int_t adc;
198   
199   if ( gainMean < 1E-6 )
200   {
201     AliError(Form("Got a too small gain %e for DE=%d manuId=%d manuChannel=%d. "
202                   "Setting signal to 0.",
203                   gainMean,detElemId,manuId,manuChannel));
204     adc = 0;
205   }
206   else
207   {
208     adc = TMath::Nint( signal / gainMean + pedestalMean );
209     
210     if ( adc <= pedestalMean + fgkNSigmas*pedestalSigma ) 
211     {
212       adc = 0;
213     }
214   }
215   // be sure we stick to 12 bits.
216   if ( adc > kMaxADC )
217   {
218     adc = kMaxADC;
219   }
220   digit.SetPhysicsSignal(TMath::Nint(signal));
221   digit.SetSignal(adc);
222   digit.SetADC(adc);
223 }
224
225 //_____________________________________________________________________________
226 void 
227 AliMUONDigitizerV3::ApplyResponseToTriggerDigit(AliMUONDigit& digit,
228                                                 AliMUONData* data)
229 {
230   if ( !fTriggerEfficiency ) return;
231
232   AliMUONDigit* correspondingDigit = FindCorrespondingDigit(digit,data);
233
234   Int_t detElemId = digit.DetElemId();
235   
236   const AliMpVSegmentation* segment[2] = 
237   {
238     Segmentation()->GetMpSegmentation(detElemId,digit.Cathode()), 
239     Segmentation()->GetMpSegmentation(detElemId,correspondingDigit->Cathode())
240   };
241
242   AliMpPad pad[2] = 
243   {
244     segment[0]->PadByIndices(AliMpIntPair(digit.PadX(),digit.PadY()),kTRUE), 
245     segment[1]->PadByIndices(AliMpIntPair(correspondingDigit->PadX(),correspondingDigit->PadY()),kTRUE)
246   };
247
248   Int_t ix(0);
249   Int_t iy(1);
250
251   if (digit.Cathode()==0)
252   {
253           ix=1;
254           iy=0;
255   }
256   
257   Float_t x = pad[ix].Position().X();
258   Float_t y = pad[iy].Position().Y();
259   if ( x==-1 && y==-1 )
260   {
261           x=-9999.;
262           y=-9999.;
263     AliError(Form("Got an unknown position for a digit in DE %d at (ix,iy)=(%d,%d)",
264              detElemId,pad[ix].GetIndices().GetFirst(),pad[iy].GetIndices().GetSecond()));
265   }
266   Float_t x0 = segment[0]->Dimensions().X();
267   Float_t y0 = segment[1]->Dimensions().Y();
268   TVector2 newCoord = fTriggerEfficiency->ChangeReferenceFrame(x, y, x0, y0);
269   
270   Bool_t isTrig[2];
271   fTriggerEfficiency->IsTriggered(detElemId, newCoord.Px(), newCoord.Py(), 
272                                   isTrig[0], isTrig[1]);
273   
274   if (!isTrig[digit.Cathode()])
275   {
276           digit.SetSignal(0);
277   }
278   
279   if ( &digit != correspondingDigit )
280   {
281           if (!isTrig[correspondingDigit->Cathode()])
282     {
283       correspondingDigit->SetSignal(0);
284           }
285   }
286 }
287
288 //_____________________________________________________________________________
289 void
290 AliMUONDigitizerV3::ApplyResponse()
291 {
292   //
293   // Loop over all chamber digits, and apply the response to them
294   // Note that this method may remove digits.
295   //
296   const Bool_t kAddNoise = kTRUE;
297   
298   for ( Int_t ich = 0; ich < AliMUONConstants::NCh(); ++ich )
299   {
300     TClonesArray* digits = fOutputData->Digits(ich);
301     Int_t n = digits->GetEntriesFast();
302     Bool_t trackingChamber = ( ich < AliMUONConstants::NTrackingCh() );
303     for ( Int_t i = 0; i < n; ++i )
304     {
305       AliMUONDigit* d = static_cast<AliMUONDigit*>(digits->UncheckedAt(i));
306       if ( trackingChamber )
307       {
308         ApplyResponseToTrackerDigit(*d,kAddNoise);
309       }
310       else
311       {
312         ApplyResponseToTriggerDigit(*d,fOutputData);
313       }
314       if ( d->Signal() <= 0 )
315       {
316         digits->RemoveAt(i);
317       }
318     }
319     digits->Compress();
320   }    
321   
322 // The version below, using iterator, does not yet work (as the iterator
323 // assumes it is reading digits from the tree, while in this case it's
324 // writing...)
325 //
326 //  AliMUONDigit* digit(0x0);
327 //
328 //  // First loop on tracker digits
329 //  AliMUONDataIterator tracker(fOutputData,"D",AliMUONDataIterator::kTrackingChambers);
330 //  
331 //  while ( ( digit = static_cast<AliMUONDigit*>(tracker.Next()) ) )
332 //  {
333 //    ApplyResponseToTrackerDigit(*digit);
334 //    if ( digit->Signal() <= 0 )
335 //    {
336 //      tracker.Remove();
337 //    }    
338 //    
339 //  }
340 //
341 //  // Then loop on trigger digits
342 //  AliMUONDataIterator trigger(fOutputData,"D",AliMUONDataIterator::kTriggerChambers);
343 //  
344 //  while ( ( digit = static_cast<AliMUONDigit*>(trigger.Next()) ) )
345 //  {
346 //    ApplyResponseToTriggerDigit(*digit,fOutputData);
347 //    if ( digit->Signal() <= 0 )
348 //    {
349 //      trigger.Remove();
350 //    }    
351 //  }
352 }
353
354 //_____________________________________________________________________________
355 void
356 AliMUONDigitizerV3::AddOrUpdateDigit(TClonesArray& array, 
357                                      const AliMUONDigit& digit)
358 {
359   //
360   // Add or update a digit, depending on whether there's already a digit
361   // for the corresponding channel.
362   //
363   Int_t ix = FindDigitIndex(array,digit);
364   
365   if (ix>=0)
366   {
367     AliMUONDigit* d = static_cast<AliMUONDigit*>(array.UncheckedAt(ix));
368     Bool_t ok = MergeDigits(digit,*d);
369     if (!ok)
370     {
371       AliError("Digits are not mergeable !");
372     }
373   }
374   else
375   {
376     ix = array.GetLast() + 1;
377     new(array[ix]) AliMUONDigit(digit);
378   }
379   
380 }
381
382 //_____________________________________________________________________________
383 void
384 AliMUONDigitizerV3::Exec(Option_t*)
385 {
386   //
387   // Main method.
388   // We first loop over input files, and merge the sdigits we found there.
389   // Second, we digitize all the resulting sdigits
390   // Then we generate noise-only digits (for tracker only)
391   // And we finally generate the trigger outputs.
392   //
393     
394   AliDebug(1, "Running digitizer.");
395   
396   if ( fManager->GetNinputs() == 0 )
397   {
398     AliWarning("No input set. Nothing to do.");
399     return;
400   }
401   
402   if ( !fIsInitialized )
403   {
404     AliError("Not initialized. Cannot perform the work. Sorry");
405     return;
406   }
407   
408   fExecTimer.Start(kFALSE);
409
410   Int_t nInputFiles = fManager->GetNinputs();
411   
412   if ( fOutputData->TreeD() == 0x0 )
413   {
414     AliDebug(1,"Calling MakeDigitsContainer");
415     fOutputData->GetLoader()->MakeDigitsContainer();
416   }
417   fOutputData->MakeBranch("D,GLT");
418   fOutputData->SetTreeAddress("D,GLT");
419   
420   // Loop over all the input files, and merge the sdigits found in those
421   // files.
422   for ( Int_t iFile = 0; iFile < nInputFiles; ++iFile )
423   {    
424     AliMUONData* inputData = GetDataAccess(fManager->GetInputFolderName(iFile));
425     if (!inputData)
426     {
427       AliFatal(Form("Could not get access to input file #%d",iFile));
428     }
429
430     inputData->GetLoader()->LoadSDigits("READ");
431     inputData->SetTreeAddress("S");
432     inputData->GetSDigits();
433
434     MergeWithSDigits(*fOutputData,*inputData,fManager->GetMask(iFile));
435     
436     inputData->ResetSDigits();
437     inputData->GetLoader()->UnloadSDigits();
438     delete inputData;
439   }
440   
441   // At this point, we do have digit arrays (one per chamber) which contains 
442   // the merging of all the sdigits of the input file(s).
443   // We now massage them to apply the detector response, i.e. this
444   // is here that we do the "digitization" work.
445   
446   ApplyResponse();
447   
448   if ( fGenerateNoisyDigits )
449   {
450     // Generate noise-only digits for tracker.
451     GenerateNoisyDigits();
452   }
453   
454   // We generate the global and local trigger decisions.
455   fTriggerProcessor->ExecuteTask();
456   
457   // Fill the output treeD
458   fOutputData->Fill("D,GLT");
459   
460   // Write to the output tree(D).
461   // Please note that as GlobalTrigger, LocalTrigger and Digits are in the same
462   // tree (=TreeD) in different branches, this WriteDigits in fact writes all of 
463   // the 3 branches.
464   fOutputData->GetLoader()->WriteDigits("OVERWRITE");
465   
466   // Finally, we clean up after ourselves.
467   fOutputData->ResetDigits();
468   fOutputData->ResetTrigger();
469   fOutputData->GetLoader()->UnloadDigits();
470   
471   fExecTimer.Stop();
472 }
473
474 //_____________________________________________________________________________
475 AliMUONDigit* 
476 AliMUONDigitizerV3::FindCorrespondingDigit(AliMUONDigit& digit,
477                                            AliMUONData* data)
478 {                                                
479   AliMUONDataIterator it(data,"D",AliMUONDataIterator::kAllChambers);
480   AliMUONDigit* cd;
481   
482   while ( ( cd = static_cast<AliMUONDigit*>(it.Next()) ) )
483   {
484     if ( cd->DetElemId() == digit.DetElemId() &&
485          cd->Hit() == digit.Hit() &&
486          cd->Cathode() != digit.Cathode() )
487     {
488       return cd;
489     }
490   }
491   return 0x0;
492 }
493
494
495 //_____________________________________________________________________________
496 Int_t
497 AliMUONDigitizerV3::FindDigitIndex(TClonesArray& array, 
498                                    const AliMUONDigit& digit) const
499 {
500   // 
501   // Return the index of digit within array, if that digit is there, 
502   // otherwise returns -1
503   //
504   // FIXME: this is of course not the best implementation you can think of.
505   // Reconsider the use of hit/digit map... ? (but be sure it's needed!)
506   //
507   
508   fFindDigitIndexTimer.Start(kFALSE);
509   
510   Int_t n = array.GetEntriesFast();
511   for ( Int_t i = 0; i < n; ++i )
512   {
513     AliMUONDigit* d = static_cast<AliMUONDigit*>(array.UncheckedAt(i));
514     if ( d->DetElemId() == digit.DetElemId() &&
515          d->PadX() == digit.PadX() &&
516          d->PadY() == digit.PadY() && 
517          d->Cathode() == digit.Cathode() )
518     {
519       fFindDigitIndexTimer.Stop();
520       return i;
521     }
522   }
523   fFindDigitIndexTimer.Stop();
524   return -1;
525 }
526
527 //_____________________________________________________________________________
528 void
529 AliMUONDigitizerV3::GenerateNoisyDigits()
530 {
531   //
532   // According to a given probability, generate digits that
533   // have a signal above the noise cut (ped+n*sigma_ped), i.e. digits
534   // that are "only noise".
535   //
536   
537   if ( !fNoiseFunction )
538   {
539     fNoiseFunction = new TF1("AliMUONDigitizerV3::fNoiseFunction","gaus",
540                              fgkNSigmas,fgkNSigmas*10);
541     
542     fNoiseFunction->SetParameters(1,0,1);
543   }
544   
545   fGenerateNoisyDigitsTimer.Start(kFALSE);
546   
547   for ( Int_t i = 0; i < AliMUONConstants::NTrackingCh(); ++i )
548   {
549     AliMpDEIterator it;
550   
551     it.First(i);
552   
553     while ( !it.IsDone() )
554     {
555       for ( Int_t cathode = 0; cathode < 2; ++cathode )
556       {
557         GenerateNoisyDigitsForOneCathode(it.CurrentDE(),cathode);
558       }
559       it.Next();
560     }
561   }
562   
563   fGenerateNoisyDigitsTimer.Stop();
564 }
565  
566 //_____________________________________________________________________________
567 void
568 AliMUONDigitizerV3::GenerateNoisyDigitsForOneCathode(Int_t detElemId, Int_t cathode)
569 {
570   //
571   // Generate noise-only digits for one cathode of one detection element.
572   // Called by GenerateNoisyDigits()
573   //
574   
575   TClonesArray* digits = fOutputData->Digits(detElemId/100-1);
576   
577   const AliMpVSegmentation* seg = Segmentation()->GetMpSegmentation(detElemId,cathode);
578   Int_t nofPads = seg->NofPads();
579   
580   Int_t maxIx = seg->MaxPadIndexX();
581   Int_t maxIy = seg->MaxPadIndexY();
582   
583   static const Double_t probToBeOutsideNsigmas = 1 - TMath::Erf(fgkNSigmas/TMath::Sqrt(2.0));
584   
585   Int_t nofNoisyPads = TMath::Nint(probToBeOutsideNsigmas*nofPads);
586   if ( !nofNoisyPads ) return;
587   
588   nofNoisyPads = 
589     TMath::Nint(gRandom->Gaus(nofNoisyPads,
590                               nofNoisyPads/TMath::Sqrt(nofNoisyPads)));
591   
592   AliDebug(3,Form("DE %d cath %d nofNoisyPads %d",detElemId,cathode,nofNoisyPads));
593   
594   for ( Int_t i = 0; i < nofNoisyPads; ++i )
595   {
596     Int_t ix(-1);
597     Int_t iy(-1);
598     do {
599       ix = gRandom->Integer(maxIx+1);
600       iy = gRandom->Integer(maxIy+1);
601     } while ( !seg->HasPad(AliMpIntPair(ix,iy)) );
602     AliMUONDigit d;
603     d.SetDetElemId(detElemId);
604     d.SetCathode(cathode);
605     d.SetPadX(ix);
606     d.SetPadY(iy);
607     if ( FindDigitIndex(*digits,d) >= 0 )
608     {
609       // this digit is already there, and not noise-only, we simply skip it
610       continue;
611     }
612     AliMpPad pad = seg->PadByIndices(AliMpIntPair(ix,iy));
613     Int_t manuId = pad.GetLocation().GetFirst();
614     Int_t manuChannel = pad.GetLocation().GetSecond();
615     
616     d.SetElectronics(manuId,manuChannel);
617     
618     AliMUONVCalibParam* pedestals = fCalibrationData->Pedestals(detElemId,manuId);
619     
620     Float_t pedestalMean = pedestals->ValueAsFloat(manuChannel,0);
621     Float_t pedestalSigma = pedestals->ValueAsFloat(manuChannel,1);
622     
623     Double_t ped = fNoiseFunction->GetRandom()*pedestalSigma;
624     
625     d.SetSignal(TMath::Nint(ped+pedestalMean+0.5));
626     d.NoiseOnly(kTRUE);
627     AliDebug(3,Form("Adding a pure noise digit :"));
628     StdoutToAliDebug(3,cout << "Before Response: " << endl; 
629                      d.Print(););
630     ApplyResponseToTrackerDigit(d,kFALSE);
631     if ( d.Signal() > 0 )
632     {
633       AddOrUpdateDigit(*digits,d);
634     }
635     else
636     {
637       AliError("Pure noise below threshold. This should not happen. Not adding "
638                "this digit.");
639     }
640     StdoutToAliDebug(3,cout << "After Response: " << endl; 
641                      d.Print(););
642   }
643 }
644
645 //_____________________________________________________________________________
646 AliMUONData* 
647 AliMUONDigitizerV3::GetDataAccess(const TString& folderName)
648 {
649   //
650   // Create an AliMUONData to deal with data found in folderName.
651   //
652   AliDebug(1,Form("Getting access to folder %s",folderName.Data()));
653   AliRunLoader* runLoader = AliRunLoader::GetRunLoader(folderName);
654   if (!runLoader)
655   {
656     AliError(Form("Could not get RunLoader from folder %s",folderName.Data()));
657     return 0x0;
658   }
659   AliLoader* loader = static_cast<AliLoader*>(runLoader->GetLoader("MUONLoader"));
660   if (!loader)
661   {
662     AliError(Form("Could not get MuonLoader from folder %s",folderName.Data()));
663     return 0x0;
664   }
665   AliMUONData* data = new AliMUONData(loader,"MUON","MUONDataForDigitOutput");
666   AliDebug(1,Form("AliMUONData=%p loader=%p",data,loader));
667   return data;
668 }
669
670 //_____________________________________________________________________________
671 Bool_t
672 AliMUONDigitizerV3::Init()
673 {
674   //
675   // Initialization of the TTask :
676   // a) set the outputData pointer
677   // b) create the calibrationData, according to run number
678   // c) create the trigger processing task
679   //
680   AliDebug(1,"");
681   
682   if ( fIsInitialized )
683   {
684     AliError("Object already initialized.");
685     return kFALSE;
686   }
687   
688   if (!fManager)
689   {
690     AliError("fManager is null !");
691     return kFALSE;
692   }
693   
694   fOutputData = GetDataAccess(fManager->GetOutputFolderName());
695   if (!fOutputData)
696   {
697     AliError("Can not perform digitization. I'm sorry");
698     return kFALSE;
699   }
700   AliDebug(1,Form("fOutputData=%p",fOutputData));
701   
702   AliRunLoader* runLoader = fOutputData->GetLoader()->GetRunLoader();
703   AliRun* galice = runLoader->GetAliRun();  
704   Int_t runnumber = galice->GetRunNumber();
705   
706   fCalibrationData = new AliMUONCalibrationData(runnumber);
707   
708   switch (fTriggerCodeVersion)
709   {
710     case kTriggerDecision:
711       fTriggerProcessor = new AliMUONTriggerDecisionV1(fOutputData);
712       break;
713     case kTriggerElectronics:
714       fTriggerProcessor = new AliMUONTriggerElectronics(fOutputData,fCalibrationData);
715       break;
716     default:
717       AliFatal("Unknown trigger processor type");
718       break;
719   }
720   AliDebug(1,Form("Using the following trigger code %s - %s",
721                   fTriggerProcessor->GetName(),fTriggerProcessor->GetTitle()));
722   
723   if ( fUseTriggerEfficiency )
724   {
725     fTriggerEfficiency = fCalibrationData->TriggerEfficiency();
726     if ( fTriggerEfficiency )
727     {
728       AliInfo("Will apply trigger efficiency");
729     }
730     else
731     {
732       AliError("I was requested to apply trigger efficiency, but I could "
733                "not get it !");
734     }
735   }
736   
737   if ( fGenerateNoisyDigits )
738   {
739     AliInfo("Will generate noise-only digits for tracker");
740   }
741   
742   fIsInitialized = kTRUE;
743   return kTRUE;
744 }
745
746 //_____________________________________________________________________________
747 Bool_t
748 AliMUONDigitizerV3::MergeDigits(const AliMUONDigit& src, 
749                                 AliMUONDigit& srcAndDest)
750 {
751   //
752   // Merge 2 digits (src and srcAndDest) into srcAndDest.
753   //
754   AliDebug(1,"Merging the following digits:");
755   StdoutToAliDebug(1,src.Print("tracks"););
756   StdoutToAliDebug(1,srcAndDest.Print("tracks"););
757   
758   Bool_t check = ( src.DetElemId() == srcAndDest.DetElemId() &&
759                    src.PadX() == srcAndDest.PadX() &&
760                    src.PadY() == srcAndDest.PadY() &&
761                    src.Cathode() == srcAndDest.Cathode() );
762   if (!check)
763   {
764     return kFALSE;
765   }
766   
767   srcAndDest.AddSignal(src.Signal());
768   srcAndDest.AddPhysicsSignal(src.Physics());
769   for ( Int_t i = 0; i < src.Ntracks(); ++i )
770   {
771     srcAndDest.AddTrack(src.Track(i),src.TrackCharge(i));
772   }
773   StdoutToAliDebug(1,cout << "result:"; srcAndDest.Print("tracks"););
774   return kTRUE;
775 }
776
777 //_____________________________________________________________________________
778 void 
779 AliMUONDigitizerV3::MergeWithSDigits(AliMUONData& outputData, 
780                                      const AliMUONData& inputData, Int_t mask)
781 {
782   //
783   // Merge the sdigits in inputData with the digits already present in outputData
784   //
785   AliDebug(1,"");
786   
787         for ( Int_t ich = 0; ich < AliMUONConstants::NCh(); ++ich )
788         {
789     TClonesArray* iDigits = inputData.SDigits(ich); 
790     TClonesArray* oDigits = outputData.Digits(ich);
791     if (!iDigits)
792     {
793       AliError(Form("Could not get sdigits for ich=%d",ich));
794       return;
795     }
796     Int_t nSDigits = iDigits->GetEntriesFast();
797     for ( Int_t k = 0; k < nSDigits; ++k )
798                 {
799                         AliMUONDigit* sdigit = static_cast<AliMUONDigit*>(iDigits->UncheckedAt(k));
800       if (!sdigit)
801       {
802         AliError(Form("Could not get sdigit for ich=%d and k=%d",ich,k));
803       }
804       else
805       {
806         // Update the track references using the mask.
807         // FIXME: this is dirty, for backward compatibility only.
808         // Should re-design all this way of keeping track of MC information...
809         if ( mask ) sdigit->PatchTracks(mask);
810         // Then add or update the digit to the output.
811         AddOrUpdateDigit(*oDigits,*sdigit);
812       }
813                 }   
814   }
815 }