Use access functions to AliMUONDigit, ... member data.
[u/mrichter/AliRoot.git] / MUON / AliMUONEventReconstructor.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.22  2001/01/26 20:00:53  hristov
19 Major upgrade of AliRoot code
20 Revision 1.20  2001/01/08 11:01:02  gosset
21 Modifications used for addendum to Dimuon TDR (JP Cussonneau):
22 *. MaxBendingMomentum to make both a segment and a track (default 500)
23 *. MaxChi2 per degree of freedom to make a track (default 100)
24 *. MinBendingMomentum used also to make a track
25    and not only a segment (default 3)
26 *. wider roads for track search in stations 1 to 3
27 *. extrapolation to actual Z instead of Z(chamber) in FollowTracks
28 *. in track fit:
29    - limits on parameters X and Y (+/-500)
30    - covariance matrices in double precision
31    - normalization of covariance matrices before inversion
32    - suppression of Minuit printouts
33 *. correction against memory leak (delete extrapHit) in FollowTracks
34 *. RMax to 10 degrees with Z(chamber) instead of fixed values;
35    RMin and Rmax cuts suppressed in NewHitForRecFromGEANT,
36    because useless with realistic geometry
37
38 Revision 1.19  2000/11/20 11:24:10  gosset
39 New package for reconstructed tracks (A. Gheata):
40 * tree output in the file "tree_reco.root"
41 * display events and make histograms from this file
42
43 Revision 1.18  2000/10/26 12:47:03  gosset
44 Real distance between chambers of each station taken into account
45 for the reconstruction parameters "fSegmentMaxDistBending[5]"
46
47 Revision 1.17  2000/10/24 09:26:20  gosset
48 Comments updated
49
50 Revision 1.16  2000/10/24 09:22:35  gosset
51 Method AddHitsForRecFromRawClusters: real Z of raw cluster and not Z of chamber
52
53 Revision 1.15  2000/10/12 15:17:30  gosset
54 Sign of fSimpleBValue corrected: sign ox Bx and not Bz (thanks to Galina)
55
56 Revision 1.14  2000/10/04 18:21:26  morsch
57 Include stdlib.h
58
59 Revision 1.13  2000/10/02 21:28:09  fca
60 Removal of useless dependecies via forward declarations
61
62 Revision 1.12  2000/10/02 16:58:29  egangler
63 Cleaning of the code :
64 -> coding conventions
65 -> void Streamers
66 -> some useless includes removed or replaced by "class" statement
67
68 Revision 1.11  2000/09/22 09:16:33  hristov
69 Casting needed on DEC
70
71 Revision 1.10  2000/09/19 09:49:50  gosset
72 AliMUONEventReconstructor package
73 * track extrapolation independent from reco_muon.F, use of AliMagF...
74 * possibility to use new magnetic field (automatic from generated root file)
75
76 Revision 1.9  2000/07/20 12:45:27  gosset
77 New "EventReconstructor..." structure,
78         hopefully more adapted to tree/streamer.
79 "AliMUONEventReconstructor::RemoveDoubleTracks"
80         to keep only one track among similar ones.
81
82 Revision 1.8  2000/07/18 16:04:06  gosset
83 AliMUONEventReconstructor package:
84 * a few minor modifications and more comments
85 * a few corrections
86   * right sign for Z of raw clusters
87   * right loop over chambers inside station
88   * symmetrized covariance matrix for measurements (TrackChi2MCS)
89   * right sign of charge in extrapolation (ExtrapToZ)
90   * right zEndAbsorber for Branson correction below 3 degrees
91 * use of TVirtualFitter instead of TMinuit for AliMUONTrack::Fit
92 * no parameter for AliMUONTrack::Fit() but more fit parameters in Track object
93
94 Revision 1.7  2000/07/03 12:28:06  gosset
95 Printout at the right place after extrapolation to vertex
96
97 Revision 1.6  2000/06/30 12:01:06  gosset
98 Correction for hit search in the right chamber (JPC)
99
100 Revision 1.5  2000/06/30 10:15:48  gosset
101 Changes to EventReconstructor...:
102 precision fit with multiple Coulomb scattering;
103 extrapolation to vertex with Branson correction in absorber (JPC)
104
105 Revision 1.4  2000/06/27 14:11:36  gosset
106 Corrections against violations of coding conventions
107
108 Revision 1.3  2000/06/16 07:27:08  gosset
109 To remove problem in running RuleChecker, like in MUON-dev
110
111 Revision 1.1.2.5  2000/06/16 07:00:26  gosset
112 To remove problem in running RuleChecker
113
114 Revision 1.1.2.4  2000/06/12 08:00:07  morsch
115 Dummy streamer to solve CINT compilation problem (to be investigated !)
116
117 Revision 1.1.2.3  2000/06/09 20:59:57  morsch
118 Make includes consistent with new file structure.
119
120 Revision 1.1.2.2  2000/06/09 12:58:05  gosset
121 Removed comment beginnings in Log sections of .cxx files
122 Suppressed most violations of coding rules
123
124 Revision 1.1.2.1  2000/06/07 14:44:53  gosset
125 Addition of files for track reconstruction in C++
126 */
127
128 //__________________________________________________________________________
129 //
130 // MUON event reconstructor in ALICE
131 //
132 // This class contains as data:
133 // * the parameters for the event reconstruction
134 // * a pointer to the array of hits to be reconstructed (the event)
135 // * a pointer to the array of segments made with these hits inside each station
136 // * a pointer to the array of reconstructed tracks
137 //
138 // It contains as methods, among others:
139 // * MakeEventToBeReconstructed to build the array of hits to be reconstructed
140 // * MakeSegments to build the segments
141 // * MakeTracks to build the tracks
142 //__________________________________________________________________________
143
144 #include <iostream.h>
145 #include <stdlib.h>
146
147 #include <TRandom.h>
148 #include <TFile.h>
149 #include <TTree.h>
150
151 #include "AliMUONEventReconstructor.h"
152 #include "AliMUON.h"
153 #include "AliMUONHitForRec.h"
154 #include "AliMUONSegment.h"
155 #include "AliMUONHit.h"
156 #include "AliMUONRawCluster.h"
157 #include "AliMUONTrack.h"
158 #include "AliMUONChamber.h"
159 #include "AliMUONTrackHit.h"
160 #include "AliMagF.h"
161 #include "AliRun.h"
162 #include "TParticle.h"
163 #include "AliMUONRecoEvent.h"
164
165 //************* Defaults parameters for reconstruction
166 static const Double_t kDefaultMinBendingMomentum = 3.0;
167 static const Double_t kDefaultMaxBendingMomentum = 500.0;
168 static const Double_t kDefaultMaxChi2 = 100.0;
169 static const Double_t kDefaultMaxSigma2Distance = 16.0;
170 static const Double_t kDefaultBendingResolution = 0.01;
171 static const Double_t kDefaultNonBendingResolution = 0.144;
172 static const Double_t kDefaultChamberThicknessInX0 = 0.03;
173 // Simple magnetic field:
174 // Value taken from macro MUONtracking.C: 0.7 T, hence 7 kG
175 // Length and Position from reco_muon.F, with opposite sign:
176 // Length = ZMAGEND-ZCOIL
177 // Position = (ZMAGEND+ZCOIL)/2
178 // to be ajusted differently from real magnetic field ????
179 static const Double_t kDefaultSimpleBValue = 7.0;
180 static const Double_t kDefaultSimpleBLength = 428.0;
181 static const Double_t kDefaultSimpleBPosition = 1019.0;
182 static const Int_t kDefaultRecGeantHits = 0;
183 static const Double_t kDefaultEfficiency = 0.95;
184
185 static const Int_t kDefaultPrintLevel = 0;
186
187 ClassImp(AliMUONEventReconstructor) // Class implementation in ROOT context
188
189   //__________________________________________________________________________
190 AliMUONEventReconstructor::AliMUONEventReconstructor(void)
191 {
192   // Constructor for class AliMUONEventReconstructor
193   SetReconstructionParametersToDefaults();
194   // Memory allocation for the TClonesArray of hits for reconstruction
195   // Is 10000 the right size ????
196   fHitsForRecPtr = new TClonesArray("AliMUONHitForRec", 10000);
197   fNHitsForRec = 0; // really needed or GetEntriesFast sufficient ????
198   // Memory allocation for the TClonesArray's of segments in stations
199   // Is 2000 the right size ????
200   for (Int_t st = 0; st < kMaxMuonTrackingStations; st++) {
201     fSegmentsPtr[st] = new TClonesArray("AliMUONSegment", 2000);
202     fNSegments[st] = 0; // really needed or GetEntriesFast sufficient ????
203   }
204   // Memory allocation for the TClonesArray of reconstructed tracks
205   // Is 10 the right size ????
206   fRecTracksPtr = new TClonesArray("AliMUONTrack", 10);
207   fNRecTracks = 0; // really needed or GetEntriesFast sufficient ????
208   // Memory allocation for the TClonesArray of hits on reconstructed tracks
209   // Is 100 the right size ????
210   fRecTrackHitsPtr = new TClonesArray("AliMUONTrack", 100);
211   fNRecTrackHits = 0; // really needed or GetEntriesFast sufficient ????
212
213   // Sign of fSimpleBValue according to sign of Bx value at (50,50,950).
214   Float_t b[3], x[3];
215   x[0] = 50.; x[1] = 50.; x[2] = 950.;
216   gAlice->Field()->Field(x, b);
217   fSimpleBValue = TMath::Sign(fSimpleBValue,(Double_t) b[0]);
218   // See how to get fSimple(BValue, BLength, BPosition)
219   // automatically calculated from the actual magnetic field ????
220
221   if (fPrintLevel >= 0) {
222     cout << "AliMUONEventReconstructor constructed with defaults" << endl; Dump();
223     cout << endl << "Magnetic field from root file:" << endl;
224     gAlice->Field()->Dump();
225     cout << endl;
226   }
227   
228   // Initialize to 0 pointers to RecoEvent, tree and tree file
229   fRecoEvent = 0;
230   fEventTree = 0;
231   fTreeFile  = 0;
232   
233   return;
234 }
235
236 AliMUONEventReconstructor::AliMUONEventReconstructor (const AliMUONEventReconstructor& Reconstructor)
237 {
238   // Dummy copy constructor
239 }
240
241 AliMUONEventReconstructor & AliMUONEventReconstructor::operator=(const AliMUONEventReconstructor& Reconstructor)
242 {
243   // Dummy assignment operator
244     return *this;
245 }
246
247   //__________________________________________________________________________
248 AliMUONEventReconstructor::~AliMUONEventReconstructor(void)
249 {
250   // Destructor for class AliMUONEventReconstructor
251   if (fTreeFile) {
252      fTreeFile->Close();
253      delete fTreeFile;
254   }
255 //  if (fEventTree) delete fEventTree;
256   if (fRecoEvent) delete fRecoEvent;
257   delete fHitsForRecPtr; // Correct destruction of everything ???? or delete [] ????
258   for (Int_t st = 0; st < kMaxMuonTrackingStations; st++)
259     delete fSegmentsPtr[st]; // Correct destruction of everything ????
260   return;
261 }
262
263   //__________________________________________________________________________
264 void AliMUONEventReconstructor::SetReconstructionParametersToDefaults(void)
265 {
266   // Set reconstruction parameters to default values
267   // Would be much more convenient with a structure (or class) ????
268   fMinBendingMomentum = kDefaultMinBendingMomentum;
269   fMaxBendingMomentum = kDefaultMaxBendingMomentum;
270   fMaxChi2 = kDefaultMaxChi2;
271   fMaxSigma2Distance = kDefaultMaxSigma2Distance;
272
273   AliMUON *pMUON = (AliMUON*) gAlice->GetModule("MUON");
274   // ******** Parameters for making HitsForRec
275   // minimum radius,
276   // like in TRACKF_STAT:
277   // 2 degrees for stations 1 and 2, or ch(0...) from 0 to 3;
278   // 30 cm for stations 3 to 5, or ch(0...) from 4 to 9
279   for (Int_t ch = 0; ch < kMaxMuonTrackingChambers; ch++) {
280     if (ch < 4) fRMin[ch] = TMath::Abs((&(pMUON->Chamber(ch)))->Z()) *
281                   2.0 * TMath::Pi() / 180.0;
282     else fRMin[ch] = 30.0;
283     // maximum radius at 10 degrees and Z of chamber
284     fRMax[ch] = TMath::Abs((&(pMUON->Chamber(ch)))->Z()) *
285                   10.0 * TMath::Pi() / 180.0;
286   }
287
288   // ******** Parameters for making segments
289   // should be parametrized ????
290   // according to interval between chambers in a station ????
291   // Maximum distance in non bending plane
292   // 5 * 0.22 just to remember the way it was made in TRACKF_STAT
293   // SIGCUT*DYMAX(IZ)
294   for (Int_t st = 0; st < kMaxMuonTrackingStations; st++)
295     fSegmentMaxDistNonBending[st] = 5. * 0.22;
296   // Maximum distance in bending plane:
297   // values from TRACKF_STAT, corresponding to (J psi 20cm),
298   // scaled to the real distance between chambers in a station
299   fSegmentMaxDistBending[0] = 1.5 *
300     ((&(pMUON->Chamber(1)))->Z() - (&(pMUON->Chamber(0)))->Z()) / 20.0;
301   fSegmentMaxDistBending[1] = 1.5 *
302     ((&(pMUON->Chamber(3)))->Z() - (&(pMUON->Chamber(2)))->Z()) / 20.0;
303   fSegmentMaxDistBending[2] = 3.0 *
304     ((&(pMUON->Chamber(5)))->Z() - (&(pMUON->Chamber(4)))->Z()) / 20.0;
305   fSegmentMaxDistBending[3] = 6.0 *
306     ((&(pMUON->Chamber(7)))->Z() - (&(pMUON->Chamber(6)))->Z()) / 20.0;
307   fSegmentMaxDistBending[4] = 6.0 *
308     ((&(pMUON->Chamber(9)))->Z() - (&(pMUON->Chamber(8)))->Z()) / 20.0;
309   
310   fBendingResolution = kDefaultBendingResolution;
311   fNonBendingResolution = kDefaultNonBendingResolution;
312   fChamberThicknessInX0 = kDefaultChamberThicknessInX0;
313   fSimpleBValue = kDefaultSimpleBValue;
314   fSimpleBLength = kDefaultSimpleBLength;
315   fSimpleBPosition = kDefaultSimpleBPosition;
316   fRecGeantHits = kDefaultRecGeantHits;
317   fEfficiency = kDefaultEfficiency;
318   fPrintLevel = kDefaultPrintLevel;
319   return;
320 }
321
322 //__________________________________________________________________________
323 Double_t AliMUONEventReconstructor::GetImpactParamFromBendingMomentum(Double_t BendingMomentum)
324 {
325   // Returns impact parameter at vertex in bending plane (cm),
326   // from the signed bending momentum "BendingMomentum" in bending plane (GeV/c),
327   // using simple values for dipole magnetic field.
328   // The sign of "BendingMomentum" is the sign of the charge.
329   return (-0.0003 * fSimpleBValue * fSimpleBLength * fSimpleBPosition /
330           BendingMomentum);
331 }
332
333 //__________________________________________________________________________
334 Double_t AliMUONEventReconstructor::GetBendingMomentumFromImpactParam(Double_t ImpactParam)
335 {
336   // Returns signed bending momentum in bending plane (GeV/c),
337   // the sign being the sign of the charge for particles moving forward in Z,
338   // from the impact parameter "ImpactParam" at vertex in bending plane (cm),
339   // using simple values for dipole magnetic field.
340   return (-0.0003 * fSimpleBValue * fSimpleBLength * fSimpleBPosition /
341           ImpactParam);
342 }
343
344 //__________________________________________________________________________
345 void AliMUONEventReconstructor::SetBkgGeantFile(Text_t *BkgGeantFileName)
346 {
347   // Set background file ... for GEANT hits
348   // Must be called after having loaded the firts signal event
349   if (fPrintLevel >= 0) {
350     cout << "Enter SetBkgGeantFile with BkgGeantFileName ``"
351          << BkgGeantFileName << "''" << endl;}
352   if (strlen(BkgGeantFileName)) {
353     // BkgGeantFileName not empty: try to open the file
354     if (fPrintLevel >= 2) {cout << "Before File(Bkg)" << endl; gDirectory->Dump();}
355     fBkgGeantFile = new TFile(BkgGeantFileName);
356     if (fPrintLevel >= 2) {cout << "After File(Bkg)" << endl; gDirectory->Dump();}
357     if (fBkgGeantFile-> IsOpen()) {
358       if (fPrintLevel >= 0) {
359         cout << "Background for GEANT hits in file: ``" << BkgGeantFileName
360              << "'' successfully opened" << endl;}
361     }
362     else {
363       cout << "Background for GEANT hits in file: " << BkgGeantFileName << endl;
364       cout << "NOT FOUND: EXIT" << endl;
365       exit(0); // right instruction for exit ????
366     }
367     // Arrays for "particles" and "hits"
368     fBkgGeantParticles = new TClonesArray("TParticle", 200);
369     fBkgGeantHits = new TClonesArray("AliMUONHit", 2000);
370     // Event number to -1 for initialization
371     fBkgGeantEventNumber = -1;
372     // Back to the signal file:
373     // first signal event must have been loaded previously,
374     // otherwise, Segmentation violation at the next instruction
375     // How is it possible to do smething better ????
376     ((gAlice->TreeK())->GetCurrentFile())->cd();
377     if (fPrintLevel >= 2) {cout << "After cd(gAlice)" << endl; gDirectory->Dump();}
378   }
379   return;
380 }
381
382 //__________________________________________________________________________
383 void AliMUONEventReconstructor::NextBkgGeantEvent(void)
384 {
385   // Get next event in background file for GEANT hits
386   // Goes back to event number 0 when end of file is reached
387   char treeName[20];
388   TBranch *branch;
389   if (fPrintLevel >= 0) {
390     cout << "Enter NextBkgGeantEvent" << endl;}
391   // Clean previous event
392   if(fBkgGeantTK) delete fBkgGeantTK;
393   fBkgGeantTK = NULL;
394   if(fBkgGeantParticles) fBkgGeantParticles->Clear();
395   if(fBkgGeantTH) delete fBkgGeantTH;
396   fBkgGeantTH = NULL;
397   if(fBkgGeantHits) fBkgGeantHits->Clear();
398   // Increment event number
399   fBkgGeantEventNumber++;
400   // Get access to Particles and Hits for event from background file
401   if (fPrintLevel >= 2) {cout << "Before cd(Bkg)" << endl; gDirectory->Dump();}
402   fBkgGeantFile->cd();
403   if (fPrintLevel >= 2) {cout << "After cd(Bkg)" << endl; gDirectory->Dump();}
404   // Particles: TreeK for event and branch "Particles"
405   sprintf(treeName, "TreeK%d", fBkgGeantEventNumber);
406   fBkgGeantTK = (TTree*)gDirectory->Get(treeName);
407   if (!fBkgGeantTK) {
408     if (fPrintLevel >= 0) {
409       cout << "Cannot find Kine Tree for background event: " <<
410         fBkgGeantEventNumber << endl;
411       cout << "Goes back to event 0" << endl;
412     }
413     fBkgGeantEventNumber = 0;
414     sprintf(treeName, "TreeK%d", fBkgGeantEventNumber);
415     fBkgGeantTK = (TTree*)gDirectory->Get(treeName);
416     if (!fBkgGeantTK) {
417       cout << "ERROR: cannot find Kine Tree for background event: " <<
418         fBkgGeantEventNumber << endl;
419       exit(0);
420     }
421   }
422   if (fBkgGeantTK) 
423     fBkgGeantTK->SetBranchAddress("Particles", &fBkgGeantParticles);
424   fBkgGeantTK->GetEvent(0); // why event 0 ???? necessary ????
425   // Hits: TreeH for event and branch "MUON"
426   sprintf(treeName, "TreeH%d", fBkgGeantEventNumber);
427   fBkgGeantTH = (TTree*)gDirectory->Get(treeName);
428   if (!fBkgGeantTH) {
429     cout << "ERROR: cannot find Hits Tree for background event: " <<
430       fBkgGeantEventNumber << endl;
431       exit(0);
432   }
433   if (fBkgGeantTH && fBkgGeantHits) {
434     branch = fBkgGeantTH->GetBranch("MUON");
435     if (branch) branch->SetAddress(&fBkgGeantHits);
436   }
437   fBkgGeantTH->GetEntries(); // necessary ????
438   // Back to the signal file
439   ((gAlice->TreeK())->GetCurrentFile())->cd();
440   if (fPrintLevel >= 2) {cout << "After cd(gAlice)" << endl; gDirectory->Dump();}
441   return;
442 }
443
444 //__________________________________________________________________________
445 void AliMUONEventReconstructor::EventReconstruct(void)
446 {
447   // To reconstruct one event
448   if (fPrintLevel >= 1) cout << "enter EventReconstruct" << endl;
449   MakeEventToBeReconstructed();
450   MakeSegments();
451   MakeTracks();
452   return;
453 }
454
455   //__________________________________________________________________________
456 void AliMUONEventReconstructor::ResetHitsForRec(void)
457 {
458   // To reset the array and the number of HitsForRec,
459   // and also the number of HitsForRec
460   // and the index of the first HitForRec per chamber
461   if (fHitsForRecPtr) fHitsForRecPtr->Clear();
462   fNHitsForRec = 0;
463   for (Int_t ch = 0; ch < kMaxMuonTrackingChambers; ch++)
464     fNHitsForRecPerChamber[ch] = fIndexOfFirstHitForRecPerChamber[ch] = 0;
465   return;
466 }
467
468   //__________________________________________________________________________
469 void AliMUONEventReconstructor::ResetSegments(void)
470 {
471   // To reset the TClonesArray of segments and the number of Segments
472   // for all stations
473   for (Int_t st = 0; st < kMaxMuonTrackingStations; st++) {
474     if (fSegmentsPtr[st]) fSegmentsPtr[st]->Clear();
475     fNSegments[st] = 0;
476   }
477   return;
478 }
479
480   //__________________________________________________________________________
481 void AliMUONEventReconstructor::ResetTracks(void)
482 {
483   // To reset the TClonesArray of reconstructed tracks
484   if (fRecTracksPtr) fRecTracksPtr->Delete();
485   // Delete in order that the Track destructors are called,
486   // hence the space for the TClonesArray of pointers to TrackHit's is freed
487   fNRecTracks = 0;
488   return;
489 }
490
491   //__________________________________________________________________________
492 void AliMUONEventReconstructor::ResetTrackHits(void)
493 {
494   // To reset the TClonesArray of hits on reconstructed tracks
495   if (fRecTrackHitsPtr) fRecTrackHitsPtr->Clear();
496   fNRecTrackHits = 0;
497   return;
498 }
499
500   //__________________________________________________________________________
501 void AliMUONEventReconstructor::MakeEventToBeReconstructed(void)
502 {
503   // To make the list of hits to be reconstructed,
504   // either from the GEANT hits or from the raw clusters
505   // according to the parameter set for the reconstructor
506   if (fPrintLevel >= 1) cout << "enter MakeEventToBeReconstructed" << endl;
507   ResetHitsForRec();
508   if (fRecGeantHits == 1) {
509     // Reconstruction from GEANT hits
510     // Back to the signal file
511     ((gAlice->TreeK())->GetCurrentFile())->cd();
512     // Signal hits
513     // AliMUON *MUON  = (AliMUON*) gAlice->GetModule("MUON"); // necessary ????
514     // Security on MUON ????
515     AddHitsForRecFromGEANT(gAlice->TreeH());
516     // Background hits
517     AddHitsForRecFromBkgGEANT(fBkgGeantTH, fBkgGeantHits);
518     // Sort HitsForRec in increasing order with respect to chamber number
519     SortHitsForRecWithIncreasingChamber();
520   }
521   else {
522     // Reconstruction from raw clusters
523     // AliMUON *MUON  = (AliMUON*) gAlice->GetModule("MUON"); // necessary ????
524     // Security on MUON ????
525     // TreeR assumed to be be "prepared" in calling function
526     // by "MUON->GetTreeR(nev)" ????
527     TTree *treeR = gAlice->TreeR();
528     AddHitsForRecFromRawClusters(treeR);
529     // No sorting: it is done automatically in the previous function
530   }
531   if (fPrintLevel >= 10) {
532     cout << "end of MakeEventToBeReconstructed" << endl;
533     cout << "NHitsForRec: " << fNHitsForRec << endl;
534     for (Int_t ch = 0; ch < kMaxMuonTrackingChambers; ch++) {
535       cout << "chamber(0...): " << ch
536            << "  NHitsForRec: " << fNHitsForRecPerChamber[ch]
537            << "  index(first HitForRec): " << fIndexOfFirstHitForRecPerChamber[ch]
538            << endl;
539       for (Int_t hit = fIndexOfFirstHitForRecPerChamber[ch];
540            hit < fIndexOfFirstHitForRecPerChamber[ch] + fNHitsForRecPerChamber[ch];
541            hit++) {
542         cout << "HitForRec index(0...): " << hit << endl;
543         ((*fHitsForRecPtr)[hit])->Dump();
544       }
545     }
546   }
547   return;
548 }
549
550   //__________________________________________________________________________
551 void AliMUONEventReconstructor::AddHitsForRecFromGEANT(TTree *TH)
552 {
553   // To add to the list of hits for reconstruction
554   // the GEANT signal hits from a hit tree TH.
555   if (fPrintLevel >= 2)
556     cout << "enter AddHitsForRecFromGEANT with TH: " << TH << endl;
557   if (TH == NULL) return;
558   AliMUON *pMUON  = (AliMUON*) gAlice->GetModule("MUON"); // necessary ????
559   // Security on MUON ????
560   // See whether it could be the same for signal and background ????
561   // Loop over tracks in tree
562   Int_t ntracks = (Int_t) TH->GetEntries();
563   if (fPrintLevel >= 2)
564     cout << "ntracks: " << ntracks << endl;
565   for (Int_t track = 0; track < ntracks; track++) {
566     gAlice->ResetHits();
567     TH->GetEvent(track);
568     // Loop over hits
569     Int_t hit = 0;
570     for (AliMUONHit* mHit = (AliMUONHit*) pMUON->FirstHit(-1); 
571          mHit;
572          mHit = (AliMUONHit*) pMUON->NextHit(), hit++) {
573       NewHitForRecFromGEANT(mHit,track, hit, 1);
574     } // end of hit loop
575   } // end of track loop
576   return;
577 }
578
579   //__________________________________________________________________________
580 void AliMUONEventReconstructor::AddHitsForRecFromBkgGEANT(TTree *TH, TClonesArray *Hits)
581 {
582   // To add to the list of hits for reconstruction
583   // the GEANT background hits from a hit tree TH and a pointer Hits to a hit list.
584   // How to have only one function "AddHitsForRecFromGEANT" ????
585   if (fPrintLevel >= 2)
586     cout << "enter AddHitsForRecFromBkgGEANT with TH: " << TH << endl;
587   if (TH == NULL) return;
588   // Loop over tracks in tree
589   Int_t ntracks = (Int_t) TH->GetEntries();
590   if (fPrintLevel >= 2)
591     cout << "ntracks: " << ntracks << endl;
592   for (Int_t track = 0; track < ntracks; track++) {
593     if (Hits) Hits->Clear();
594     TH->GetEvent(track);
595     // Loop over hits
596     for (Int_t hit = 0; hit < Hits->GetEntriesFast(); hit++) {
597       NewHitForRecFromGEANT((AliMUONHit*) (*Hits)[hit], track, hit, 0);
598     } // end of hit loop
599   } // end of track loop
600   return;
601 }
602
603   //__________________________________________________________________________
604 AliMUONHitForRec* AliMUONEventReconstructor::NewHitForRecFromGEANT(AliMUONHit* Hit, Int_t TrackNumber, Int_t HitNumber, Int_t Signal)
605 {
606   // To make a new hit for reconstruction from a GEANT hit pointed to by "Hit",
607   // with hit number "HitNumber" in the track numbered "TrackNumber",
608   // either from signal ("Signal" = 1) or background ("Signal" = 0) event.
609   // Selects hits in tracking (not trigger) chambers.
610   // Takes into account the efficiency (fEfficiency)
611   // and the smearing from resolution (fBendingResolution and fNonBendingResolution).
612   // Adds a condition on the radius between RMin and RMax
613   // to better simulate the real chambers.
614   // Returns the pointer to the new hit for reconstruction,
615   // or NULL in case of inefficiency or non tracking chamber or bad radius.
616   // No condition on at most 20 cm from a muon from a resonance
617   // like in Fortran TRACKF_STAT.
618   AliMUONHitForRec* hitForRec;
619   Double_t bendCoor, nonBendCoor, radius;
620   Int_t chamber = Hit->Chamber() - 1; // chamber(0...)
621   // only in tracking chambers (fChamber starts at 1)
622   if (chamber >= kMaxMuonTrackingChambers) return NULL;
623   // only if hit is efficient (keep track for checking ????)
624   if (gRandom->Rndm() > fEfficiency) return NULL;
625   // only if radius between RMin and RMax
626   bendCoor = Hit->Y();
627   nonBendCoor = Hit->X();
628   radius = TMath::Sqrt((bendCoor * bendCoor) + (nonBendCoor * nonBendCoor));
629   // This cut is not needed with a realistic chamber geometry !!!!
630 //   if ((radius < fRMin[chamber]) || (radius > fRMax[chamber])) return NULL;
631   // new AliMUONHitForRec from GEANT hit and increment number of AliMUONHitForRec's
632   hitForRec = new ((*fHitsForRecPtr)[fNHitsForRec]) AliMUONHitForRec(Hit);
633   fNHitsForRec++;
634   // add smearing from resolution
635   hitForRec->SetBendingCoor(bendCoor + gRandom->Gaus(0., fBendingResolution));
636   hitForRec->SetNonBendingCoor(nonBendCoor
637                                + gRandom->Gaus(0., fNonBendingResolution));
638 //   // !!!! without smearing
639 //   hitForRec->SetBendingCoor(bendCoor);
640 //   hitForRec->SetNonBendingCoor(nonBendCoor);
641   // more information into HitForRec
642   //  resolution: angular effect to be added here ????
643   hitForRec->SetBendingReso2(fBendingResolution * fBendingResolution);
644   hitForRec->SetNonBendingReso2(fNonBendingResolution * fNonBendingResolution);
645   //  GEANT track info
646   hitForRec->SetHitNumber(HitNumber);
647   hitForRec->SetTHTrack(TrackNumber);
648   hitForRec->SetGeantSignal(Signal);
649   if (fPrintLevel >= 10) {
650     cout << "track: " << TrackNumber << " hit: " << HitNumber << endl;
651     Hit->Dump();
652     cout << "AliMUONHitForRec number (1...): " << fNHitsForRec << endl;
653     hitForRec->Dump();}
654   return hitForRec;
655 }
656
657   //__________________________________________________________________________
658 void AliMUONEventReconstructor::SortHitsForRecWithIncreasingChamber()
659 {
660   // Sort HitsForRec's in increasing order with respect to chamber number.
661   // Uses the function "Compare".
662   // Update the information for HitsForRec per chamber too.
663   Int_t ch, nhits, prevch;
664   fHitsForRecPtr->Sort();
665   for (ch = 0; ch < kMaxMuonTrackingChambers; ch++) {
666     fNHitsForRecPerChamber[ch] = 0;
667     fIndexOfFirstHitForRecPerChamber[ch] = 0;
668   }
669   prevch = 0; // previous chamber
670   nhits = 0; // number of hits in current chamber
671   // Loop over HitsForRec
672   for (Int_t hit = 0; hit < fNHitsForRec; hit++) {
673     // chamber number (0...)
674     ch = ((AliMUONHitForRec*)  ((*fHitsForRecPtr)[hit]))->GetChamberNumber();
675     // increment number of hits in current chamber
676     (fNHitsForRecPerChamber[ch])++;
677     // update index of first HitForRec in current chamber
678     // if chamber number different from previous one
679     if (ch != prevch) {
680       fIndexOfFirstHitForRecPerChamber[ch] = hit;
681       prevch = ch;
682     }
683   }
684   return;
685 }
686
687 //   //__________________________________________________________________________
688 // void AliMUONEventReconstructor::AddHitsForRecFromCathodeCorrelations(TTree* TC)
689 // {
690 //   // OLD VERSION WHEN ONE ONE WAS USING SO CALLED CATHODE CORRELATIONS
691 //   // To add to the list of hits for reconstruction
692 //   // the (cathode correlated) raw clusters
693 //   // No condition added, like in Fortran TRACKF_STAT,
694 //   // on the radius between RMin and RMax.
695 //   AliMUONHitForRec *hitForRec;
696 //   if (fPrintLevel >= 1) cout << "enter AddHitsForRecFromCathodeCorrelations" << endl;
697 //   AliMUON *MUON  = (AliMUON*) gAlice->GetModule("MUON"); // necessary ????
698 //   // Security on MUON ????
699 //   // Loop over tracking chambers
700 //   for (Int_t ch = 0; ch < kMaxMuonTrackingChambers; ch++) {
701 //     // number of HitsForRec to 0 for the chamber
702 //     fNHitsForRecPerChamber[ch] = 0;
703 //     // index of first HitForRec for the chamber
704 //     if (ch == 0) fIndexOfFirstHitForRecPerChamber[ch] = 0;
705 //     else fIndexOfFirstHitForRecPerChamber[ch] = fNHitsForRec;
706 //     TClonesArray *reconst_hits  = MUON->ReconstHitsAddress(ch);
707 //     MUON->ResetReconstHits();
708 //     TC->GetEvent();
709 //     Int_t ncor = (Int_t)reconst_hits->GetEntries();
710 //     // Loop over (cathode correlated) raw clusters
711 //     for (Int_t cor = 0; cor < ncor; cor++) {
712 //       AliMUONReconstHit * mCor = 
713 //      (AliMUONReconstHit*) reconst_hits->UncheckedAt(cor);
714 //       // new AliMUONHitForRec from (cathode correlated) raw cluster
715 //       // and increment number of AliMUONHitForRec's (total and in chamber)
716 //       hitForRec = new ((*fHitsForRecPtr)[fNHitsForRec]) AliMUONHitForRec(mCor);
717 //       fNHitsForRec++;
718 //       (fNHitsForRecPerChamber[ch])++;
719 //       // more information into HitForRec
720 //       hitForRec->SetChamberNumber(ch);
721 //       hitForRec->SetHitNumber(cor);
722 //       // Z coordinate of the chamber (cm) with sign opposite to GEANT sign
723 //       // could (should) be more exact from chamber geometry ???? 
724 //       hitForRec->SetZ(-(&(MUON->Chamber(ch)))->Z());
725 //       if (fPrintLevel >= 10) {
726 //      cout << "chamber (0...): " << ch <<
727 //        " cathcorrel (0...): " << cor << endl;
728 //      mCor->Dump();
729 //      cout << "AliMUONHitForRec number (1...): " << fNHitsForRec << endl;
730 //      hitForRec->Dump();}
731 //     } // end of cluster loop
732 //   } // end of chamber loop
733 //   return;
734 // }
735
736   //__________________________________________________________________________
737 void AliMUONEventReconstructor::AddHitsForRecFromRawClusters(TTree* TR)
738 {
739   // To add to the list of hits for reconstruction all the raw clusters
740   // No condition added, like in Fortran TRACKF_STAT,
741   // on the radius between RMin and RMax.
742   AliMUONHitForRec *hitForRec;
743   AliMUONRawCluster *clus;
744   Int_t iclus, nclus;
745   TClonesArray *rawclusters;
746   if (fPrintLevel >= 1) cout << "enter AddHitsForRecFromRawClusters" << endl;
747   AliMUON *pMUON  = (AliMUON*) gAlice->GetModule("MUON"); // necessary ????
748   // Security on MUON ????
749   // Loop over tracking chambers
750   for (Int_t ch = 0; ch < kMaxMuonTrackingChambers; ch++) {
751     // number of HitsForRec to 0 for the chamber
752     fNHitsForRecPerChamber[ch] = 0;
753     // index of first HitForRec for the chamber
754     if (ch == 0) fIndexOfFirstHitForRecPerChamber[ch] = 0;
755     else fIndexOfFirstHitForRecPerChamber[ch] = fNHitsForRec;
756     rawclusters = pMUON->RawClustAddress(ch);
757     pMUON->ResetRawClusters();
758     TR->GetEvent((Int_t) (TR->GetEntries()) - 1); // to be checked ????
759     nclus = (Int_t) (rawclusters->GetEntries());
760     // Loop over (cathode correlated) raw clusters
761     for (iclus = 0; iclus < nclus; iclus++) {
762       clus = (AliMUONRawCluster*) rawclusters->UncheckedAt(iclus);
763       // new AliMUONHitForRec from raw cluster
764       // and increment number of AliMUONHitForRec's (total and in chamber)
765       hitForRec = new ((*fHitsForRecPtr)[fNHitsForRec]) AliMUONHitForRec(clus);
766       fNHitsForRec++;
767       (fNHitsForRecPerChamber[ch])++;
768       // more information into HitForRec
769       //  resolution: info should be already in raw cluster and taken from it ????
770       hitForRec->SetBendingReso2(fBendingResolution * fBendingResolution);
771       hitForRec->SetNonBendingReso2(fNonBendingResolution * fNonBendingResolution);
772       //  original raw cluster
773       hitForRec->SetChamberNumber(ch);
774       hitForRec->SetHitNumber(iclus);
775       // Z coordinate of the raw cluster (cm)
776       hitForRec->SetZ(clus->fZ[0]);
777       if (fPrintLevel >= 10) {
778         cout << "chamber (0...): " << ch <<
779           " raw cluster (0...): " << iclus << endl;
780         clus->Dump();
781         cout << "AliMUONHitForRec number (1...): " << fNHitsForRec << endl;
782         hitForRec->Dump();}
783     } // end of cluster loop
784   } // end of chamber loop
785   return;
786 }
787
788   //__________________________________________________________________________
789 void AliMUONEventReconstructor::MakeSegments(void)
790 {
791   // To make the list of segments in all stations,
792   // from the list of hits to be reconstructed
793   if (fPrintLevel >= 1) cout << "enter MakeSegments" << endl;
794   ResetSegments();
795   // Loop over stations
796   for (Int_t st = 0; st < kMaxMuonTrackingStations; st++)
797     MakeSegmentsPerStation(st); 
798   if (fPrintLevel >= 10) {
799     cout << "end of MakeSegments" << endl;
800     for (Int_t st = 0; st < kMaxMuonTrackingStations; st++) {
801       cout << "station(0...): " << st
802            << "  Segments: " << fNSegments[st]
803            << endl;
804       for (Int_t seg = 0;
805            seg < fNSegments[st];
806            seg++) {
807         cout << "Segment index(0...): " << seg << endl;
808         ((*fSegmentsPtr[st])[seg])->Dump();
809       }
810     }
811   }
812   return;
813 }
814
815   //__________________________________________________________________________
816 void AliMUONEventReconstructor::MakeSegmentsPerStation(Int_t Station)
817 {
818   // To make the list of segments in station number "Station" (0...)
819   // from the list of hits to be reconstructed.
820   // Updates "fNSegments"[Station].
821   // Segments in stations 4 and 5 are sorted
822   // according to increasing absolute value of "impact parameter"
823   AliMUONHitForRec *hit1Ptr, *hit2Ptr;
824   AliMUONSegment *segment;
825   Bool_t last2st;
826   Double_t bendingSlope, distBend, distNonBend, extBendCoor, extNonBendCoor,
827       impactParam = 0., maxImpactParam = 0., minImpactParam = 0.; // =0 to avoid compilation warnings.
828   AliMUON *pMUON  = (AliMUON*) gAlice->GetModule("MUON"); // necessary ????
829   if (fPrintLevel >= 1)
830     cout << "enter MakeSegmentsPerStation (0...) " << Station << endl;
831   // first and second chambers (0...) in the station
832   Int_t ch1 = 2 * Station;
833   Int_t ch2 = ch1 + 1;
834   // variable true for stations downstream of the dipole:
835   // Station(0..4) equal to 3 or 4
836   if ((Station == 3) || (Station == 4)) {
837     last2st = kTRUE;
838     // maximum impact parameter (cm) according to fMinBendingMomentum...
839     maxImpactParam =
840       TMath::Abs(GetImpactParamFromBendingMomentum(fMinBendingMomentum));
841     // minimum impact parameter (cm) according to fMaxBendingMomentum...
842     minImpactParam =
843       TMath::Abs(GetImpactParamFromBendingMomentum(fMaxBendingMomentum));
844   }
845   else last2st = kFALSE;
846   // extrapolation factor from Z of first chamber to Z of second chamber
847   // dZ to be changed to take into account fine structure of chambers ????
848   Double_t extrapFact =
849     (&(pMUON->Chamber(ch2)))->Z() / (&(pMUON->Chamber(ch1)))->Z();
850   // index for current segment
851   Int_t segmentIndex = 0;
852   // Loop over HitsForRec in the first chamber of the station
853   for (Int_t hit1 = fIndexOfFirstHitForRecPerChamber[ch1];
854        hit1 < fIndexOfFirstHitForRecPerChamber[ch1] + fNHitsForRecPerChamber[ch1];
855        hit1++) {
856     // pointer to the HitForRec
857     hit1Ptr = (AliMUONHitForRec*) ((*fHitsForRecPtr)[hit1]);
858     // extrapolation,
859     // on the straight line joining the HitForRec to the vertex (0,0,0),
860     // to the Z of the second chamber of the station
861     extBendCoor = extrapFact * hit1Ptr->GetBendingCoor();
862     extNonBendCoor = extrapFact * hit1Ptr->GetNonBendingCoor();
863     // Loop over HitsForRec in the second chamber of the station
864     for (Int_t hit2 = fIndexOfFirstHitForRecPerChamber[ch2];
865          hit2 < fIndexOfFirstHitForRecPerChamber[ch2] + fNHitsForRecPerChamber[ch2];
866          hit2++) {
867       // pointer to the HitForRec
868       hit2Ptr = (AliMUONHitForRec*) ((*fHitsForRecPtr)[hit2]);
869       // absolute values of distances, in bending and non bending planes,
870       // between the HitForRec in the second chamber
871       // and the previous extrapolation
872       distBend = TMath::Abs(hit2Ptr->GetBendingCoor() - extBendCoor);
873       distNonBend = TMath::Abs(hit2Ptr->GetNonBendingCoor() - extNonBendCoor);
874       if (last2st) {
875         // bending slope
876         bendingSlope = (hit1Ptr->GetBendingCoor() - hit2Ptr->GetBendingCoor()) /
877           (hit1Ptr->GetZ() - hit2Ptr->GetZ());
878         // absolute value of impact parameter
879         impactParam =
880           TMath::Abs(hit1Ptr->GetBendingCoor() - hit2Ptr->GetZ() * bendingSlope);
881       }
882       // check for distances not too large,
883       // and impact parameter not too big if stations downstream of the dipole.
884       // Conditions "distBend" and "impactParam" correlated for these stations ????
885       if ((distBend < fSegmentMaxDistBending[Station]) &&
886           (distNonBend < fSegmentMaxDistNonBending[Station]) &&
887           (!last2st || (impactParam < maxImpactParam)) &&
888           (!last2st || (impactParam > minImpactParam))) {
889         // make new segment
890         segment = new ((*fSegmentsPtr[Station])[segmentIndex])
891           AliMUONSegment(hit1Ptr, hit2Ptr);
892         // update "link" to this segment from the hit in the first chamber
893         if (hit1Ptr->GetNSegments() == 0)
894           hit1Ptr->SetIndexOfFirstSegment(segmentIndex);
895         hit1Ptr->SetNSegments(hit1Ptr->GetNSegments() + 1);
896         if (fPrintLevel >= 10) {
897           cout << "segmentIndex(0...): " << segmentIndex
898                << "  distBend: " << distBend
899                << "  distNonBend: " << distNonBend
900                << endl;
901           segment->Dump();
902           cout << "HitForRec in first chamber" << endl;
903           hit1Ptr->Dump();
904           cout << "HitForRec in second chamber" << endl;
905           hit2Ptr->Dump();
906         };
907         // increment index for current segment
908         segmentIndex++;
909       }
910     } //for (Int_t hit2
911   } // for (Int_t hit1...
912   fNSegments[Station] = segmentIndex;
913   // Sorting according to "impact parameter" if station(1..5) 4 or 5,
914   // i.e. Station(0..4) 3 or 4, using the function "Compare".
915   // After this sorting, it is impossible to use
916   // the "fNSegments" and "fIndexOfFirstSegment"
917   // of the HitForRec in the first chamber to explore all segments formed with it.
918   // Is this sorting really needed ????
919   if ((Station == 3) || (Station == 4)) (fSegmentsPtr[Station])->Sort();
920   if (fPrintLevel >= 1) cout << "Station: " << Station << "  NSegments: "
921                              << fNSegments[Station] << endl;
922   return;
923 }
924
925   //__________________________________________________________________________
926 void AliMUONEventReconstructor::MakeTracks(void)
927 {
928   // To make the tracks,
929   // from the list of segments and points in all stations
930   if (fPrintLevel >= 1) cout << "enter MakeTracks" << endl;
931   // The order may be important for the following Reset's
932   ResetTracks();
933   ResetTrackHits();
934   // Look for candidates from at least 3 aligned points in stations(1..) 4 and 5
935   MakeTrackCandidates();
936   // Follow tracks in stations(1..) 3, 2 and 1
937   FollowTracks();
938   // Remove double tracks
939   RemoveDoubleTracks();
940   return;
941 }
942
943   //__________________________________________________________________________
944 Int_t AliMUONEventReconstructor::MakeTrackCandidatesWithTwoSegments(AliMUONSegment *BegSegment)
945 {
946   // To make track candidates with two segments in stations(1..) 4 and 5,
947   // the first segment being pointed to by "BegSegment".
948   // Returns the number of such track candidates.
949   Int_t endStation, iEndSegment, nbCan2Seg;
950   AliMUONSegment *endSegment, *extrapSegment;
951   AliMUONTrack *recTrack;
952   Double_t mcsFactor;
953   if (fPrintLevel >= 1) cout << "enter MakeTrackCandidatesWithTwoSegments" << endl;
954   // Station for the end segment
955   endStation = 7 - (BegSegment->GetHitForRec1())->GetChamberNumber() / 2;
956   // multiple scattering factor corresponding to one chamber
957   mcsFactor = 0.0136 /
958     GetBendingMomentumFromImpactParam(BegSegment->GetBendingImpact());
959   mcsFactor     = fChamberThicknessInX0 * mcsFactor * mcsFactor;
960   // linear extrapolation to end station
961   extrapSegment =
962     BegSegment->CreateSegmentFromLinearExtrapToStation(endStation, mcsFactor);
963   // number of candidates with 2 segments to 0
964   nbCan2Seg = 0;
965   // Loop over segments in the end station
966   for (iEndSegment = 0; iEndSegment < fNSegments[endStation]; iEndSegment++) {
967     // pointer to segment
968     endSegment = (AliMUONSegment*) ((*fSegmentsPtr[endStation])[iEndSegment]);
969     // test compatibility between current segment and "extrapSegment"
970     // 4 because 4 quantities in chi2
971     if ((endSegment->
972          NormalizedChi2WithSegment(extrapSegment,
973                                    fMaxSigma2Distance)) <= 4.0) {
974       // both segments compatible:
975       // make track candidate from "begSegment" and "endSegment"
976       if (fPrintLevel >= 2)
977         cout << "TrackCandidate with Segment " << iEndSegment <<
978           " in Station(0..) " << endStation << endl;
979       // flag for both segments in one track:
980       // to be done in track constructor ????
981       BegSegment->SetInTrack(kTRUE);
982       endSegment->SetInTrack(kTRUE);
983       recTrack = new ((*fRecTracksPtr)[fNRecTracks])
984         AliMUONTrack(BegSegment, endSegment, this);
985       fNRecTracks++;
986       if (fPrintLevel >= 10) recTrack->RecursiveDump();
987       // increment number of track candidates with 2 segments
988       nbCan2Seg++;
989     }
990   } // for (iEndSegment = 0;...
991   delete extrapSegment; // should not delete HitForRec's it points to !!!!
992   return nbCan2Seg;
993 }
994
995   //__________________________________________________________________________
996 Int_t AliMUONEventReconstructor::MakeTrackCandidatesWithOneSegmentAndOnePoint(AliMUONSegment *BegSegment)
997 {
998   // To make track candidates with one segment and one point
999   // in stations(1..) 4 and 5,
1000   // the segment being pointed to by "BegSegment".
1001   Int_t ch, ch1, ch2, endStation, iHit, iHitMax, iHitMin, nbCan1Seg1Hit;
1002   AliMUONHitForRec *extrapHitForRec, *hit;
1003   AliMUONTrack *recTrack;
1004   Double_t mcsFactor;
1005   if (fPrintLevel >= 1)
1006     cout << "enter MakeTrackCandidatesWithOneSegmentAndOnePoint" << endl;
1007   // station for the end point
1008   endStation = 7 - (BegSegment->GetHitForRec1())->GetChamberNumber() / 2;
1009   // multiple scattering factor corresponding to one chamber
1010   mcsFactor = 0.0136 /
1011     GetBendingMomentumFromImpactParam(BegSegment->GetBendingImpact());
1012   mcsFactor     = fChamberThicknessInX0 * mcsFactor * mcsFactor;
1013   // first and second chambers(0..) in the end station
1014   ch1 = 2 * endStation;
1015   ch2 = ch1 + 1;
1016   // number of candidates to 0
1017   nbCan1Seg1Hit = 0;
1018   // Loop over chambers of the end station
1019   for (ch = ch2; ch >= ch1; ch--) {
1020     // linear extrapolation to chamber
1021     extrapHitForRec =
1022       BegSegment->CreateHitForRecFromLinearExtrapToChamber(ch, mcsFactor);
1023     // limits for the hit index in the loop
1024     iHitMin = fIndexOfFirstHitForRecPerChamber[ch];
1025     iHitMax = iHitMin + fNHitsForRecPerChamber[ch];
1026     // Loop over HitForRec's in the chamber
1027     for (iHit = iHitMin; iHit < iHitMax; iHit++) {
1028       // pointer to HitForRec
1029       hit = (AliMUONHitForRec*) ((*fHitsForRecPtr)[iHit]);
1030       // test compatibility between current HitForRec and "extrapHitForRec"
1031       // 2 because 2 quantities in chi2
1032       if ((hit->
1033            NormalizedChi2WithHitForRec(extrapHitForRec,
1034                                        fMaxSigma2Distance)) <= 2.0) {
1035         // both HitForRec's compatible:
1036         // make track candidate from begSegment and current HitForRec
1037         if (fPrintLevel >= 2)
1038           cout << "TrackCandidate with HitForRec " << iHit <<
1039             " in Chamber(0..) " << ch << endl;
1040         // flag for beginning segments in one track:
1041         // to be done in track constructor ????
1042         BegSegment->SetInTrack(kTRUE);
1043         recTrack = new ((*fRecTracksPtr)[fNRecTracks])
1044           AliMUONTrack(BegSegment, hit, this);
1045         // the right place to eliminate "double counting" ???? how ????
1046         fNRecTracks++;
1047         if (fPrintLevel >= 10) recTrack->RecursiveDump();
1048         // increment number of track candidates
1049         nbCan1Seg1Hit++;
1050       }
1051     } // for (iHit = iHitMin;...
1052     delete extrapHitForRec;
1053   } // for (ch = ch2;...
1054   return nbCan1Seg1Hit;
1055 }
1056
1057   //__________________________________________________________________________
1058 void AliMUONEventReconstructor::MakeTrackCandidates(void)
1059 {
1060   // To make track candidates
1061   // with at least 3 aligned points in stations(1..) 4 and 5
1062   // (two Segment's or one Segment and one HitForRec)
1063   Int_t begStation, iBegSegment, nbCan1Seg1Hit, nbCan2Seg;
1064   AliMUONSegment *begSegment;
1065   if (fPrintLevel >= 1) cout << "enter MakeTrackCandidates" << endl;
1066   // Loop over stations(1..) 5 and 4 for the beginning segment
1067   for (begStation = 4; begStation > 2; begStation--) {
1068     // Loop over segments in the beginning station
1069     for (iBegSegment = 0; iBegSegment < fNSegments[begStation]; iBegSegment++) {
1070       // pointer to segment
1071       begSegment = (AliMUONSegment*) ((*fSegmentsPtr[begStation])[iBegSegment]);
1072       if (fPrintLevel >= 2)
1073         cout << "look for TrackCandidate's with Segment " << iBegSegment <<
1074           " in Station(0..) " << begStation << endl;
1075       // Look for track candidates with two segments,
1076       // "begSegment" and all compatible segments in other station.
1077       // Only for beginning station(1..) 5
1078       // because candidates with 2 segments have to looked for only once.
1079       if (begStation == 4)
1080         nbCan2Seg = MakeTrackCandidatesWithTwoSegments(begSegment);
1081       // Look for track candidates with one segment and one point,
1082       // "begSegment" and all compatible HitForRec's in other station.
1083       // Only if "begSegment" does not belong already to a track candidate.
1084       // Is that a too strong condition ????
1085       if (!(begSegment->GetInTrack()))
1086         nbCan1Seg1Hit = MakeTrackCandidatesWithOneSegmentAndOnePoint(begSegment);
1087     } // for (iBegSegment = 0;...
1088   } // for (begStation = 4;...
1089   return;
1090 }
1091
1092   //__________________________________________________________________________
1093 void AliMUONEventReconstructor::FollowTracks(void)
1094 {
1095   // Follow tracks in stations(1..) 3, 2 and 1
1096   // too long: should be made more modular !!!!
1097   AliMUONHitForRec *bestHit, *extrapHit, *extrapCorrHit, *hit;
1098   AliMUONSegment *bestSegment, *extrapSegment, *extrapCorrSegment, *segment;
1099   AliMUONTrack *track, *nextTrack;
1100   AliMUONTrackParam *trackParam1, trackParam[2], trackParamVertex;
1101   // -1 to avoid compilation warnings
1102   Int_t ch = -1, chInStation, chBestHit = -1, iHit, iSegment, station, trackIndex; 
1103   Double_t bestChi2, chi2, dZ1, dZ2, dZ3, maxSigma2Distance, mcsFactor;
1104   Double_t bendingMomentum, chi2Norm = 0.;
1105   AliMUON *pMUON = (AliMUON*) gAlice->GetModule("MUON"); // necessary ????
1106   // local maxSigma2Distance, for easy increase in testing
1107   maxSigma2Distance = fMaxSigma2Distance;
1108   if (fPrintLevel >= 2)
1109     cout << "enter FollowTracks" << endl;
1110   // Loop over track candidates
1111   track = (AliMUONTrack*) fRecTracksPtr->First();
1112   trackIndex = -1;
1113   while (track) {
1114     // Follow function for each track candidate ????
1115     trackIndex++;
1116     nextTrack = (AliMUONTrack*) fRecTracksPtr->After(track); // prepare next track
1117     if (fPrintLevel >= 2)
1118       cout << "FollowTracks: track candidate(0..): " << trackIndex << endl;
1119     // Fit track candidate
1120     track->SetFitMCS(0); // without multiple Coulomb scattering
1121     track->SetFitNParam(3); // with 3 parameters (X = Y = 0)
1122     track->SetFitStart(0); // from parameters at vertex
1123     track->Fit();
1124     if (fPrintLevel >= 10) {
1125       cout << "FollowTracks: track candidate(0..): " << trackIndex
1126            << " after fit in stations(0..) 3 and 4" << endl;
1127       track->RecursiveDump();
1128     }
1129     // Loop over stations(1..) 3, 2 and 1
1130     // something SPECIAL for stations 2 and 1 for majority 3 coincidence ????
1131     // otherwise: majority coincidence 2 !!!!
1132     for (station = 2; station >= 0; station--) {
1133       // Track parameters at first track hit (smallest Z)
1134       trackParam1 = ((AliMUONTrackHit*)
1135                      (track->GetTrackHitsPtr()->First()))->GetTrackParam();
1136       // extrapolation to station
1137       trackParam1->ExtrapToStation(station, trackParam);
1138       extrapSegment = new AliMUONSegment(); //  empty segment
1139       extrapCorrSegment = new AliMUONSegment(); //  empty corrected segment
1140       // multiple scattering factor corresponding to one chamber
1141       // and momentum in bending plane (not total)
1142       mcsFactor = 0.0136 * trackParam1->GetInverseBendingMomentum();
1143       mcsFactor = fChamberThicknessInX0 * mcsFactor * mcsFactor;
1144       // Z difference from previous station
1145       dZ1 = (&(pMUON->Chamber(2 * station)))->Z() -
1146         (&(pMUON->Chamber(2 * station + 2)))->Z();
1147       // Z difference between the two previous stations
1148       dZ2 = (&(pMUON->Chamber(2 * station + 2)))->Z() -
1149         (&(pMUON->Chamber(2 * station + 4)))->Z();
1150       // Z difference between the two chambers in the previous station
1151       dZ3 = (&(pMUON->Chamber(2 * station)))->Z() -
1152         (&(pMUON->Chamber(2 * station + 1)))->Z();
1153       extrapSegment->SetBendingCoorReso2(fBendingResolution * fBendingResolution);
1154       extrapSegment->
1155         SetNonBendingCoorReso2(fNonBendingResolution * fNonBendingResolution);
1156       extrapSegment->UpdateFromStationTrackParam
1157         (trackParam, mcsFactor, dZ1, dZ2, dZ3, station,
1158          trackParam1->GetInverseBendingMomentum());
1159       // same thing for corrected segment
1160       // better to use copy constructor, after checking that it works properly !!!!
1161       extrapCorrSegment->SetBendingCoorReso2(fBendingResolution * fBendingResolution);
1162       extrapCorrSegment->
1163         SetNonBendingCoorReso2(fNonBendingResolution * fNonBendingResolution);
1164       extrapCorrSegment->UpdateFromStationTrackParam
1165         (trackParam, mcsFactor, dZ1, dZ2, dZ3, station,
1166          trackParam1->GetInverseBendingMomentum());
1167       bestChi2 = 5.0;
1168       bestSegment = NULL;
1169       if (fPrintLevel >= 10) {
1170         cout << "FollowTracks: track candidate(0..): " << trackIndex
1171              << " Look for segment in station(0..): " << station << endl;
1172       }
1173       // Loop over segments in station
1174       for (iSegment = 0; iSegment < fNSegments[station]; iSegment++) {
1175         // Look for best compatible Segment in station
1176         // should consider all possibilities ????
1177         // multiple scattering ????
1178         // separation in 2 functions: Segment and HitForRec ????
1179         segment = (AliMUONSegment*) ((*fSegmentsPtr[station])[iSegment]);
1180         // correction of corrected segment (fBendingCoor and fNonBendingCoor)
1181         // according to real Z value of "segment" and slopes of "extrapSegment"
1182         extrapCorrSegment->
1183           SetBendingCoor(extrapSegment->GetBendingCoor() +
1184                          extrapSegment->GetBendingSlope() *
1185                          (segment->GetHitForRec1()->GetZ() -
1186                           (&(pMUON->Chamber(2 * station)))->Z()));
1187         extrapCorrSegment->
1188           SetNonBendingCoor(extrapSegment->GetNonBendingCoor() +
1189                             extrapSegment->GetNonBendingSlope() *
1190                             (segment->GetHitForRec1()->GetZ() -
1191                              (&(pMUON->Chamber(2 * station)))->Z()));
1192         chi2 = segment->
1193           NormalizedChi2WithSegment(extrapCorrSegment, maxSigma2Distance);
1194         if (chi2 < bestChi2) {
1195           // update best Chi2 and Segment if better found
1196           bestSegment = segment;
1197           bestChi2 = chi2;
1198         }
1199       }
1200       if (bestSegment) {
1201         // best segment found: add it to track candidate
1202         track->AddSegment(bestSegment);
1203         // set track parameters at these two TrakHit's
1204         track->SetTrackParamAtHit(track->GetNTrackHits() - 2, &(trackParam[0]));
1205         track->SetTrackParamAtHit(track->GetNTrackHits() - 1, &(trackParam[1]));
1206         if (fPrintLevel >= 10) {
1207           cout << "FollowTracks: track candidate(0..): " << trackIndex
1208                << " Added segment in station(0..): " << station << endl;
1209           track->RecursiveDump();
1210         }
1211       }
1212       else {
1213         // No best segment found:
1214         // Look for best compatible HitForRec in station:
1215         // should consider all possibilities ????
1216         // multiple scattering ???? do about like for extrapSegment !!!!
1217         extrapHit = new AliMUONHitForRec(); //  empty hit
1218         extrapCorrHit = new AliMUONHitForRec(); //  empty corrected hit
1219         bestChi2 = 3.0;
1220         bestHit = NULL;
1221         if (fPrintLevel >= 10) {
1222           cout << "FollowTracks: track candidate(0..): " << trackIndex
1223                << " Segment not found, look for hit in station(0..): " << station
1224                << endl;
1225         }
1226         // Loop over chambers of the station
1227         for (chInStation = 0; chInStation < 2; chInStation++) {
1228           // coordinates of extrapolated hit
1229           extrapHit->
1230             SetBendingCoor((&(trackParam[chInStation]))->GetBendingCoor());
1231           extrapHit->
1232             SetNonBendingCoor((&(trackParam[chInStation]))->GetNonBendingCoor());
1233           // resolutions from "extrapSegment"
1234           extrapHit->SetBendingReso2(extrapSegment->GetBendingCoorReso2());
1235           extrapHit->SetNonBendingReso2(extrapSegment->GetNonBendingCoorReso2());
1236           // same things for corrected hit
1237           // better to use copy constructor, after checking that it works properly !!!!
1238           extrapCorrHit->
1239             SetBendingCoor((&(trackParam[chInStation]))->GetBendingCoor());
1240           extrapCorrHit->
1241             SetNonBendingCoor((&(trackParam[chInStation]))->GetNonBendingCoor());
1242           extrapHit->SetBendingReso2(extrapSegment->GetBendingCoorReso2());
1243           extrapHit->SetNonBendingReso2(extrapSegment->GetNonBendingCoorReso2());
1244           // Loop over hits in the chamber
1245           ch = 2 * station + chInStation;
1246           for (iHit = fIndexOfFirstHitForRecPerChamber[ch];
1247                iHit < fIndexOfFirstHitForRecPerChamber[ch] +
1248                  fNHitsForRecPerChamber[ch];
1249                iHit++) {
1250             hit = (AliMUONHitForRec*) ((*fHitsForRecPtr)[iHit]);
1251             // correction of corrected hit (fBendingCoor and fNonBendingCoor)
1252             // according to real Z value of "hit" and slopes of right "trackParam"
1253             extrapCorrHit->
1254               SetBendingCoor((&(trackParam[chInStation]))->GetBendingCoor() +
1255                              (&(trackParam[chInStation]))->GetBendingSlope() *
1256                              (hit->GetZ() -
1257                               (&(trackParam[chInStation]))->GetZ()));
1258             extrapCorrHit->
1259               SetNonBendingCoor((&(trackParam[chInStation]))->GetNonBendingCoor() +
1260                                 (&(trackParam[chInStation]))->GetNonBendingSlope() *
1261                                 (hit->GetZ() -
1262                                  (&(trackParam[chInStation]))->GetZ()));
1263             // condition for hit not already in segment ????
1264             chi2 = hit->NormalizedChi2WithHitForRec(extrapHit, maxSigma2Distance);
1265             if (chi2 < bestChi2) {
1266               // update best Chi2 and HitForRec if better found
1267               bestHit = hit;
1268               bestChi2 = chi2;
1269               chBestHit = chInStation;
1270             }
1271           }
1272         }
1273         if (bestHit) {
1274           // best hit found: add it to track candidate
1275           track->AddHitForRec(bestHit);
1276           // set track parameters at this TrackHit
1277           track->SetTrackParamAtHit(track->GetNTrackHits() - 1,
1278                                     &(trackParam[chBestHit]));
1279           if (fPrintLevel >= 10) {
1280             cout << "FollowTracks: track candidate(0..): " << trackIndex
1281                  << " Added hit in station(0..): " << station << endl;
1282             track->RecursiveDump();
1283           }
1284         }
1285         else {
1286           // Remove current track candidate
1287           // and corresponding TrackHit's, ...
1288           track->Remove();
1289           delete extrapSegment;
1290           delete extrapCorrSegment;
1291           delete extrapHit;
1292           delete extrapCorrHit;
1293           break; // stop the search for this candidate:
1294           // exit from the loop over station
1295         }
1296         delete extrapHit;
1297         delete extrapCorrHit;
1298       }
1299       delete extrapSegment;
1300       delete extrapCorrSegment;
1301       // Sort track hits according to increasing Z
1302       track->GetTrackHitsPtr()->Sort();
1303       // Update track parameters at first track hit (smallest Z)
1304       trackParam1 = ((AliMUONTrackHit*)
1305                      (track->GetTrackHitsPtr()->First()))->GetTrackParam();
1306       bendingMomentum = 0.;
1307       if (TMath::Abs(trackParam1->GetInverseBendingMomentum()) > 0.)
1308         bendingMomentum = TMath::Abs(1/(trackParam1->GetInverseBendingMomentum()));
1309       // Track removed if bendingMomentum not in window [min, max]
1310       if ((bendingMomentum < fMinBendingMomentum) || (bendingMomentum > fMaxBendingMomentum)) {
1311         track->Remove();
1312         break; // stop the search for this candidate:
1313         // exit from the loop over station 
1314       }
1315       // Track fit
1316       // with multiple Coulomb scattering if all stations
1317       if (station == 0) track->SetFitMCS(1);
1318       // without multiple Coulomb scattering if not all stations
1319       else track->SetFitMCS(0);
1320       track->SetFitNParam(5);  // with 5 parameters (momentum and position)
1321       track->SetFitStart(1);  // from parameters at first hit
1322       track->Fit();
1323       Double_t numberOfDegFree = (2.0 * track->GetNTrackHits() - 5);
1324       if (numberOfDegFree > 0) {
1325         chi2Norm =  track->GetFitFMin() / numberOfDegFree;
1326       } else {
1327         chi2Norm = 1.e10;
1328       }
1329       // Track removed if normalized chi2 too high
1330       if (chi2Norm > fMaxChi2) {
1331         track->Remove();
1332         break; // stop the search for this candidate:
1333         // exit from the loop over station 
1334       }
1335       if (fPrintLevel >= 10) {
1336         cout << "FollowTracks: track candidate(0..): " << trackIndex
1337              << " after fit from station(0..): " << station << " to 4" << endl;
1338         track->RecursiveDump();
1339       }
1340       // Track extrapolation to the vertex through the absorber (Branson)
1341       // after going through the first station
1342       if (station == 0) {
1343         trackParamVertex = *trackParam1;
1344         (&trackParamVertex)->ExtrapToVertex();
1345         track->SetTrackParamAtVertex(&trackParamVertex);
1346         if (fPrintLevel >= 1) {
1347           cout << "FollowTracks: track candidate(0..): " << trackIndex
1348                << " after extrapolation to vertex" << endl;
1349           track->RecursiveDump();
1350         }
1351       }
1352     } // for (station = 2;...
1353     // go really to next track
1354     track = nextTrack;
1355   } // while (track)
1356   // Compression of track array (necessary after Remove ????)
1357   fRecTracksPtr->Compress();
1358   return;
1359 }
1360
1361   //__________________________________________________________________________
1362 void AliMUONEventReconstructor::RemoveDoubleTracks(void)
1363 {
1364   // To remove double tracks.
1365   // Tracks are considered identical
1366   // if they have at least half of their hits in common.
1367   // Among two identical tracks, one keeps the track with the larger number of hits
1368   // or, if these numbers are equal, the track with the minimum Chi2.
1369   AliMUONTrack *track1, *track2, *trackToRemove;
1370   Bool_t identicalTracks;
1371   Int_t hitsInCommon, nHits1, nHits2;
1372   identicalTracks = kTRUE;
1373   while (identicalTracks) {
1374     identicalTracks = kFALSE;
1375     // Loop over first track of the pair
1376     track1 = (AliMUONTrack*) fRecTracksPtr->First();
1377     while (track1 && (!identicalTracks)) {
1378       nHits1 = track1->GetNTrackHits();
1379       // Loop over second track of the pair
1380       track2 = (AliMUONTrack*) fRecTracksPtr->After(track1);
1381       while (track2 && (!identicalTracks)) {
1382         nHits2 = track2->GetNTrackHits();
1383         // number of hits in common between two tracks
1384         hitsInCommon = track1->HitsInCommon(track2);
1385         // check for identical tracks
1386         if ((4 * hitsInCommon) >= (nHits1 + nHits2)) {
1387           identicalTracks = kTRUE;
1388           // decide which track to remove
1389           if (nHits1 > nHits2) trackToRemove = track2;
1390           else if (nHits1 < nHits2) trackToRemove = track1;
1391           else if ((track1->GetFitFMin()) < (track2->GetFitFMin()))
1392             trackToRemove = track2;
1393           else trackToRemove = track1;
1394           // remove it
1395           trackToRemove->Remove();
1396         }
1397         track2 = (AliMUONTrack*) fRecTracksPtr->After(track2);
1398       } // track2
1399       track1 = (AliMUONTrack*) fRecTracksPtr->After(track1);
1400     } // track1
1401   }
1402   return;
1403 }
1404
1405   //__________________________________________________________________________
1406 void AliMUONEventReconstructor::EventDump(void)
1407 {
1408   // Dump reconstructed event (track parameters at vertex and at first hit),
1409   // and the particle parameters
1410
1411   AliMUONTrack *track;
1412   AliMUONTrackParam *trackParam, *trackParam1;
1413   TParticle *p;
1414   Double_t bendingSlope, nonBendingSlope, pYZ;
1415   Double_t pX, pY, pZ, x, y, z, c;
1416   Int_t np, trackIndex, nTrackHits;
1417  
1418   if (fPrintLevel >= 1) cout << "****** enter EventDump ******" << endl;
1419   if (fPrintLevel >= 1) {
1420     cout << " Number of Reconstructed tracks :" <<  fNRecTracks << endl; 
1421   }
1422   fRecTracksPtr->Compress(); // for simple loop without "Next" since no hole
1423   // Loop over reconstructed tracks
1424   for (trackIndex = 0; trackIndex < fNRecTracks; trackIndex++) {
1425     if (fPrintLevel >= 1)
1426       cout << " track number: " << trackIndex << endl;
1427     // function for each track for modularity ????
1428     track = (AliMUONTrack*) ((*fRecTracksPtr)[trackIndex]);
1429     nTrackHits = track->GetNTrackHits();
1430     if (fPrintLevel >= 1)
1431       cout << " number of track hits: " << nTrackHits << endl;
1432     // track parameters at Vertex
1433     trackParam = track->GetTrackParamAtVertex();
1434     x = trackParam->GetNonBendingCoor();
1435     y = trackParam->GetBendingCoor();
1436     z = trackParam->GetZ();
1437     bendingSlope = trackParam->GetBendingSlope();
1438     nonBendingSlope = trackParam->GetNonBendingSlope();
1439     pYZ = 1/TMath::Abs(trackParam->GetInverseBendingMomentum());
1440     pZ = pYZ/TMath::Sqrt(1+bendingSlope*bendingSlope);
1441     pX = pZ * nonBendingSlope;
1442     pY = pZ * bendingSlope;
1443     c = TMath::Sign(1.0, trackParam->GetInverseBendingMomentum());
1444     if (fPrintLevel >= 1)
1445       printf(" track parameters at Vertex z= %f: X= %f Y= %f pX= %f pY= %f pZ= %f c= %f\n",
1446              z, x, y, pX, pY, pZ, c);
1447
1448     // track parameters at first hit
1449     trackParam1 = ((AliMUONTrackHit*)
1450                    (track->GetTrackHitsPtr()->First()))->GetTrackParam();
1451     x = trackParam1->GetNonBendingCoor();
1452     y = trackParam1->GetBendingCoor();
1453     z = trackParam1->GetZ();
1454     bendingSlope = trackParam1->GetBendingSlope();
1455     nonBendingSlope = trackParam1->GetNonBendingSlope();
1456     pYZ = 1/TMath::Abs(trackParam1->GetInverseBendingMomentum());
1457     pZ = pYZ/TMath::Sqrt(1.0 + bendingSlope * bendingSlope);
1458     pX = pZ * nonBendingSlope;
1459     pY = pZ * bendingSlope;
1460     c = TMath::Sign(1.0, trackParam1->GetInverseBendingMomentum());
1461     if (fPrintLevel >= 1)
1462       printf(" track parameters at z= %f: X= %f Y= %f pX= %f pY= %f pZ= %f c= %f\n",
1463              z, x, y, pX, pY, pZ, c);
1464   }
1465   // informations about generated particles
1466   np = gAlice->GetNtrack();
1467   printf(" **** number of generated particles: %d  \n", np);
1468   
1469   for (Int_t iPart = 0; iPart < np; iPart++) {
1470     p = gAlice->Particle(iPart);
1471     printf(" particle %d: type= %d px= %f py= %f pz= %f pdg= %d\n",
1472            iPart, p->GetPdgCode(), p->Px(), p->Py(), p->Pz(), p->GetPdgCode());    
1473   }
1474   return;
1475 }
1476
1477 void AliMUONEventReconstructor::FillEvent()
1478 {
1479 // Create a new AliMUONRecoEvent, fill its track list, then add it as a
1480 // leaf in the Event branch of TreeRecoEvent tree
1481    cout << "Enter FillEvent() ...\n";
1482
1483    if (!fRecoEvent) {
1484       fRecoEvent = new AliMUONRecoEvent();
1485    } else {
1486       fRecoEvent->Clear();
1487    }
1488    //save current directory
1489    TDirectory *current =  gDirectory;
1490    if (!fTreeFile)  fTreeFile  = new TFile("tree_reco.root", "RECREATE");
1491    if (!fEventTree) fEventTree = new TTree("TreeRecoEvent", "MUON reconstructed events");
1492    if (fRecoEvent->MakeDumpTracks(fRecTracksPtr)) {
1493       if (fPrintLevel > 1) fRecoEvent->EventInfo();
1494       TBranch *branch = fEventTree->GetBranch("Event");
1495       if (!branch) branch = fEventTree->Branch("Event", "AliMUONRecoEvent", &fRecoEvent, 64000,1);
1496       branch->SetAutoDelete();
1497       fTreeFile->cd();
1498       fEventTree->Fill();
1499       fTreeFile->Write();
1500    }
1501    // restore directory
1502    current->cd();
1503 }