1 /**************************************************************************
2 * Copyright(c) 1998-2000, ALICE Experiment at CERN, All rights reserved. *
4 * Author: The ALICE Off-line Project. *
5 * Contributors are mentioned in the code where appropriate. *
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 **************************************************************************/
18 #include "AliMUONDigitizer.h"
19 #include "AliMUONConstants.h"
20 #include "AliMUONSegmentation.h"
21 #include "AliMUONHitMapA1.h"
23 #include "AliMUONLoader.h"
24 #include "AliMUONConstants.h"
25 #include "AliMUONTransientDigit.h"
26 #include "AliMUONTriggerDecision.h"
28 #include "AliMUONGeometryTransformer.h"
29 #include "AliMUONGeometryModule.h"
30 #include "AliMUONGeometryStore.h"
33 #include "AliRunDigitizer.h"
34 #include "AliRunLoader.h"
36 /////////////////////////////////////////////////////////////////////////////////////
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.
45 /////////////////////////////////////////////////////////////////////////////////////
47 ClassImp(AliMUONDigitizer)
49 //___________________________________________
50 AliMUONDigitizer::AliMUONDigitizer() :
64 /// Default constructor.
65 /// Initializes all pointers to NULL.
68 //___________________________________________
69 AliMUONDigitizer::AliMUONDigitizer(AliRunDigitizer* manager) :
70 AliDigitizer(manager),
83 /// Constructor which should be used rather than the default constructor.
84 /// Initializes all pointers to NULL.
87 //___________________________________________
88 AliMUONDigitizer::~AliMUONDigitizer()
99 //------------------------------------------------------------------------
100 Bool_t AliMUONDigitizer::Init()
102 /// Initialize - Does nothing.
107 //------------------------------------------------------------------------
108 void AliMUONDigitizer::Exec(Option_t* /*option*/)
110 /// The main work loop starts here.
111 /// The digitization process is broken up into two steps:
112 /// 1) Loop over input streams and create transient digits from the input.
113 /// Done in GenerateTransientDigits()
114 /// 2) Loop over the generated transient digits and write them to the output
115 /// stream. Done in CreateDigits()
117 AliDebug(1, "Running digitiser.");
119 if (fManager->GetNinputs() == 0)
121 AliWarning("No inputs set, nothing to do.");
125 if (!FetchLoaders(fManager->GetInputFolderName(0), fRunLoader, fGime) ) return;
126 if (! FetchGlobalPointers(fRunLoader) ) return;
127 if (! FetchTriggerPointer(fGime) ) return;
131 AliDebug(2, Form("Event Number is %d.", fManager->GetOutputEventNr()));
133 // Loop over files to merge and to digitize
135 for (Int_t inputFile = 0; inputFile < fManager->GetNinputs(); inputFile++)
137 fMask = fManager->GetMask(inputFile);
138 AliDebug(2, Form("Digitising folder %d, with fMask = %d: %s", inputFile, fMask,
139 (const char*)fManager->GetInputFolderName(inputFile)));
142 // If this is the first file then we already have the loaders loaded.
143 if (! FetchLoaders(fManager->GetInputFolderName(inputFile), fRunLoader, fGime) )
146 // If this is not the first file then it is assumed to be background.
149 if (! InitInputData(fGime) ) continue;
150 GenerateTransientDigits();
151 CleanupInputData(fGime);
154 Bool_t ok = FetchLoaders(fManager->GetOutputFolderName(), fRunLoader, fGime);
155 if (ok) ok = InitOutputData(fGime);
156 if (ok) CreateDigits();
157 if (ok) CreateTrigger();
158 if (ok) CleanupOutputData(fGime);
161 CleanupTriggerArrays();
164 //--------------------------------------------------------------------------
165 void AliMUONDigitizer::AddOrUpdateTransientDigit(AliMUONTransientDigit* mTD)
167 /// Checks to see if the transient digit exists in the corresponding fHitMap.
168 /// If it does then the digit is updated otherwise it is added.
170 if (ExistTransientDigit(mTD))
172 UpdateTransientDigit(mTD);
173 delete mTD; // The new digit can be deleted because it was not added.
176 AddTransientDigit(mTD);
179 //------------------------------------------------------------------------
180 void AliMUONDigitizer::UpdateTransientDigit(AliMUONTransientDigit* mTD)
182 /// Update the transient digit that is already in the fTDList by adding the new
183 /// transient digits charges and track lists to the existing one.
185 AliDebug(4,Form( "Updating transient digit 0x%X", (void*)mTD));
186 // Choosing the maping of the cathode plane of the chamber:
187 Int_t detElemId = mTD->DetElemId();
189 Int_t iNchCpl= fNDetElemId[detElemId] + (mTD->Cathode()-1) * AliMUONConstants::NDetElem();
191 AliMUONTransientDigit *pdigit =
192 static_cast<AliMUONTransientDigit*>( fHitMap[iNchCpl]->GetHit(mTD->PadX(),mTD->PadY()) );
195 pdigit->AddSignal( mTD->Signal() );
196 pdigit->AddPhysicsSignal( mTD->Physics() );
198 // update list of tracks
199 Int_t ntracks = mTD->GetNTracks();
200 if (ntracks > kMAXTRACKS) // Truncate the number of tracks to kMAXTRACKS if we have to.
203 "TransientDigit returned the number of tracks to be %d, which is bigger than kMAXTRACKS.",
205 AliDebug(1,Form( "Reseting the number of tracks to be %d.", kMAXTRACKS));
206 ntracks = kMAXTRACKS;
209 for (Int_t i = 0; i < ntracks; i++)
211 pdigit->UpdateTrackList( mTD->GetTrack(i), mTD->GetCharge(i) );
215 //------------------------------------------------------------------------
216 void AliMUONDigitizer::AddTransientDigit(AliMUONTransientDigit* mTD)
218 /// Adds the transient digit to the fTDList and sets the appropriate entry
219 /// in the fHitMap arrays.
221 AliDebug(4,Form( "Adding transient digit 0x%X", (void*)mTD));
222 // Choosing the maping of the cathode plane of the chamber:
224 Int_t detElemId = mTD->DetElemId();
225 Int_t iNchCpl= fNDetElemId[detElemId] + (mTD->Cathode()-1) * AliMUONConstants::NDetElem();
227 fTDList->AddAtAndExpand(mTD, fTDCounter);
228 if (iNchCpl>-1 && iNchCpl<2*AliMUONConstants::NDetElem()) {
229 fHitMap[iNchCpl]->SetHit( mTD->PadX(), mTD->PadY(), fTDCounter);
234 //------------------------------------------------------------------------
235 Bool_t AliMUONDigitizer::ExistTransientDigit(AliMUONTransientDigit* mTD)
237 /// Checks if the transient digit already exists on the corresponding fHitMap.
238 /// i.e. is there a transient digit on the same chamber, cathode and pad position
239 /// as mTD. If yes then kTRUE is returned else kFASLE is returned.
241 // Choosing the maping of the cathode plane of the chamber:
242 Int_t detElemId = mTD->DetElemId();
244 Int_t iNchCpl= fNDetElemId[detElemId] + (mTD->Cathode()-1) *AliMUONConstants::NDetElem() ;
246 // Int_t iNchCpl= mTD->Chamber() + (mTD->Cathode()-1) * AliMUONConstants::NCh();
247 if (iNchCpl>-1 && iNchCpl<2*AliMUONConstants::NDetElem())
248 return( fHitMap[iNchCpl]->TestHit(mTD->PadX(), mTD->PadY()) );
252 //-----------------------------------------------------------------------
253 void AliMUONDigitizer::CreateDigits()
255 /// Loops over the fTDList for each cathode, gets the correct signal for the
256 /// digit and adds the new digit to the output stream.
258 fTDList->Sort(); // sort by idDE
259 AliDebug(2, "Creating digits...");
260 // for (Int_t icat = 0; icat < 2; icat++) {
262 Int_t digitindex[14] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
265 // Filling Digit List
266 Int_t nentries = fTDList->GetEntriesFast();
267 for (Int_t nent = 0; nent < nentries; nent++) {
269 AliMUONTransientDigit* td = (AliMUONTransientDigit*)fTDList->At(nent);
270 if (td == NULL) continue;
272 // Must be the same cathode, otherwise we will fill a mixture
273 // of digits from both cathodes.
274 //if (icat != td->Cathode() - 1) continue;
276 AliDebug(3,Form( "Creating digit from transient digit 0x%X", (void*)td));
278 Int_t q = GetSignalFrom(td);
280 Int_t chamber = td->Chamber();
281 if (0 <= chamber && chamber <= 13 )
282 AddDigit(td, q, digitindex[chamber]++);
284 AliError(Form("Invalid chamber %d\n",chamber));
292 //------------------------------------------------------------------------
293 void AliMUONDigitizer::AddDigit(
294 AliMUONTransientDigit* td, Int_t responseCharge,
298 /// Prepares the digits, track and charge arrays in preparation for a call to
299 /// AddDigit(Int_t, Int_t[kMAXTRACKS], Int_t[kMAXTRACKS], Int_t[6])
300 /// This method is called by CreateDigits() whenever a new digit needs to be added
301 /// to the output stream trees.
302 /// The responseCharge value is used as the Signal of the new digit.
303 /// The OnWriteTransientDigit method is also called just before the adding the
304 /// digit to allow inheriting digitizers to be able to do some specific processing
307 Int_t tracks[kMAXTRACKS];
308 Int_t charges[kMAXTRACKS];
311 digits[0] = td->PadX();
312 digits[1] = td->PadY();
313 digits[2] = td->Cathode() - 1;
314 digits[3] = responseCharge;
315 digits[4] = td->Physics();
316 digits[5] = td->Hit();
317 digits[6] = td->DetElemId();
319 Int_t nptracks = td->GetNTracks();
320 if (nptracks > kMAXTRACKS) {
323 "TransientDigit returned the number of tracks to be %d, which is bigger than kMAXTRACKS.",
325 AliDebug(1, Form("Reseting the number of tracks to be %d.", kMAXTRACKS));
326 nptracks = kMAXTRACKS;
329 for (Int_t i = 0; i < nptracks; i++) {
331 tracks[i] = td->GetTrack(i);
332 charges[i] = td->GetCharge(i);
335 // Sort list of tracks according to charge
336 SortTracks(tracks,charges,nptracks);
338 if (nptracks < kMAXTRACKS ) {
340 for (Int_t i = nptracks; i < kMAXTRACKS; i++) {
346 AliDebug(4,Form( "Adding digit with charge %d.", responseCharge));
348 OnWriteTransientDigit(td);
349 AddDigit(td->Chamber(), tracks, charges, digits);
350 AddDigitTrigger(td->Chamber(), tracks, charges, digits, digitindex);
353 //------------------------------------------------------------------------
354 void AliMUONDigitizer::OnCreateTransientDigit(AliMUONTransientDigit* /*digit*/, TObject* /*source_object*/)
358 /// This is derived by Digitisers that want to trace which digits were made from
362 //------------------------------------------------------------------------
363 void AliMUONDigitizer::OnWriteTransientDigit(AliMUONTransientDigit* /*digit*/)
367 /// This is derived by Digitisers that want to trace which digits were made from
371 //------------------------------------------------------------------------
372 Bool_t AliMUONDigitizer::FetchLoaders(const char* foldername, AliRunLoader*& runloader, AliMUONLoader*& muonloader)
374 /// Fetches the run loader from the current folder, specified by 'foldername'.
375 /// The muon loader is then loaded from the fetched run loader.
376 /// kTRUE is returned if no error occurred otherwise kFALSE is returned.
378 AliDebug(3, Form("Fetching run loader and muon loader from folder: %s", foldername));
380 runloader = AliRunLoader::GetRunLoader(foldername);
381 if (runloader == NULL)
383 AliError(Form("RunLoader not found in folder: %s", foldername));
386 muonloader = (AliMUONLoader*) runloader->GetLoader("MUONLoader");
387 if (muonloader == NULL)
389 AliError(Form("MUONLoader not found in folder: %s", foldername));
396 //------------------------------------------------------------------------
397 Bool_t AliMUONDigitizer::FetchGlobalPointers(AliRunLoader* runloader)
399 /// Fetches the AliRun object into the global gAlice pointer from the specified
400 /// run loader. The AliRun object is loaded into memory using the run loader if
401 /// not yet loaded. The MUON module object is then loaded from gAlice and
402 /// AliMUONData fetched from the MUON module.
403 /// kTRUE is returned if no error occurred otherwise kFALSE is returned.
405 AliDebug(3, Form("Fetching gAlice, MUON module and AliMUONData from runloader 0x%X.",
409 if (runloader->GetAliRun() == NULL) runloader->LoadgAlice();
410 gAlice = runloader->GetAliRun();
413 AliError(Form("Could not find the AliRun object in runloader 0x%X.", (void*)runloader));
416 fMUON = (AliMUON*) gAlice->GetDetector("MUON");
419 AliError(Form("Could not find the MUON module in runloader 0x%X.", (void*)runloader));
423 AliMUONLoader *muonloader = (AliMUONLoader*) runloader->GetLoader("MUONLoader");
424 if (muonloader == NULL)
426 AliError( "MUONLoader not found ");
431 if (fMUONData == NULL) fMUONData = new AliMUONData(muonloader,"MUON","MUON");
432 if (fMUONData == NULL)
434 AliError(Form("Could not find AliMUONData object in runloader 0x%X.", (void*)runloader));
440 //-----------------------------------------------------------------------
441 Bool_t AliMUONDigitizer::FetchTriggerPointer(AliMUONLoader* loader)
443 /// \todo add description
445 if (fMUONData == NULL) {
446 AliError("MUONData not found");
450 if (fTrigDec == NULL)
451 fTrigDec = new AliMUONTriggerDecision(loader,0,fMUONData);
456 //------------------------------------------------------------------------
457 void AliMUONDigitizer::InitArrays()
459 /// Creates a new fTDList object.
460 /// Also creates an array of 2 * chamber_number AliMUONHitMapA1 objects
461 /// in the fHitMaps array. Each one is set to a chamber and cathode
462 /// specific segmentation model.
464 /// Note: the fTDList and fHitMap arrays must be NULL before calling this method.
466 AliDebug(2, "Initialising internal arrays.");
467 AliDebug(4, "Creating transient digits list.");
468 fTDList = new TObjArray;
470 // Array of pointer of the AliMUONHitMapA1:
471 // two HitMaps per chamber, or one HitMap per cahtode plane
472 fHitMap = new AliMUONHitMapA1* [2*AliMUONConstants::NDetElem()];
473 for (Int_t i=0; i<2*AliMUONConstants::NDetElem(); i++) fHitMap[i] = 0x0;
478 for (Int_t i = 0; i < AliMUONConstants::NCh(); i++) {
481 AliDebug(4,Form( "Creating hit map for chamber %d, cathode 1.", i+1));
482 AliMUONSegmentation* segmentation = fMUON->GetSegmentation();
483 AliMUONGeometrySegmentation* c1Segmentation
484 = segmentation->GetModuleSegmentation(i, 0); // Cathode plane 1
485 AliDebug(4,Form( "Creating hit map for chamber %d, cathode 2.", i+1));
486 AliMUONGeometrySegmentation* c2Segmentation
487 = segmentation->GetModuleSegmentation(i, 1); // Cathode plane 2
489 const AliMUONGeometryTransformer* kGeometryTransformer
490 = fMUON->GetGeometryTransformer();
492 AliMUONGeometryStore* detElements
493 = kGeometryTransformer->GetModuleTransformer(i)->GetDetElementStore();
496 // Loop over detection elements
497 for (Int_t j=0; j<detElements->GetNofEntries(); j++) {
499 idDE = detElements->GetEntry(j)->GetUniqueID();
500 fNDetElemId[idDE] = k;
502 Int_t npx1 = c1Segmentation->Npx(idDE)+1;
503 Int_t npy1 = c1Segmentation->Npy(idDE)+1;
504 fHitMap[k] = new AliMUONHitMapA1(npx1, npy1, fTDList);
506 Int_t npx2 = c2Segmentation->Npx(idDE)+1;
507 Int_t npy2 = c2Segmentation->Npy(idDE)+1;
508 fHitMap[k+AliMUONConstants::NDetElem()] = new AliMUONHitMapA1(npx2, npy2, fTDList);
513 //------------------------------------------------------------------------
514 void AliMUONDigitizer::CleanupArrays()
516 /// The arrays fTDList and fHitMap are deleted and the pointers set to NULL.
518 AliDebug(2, "Deleting internal arrays.");
519 for(Int_t i = 0; i < 2*AliMUONConstants::NDetElem(); i++) {
525 AliDebug(4, "Deleting transient digits list.");
532 //------------------------------------------------------------------------
533 void AliMUONDigitizer::SortTracks(Int_t *tracks, Int_t *charges, Int_t ntr) const
535 /// Sort the list of tracks contributing to a given digit
536 /// Only the 3 most significant tracks are actually sorted
538 if (ntr <= 1) return;
541 // Loop over signals, only 3 times
546 Int_t idx[3] = {-2,-2,-2};
547 Int_t jch[3] = {-2,-2,-2};
548 Int_t jtr[3] = {-2,-2,-2};
551 if (ntr < 3) imax = ntr;
554 for(i = 0; i < imax; i++)
559 for(j = 0; j < ntr; j++)
561 if ( (i == 1 && j == idx[i-1]) ||
562 (i == 2 && (j == idx[i-1] || j == idx[i-2]))
566 if(charges[j] > qmax)
576 jch[i] = charges[jmax];
577 jtr[i] = tracks[jmax];
582 for(i = 0; i < 3; i++)