971cce6e05a01d66b96daf8324b0c8993c8894bc
[u/mrichter/AliRoot.git] / MUON / AliMUONDigitizer.cxx
1 /**************************************************************************
2  * Copyright(c) 1998-2000, 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 "AliRun.h"
19 #include "AliRunDigitizer.h"
20 #include "AliRunLoader.h"
21
22 #include "AliMUONDigitizer.h"
23 #include "AliMUONConstants.h"
24 #include "AliMUONChamber.h"
25 #include "AliMUONHitMapA1.h"
26 #include "AliMUON.h"
27 #include "AliMUONLoader.h"
28 #include "AliMUONChamber.h"
29 #include "AliMUONConstants.h"
30 #include "AliMUONDigitizer.h"
31 #include "AliMUONTransientDigit.h"
32 #include "AliMUONHitMapA1.h"
33 #include "AliMUONTriggerDecision.h"
34 #include "AliLog.h"
35
36
37 /////////////////////////////////////////////////////////////////////////////////////
38 //
39 // AliMUONDigitizer should be base abstract class of all digitisers in the MUON 
40 // module. It implements the common functionality of looping over input streams
41 // filling the fTDList and writing the fTDList to the output stream. 
42 // Inheriting digitizers need to override certain methods to choose and initialize
43 // the correct input and output trees, apply the correct detector response if any
44 // and implement how the transient digits are generated from the input stream.
45 //
46 /////////////////////////////////////////////////////////////////////////////////////
47
48 ClassImp(AliMUONDigitizer)
49
50 //___________________________________________
51 AliMUONDigitizer::AliMUONDigitizer() : 
52         AliDigitizer(),
53         fHitMap(0),
54         fTDList(0),
55         fTDCounter(0),
56         fMask(0),
57         fSignal(0),
58         fDebug(0)
59 {
60 // Default constructor.
61 // Initializes all pointers to NULL.
62
63         fRunLoader = NULL;
64         fGime = NULL;
65         fMUON = NULL;
66         fMUONData = NULL;
67         fTrigDec = NULL;
68 };
69
70 //___________________________________________
71 AliMUONDigitizer::AliMUONDigitizer(AliRunDigitizer* manager) : 
72         AliDigitizer(manager),
73         fHitMap(0),
74         fTDList(0),
75         fTDCounter(0),
76         fMask(0),
77         fSignal(0),
78         fDebug(0)
79 {
80 // Constructor which should be used rather than the default constructor.
81 // Initializes all pointers to NULL.
82
83         fRunLoader = NULL;
84         fGime = NULL;
85         fMUON = NULL;
86         fMUONData = NULL;
87         fTrigDec = NULL;
88 };
89
90 //___________________________________________
91 AliMUONDigitizer::AliMUONDigitizer(const AliMUONDigitizer& rhs)
92   : AliDigitizer(rhs)
93 {
94 // Protected copy constructor
95
96   AliFatal("Not implemented.");
97 }
98
99 //___________________________________________
100 AliMUONDigitizer::~AliMUONDigitizer() 
101 {
102 // Destructor
103   if (fMUONData)
104     delete fMUONData;
105
106   if (fTrigDec)
107     delete fTrigDec;
108 }
109
110 //-------------------------------------------------------------------
111 AliMUONDigitizer&  
112 AliMUONDigitizer::operator=(const AliMUONDigitizer& rhs)
113 {
114 // Protected assignement operator
115
116   if (this == &rhs) return *this;
117
118   AliFatal("Not implemented.");
119     
120   return *this;  
121 }    
122           
123 //------------------------------------------------------------------------
124 Bool_t AliMUONDigitizer::Init()
125 {
126 // Does nothing. 
127         return kTRUE;
128 }
129
130 //------------------------------------------------------------------------
131 void AliMUONDigitizer::Exec(Option_t* option)
132 {
133 // The main work loop starts here. 
134 // The digitization process is broken up into two steps: 
135 // 1) Loop over input streams and create transient digits from the input.
136 //    Done in GenerateTransientDigits()
137 // 2) Loop over the generated transient digits and write them to the output
138 //    stream. Done in CreateDigits()
139
140         AliDebug(1, "Running digitiser.");
141         ParseOptions(option);
142
143         if (fManager->GetNinputs() == 0)
144         {
145                 AliWarning("No inputs set, nothing to do.");
146                 return;
147         };
148
149         if (!FetchLoaders(fManager->GetInputFolderName(0), fRunLoader, fGime) ) return;
150         if (! FetchGlobalPointers(fRunLoader) ) return;
151         if (! FetchTriggerPointer(fGime) ) return;
152
153         InitArrays();
154         
155         AliDebug(2, Form("Event Number is %d.", fManager->GetOutputEventNr()));
156
157         // Loop over files to merge and to digitize
158         fSignal = kTRUE;
159         for (Int_t inputFile = 0; inputFile < fManager->GetNinputs(); inputFile++)
160         {
161                 fMask = fManager->GetMask(inputFile);
162                 AliDebug(2, Form("Digitising folder %d, with fMask = %d: %s", inputFile, fMask,
163                              (const char*)fManager->GetInputFolderName(inputFile)));
164
165                 if (inputFile != 0)
166                         // If this is the first file then we already have the loaders loaded.
167                         if (! FetchLoaders(fManager->GetInputFolderName(inputFile), fRunLoader, fGime) )
168                                 continue;
169                 else
170                         // If this is not the first file then it is assumed to be background.
171                         fSignal = kFALSE;
172
173                 if (! InitInputData(fGime) ) continue;
174                 GenerateTransientDigits();
175                 CleanupInputData(fGime);
176         };
177
178         Bool_t ok = FetchLoaders(fManager->GetOutputFolderName(), fRunLoader, fGime);
179         if (ok) ok = InitOutputData(fGime);
180         if (ok) CreateDigits();
181         if (ok) CreateTrigger();
182         if (ok) CleanupOutputData(fGime);
183
184         CleanupArrays();
185         CleanupTriggerArrays();
186 };
187
188 //--------------------------------------------------------------------------
189 void AliMUONDigitizer::AddOrUpdateTransientDigit(AliMUONTransientDigit* mTD)
190 {
191 // Checks to see if the transient digit exists in the corresponding fHitMap.
192 // If it does then the digit is updated otherwise it is added. 
193
194         if (ExistTransientDigit(mTD)) 
195         {
196                 UpdateTransientDigit(mTD);
197                 delete mTD;  // The new digit can be deleted because it was not added.
198         }
199         else 
200                 AddTransientDigit(mTD);
201 };
202
203 //------------------------------------------------------------------------
204 void AliMUONDigitizer::UpdateTransientDigit(AliMUONTransientDigit* mTD)
205 {
206 // Update the transient digit that is already in the fTDList by adding the new
207 // transient digits charges and track lists to the existing one.
208
209         AliDebug(4,Form( "Updating transient digit 0x%X", (void*)mTD));
210         // Choosing the maping of the cathode plane of the chamber:
211         Int_t iNchCpl= mTD->Chamber() + (mTD->Cathode()-1) * AliMUONConstants::NCh();
212         AliMUONTransientDigit *pdigit = 
213                 static_cast<AliMUONTransientDigit*>( fHitMap[iNchCpl]->GetHit(mTD->PadX(),mTD->PadY()) );
214
215         // update charge
216         pdigit->AddSignal( mTD->Signal() );
217         pdigit->AddPhysicsSignal( mTD->Physics() );  
218         
219         // update list of tracks
220         Int_t ntracks = mTD->GetNTracks();
221         if (ntracks > kMAXTRACKS)  // Truncate the number of tracks to kMAXTRACKS if we have to.
222         {
223                 AliDebug(1,Form( 
224                         "TransientDigit returned the number of tracks to be %d, which is bigger than kMAXTRACKS.",
225                         ntracks));
226                 AliDebug(1,Form( "Reseting the number of tracks to be %d.", kMAXTRACKS));
227                 ntracks = kMAXTRACKS;
228         };
229         
230         for (Int_t i = 0; i < ntracks; i++)
231         {
232                 pdigit->UpdateTrackList( mTD->GetTrack(i), mTD->GetCharge(i) );
233         };
234 };
235
236 //------------------------------------------------------------------------
237 void AliMUONDigitizer::AddTransientDigit(AliMUONTransientDigit* mTD)
238 {
239 // Adds the transient digit to the fTDList and sets the appropriate entry
240 // in the fHitMap arrays. 
241
242         AliDebug(4,Form( "Adding transient digit 0x%X", (void*)mTD));
243         // Choosing the maping of the cathode plane of the chamber:
244         Int_t iNchCpl= mTD->Chamber() + (mTD->Cathode()-1) * AliMUONConstants::NCh();
245         fTDList->AddAtAndExpand(mTD, fTDCounter);
246         fHitMap[iNchCpl]->SetHit( mTD->PadX(), mTD->PadY(), fTDCounter);
247         fTDCounter++;
248 };
249
250 //------------------------------------------------------------------------
251 Bool_t AliMUONDigitizer::ExistTransientDigit(AliMUONTransientDigit* mTD)
252 {
253 // Checks if the transient digit already exists on the corresponding fHitMap.
254 // i.e. is there a transient digit on the same chamber, cathode and pad position 
255 // as mTD. If yes then kTRUE is returned else kFASLE is returned.
256
257         // Choosing the maping of the cathode plane of the chamber:
258         Int_t iNchCpl= mTD->Chamber() + (mTD->Cathode()-1) * AliMUONConstants::NCh();
259         return( fHitMap[iNchCpl]->TestHit(mTD->PadX(), mTD->PadY()) );
260 };
261
262 //-----------------------------------------------------------------------
263 void AliMUONDigitizer::CreateDigits()
264 {
265 // Loops over the fTDList for each cathode, gets the correct signal for the 
266 // digit and adds the new digit to the output stream.
267
268         AliDebug(2, "Creating digits...");
269         for (Int_t icat = 0; icat < 2; icat++)
270         {
271                 //
272                 // Filling Digit List
273                 Int_t nentries = fTDList->GetEntriesFast();
274                 for (Int_t nent = 0; nent < nentries; nent++)
275                 {
276                         AliMUONTransientDigit* td = (AliMUONTransientDigit*)fTDList->At(nent);
277                         if (td == NULL) continue; 
278                         
279                         // Must be the same cathode, otherwise we will fill a mixture
280                         // of digits from both cathodes.
281                         if (icat != td->Cathode() - 1) continue;
282                         
283                         AliDebug(3,Form( "Creating digit from transient digit 0x%X", (void*)td));
284
285                         Int_t q = GetSignalFrom(td);
286                         if (q > 0) AddDigit(td, q);
287                 };
288                 FillOutputData();
289         };
290 };
291
292 //------------------------------------------------------------------------
293 void AliMUONDigitizer::AddDigit(AliMUONTransientDigit* td, Int_t responseCharge)
294 {
295 // Prepares the digits, track and charge arrays in preparation for a call to
296 // AddDigit(Int_t, Int_t[kMAXTRACKS], Int_t[kMAXTRACKS], Int_t[6])
297 // This method is called by CreateDigits() whenever a new digit needs to be added
298 // to the output stream trees.
299 // The responseCharge value is used as the Signal of the new digit. 
300 // The OnWriteTransientDigit method is also called just before the adding the 
301 // digit to allow inheriting digitizers to be able to do some specific processing 
302 // at this point. 
303
304         Int_t tracks[kMAXTRACKS];
305         Int_t charges[kMAXTRACKS];
306         Int_t digits[6];
307       
308         digits[0] = td->PadX();
309         digits[1] = td->PadY();
310         digits[2] = td->Cathode() - 1;
311         digits[3] = responseCharge;
312         digits[4] = td->Physics();
313         digits[5] = td->Hit();
314         
315         Int_t nptracks = td->GetNTracks();
316         if (nptracks > kMAXTRACKS)
317         {
318                 AliDebug(1, Form(
319                         "TransientDigit returned the number of tracks to be %d, which is bigger than kMAXTRACKS.",
320                         nptracks));
321                 AliDebug(1, Form("Reseting the number of tracks to be %d.", kMAXTRACKS));
322                 nptracks = kMAXTRACKS;
323         };
324         
325         for (Int_t i = 0; i < nptracks; i++) 
326         {
327                 tracks[i]   = td->GetTrack(i);
328                 charges[i]  = td->GetCharge(i);
329         };
330
331         // Sort list of tracks according to charge
332         SortTracks(tracks,charges,nptracks);
333
334         if (nptracks < kMAXTRACKS )
335         {
336                 for (Int_t i = nptracks; i < kMAXTRACKS; i++)
337                 {
338                         tracks[i]  = -1;
339                         charges[i] = 0;
340                 };
341         };
342
343         AliDebug(4,Form( "Adding digit with charge %d.", responseCharge));
344
345         OnWriteTransientDigit(td);
346         AddDigit(td->Chamber(), tracks, charges, digits);
347         AddDigitTrigger(td->Chamber(), tracks, charges, digits);
348 };
349
350 //------------------------------------------------------------------------
351 void AliMUONDigitizer::OnCreateTransientDigit(AliMUONTransientDigit* /*digit*/, TObject* /*source_object*/)
352 {
353         // Does nothing.
354         //
355         // This is derived by Digitisers that want to trace which digits were made from
356         // which hits.
357 };
358
359 //------------------------------------------------------------------------
360 void AliMUONDigitizer::OnWriteTransientDigit(AliMUONTransientDigit* /*digit*/)
361 {
362         // Does nothing.
363         //
364         // This is derived by Digitisers that want to trace which digits were made from
365         // which hits.
366 };
367
368 //------------------------------------------------------------------------
369 Bool_t AliMUONDigitizer::FetchLoaders(const char* foldername, AliRunLoader*& runloader, AliMUONLoader*& muonloader)
370 {
371 // Fetches the run loader from the current folder, specified by 'foldername'. 
372 // The muon loader is then loaded from the fetched run loader. 
373 // kTRUE is returned if no error occurred otherwise kFALSE is returned. 
374
375         AliDebug(3, Form("Fetching run loader and muon loader from folder: %s", foldername));
376
377         runloader = AliRunLoader::GetRunLoader(foldername);
378         if (runloader == NULL)
379         {
380                 AliError(Form("RunLoader not found in folder: %s", foldername));
381                 return kFALSE; 
382         }                                                                                       
383         muonloader = (AliMUONLoader*) runloader->GetLoader("MUONLoader");
384         if (muonloader == NULL) 
385         {
386                 AliError(Form("MUONLoader not found in folder: %s", foldername));
387                 return kFALSE; 
388         }
389         return kTRUE;
390
391 };
392
393 //------------------------------------------------------------------------
394 Bool_t AliMUONDigitizer::FetchGlobalPointers(AliRunLoader* runloader)
395 {
396 // Fetches the AliRun object into the global gAlice pointer from the specified
397 // run loader. The AliRun object is loaded into memory using the run loader if 
398 // not yet loaded. The MUON module object is then loaded from gAlice and 
399 // AliMUONData fetched from the MUON module. 
400 // kTRUE is returned if no error occurred otherwise kFALSE is returned. 
401
402         AliDebug(3, Form("Fetching gAlice, MUON module and AliMUONData from runloader 0x%X.",
403                         (void*)runloader
404                     ));
405
406         if (runloader->GetAliRun() == NULL) runloader->LoadgAlice();
407         gAlice = runloader->GetAliRun();
408         if (gAlice == NULL)
409         {
410                 AliError(Form("Could not find the AliRun object in runloader 0x%X.", (void*)runloader));
411                 return kFALSE;
412         };
413         fMUON = (AliMUON*) gAlice->GetDetector("MUON");
414         if (fMUON == NULL)
415         {
416                 AliError(Form("Could not find the MUON module in runloader 0x%X.", (void*)runloader));
417                 return kFALSE;
418         };
419
420         AliMUONLoader *muonloader = (AliMUONLoader*) runloader->GetLoader("MUONLoader");
421         if (muonloader == NULL) 
422         {
423                 AliError( "MUONLoader not found ");
424                 return kFALSE; 
425         }
426
427
428         if (fMUONData == NULL) fMUONData = new AliMUONData(muonloader,"MUON","MUON");
429         if (fMUONData == NULL)
430         {
431                 AliError(Form("Could not find AliMUONData object in runloader 0x%X.", (void*)runloader));
432                 return kFALSE;
433         };
434
435         return kTRUE;
436 }
437 //-----------------------------------------------------------------------
438 Bool_t  AliMUONDigitizer::FetchTriggerPointer(AliMUONLoader* loader)
439 {
440   if (fMUONData == NULL) {
441     AliError("MUONData not found");
442     return kFALSE;
443   }
444
445   if (fTrigDec == NULL) 
446       fTrigDec = new AliMUONTriggerDecision(loader,0,fMUONData);
447   
448   return kTRUE;
449 }
450 //------------------------------------------------------------------------
451 void AliMUONDigitizer::ParseOptions(Option_t* options)
452 {
453 // Called by the Exec method. ParseOptions should parse the option string given to the Exec method.
454 // 
455 // The following options are defined:
456 //      "debug" - Sets the debug level to 99, which will show all debug messages.
457 //      "deb"   - Same as "debug", implemented for backward comparability.
458 //
459 // If an invalid option is specified it is simply ignored.
460
461         TString optionString = options;
462         if (optionString.Data() == "debug" || 
463                 optionString.Data() == "deb"   // maintained for compatability.
464            )
465         {
466                 AliInfo("Called with option \"debug\".");
467                 SetDebug(99);
468         };
469 };
470
471 //------------------------------------------------------------------------
472 void AliMUONDigitizer::InitArrays()
473 {
474 // Creates a new fTDList object. 
475 // Also creates an array of 2 * chamber_number AliMUONHitMapA1 objects
476 // in the fHitMaps array. Each one is set to a chamber and cathode
477 // specific segmentation model. 
478 //
479 // Note: the fTDList and fHitMap arrays must be NULL before calling this method.
480
481         AliDebug(2, "Initialising internal arrays.");
482         AliDebug(4, "Creating transient digits list.");
483         fTDList = new TObjArray;
484         
485         // Array of pointer of the AliMUONHitMapA1:
486         //  two HitMaps per chamber, or one HitMap per cahtode plane
487         fHitMap = new AliMUONHitMapA1* [2*AliMUONConstants::NCh()];
488
489         // Loop over chambers for the definition AliMUONHitMap
490         for (Int_t i = 0; i < AliMUONConstants::NCh(); i++) 
491         {
492                 AliDebug(4,Form( "Creating hit map for chamber %d, cathode 1.", i+1));
493                 AliMUONChamber* chamber = &(fMUON->Chamber(i));
494                 AliSegmentation* c1Segmentation = chamber->SegmentationModel(1); // Cathode plane 1
495                 fHitMap[i] = new AliMUONHitMapA1(c1Segmentation, fTDList);
496                 AliDebug(4,Form( "Creating hit map for chamber %d, cathode 2.", i+1));
497                 AliSegmentation* c2Segmentation = chamber->SegmentationModel(2); // Cathode plane 2
498                 fHitMap[i+AliMUONConstants::NCh()] = new AliMUONHitMapA1(c2Segmentation, fTDList);
499         };
500 };
501
502 //------------------------------------------------------------------------
503 void AliMUONDigitizer::CleanupArrays()
504 {
505 // The arrays fTDList and fHitMap are deleted and the pointers set to NULL.
506
507         AliDebug(2, "Deleting internal arrays.");
508         for(Int_t i = 0; i < 2*AliMUONConstants::NCh(); i++)
509         {
510                 AliDebug(4,Form( "Deleting hit map for chamber %d, cathode %d.", 
511                         i%AliMUONConstants::NCh()+1, i/AliMUONConstants::NCh()+1));
512                 delete fHitMap[i];
513         };
514         delete [] fHitMap;
515         fHitMap = NULL;
516         
517         AliDebug(4, "Deleting transient digits list.");
518         fTDList->Delete();
519         delete fTDList;
520         fTDList = NULL;
521
522 };
523
524 //------------------------------------------------------------------------
525 void AliMUONDigitizer::SortTracks(Int_t *tracks, Int_t *charges, Int_t ntr) const
526 {
527 //
528 // Sort the list of tracks contributing to a given digit
529 // Only the 3 most significant tracks are actually sorted
530 //
531
532         if (ntr <= 1) return;
533
534         //
535         //  Loop over signals, only 3 times
536         //
537
538         Int_t qmax;
539         Int_t jmax;
540         Int_t idx[3] = {-2,-2,-2};
541         Int_t jch[3] = {-2,-2,-2};
542         Int_t jtr[3] = {-2,-2,-2};
543         Int_t i, j, imax;
544
545         if (ntr < 3) imax = ntr;
546         else imax=3;
547         
548         for(i = 0; i < imax; i++)
549         {
550                 qmax=0;
551                 jmax=0;
552
553                 for(j = 0; j < ntr; j++)
554                 {
555                         if (    (i == 1 && j == idx[i-1]) || 
556                                 (i == 2 && (j == idx[i-1] || j == idx[i-2]))
557                            ) 
558                                 continue;
559
560                         if(charges[j] > qmax) 
561                         {
562                                 qmax = charges[j];
563                                 jmax = j;
564                         }       
565                 } 
566
567                 if(qmax > 0)
568                 {
569                         idx[i] = jmax;
570                         jch[i] = charges[jmax]; 
571                         jtr[i] = tracks[jmax]; 
572                 }
573
574         } 
575
576         for(i = 0; i < 3; i++)
577         {
578                 if (jtr[i] == -2) 
579                 {
580                         charges[i] = 0;
581                         tracks[i] = 0;
582                 } 
583                 else 
584                 {
585                         charges[i] = jch[i];
586                         tracks[i] = jtr[i];
587                 }
588         }
589 };