5aa2622e2c28c4baee42db057728ad91774d8a85
[u/mrichter/AliRoot.git] / STEER / AliRunDigitizer.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 /*
17 $Log$
18 Revision 1.17  2002/07/16 13:47:53  jchudoba
19 Add methods to get access to names of files used in merging.
20
21 Revision 1.16  2002/06/07 09:18:47  jchudoba
22 Changes to enable merging of ITS fast rec points. Although this class should be responsible for a creation of digits only, other solutions would be more complicated.
23
24 Revision 1.15  2002/04/09 13:38:47  jchudoba
25 Add const to the filename argument
26
27 Revision 1.14  2002/04/04 09:28:04  jchudoba
28 Change default names of TPC trees. Use update instead of recreate for the output file. Overwrite the AliRunDigitizer object in the output if it exists.
29
30 Revision 1.13  2002/02/13 09:03:32  jchudoba
31 Pass option to subtasks. Delete input TTrees. Use gAlice from memory if it is present (user must delete the default one created by aliroot if he/she wants to use gAlice from the input file!). Add new data member to store name of the special TPC TTrees.
32
33 Revision 1.12  2001/12/10 16:40:52  jchudoba
34 Import gAlice from the signal file before InitGlobal() to allow detectors to use it during initialization
35
36 Revision 1.11  2001/12/03 07:10:13  jchudoba
37 Default ctor cannot create new objects, create dummy default ctor which leaves object in not well defined state - to be used only by root for I/O
38
39 Revision 1.10  2001/11/15 11:07:25  jchudoba
40 Set to zero new pointers to TPC and TRD special trees in the default ctor. Add const to all Get functions. Remove unused constant, rename constant according coding rules.
41
42 Revision 1.9  2001/11/15 09:00:11  jchudoba
43 Add special treatment for TPC and TRD, they use different trees than other detectors
44
45 Revision 1.8  2001/10/21 18:38:43  hristov
46 Several pointers were set to zero in the default constructors to avoid memory management problems
47
48 Revision 1.7  2001/10/04 15:56:07  jchudoba
49 TTask inheritance
50
51 Revision 1.4  2001/09/19 06:23:50  jchudoba
52 Move some tasks to AliStream and AliMergeCombi classes
53
54 Revision 1.3  2001/07/30 14:04:18  jchudoba
55 correct bug in the initialization
56
57 Revision 1.2  2001/07/28 10:44:32  hristov
58 Loop variable declared once; typos corrected
59
60 Revision 1.1  2001/07/27 12:59:00  jchudoba
61 Manager class for merging/digitization
62
63 */
64
65 ////////////////////////////////////////////////////////////////////////
66 //
67 // AliRunDigitizer.cxx
68 //
69 // Manager object for merging/digitization
70 //
71 // Instance of this class manages the digitization and/or merging of
72 // Sdigits into Digits. 
73 //
74 // Only one instance of this class is created in the macro:
75 //   AliRunDigitizer * manager = 
76 //      new AliRunDigitizer(nInputStreams,SPERB);
77 // where nInputStreams is number of input streams and SPERB is
78 // signals per background variable, which determines how combinations
79 // of signal and background events are generated.
80 // Then instances of specific detector digitizers are created:
81 //   AliMUONDigitizer *dMUON  = new AliMUONDigitizer(manager)
82 // and the I/O configured (you have to specify input files 
83 // and an output file). The manager connects appropriate trees from 
84 // the input files according a combination returned by AliMergeCombi 
85 // class. It creates TreeD in the output and runs once per 
86 // event Digitize method of all existing AliDetDigitizers 
87 // (without any option). AliDetDigitizers ask manager
88 // for a TTree with input (manager->GetInputTreeS(Int_t i),
89 // merge all inputs, digitize it, and save it in the TreeD 
90 // obtained by manager->GetTreeD(). Output events are stored with 
91 // numbers from 0, this default can be changed by 
92 // manager->SetFirstOutputEventNr(Int_t) method. The particle numbers
93 // in the output are shifted by MASK, which is taken from manager.
94 //
95 // The default output is to the signal file (stream 0). This can be 
96 // changed with the SetOutputFile(TString fn)  method.
97 //
98 // Single input file is permitted. Maximum kMaxStreamsToMerge can be merged.
99 // Input from the memory (on-the-fly merging) is not yet 
100 // supported, as well as access to the input data by invoking methods
101 // on the output data.
102 //
103 // Access to the some data is via gAlice for now (supposing the 
104 // same geometry in all input files), gAlice is taken from the first 
105 // input file on the first stream.
106 //
107 // Example with MUON digitizer, no merging, just digitization
108 //
109 //  AliRunDigitizer * manager = new AliRunDigitizer(1,1);
110 //  manager->SetInputStream(0,"galice.root");
111 //  AliMUONDigitizer *dMUON  = new AliMUONDigitizer(manager);
112 //  manager->Exec("");
113 //
114 // Example with MUON digitizer, merge all events from 
115 //   galice.root (signal) file with events from bgr.root 
116 //   (background) file. Number of merged events is
117 //   min(number of events in galice.root, number of events in bgr.root)
118 //
119 //  AliRunDigitizer * manager = new AliRunDigitizer(2,1);
120 //  manager->SetInputStream(0,"galice.root");
121 //  manager->SetInputStream(1,"bgr.root");
122 //  AliMUONDigitizer *dMUON  = new AliMUONDigitizer(manager);
123 //  manager->Exec("");
124 //
125 // Example with MUON digitizer, save digits in a new file digits.root,
126 //   process only 1 event
127 //
128 //  AliRunDigitizer * manager = new AliRunDigitizer(2,1);
129 //  manager->SetInputStream(0,"galice.root");
130 //  manager->SetInputStream(1,"bgr.root");
131 //  manager->SetOutputFile("digits.root");
132 //  AliMUONDigitizer *dMUON  = new AliMUONDigitizer(manager);
133 //  manager->SetNrOfEventsToWrite(1);
134 //  manager->Exec("");
135 //
136 //////////////////////////////////////////////////////////////////////// 
137
138 // system includes
139
140 #include <iostream.h>
141
142 // ROOT includes
143
144 #include "TFile.h"
145 #include "TTree.h"
146 #include "TList.h"
147
148 // AliROOT includes
149
150 #include "AliRunDigitizer.h"
151 #include "AliDigitizer.h"
152 #include "AliRun.h"
153 #include "AliHeader.h"
154 #include "TParticle.h"
155 #include "AliStream.h"
156 #include "AliMergeCombi.h"
157
158 ClassImp(AliRunDigitizer)
159
160 ////////////////////////////////////////////////////////////////////////
161 AliRunDigitizer::AliRunDigitizer()
162 {
163 // root requires default ctor, where no new objects can be created
164 // do not use this ctor, it is supplied only for root needs
165   
166 // just set all pointers - data members to 0
167   fOutput = 0;
168   fTreeD = 0;
169   fTreeR = 0;
170   fTreeDTPC = 0;
171   fTreeDTRD = 0;
172   fInputStreams = 0;
173   for (Int_t i=0;i<kMaxStreamsToMerge;i++) {
174     fArrayTreeS[i]=fArrayTreeH[i]=fArrayTreeTPCS[i]=fArrayTreeTRDS[i]=NULL;
175     fInputFiles[i]=0;
176   }
177   fCombi = 0;
178
179 }
180
181 ////////////////////////////////////////////////////////////////////////
182 AliRunDigitizer::AliRunDigitizer(Int_t nInputStreams, Int_t sperb) : TTask("AliRunDigitizer","The manager for Merging")
183 {
184 // ctor which should be used to create a manager for merging/digitization
185   if (nInputStreams == 0) {
186     Error("AliRunDigitizer","Specify nr of input streams");
187     return;
188   }
189   Int_t i;
190   fNinputs = nInputStreams;
191   fOutputFileName = "";
192   fOutputDirName = ".";
193   fCombination.Set(kMaxStreamsToMerge);
194   for (i=0;i<kMaxStreamsToMerge;i++) {
195     fArrayTreeS[i]=fArrayTreeH[i]=fArrayTreeTPCS[i]=fArrayTreeTRDS[i]=NULL;
196     fCombination[i]=-1;
197   }
198   fkMASKSTEP = 10000000;
199   fkMASK[0] = 0;
200   for (i=1;i<kMaxStreamsToMerge;i++) {
201     fkMASK[i] = fkMASK[i-1] + fkMASKSTEP;
202   }
203   fInputStreams = new TClonesArray("AliStream",nInputStreams);
204   TClonesArray &lInputStreams = *fInputStreams;
205 // the first Input is open RW to be output as well
206   new(lInputStreams[0]) AliStream("UPDATE");
207   for (i=1;i<nInputStreams;i++) {
208     new(lInputStreams[i]) AliStream("READ");
209   }
210   fOutput = 0;
211   fEvent = 0;
212   fNrOfEventsToWrite = -1;
213   fNrOfEventsWritten = 0;
214   fCopyTreesFromInput = -1;
215   fCombi = new AliMergeCombi(nInputStreams,sperb);
216   fDebug = 0;
217   fTreeD = 0;
218   fTreeR = 0;
219   fTreeDTPC = 0;
220   fTreeDTRD = 0;
221   fTreeDTPCBaseName = "TreeD_75x40_100x60_150x60_";
222   fTreeTPCSBaseName = "TreeS_75x40_100x60_150x60_";
223
224   for (i=0; i<kMaxStreamsToMerge; i++) fInputFiles[i]=0;
225 }
226
227 ////////////////////////////////////////////////////////////////////////
228
229 AliRunDigitizer::~AliRunDigitizer() {
230 // dtor
231
232 // do not delete subtasks, let the creator delete them
233   if (GetListOfTasks()) 
234     GetListOfTasks()->Clear("nodelete");
235   
236   if (fInputStreams) {
237     delete fInputStreams;
238     fInputStreams = 0;
239   }
240   if (fCombi) {
241     delete fCombi;
242     fCombi = 0;
243   }
244
245 }
246 ////////////////////////////////////////////////////////////////////////
247 void AliRunDigitizer::AddDigitizer(AliDigitizer *digitizer)
248 {
249 // add digitizer to the list of active digitizers
250   this->Add(digitizer);
251 }
252 ////////////////////////////////////////////////////////////////////////
253 void AliRunDigitizer::SetInputStream(Int_t i, const char *inputFile)
254 {
255   if (i > fInputStreams->GetLast()) {
256     Error("SetInputStream","Input stream number too high");
257     return;
258   }
259   static_cast<AliStream*>(fInputStreams->At(i))->AddFile(inputFile);
260 }
261
262 ////////////////////////////////////////////////////////////////////////
263 void AliRunDigitizer::Digitize(Option_t* option)
264 {
265 // get a new combination of inputs, connect input trees and loop 
266 // over all digitizers
267
268 // take gAlice from the first input file. It is needed to access
269 //  geometry data
270 // If gAlice is already in memory, use it
271   if (!gAlice) {
272     if (!static_cast<AliStream*>(fInputStreams->At(0))->ImportgAlice()) {
273       cerr<<"gAlice object not found in the first file of "
274           <<"the 1st stream"<<endl;
275       return;
276     }
277   }
278   if (!InitGlobal()) {
279     cerr<<"False from InitGlobal"<<endl;
280     return;
281   }
282   Int_t eventsCreated = 0;
283 // loop until there is anything on the input in case fNrOfEventsToWrite < 0
284   while ((eventsCreated++ < fNrOfEventsToWrite) || (fNrOfEventsToWrite < 0)) {
285     if (!ConnectInputTrees()) break;
286     InitEvent();
287 // loop over all registered digitizers and let them do the work
288     ExecuteTasks(option);
289     CleanTasks();
290     FinishEvent();
291   }
292   FinishGlobal();
293 }
294
295 ////////////////////////////////////////////////////////////////////////
296 Bool_t AliRunDigitizer::ConnectInputTrees()
297 {
298 // fill arrays fArrayTreeS, fArrayTreeH and fArrayTreeTPCS with 
299 // pointers to the correct events according fCombination values
300 // null pointers can be in the output, AliDigitizer has to check it
301
302   TTree *tree;
303   char treeName[50];
304   Int_t serialNr;
305   Int_t eventNr[kMaxStreamsToMerge], delta[kMaxStreamsToMerge];
306   fCombi->Combination(eventNr, delta);
307   for (Int_t i=0;i<fNinputs;i++) {
308     if (delta[i] == 1) {
309       AliStream *iStream = static_cast<AliStream*>(fInputStreams->At(i));
310       if (!iStream->NextEventInStream(serialNr)) return kFALSE;
311       fInputFiles[i]=iStream->CurrentFile();
312       sprintf(treeName,"TreeS%d",serialNr);
313       tree = static_cast<TTree*>(iStream->CurrentFile()->Get(treeName));
314       if (fArrayTreeS[i]) {
315         delete fArrayTreeS[i];
316         fArrayTreeS[i] = 0;
317       }
318       fArrayTreeS[i] = tree;
319       sprintf(treeName,"TreeH%d",serialNr);
320       tree = static_cast<TTree*>(iStream->CurrentFile()->Get(treeName));
321       if (fArrayTreeH[i]) {
322         delete fArrayTreeH[i];
323         fArrayTreeH[i] = 0;
324       }
325       fArrayTreeH[i] = tree;
326       sprintf(treeName,"%s%d",fTreeTPCSBaseName,serialNr);
327       tree = static_cast<TTree*>(iStream->CurrentFile()->Get(treeName));
328       if (fArrayTreeTPCS[i]) {
329         delete fArrayTreeTPCS[i];
330         fArrayTreeTPCS[i] = 0;
331       }
332       fArrayTreeTPCS[i] = tree;
333       sprintf(treeName,"TreeS%d_TRD",serialNr);
334       tree = static_cast<TTree*>(iStream->CurrentFile()->Get(treeName));
335       if (fArrayTreeTRDS[i]) {
336         delete fArrayTreeTRDS[i];
337         fArrayTreeTRDS[i] = 0;
338       }
339       fArrayTreeTRDS[i] = tree;
340     } else if (delta[i] != 0) {
341       Error("ConnectInputTrees","Only delta 0 or 1 is implemented");
342       return kFALSE;
343     }
344   }
345   return kTRUE;
346 }
347
348 ////////////////////////////////////////////////////////////////////////
349 Bool_t AliRunDigitizer::InitGlobal()
350 {
351 // called once before Digitize() is called, initialize digitizers and output
352
353   TList* subTasks = this->GetListOfTasks();
354   if (subTasks) {
355     subTasks->ForEach(AliDigitizer,Init)();
356   }  
357   return kTRUE;
358 }
359
360 ////////////////////////////////////////////////////////////////////////
361
362 void AliRunDigitizer::SetOutputFile(TString fn)
363 // the output will be to separate file, not to the signal file
364 {
365   fOutputFileName = fn;
366   (static_cast<AliStream*>(fInputStreams->At(0)))->ChangeMode("READ");
367   InitOutputGlobal();
368 }
369
370 ////////////////////////////////////////////////////////////////////////
371 Bool_t AliRunDigitizer::InitOutputGlobal()
372 {
373 // Creates the output file, called by InitEvent()
374
375   TString fn;
376   fn = fOutputDirName + '/' + fOutputFileName;
377   fOutput = new TFile(fn,"update");
378   if (GetDebug()>2) {
379     cerr<<"AliRunDigitizer::InitOutputGlobal(): file "<<fn.Data()<<" was opened"<<endl;
380   }
381   if (fOutput) return kTRUE;
382   Error("InitOutputGlobal","Could not create output file.");
383   return kFALSE;
384 }
385
386
387 ////////////////////////////////////////////////////////////////////////
388 void AliRunDigitizer::InitEvent()
389 {
390 // Creates TreeDxx in the output file, called from Digitize() once for 
391 //  each event. xx = fEvent
392
393   if (GetDebug()>2) 
394     cerr<<"AliRunDigitizer::InitEvent: fEvent = "<<fEvent<<endl;
395
396 // if fOutputFileName was not given, write output to signal file
397   if (fOutputFileName == "") {
398     fOutput = (static_cast<AliStream*>(fInputStreams->At(0)))->CurrentFile();
399   }
400   fOutput->cd();
401   char treeName[30];
402   sprintf(treeName,"TreeD%d",fEvent);
403   fTreeD = static_cast<TTree*>(fOutput->Get(treeName));
404   if (!fTreeD) {
405     fTreeD = new TTree(treeName,"Digits");
406     fTreeD->Write(0,TObject::kOverwrite);
407   }
408
409 // tree for ITS fast points
410   sprintf(treeName,"TreeR%d",fEvent);
411   fTreeR = static_cast<TTree*>(fOutput->Get(treeName));
412   if (!fTreeR) {
413     fTreeR = new TTree(treeName,"Reconstruction");
414     fTreeR->Write(0,TObject::kOverwrite);
415   }
416
417 // special tree for TPC
418   sprintf(treeName,"%s%d",fTreeDTPCBaseName,fEvent);
419   fTreeDTPC = static_cast<TTree*>(fOutput->Get(treeName));
420   if (!fTreeDTPC) {
421     fTreeDTPC = new TTree(treeName,"TPC_Digits");
422     fTreeDTPC->Write(0,TObject::kOverwrite);
423   }
424
425 // special tree for TRD
426   sprintf(treeName,"TreeD%d_TRD",fEvent);
427   fTreeDTRD = static_cast<TTree*>(fOutput->Get(treeName));
428   if (!fTreeDTRD) {
429     fTreeDTRD = new TTree(treeName,"TRD_Digits");
430     fTreeDTRD->Write(0,TObject::kOverwrite);
431   }
432
433 }
434
435 ////////////////////////////////////////////////////////////////////////
436 void AliRunDigitizer::FinishEvent()
437 {
438 // called at the end of loop over digitizers
439
440   Int_t i;
441   fOutput->cd();
442   if (fCopyTreesFromInput > -1) {
443     char treeName[20];
444     i = fCopyTreesFromInput; 
445     sprintf(treeName,"TreeK%d",fCombination[i]);
446     fInputFiles[i]->Get(treeName)->Clone()->Write();
447     sprintf(treeName,"TreeH%d",fCombination[i]);
448     fInputFiles[i]->Get(treeName)->Clone()->Write();
449   }
450   fEvent++;
451   fNrOfEventsWritten++;
452   if (fTreeD) {
453     delete fTreeD;
454     fTreeD = 0;
455   }
456   if (fTreeR) {
457     delete fTreeR;
458     fTreeR = 0;
459   }
460   if (fTreeDTPC) {
461     delete fTreeDTPC;
462     fTreeDTPC = 0;
463   }
464   if (fTreeDTRD) {
465     delete fTreeDTRD;
466     fTreeDTRD = 0;
467   }
468 }
469 ////////////////////////////////////////////////////////////////////////
470 void AliRunDigitizer::FinishGlobal()
471 {
472 // called at the end of Exec
473 // save unique objects to the output file
474
475   fOutput->cd();
476   this->Write(0,TObject::kOverwrite);
477   if (fCopyTreesFromInput > -1) {
478     fInputFiles[fCopyTreesFromInput]->Get("TE")->Clone()->Write();
479     gAlice->Write();
480   }
481   fOutput->Close();
482 }
483
484
485 ////////////////////////////////////////////////////////////////////////
486 Int_t  AliRunDigitizer::GetNParticles(Int_t event) const
487 {
488 // return number of particles in all input files for a given
489 // event (as numbered in the output file)
490 // return -1 if some file cannot be accessed
491
492   Int_t sum = 0;
493   Int_t sumI;
494   for (Int_t i = 0; i < fNinputs; i++) {
495     sumI = GetNParticles(GetInputEventNumber(event,i), i);
496     if (sumI < 0) return -1;
497     sum += sumI;
498   }
499   return sum;
500 }
501
502 ////////////////////////////////////////////////////////////////////////
503 Int_t  AliRunDigitizer::GetNParticles(Int_t event, Int_t input) const
504 {
505 // return number of particles in input file input for a given
506 // event (as numbered in this input file)
507 // return -1 if some error
508
509 // Must be revised in the version with AliStream
510
511   return -1;
512
513 /*
514   TFile *file = ConnectInputFile(input);
515   if (!file) {
516     Error("GetNParticles","Cannot open input file");
517     return -1;
518   }
519
520 // find the header and get Nprimaries and Nsecondaries
521   TTree* tE = (TTree *)file->Get("TE") ;
522   if (!tE) {
523     Error("GetNParticles","input file does not contain TE");
524     return -1;
525   }
526   AliHeader* header;
527   header = 0;
528   tE->SetBranchAddress("Header", &header);
529   if (!tE->GetEntry(event)) {
530     Error("GetNParticles","event %d not found",event);
531     return -1;
532   }
533   if (GetDebug()>2) {
534     cerr<<"Nprimary: "<< header->GetNprimary()<<endl;
535     cerr<<"Nsecondary: "<<header->GetNsecondary()<<endl;
536   }
537   return header->GetNprimary() + header->GetNsecondary();
538 */
539 }
540
541 ////////////////////////////////////////////////////////////////////////
542 Int_t* AliRunDigitizer::GetInputEventNumbers(Int_t event) const
543 {
544 // return pointer to an int array with input event numbers which were
545 // merged in the output event event
546
547 // simplified for now, implement later
548   Int_t * a = new Int_t[kMaxStreamsToMerge];
549   for (Int_t i = 0; i < fNinputs; i++) {
550     a[i] = event;
551   }
552   return a;
553 }
554 ////////////////////////////////////////////////////////////////////////
555 Int_t AliRunDigitizer::GetInputEventNumber(Int_t event, Int_t input) const
556 {
557 // return an event number of an eventInput from input file input
558 // which was merged to create output event event
559
560 // simplified for now, implement later
561   return event;
562 }
563 ////////////////////////////////////////////////////////////////////////
564 TParticle* AliRunDigitizer::GetParticle(Int_t i, Int_t event) const
565 {
566 // return pointer to particle with index i (index with mask)
567
568 // decode the MASK
569   Int_t input = i/fkMASKSTEP;
570   return GetParticle(i,input,GetInputEventNumber(event,input));
571 }
572
573 ////////////////////////////////////////////////////////////////////////
574 TParticle* AliRunDigitizer::GetParticle(Int_t i, Int_t input, Int_t event) const
575 {
576 // return pointer to particle with index i in the input file input
577 // (index without mask)
578 // event is the event number in the file input
579 // return 0 i fit does not exist
580
581 // Must be revised in the version with AliStream
582
583   return 0;
584 /*
585   TFile *file = ConnectInputFile(input);
586   if (!file) {
587     Error("GetParticle","Cannot open input file");
588     return 0;
589   }
590
591 // find the header and get Nprimaries and Nsecondaries
592   TTree* tE = (TTree *)file->Get("TE") ;
593   if (!tE) {
594     Error("GetParticle","input file does not contain TE");
595     return 0;
596   }
597   AliHeader* header;
598   header = 0;
599   tE->SetBranchAddress("Header", &header);
600   if (!tE->GetEntry(event)) {
601     Error("GetParticle","event %d not found",event);
602     return 0;
603   }
604   
605 // connect TreeK  
606   char treeName[30];
607   sprintf(treeName,"TreeK%d",event);  
608   TTree* tK = static_cast<TTree*>(file->Get(treeName));
609   if (!tK) {
610     Error("GetParticle","input file does not contain TreeK%d",event);
611     return 0;
612   }
613   TParticle *particleBuffer;
614   particleBuffer = 0;
615   tK->SetBranchAddress("Particles", &particleBuffer);
616
617
618 // algorithmic way of getting entry index
619 // (primary particles are filled after secondaries)
620   Int_t entry;
621   if (i<header->GetNprimary())
622     entry = i+header->GetNsecondary();
623   else 
624     entry = i-header->GetNprimary();
625   Int_t bytesRead = tK->GetEntry(entry);
626 //  new ((*fParticles)[nentries]) TParticle(*fParticleBuffer);
627   if (bytesRead)
628     return particleBuffer;
629   return  0;
630 */
631 }
632
633 ////////////////////////////////////////////////////////////////////////
634 void AliRunDigitizer::ExecuteTask(Option_t* option)
635 {
636 // overwrite ExecuteTask to do Digitize only
637
638   if (!IsActive()) return;
639   Digitize(option);
640   fHasExecuted = kTRUE;
641   return;
642 }
643 ////////////////////////////////////////////////////////////////////////
644 TString AliRunDigitizer::GetInputFileName(const Int_t input, const Int_t order) const 
645 {
646 // returns file name of the order-th file in the input stream input
647 // returns empty string if such file does not exist
648 // first input stream is 0
649 // first file in the input stream is 0
650   TString fileName("");
651   if (input >= fNinputs) return fileName;
652   AliStream * stream = static_cast<AliStream*>(fInputStreams->At(input));
653   if (order > stream->GetNInputFiles()) return fileName;
654   fileName = stream->GetFileName(order);
655   return fileName;
656 }
657 ////////////////////////////////////////////////////////////////////////