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