]> git.uio.no Git - u/mrichter/AliRoot.git/blob - MUON/AliMUONTrack.cxx
Correcting preprocessor variable (ALI_MUON_GEOMETRY_MODULE_TRANSFORMS_H)
[u/mrichter/AliRoot.git] / MUON / AliMUONTrack.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 /* $Id$ */
17
18 ///////////////////////////////////////////////////
19 //
20 // Reconstructed track
21 // in
22 // ALICE
23 // dimuon
24 // spectrometer
25 //
26 ///////////////////////////////////////////////////
27
28 #include "AliMUONTrack.h"
29
30 #include "AliMUONTrackReconstructor.h" 
31 #include "AliMUONHitForRec.h" 
32 #include "AliMUONSegment.h" 
33 #include "AliMUONTrackHit.h"
34 #include "AliMUONTriggerTrack.h"
35 #include "AliMUONConstants.h"
36
37 #include "AliLog.h"
38
39 #include <Riostream.h> // for cout
40 #include <TMath.h>
41 #include <TMatrixD.h>
42 #include <TObjArray.h>
43 #include <TVirtualFitter.h>
44
45 #include <stdlib.h> // for exit()
46
47 // Functions to be minimized with Minuit
48 void TrackChi2(Int_t &NParam, Double_t *Gradient, Double_t &Chi2, Double_t *Param, Int_t Flag);
49 void TrackChi2MCS(Int_t &NParam, Double_t *Gradient, Double_t &Chi2, Double_t *Param, Int_t Flag);
50
51 void mnvertLocal(Double_t* a, Int_t l, Int_t m, Int_t n, Int_t& ifail);
52
53 Double_t MultipleScatteringAngle2(AliMUONTrackHit *TrackHit);
54
55 TVirtualFitter* AliMUONTrack::fgFitter = NULL; 
56
57 ClassImp(AliMUONTrack) // Class implementation in ROOT context
58
59 //__________________________________________________________________________
60 AliMUONTrack::AliMUONTrack()
61   : TObject() 
62 {
63   // Default constructor
64   fgFitter = 0;
65   fTrackReconstructor = 0;
66   fTrackHitsPtr = new TObjArray(10);
67   fTrackParamAtHit = new TClonesArray("AliMUONTrackParam",10);  
68   fHitForRecAtHit = new TClonesArray("AliMUONHitForRec",10); 
69   fTrackID = 0;
70 }
71
72   //__________________________________________________________________________
73 AliMUONTrack::AliMUONTrack(AliMUONSegment* BegSegment, AliMUONSegment* EndSegment, AliMUONTrackReconstructor* TrackReconstructor)
74   : TObject()
75 {
76   // Constructor from two Segment's
77   fTrackReconstructor = TrackReconstructor; // link back to TrackReconstructor
78   // memory allocation for the TObjArray of pointers to reconstructed TrackHit's
79   fTrackHitsPtr = new TObjArray(10);
80   fNTrackHits = 0;
81   AddSegment(BegSegment); // add hits from BegSegment
82   AddSegment(EndSegment); // add hits from EndSegment
83   fTrackHitsPtr->Sort(); // sort TrackHits according to increasing Z
84   SetTrackParamAtVertex(); // set track parameters at vertex
85   fTrackParamAtHit = new TClonesArray("AliMUONTrackParam",10);
86   fHitForRecAtHit = new TClonesArray("AliMUONHitForRec",10);
87   // set fit conditions...
88   fFitMCS = 0;
89   fFitNParam = 3;
90   fFitStart = 1;
91   fFitFMin = -1.0;
92   fMatchTrigger = kFALSE;
93   fChi2MatchTrigger = 0;
94   fTrackID = 0;
95   return;
96 }
97
98   //__________________________________________________________________________
99 AliMUONTrack::AliMUONTrack(AliMUONSegment* Segment, AliMUONHitForRec* HitForRec, AliMUONTrackReconstructor* TrackReconstructor)
100   : TObject()
101 {
102   // Constructor from one Segment and one HitForRec
103   fTrackReconstructor = TrackReconstructor; // link back to TrackReconstructor
104   // memory allocation for the TObjArray of pointers to reconstructed TrackHit's
105   fTrackHitsPtr = new TObjArray(10);
106   fNTrackHits = 0;
107   AddSegment(Segment); // add hits from Segment
108   AddHitForRec(HitForRec); // add HitForRec
109   fTrackHitsPtr->Sort(); // sort TrackHits according to increasing Z
110   SetTrackParamAtVertex(); // set track parameters at vertex
111   fTrackParamAtHit = new TClonesArray("AliMUONTrackParam",10);
112   fHitForRecAtHit = new TClonesArray("AliMUONHitForRec",10);
113   // set fit conditions...
114   fFitMCS = 0;
115   fFitNParam = 3;
116   fFitStart = 1;
117   fFitFMin = -1.0;
118   fMatchTrigger = kFALSE;
119   fChi2MatchTrigger = 0;
120   fTrackID = 0;
121   return;
122 }
123
124   //__________________________________________________________________________
125 AliMUONTrack::~AliMUONTrack()
126 {
127   // Destructor
128   if (fTrackHitsPtr) {
129     // delete the TObjArray of pointers to TrackHit's   
130     delete fTrackHitsPtr; 
131     fTrackHitsPtr = NULL;
132   }
133   
134   if (fTrackParamAtHit) {
135     // delete the TClonesArray of pointers to TrackParam
136     delete fTrackParamAtHit;
137     fTrackParamAtHit = NULL;
138   }
139
140   if (fHitForRecAtHit) {
141     // delete the TClonesArray of pointers to HitForRec
142     delete fHitForRecAtHit;
143     fHitForRecAtHit = NULL;
144   }
145 }
146
147   //__________________________________________________________________________
148 AliMUONTrack::AliMUONTrack (const AliMUONTrack& theMUONTrack)
149   :  TObject(theMUONTrack)
150 {
151   //fTrackReconstructor = new AliMUONTrackReconstructor(*MUONTrack.fTrackReconstructor);
152                                // is it right ?
153                                // NO, because it would use dummy copy constructor
154                                // and AliMUONTrack is not the owner of its TrackReconstructor 
155   fTrackReconstructor = theMUONTrack.fTrackReconstructor;
156   fTrackParamAtVertex = theMUONTrack.fTrackParamAtVertex;
157
158  // necessary to make a copy of the objects and not only the pointers in TObjArray.
159   fTrackHitsPtr  =  new TObjArray(10);
160   for (Int_t index = 0; index < (theMUONTrack.fTrackHitsPtr)->GetEntriesFast(); index++) {
161     AliMUONTrackHit *trackHit = new AliMUONTrackHit(*(AliMUONTrackHit*)(theMUONTrack.fTrackHitsPtr)->At(index));
162     fTrackHitsPtr->Add(trackHit);
163   }
164   fTrackHitsPtr->SetOwner(); // nedeed for deleting TClonesArray
165
166   // necessary to make a copy of the objects and not only the pointers in TClonesArray.
167   fTrackParamAtHit  =  new TClonesArray("AliMUONTrackParam",10);
168   for (Int_t index = 0; index < (theMUONTrack.fTrackParamAtHit)->GetEntriesFast(); index++) {
169     {new ((*fTrackParamAtHit)[fTrackParamAtHit->GetEntriesFast()]) 
170         AliMUONTrackParam(*(AliMUONTrackParam*)(theMUONTrack.fTrackParamAtHit)->At(index));}
171   }
172
173   // necessary to make a copy of the objects and not only the pointers in TClonesArray.
174   fHitForRecAtHit  =  new TClonesArray("AliMUONHitForRec",10);
175   for (Int_t index = 0; index < (theMUONTrack.fHitForRecAtHit)->GetEntriesFast(); index++) {
176     {new ((*fHitForRecAtHit)[fHitForRecAtHit->GetEntriesFast()]) 
177         AliMUONHitForRec(*(AliMUONHitForRec*)(theMUONTrack.fHitForRecAtHit)->At(index));}
178   }
179
180   fNTrackHits       =  theMUONTrack.fNTrackHits;
181   fFitMCS           =  theMUONTrack.fFitMCS;
182   fFitNParam        =  theMUONTrack.fFitNParam;
183   fFitFMin          =  theMUONTrack.fFitFMin;
184   fFitStart         =  theMUONTrack.fFitStart;
185   fMatchTrigger     =  theMUONTrack.fMatchTrigger;
186   fChi2MatchTrigger =  theMUONTrack.fChi2MatchTrigger;
187   fTrackID          =  theMUONTrack.fTrackID;
188 }
189
190   //__________________________________________________________________________
191 AliMUONTrack & AliMUONTrack::operator=(const AliMUONTrack& theMUONTrack)
192 {
193
194   // check assignement to self
195   if (this == &theMUONTrack)
196     return *this;
197
198   // base class assignement
199   TObject::operator=(theMUONTrack);
200
201   // fTrackReconstructor =  new AliMUONTrackReconstructor(*MUONTrack.fTrackReconstructor); 
202   // is it right ?
203   // is it right ? NO because it would use dummy copy constructor
204   fTrackReconstructor =  theMUONTrack.fTrackReconstructor;
205   fTrackParamAtVertex =  theMUONTrack.fTrackParamAtVertex;
206
207  // necessary to make a copy of the objects and not only the pointers in TObjArray.
208   fTrackHitsPtr  =  new TObjArray(10);
209   for (Int_t index = 0; index < (theMUONTrack.fTrackHitsPtr)->GetEntriesFast(); index++) {
210     AliMUONTrackHit *trackHit = new AliMUONTrackHit(*(AliMUONTrackHit*)(theMUONTrack.fTrackHitsPtr)->At(index));
211     fTrackHitsPtr->Add(trackHit);
212   }
213   fTrackHitsPtr->SetOwner();  // nedeed for deleting TClonesArray
214
215   // necessary to make a copy of the objects and not only the pointers in TClonesArray.
216   fTrackParamAtHit  =  new TClonesArray("AliMUONTrackParam",10);
217   for (Int_t index = 0; index < (theMUONTrack.fTrackParamAtHit)->GetEntriesFast(); index++) {
218     {new ((*fTrackParamAtHit)[fTrackParamAtHit->GetEntriesFast()]) 
219         AliMUONTrackParam(*(AliMUONTrackParam*)(theMUONTrack.fTrackParamAtHit)->At(index));}
220   }
221
222   // necessary to make a copy of the objects and not only the pointers in TClonesArray.
223   fHitForRecAtHit  =  new TClonesArray("AliMUONHitForRec",10);
224   for (Int_t index = 0; index < (theMUONTrack.fHitForRecAtHit)->GetEntriesFast(); index++) {
225     {new ((*fHitForRecAtHit)[fHitForRecAtHit->GetEntriesFast()]) 
226         AliMUONHitForRec(*(AliMUONHitForRec*)(theMUONTrack.fHitForRecAtHit)->At(index));}
227   }
228
229   fNTrackHits         =  theMUONTrack.fNTrackHits;
230   fFitMCS             =  theMUONTrack.fFitMCS;
231   fFitNParam          =  theMUONTrack.fFitNParam;
232   fFitFMin            =  theMUONTrack.fFitFMin;
233   fFitStart           =  theMUONTrack.fFitStart;
234   fMatchTrigger       =  theMUONTrack.fMatchTrigger;
235   fChi2MatchTrigger   =  theMUONTrack.fChi2MatchTrigger;
236   fTrackID            =  theMUONTrack.fTrackID;
237
238   return *this;
239 }
240
241   //__________________________________________________________________________
242 void AliMUONTrack::Remove()
243 {
244   // Remove current track from array of tracks,
245   // and corresponding track hits from array of track hits.
246   // Compress the TClonesArray it belongs to.
247   AliMUONTrackHit *nextTrackHit;
248   AliMUONTrackReconstructor *eventRec = this->fTrackReconstructor;
249   TClonesArray *trackHitsPtr = eventRec->GetRecTrackHitsPtr();
250   // Loop over all track hits of track
251   AliMUONTrackHit *trackHit = (AliMUONTrackHit*) fTrackHitsPtr->First();
252   while (trackHit) {
253     nextTrackHit = (AliMUONTrackHit*) fTrackHitsPtr->After(trackHit);
254     // Remove TrackHit from event TClonesArray.
255     // Destructor is called,
256     // hence links between HitForRec's and TrackHit's are updated
257     trackHitsPtr->Remove(trackHit);
258     trackHit = nextTrackHit;
259   }
260   // Remove the track from event TClonesArray
261   // Destructor is called,
262   // hence space for TObjArray of pointers to TrackHit's is freed
263   eventRec->GetRecTracksPtr()->Remove(this);
264   // Number of tracks decreased by 1
265   eventRec->SetNRecTracks(eventRec->GetNRecTracks() - 1);
266   // Compress event TClonesArray of Track's:
267   // this is essential to retrieve the TClonesArray afterwards
268   eventRec->GetRecTracksPtr()->Compress();
269   // Compress event TClonesArray of TrackHit's:
270   // this is probably also essential to retrieve the TClonesArray afterwards
271   trackHitsPtr->Compress();
272 }
273
274   //__________________________________________________________________________
275 void AliMUONTrack::SetFitMCS(Int_t FitMCS)
276 {
277   // Set multiple Coulomb scattering option for track fit "fFitMCS"
278   // from "FitMCS" argument: 0 without, 1 with
279   if ((FitMCS == 0) || (FitMCS == 1)) fFitMCS = FitMCS;
280   // better implementation with enum(with, without) ????
281   else {
282     cout << "ERROR in AliMUONTrack::SetFitMCS(FitMCS)" << endl;
283     cout << "FitMCS = " << FitMCS << " is neither 0 nor 1" << endl;
284     exit(0);
285   }
286   return;
287 }
288
289   //__________________________________________________________________________
290 void AliMUONTrack::SetFitNParam(Int_t FitNParam)
291 {
292   // Set number of parameters for track fit "fFitNParam" from "FitNParam":
293   // 3 for momentum, 5 for momentum and position
294   if ((FitNParam == 3) || (FitNParam == 5)) fFitNParam = FitNParam;
295   else {
296     cout << "ERROR in AliMUONTrack::SetFitNParam(FitNParam)" << endl;
297     cout << "FitNParam = " << FitNParam << " is neither 3 nor 5" << endl;
298     exit(0);
299   }
300   return;
301 }
302
303   //__________________________________________________________________________
304 void AliMUONTrack::SetFitStart(Int_t FitStart)
305 {
306   // Set multiple Coulomb scattering option for track fit "fFitStart"
307   // from "FitStart" argument: 0 without, 1 with
308   if ((FitStart == 0) || (FitStart == 1)) fFitStart = FitStart;
309   // better implementation with enum(vertex, firstHit) ????
310   else {
311     cout << "ERROR in AliMUONTrack::SetFitStart(FitStart)" << endl;
312     cout << "FitStart = " << FitStart << " is neither 0 nor 1" << endl;
313     exit(0);
314   }
315   return;
316 }
317
318   //__________________________________________________________________________
319 AliMUONTrackParam* AliMUONTrack::GetTrackParamAtFirstHit(void) const {
320   // Get pointer to TrackParamAtFirstHit
321   return ((AliMUONTrackHit*) (fTrackHitsPtr->First()))->GetTrackParam();}
322
323   //__________________________________________________________________________
324 void AliMUONTrack::RecursiveDump(void) const
325 {
326   // Recursive dump of AliMUONTrack, i.e. with dump of TrackHit's and HitForRec's
327   AliMUONTrackHit *trackHit;
328   AliMUONHitForRec *hitForRec;
329   cout << "Recursive dump of Track: " << this << endl;
330   // Track
331   this->Dump();
332   for (Int_t trackHitIndex = 0; trackHitIndex < fNTrackHits; trackHitIndex++) {
333     trackHit = (AliMUONTrackHit*) ((*fTrackHitsPtr)[trackHitIndex]);
334     // TrackHit
335     cout << "TrackHit: " << trackHit << " (index: " << trackHitIndex << ")" << endl;
336     trackHit->Dump();
337     hitForRec = trackHit->GetHitForRecPtr();
338     // HitForRec
339     cout << "HitForRec: " << hitForRec << endl;
340     hitForRec->Dump();
341   }
342   return;
343 }
344   
345   //__________________________________________________________________________
346 Bool_t* AliMUONTrack::CompatibleTrack(AliMUONTrack * Track, Double_t Sigma2Cut) const
347 {
348   // Return kTRUE/kFALSE for each chamber if hit is compatible or not 
349   TClonesArray *hitArray, *thisHitArray;
350   AliMUONHitForRec *hit, *thisHit;
351   Int_t chamberNumber;
352   Float_t deltaZ;
353   Float_t deltaZMax = 1.; // 1 cm
354   Float_t chi2 = 0;
355   Bool_t *nCompHit = new Bool_t[AliMUONConstants::NTrackingCh()]; 
356
357   for ( Int_t ch = 0; ch < AliMUONConstants::NTrackingCh(); ch++) {
358     nCompHit[ch] = kFALSE;
359   }
360
361   thisHitArray = this->GetHitForRecAtHit();
362
363   hitArray =  Track->GetHitForRecAtHit();
364
365   for (Int_t iHthis = 0; iHthis < thisHitArray->GetEntriesFast(); iHthis++) {
366     thisHit = (AliMUONHitForRec*) thisHitArray->At(iHthis);
367     chamberNumber = thisHit->GetChamberNumber();
368     if (chamberNumber < 0 || chamberNumber > AliMUONConstants::NTrackingCh()) continue; 
369     nCompHit[chamberNumber] = kFALSE;
370     for (Int_t iH = 0; iH < hitArray->GetEntriesFast(); iH++) {
371       hit = (AliMUONHitForRec*) hitArray->At(iH);
372       deltaZ = TMath::Abs(thisHit->GetZ() - hit->GetZ());
373       chi2 = thisHit->NormalizedChi2WithHitForRec(hit,Sigma2Cut); // set cut to 4 sigmas
374       if (chi2 < 3. && deltaZ < deltaZMax) {
375         nCompHit[chamberNumber] = kTRUE;
376         break;
377       }
378     }  
379   }
380   
381   return nCompHit;
382 }
383
384   //__________________________________________________________________________
385 Int_t AliMUONTrack::HitsInCommon(AliMUONTrack* Track) const
386 {
387   // Returns the number of hits in common
388   // between the current track ("this")
389   // and the track pointed to by "Track".
390   Int_t hitsInCommon = 0;
391   AliMUONTrackHit *trackHit1, *trackHit2;
392   // Loop over hits of first track
393   trackHit1 = (AliMUONTrackHit*) this->GetTrackHitsPtr()->First();
394   while (trackHit1) {
395     // Loop over hits of second track
396     trackHit2 = (AliMUONTrackHit*) Track->GetTrackHitsPtr()->First();
397     while (trackHit2) {
398       // Increment "hitsInCommon" if both TrackHits point to the same HitForRec
399       if ( (trackHit1->GetHitForRecPtr()) ==
400            (trackHit2->GetHitForRecPtr())    ) hitsInCommon++;
401       trackHit2 = (AliMUONTrackHit*) Track->GetTrackHitsPtr()->After(trackHit2);
402     } // trackHit2
403     trackHit1 = (AliMUONTrackHit*) this->GetTrackHitsPtr()->After(trackHit1);
404   } // trackHit1
405   return hitsInCommon;
406 }
407
408   //__________________________________________________________________________
409 void AliMUONTrack::MatchTriggerTrack(TClonesArray *triggerTrackArray)
410 {
411   // Match this track with one trigger track if possible
412   AliMUONTrackParam trackParam; 
413   AliMUONTriggerTrack *triggerTrack;
414   Double_t xTrack, yTrack, ySlopeTrack, dTrigTrackMin2, dTrigTrack2;
415   Double_t nSigmaCut2;
416
417   Double_t distSigma[3]={1,1,0.02}; // sigma of distributions (trigger-track) X,Y,slopeY
418   Double_t distTriggerTrack[3] = {0,0,0};
419
420   fMatchTrigger = kFALSE;
421   fChi2MatchTrigger = 0;
422
423   trackParam = *((AliMUONTrackParam*) fTrackParamAtHit->Last()); 
424   trackParam.ExtrapToZ(AliMUONConstants::DefaultChamberZ(10)); // extrap to 1st trigger chamber
425
426   nSigmaCut2 =  fTrackReconstructor->GetMaxSigma2Distance(); // nb of sigma**2 for cut
427   xTrack = trackParam.GetNonBendingCoor();
428   yTrack = trackParam.GetBendingCoor();
429   ySlopeTrack = trackParam.GetBendingSlope();
430   dTrigTrackMin2 = 999;
431   
432   triggerTrack = (AliMUONTriggerTrack*) triggerTrackArray->First();
433   while(triggerTrack){
434     distTriggerTrack[0] = (triggerTrack->GetX11()-xTrack)/distSigma[0];
435     distTriggerTrack[1] = (triggerTrack->GetY11()-yTrack)/distSigma[1];
436     distTriggerTrack[2] = (TMath::Tan(triggerTrack->GetThetay())-ySlopeTrack)/distSigma[2];
437     dTrigTrack2 = 0;
438     for (Int_t iVar = 0; iVar < 3; iVar++)
439       dTrigTrack2 += distTriggerTrack[iVar]*distTriggerTrack[iVar];
440     if (dTrigTrack2 < dTrigTrackMin2 && dTrigTrack2 < nSigmaCut2) {
441       dTrigTrackMin2 = dTrigTrack2;
442       fMatchTrigger = kTRUE;
443       fChi2MatchTrigger =  dTrigTrack2/3.; // Normalized Chi2, 3 variables (X,Y,slopeY)
444     }
445     triggerTrack = (AliMUONTriggerTrack*) triggerTrackArray->After(triggerTrack);
446   }
447
448 }
449   //__________________________________________________________________________
450 void AliMUONTrack::Fit()
451 {
452   // Fit the current track ("this"),
453   // with or without multiple Coulomb scattering according to "fFitMCS",
454   // with the number of parameters given by "fFitNParam"
455   // (3 if one keeps X and Y fixed in "TrackParam", 5 if one lets them vary),
456   // starting, according to "fFitStart",
457   // with track parameters at vertex or at the first TrackHit.
458   // "fFitMCS", "fFitNParam" and "fFitStart" have to be set before
459   // by calling the corresponding Set methods.
460   Double_t arg[1], benC, errorParam, invBenP, lower, nonBenC, upper, x, y;
461   char parName[50];
462   AliMUONTrackParam *trackParam;
463   // Check if Minuit is initialized...
464   fgFitter = TVirtualFitter::Fitter(this); // add 3 or 5 for the maximum number of parameters ???
465   fgFitter->Clear(); // necessary ???? probably yes
466   // how to reset the printout number at every fit ????
467   // is there any risk to leave it like that ????
468   // how to go faster ???? choice of Minuit parameters like EDM ????
469   // choice of function to be minimized according to fFitMCS
470   if (fFitMCS == 0) fgFitter->SetFCN(TrackChi2);
471   else fgFitter->SetFCN(TrackChi2MCS);
472   // Switch off printout
473   arg[0] = -1;
474   fgFitter->ExecuteCommand("SET PRINT", arg, 1); // More printing !!!!
475   // No warnings
476   fgFitter->ExecuteCommand("SET NOW", arg, 0);
477   // Parameters according to "fFitStart"
478   // (should be a function to be used at every place where needed ????)
479   if (fFitStart == 0) trackParam = &fTrackParamAtVertex;
480   else trackParam = this->GetTrackParamAtFirstHit();
481   // set first 3 Minuit parameters
482   // could be tried with no limits for the search (min=max=0) ????
483   fgFitter->SetParameter(0, "InvBenP",
484                          trackParam->GetInverseBendingMomentum(),
485                          0.003, -0.4, 0.4);
486   fgFitter->SetParameter(1, "BenS",
487                          trackParam->GetBendingSlope(),
488                          0.001, -0.5, 0.5);
489   fgFitter->SetParameter(2, "NonBenS",
490                          trackParam->GetNonBendingSlope(),
491                          0.001, -0.5, 0.5);
492   if (fFitNParam == 5) {
493     // set last 2 Minuit parameters
494     // mandatory limits in Bending to avoid NaN values of parameters
495     fgFitter->SetParameter(3, "X",
496                            trackParam->GetNonBendingCoor(),
497                            0.03, -500.0, 500.0);
498     // mandatory limits in non Bending to avoid NaN values of parameters
499     fgFitter->SetParameter(4, "Y",
500                            trackParam->GetBendingCoor(),
501                            0.10, -500.0, 500.0);
502   }
503   // search without gradient calculation in the function
504   fgFitter->ExecuteCommand("SET NOGRADIENT", arg, 0);
505   // minimization
506   fgFitter->ExecuteCommand("MINIMIZE", arg, 0);
507   // exit from Minuit
508   //  fgFitter->ExecuteCommand("EXIT", arg, 0); // necessary ????
509   // get results into "invBenP", "benC", "nonBenC" ("x", "y")
510   fgFitter->GetParameter(0, parName, invBenP, errorParam, lower, upper);
511   fgFitter->GetParameter(1, parName, benC, errorParam, lower, upper);
512   fgFitter->GetParameter(2, parName, nonBenC, errorParam, lower, upper);
513   if (fFitNParam == 5) {
514     fgFitter->GetParameter(3, parName, x, errorParam, lower, upper);
515     fgFitter->GetParameter(4, parName, y, errorParam, lower, upper);
516   }
517   // result of the fit into track parameters
518   trackParam->SetInverseBendingMomentum(invBenP);
519   trackParam->SetBendingSlope(benC);
520   trackParam->SetNonBendingSlope(nonBenC);
521   if (fFitNParam == 5) {
522     trackParam->SetNonBendingCoor(x);
523     trackParam->SetBendingCoor(y);
524   }
525   // global result of the fit
526   Double_t fedm, errdef;
527   Int_t npari, nparx;
528   fgFitter->GetStats(fFitFMin, fedm, errdef, npari, nparx);
529 }
530
531   //__________________________________________________________________________
532 void AliMUONTrack::AddSegment(AliMUONSegment* Segment)
533 {
534   // Add Segment to the track
535   AddHitForRec(Segment->GetHitForRec1()); // 1st hit
536   AddHitForRec(Segment->GetHitForRec2()); // 2nd hit
537 }
538
539   //__________________________________________________________________________
540 void AliMUONTrack::AddHitForRec(AliMUONHitForRec* HitForRec)
541 {
542   // Add HitForRec to the track:
543   // actual TrackHit into TClonesArray of TrackHit's for the event;
544   // pointer to actual TrackHit in TObjArray of pointers to TrackHit's for the track
545   TClonesArray *recTrackHitsPtr = this->fTrackReconstructor->GetRecTrackHitsPtr();
546   Int_t eventTrackHits = this->fTrackReconstructor->GetNRecTrackHits();
547   // event
548   AliMUONTrackHit* trackHit =
549     new ((*recTrackHitsPtr)[eventTrackHits]) AliMUONTrackHit(HitForRec);
550   this->fTrackReconstructor->SetNRecTrackHits(eventTrackHits + 1);
551   // track
552   if (fTrackHitsPtr->IsOwner()) AliFatal("fTrackHitsPtr is owner");
553   fTrackHitsPtr->Add(trackHit);
554   fNTrackHits++;
555 }
556
557   //__________________________________________________________________________
558 void AliMUONTrack::SetTrackParamAtHit(Int_t indexHit, AliMUONTrackParam *TrackParam) const
559 {
560   // Set track parameters at TrackHit with index "indexHit"
561   // from the track parameters pointed to by "TrackParam".
562   //PH  AliMUONTrackHit* trackHit = (AliMUONTrackHit*) ((*fTrackHitsPtr)[indexHit]);
563   AliMUONTrackHit* trackHit = (AliMUONTrackHit*) (fTrackHitsPtr->At(indexHit));
564   trackHit->SetTrackParam(TrackParam);
565 }
566
567   //__________________________________________________________________________
568 void AliMUONTrack::SetTrackParamAtVertex()
569 {
570   // Set track parameters at vertex.
571   // TrackHit's are assumed to be only in stations(1..) 4 and 5,
572   // and sorted according to increasing Z..
573   // Parameters are calculated from information in HitForRec's
574   // of first and last TrackHit's.
575   AliMUONTrackParam *trackParam =
576     &fTrackParamAtVertex; // pointer to track parameters
577   // Pointer to HitForRec of first TrackHit
578   AliMUONHitForRec *firstHit =
579     ((AliMUONTrackHit*) (fTrackHitsPtr->First()))->GetHitForRecPtr();
580   // Pointer to HitForRec of last TrackHit
581   AliMUONHitForRec *lastHit =
582     ((AliMUONTrackHit*) (fTrackHitsPtr->Last()))->GetHitForRecPtr();
583   // Z difference between first and last hits
584   Double_t deltaZ = firstHit->GetZ() - lastHit->GetZ();
585   // bending slope in stations(1..) 4 and 5
586   Double_t bendingSlope =
587     (firstHit->GetBendingCoor() - lastHit->GetBendingCoor()) / deltaZ;
588   trackParam->SetBendingSlope(bendingSlope);
589   // impact parameter
590   Double_t impactParam =
591     firstHit->GetBendingCoor() - bendingSlope * firstHit->GetZ(); // same if from firstHit and  lastHit ????
592   // signed bending momentum
593   Double_t signedBendingMomentum =
594     fTrackReconstructor->GetBendingMomentumFromImpactParam(impactParam);
595   trackParam->SetInverseBendingMomentum(1.0 / signedBendingMomentum);
596   // bending slope at vertex
597   trackParam->
598     SetBendingSlope(bendingSlope +
599                     impactParam / fTrackReconstructor->GetSimpleBPosition());
600   // non bending slope
601   Double_t nonBendingSlope =
602     (firstHit->GetNonBendingCoor() - lastHit->GetNonBendingCoor()) / deltaZ;
603   trackParam->SetNonBendingSlope(nonBendingSlope);
604   // vertex coordinates at (0,0,0)
605   trackParam->SetZ(0.0);
606   trackParam->SetBendingCoor(0.0);
607   trackParam->SetNonBendingCoor(0.0);
608 }
609
610   //__________________________________________________________________________
611 void TrackChi2(Int_t &NParam, Double_t * /*Gradient*/, Double_t &Chi2, Double_t *Param, Int_t /*Flag*/)
612 {
613   // Return the "Chi2" to be minimized with Minuit for track fitting,
614   // with "NParam" parameters
615   // and their current values in array pointed to by "Param".
616   // Assumes that the track hits are sorted according to increasing Z.
617   // Track parameters at each TrackHit are updated accordingly.
618   // Multiple Coulomb scattering is not taken into account
619   AliMUONTrack *trackBeingFitted;
620   AliMUONTrackHit* hit;
621   AliMUONTrackParam param1;
622   Int_t hitNumber;
623   Double_t zHit;
624   Chi2 = 0.0; // initialize Chi2
625   // copy of track parameters to be fitted
626   trackBeingFitted = (AliMUONTrack*) AliMUONTrack::Fitter()->GetObjectFit();
627   if (trackBeingFitted->GetFitStart() == 0)
628     param1 = *(trackBeingFitted->GetTrackParamAtVertex());
629   else param1 = *(trackBeingFitted->GetTrackParamAtFirstHit());
630   // Minuit parameters to be fitted into this copy
631   param1.SetInverseBendingMomentum(Param[0]);
632   param1.SetBendingSlope(Param[1]);
633   param1.SetNonBendingSlope(Param[2]);
634   if (NParam == 5) {
635     param1.SetNonBendingCoor(Param[3]);
636     param1.SetBendingCoor(Param[4]);
637   }
638   // Follow track through all planes of track hits
639   for (hitNumber = 0; hitNumber < trackBeingFitted->GetNTrackHits(); hitNumber++) {
640     hit = (AliMUONTrackHit*) (*(trackBeingFitted->GetTrackHitsPtr()))[hitNumber];
641     zHit = hit->GetHitForRecPtr()->GetZ();
642     // do something special if 2 hits with same Z ????
643     // security against infinite loop ????
644     (&param1)->ExtrapToZ(zHit); // extrapolation
645     hit->SetTrackParam(&param1);
646     // Increment Chi2
647     // done hit per hit, with hit resolution,
648     // and not with point and angle like in "reco_muon.F" !!!!
649     // Needs to add multiple scattering contribution ????
650     Double_t dX =
651       hit->GetHitForRecPtr()->GetNonBendingCoor() - (&param1)->GetNonBendingCoor();
652     Double_t dY =
653       hit->GetHitForRecPtr()->GetBendingCoor() - (&param1)->GetBendingCoor();
654     Chi2 =
655       Chi2 +
656       dX * dX / hit->GetHitForRecPtr()->GetNonBendingReso2() +
657       dY * dY / hit->GetHitForRecPtr()->GetBendingReso2();
658   }
659 }
660
661   //__________________________________________________________________________
662 void TrackChi2MCS(Int_t &NParam, Double_t * /*Gradient*/, Double_t &Chi2, Double_t *Param, Int_t /*Flag*/)
663 {
664   // Return the "Chi2" to be minimized with Minuit for track fitting,
665   // with "NParam" parameters
666   // and their current values in array pointed to by "Param".
667   // Assumes that the track hits are sorted according to increasing Z.
668   // Track parameters at each TrackHit are updated accordingly.
669   // Multiple Coulomb scattering is taken into account with covariance matrix.
670   AliMUONTrack *trackBeingFitted;
671   AliMUONTrackParam param1;
672   Chi2 = 0.0; // initialize Chi2
673   // copy of track parameters to be fitted
674   trackBeingFitted = (AliMUONTrack*) AliMUONTrack::Fitter()->GetObjectFit();
675   if (trackBeingFitted->GetFitStart() == 0)
676     param1 = *(trackBeingFitted->GetTrackParamAtVertex());
677   else param1 = *(trackBeingFitted->GetTrackParamAtFirstHit());
678   // Minuit parameters to be fitted into this copy
679   param1.SetInverseBendingMomentum(Param[0]);
680   param1.SetBendingSlope(Param[1]);
681   param1.SetNonBendingSlope(Param[2]);
682   if (NParam == 5) {
683     param1.SetNonBendingCoor(Param[3]);
684     param1.SetBendingCoor(Param[4]);
685   }
686
687   AliMUONTrackHit *hit;
688   Int_t chCurrent, chPrev = 0, hitNumber, hitNumber1, hitNumber2, hitNumber3;
689   Double_t z, z1, z2, z3;
690   AliMUONTrackHit *hit1, *hit2, *hit3;
691   Double_t hbc1, hbc2, pbc1, pbc2;
692   Double_t hnbc1, hnbc2, pnbc1, pnbc2;
693   Int_t numberOfHit = trackBeingFitted->GetNTrackHits();
694   TMatrixD *covBending = new TMatrixD(numberOfHit, numberOfHit);
695   TMatrixD *covNonBending = new TMatrixD(numberOfHit, numberOfHit);
696   Double_t *msa2 = new Double_t[numberOfHit];
697
698   // Predicted coordinates and  multiple scattering angles are first calculated
699   for (hitNumber = 0; hitNumber < numberOfHit; hitNumber++) {
700     hit = (AliMUONTrackHit*) (*(trackBeingFitted->GetTrackHitsPtr()))[hitNumber];
701     z = hit->GetHitForRecPtr()->GetZ();
702     // do something special if 2 hits with same Z ????
703     // security against infinite loop ????
704     (&param1)->ExtrapToZ(z); // extrapolation
705     hit->SetTrackParam(&param1);
706     // square of multiple scattering angle at current hit, with one chamber
707     msa2[hitNumber] = MultipleScatteringAngle2(hit);
708     // correction for eventual missing hits or multiple hits in a chamber,
709     // according to the number of chambers
710     // between the current hit and the previous one
711     chCurrent = hit->GetHitForRecPtr()->GetChamberNumber();
712     if (hitNumber > 0) msa2[hitNumber] = msa2[hitNumber] * (chCurrent - chPrev);
713     chPrev = chCurrent;
714   }
715
716   // Calculates the covariance matrix
717   for (hitNumber1 = 0; hitNumber1 < numberOfHit; hitNumber1++) { 
718     hit1 = (AliMUONTrackHit*) (*(trackBeingFitted->GetTrackHitsPtr()))[hitNumber1];
719     z1 = hit1->GetHitForRecPtr()->GetZ();
720     for (hitNumber2 = hitNumber1; hitNumber2 < numberOfHit; hitNumber2++) {
721       hit2 = (AliMUONTrackHit*) (*(trackBeingFitted->GetTrackHitsPtr()))[hitNumber2];
722       z2 = hit2->GetHitForRecPtr()->GetZ();
723       // initialization to 0 (diagonal plus upper triangular part)
724       (*covBending)(hitNumber2, hitNumber1) = 0.0;
725       // contribution from multiple scattering in bending plane:
726       // loop over upstream hits
727       for (hitNumber3 = 0; hitNumber3 < hitNumber1; hitNumber3++) {     
728         hit3 = (AliMUONTrackHit*)
729           (*(trackBeingFitted->GetTrackHitsPtr()))[hitNumber3];
730         z3 = hit3->GetHitForRecPtr()->GetZ();
731         (*covBending)(hitNumber2, hitNumber1) =
732           (*covBending)(hitNumber2, hitNumber1) +
733           ((z1 - z3) * (z2 - z3) * msa2[hitNumber3]); 
734       }
735       // equal contribution from multiple scattering in non bending plane
736       (*covNonBending)(hitNumber2, hitNumber1) =
737         (*covBending)(hitNumber2, hitNumber1);
738       if (hitNumber1 == hitNumber2) {
739         // Diagonal elements: add contribution from position measurements
740         // in bending plane
741         (*covBending)(hitNumber2, hitNumber1) =
742           (*covBending)(hitNumber2, hitNumber1) +
743           hit1->GetHitForRecPtr()->GetBendingReso2();
744         // and in non bending plane
745         (*covNonBending)(hitNumber2, hitNumber1) =
746           (*covNonBending)(hitNumber2, hitNumber1) +
747           hit1->GetHitForRecPtr()->GetNonBendingReso2();
748       }
749       else {
750         // Non diagonal elements: symmetrization
751         // for bending plane
752         (*covBending)(hitNumber1, hitNumber2) =
753           (*covBending)(hitNumber2, hitNumber1);
754         // and non bending plane
755         (*covNonBending)(hitNumber1, hitNumber2) =
756           (*covNonBending)(hitNumber2, hitNumber1);
757       }
758     } // for (hitNumber2 = hitNumber1;...
759   } // for (hitNumber1 = 0;...
760     
761   // Inversion of covariance matrices
762   // with "mnvertLocal", local "mnvert" function of Minuit.
763   // One cannot use directly "mnvert" since "TVirtualFitter" does not know it.
764   // One will have to replace this local function by the right inversion function
765   // from a specialized Root package for symmetric positive definite matrices,
766   // when available!!!!
767   Int_t ifailBending;
768   mnvertLocal(&((*covBending)(0,0)), numberOfHit, numberOfHit, numberOfHit,
769               ifailBending);
770   Int_t ifailNonBending;
771   mnvertLocal(&((*covNonBending)(0,0)), numberOfHit, numberOfHit, numberOfHit,
772               ifailNonBending);
773
774   // It would be worth trying to calculate the inverse of the covariance matrix
775   // only once per fit, since it cannot change much in principle,
776   // and it would save a lot of computing time !!!!
777   
778   // Calculates Chi2
779   if ((ifailBending == 0) && (ifailNonBending == 0)) {
780     // with Multiple Scattering if inversion correct
781     for (hitNumber1 = 0; hitNumber1 < numberOfHit ; hitNumber1++) { 
782       hit1 = (AliMUONTrackHit*) (*(trackBeingFitted->GetTrackHitsPtr()))[hitNumber1];
783       hbc1 = hit1->GetHitForRecPtr()->GetBendingCoor();
784       pbc1 = hit1->GetTrackParam()->GetBendingCoor();
785       hnbc1 = hit1->GetHitForRecPtr()->GetNonBendingCoor();
786       pnbc1 = hit1->GetTrackParam()->GetNonBendingCoor();
787       for (hitNumber2 = 0; hitNumber2 < numberOfHit; hitNumber2++) {
788         hit2 = (AliMUONTrackHit*)
789           (*(trackBeingFitted->GetTrackHitsPtr()))[hitNumber2];
790         hbc2 = hit2->GetHitForRecPtr()->GetBendingCoor();
791         pbc2 = hit2->GetTrackParam()->GetBendingCoor();
792         hnbc2 = hit2->GetHitForRecPtr()->GetNonBendingCoor();
793         pnbc2 = hit2->GetTrackParam()->GetNonBendingCoor();
794         Chi2 = Chi2 +
795           ((*covBending)(hitNumber2, hitNumber1) *
796            (hbc1 - pbc1) * (hbc2 - pbc2)) +
797           ((*covNonBending)(hitNumber2, hitNumber1) *
798            (hnbc1 - pnbc1) * (hnbc2 - pnbc2));
799       }
800     }
801   } else {
802     // without Multiple Scattering if inversion impossible
803     for (hitNumber1 = 0; hitNumber1 < numberOfHit ; hitNumber1++) { 
804       hit1 = (AliMUONTrackHit*) (*(trackBeingFitted->GetTrackHitsPtr()))[hitNumber1];
805       hbc1 = hit1->GetHitForRecPtr()->GetBendingCoor();
806       pbc1 = hit1->GetTrackParam()->GetBendingCoor();
807       hnbc1 = hit1->GetHitForRecPtr()->GetNonBendingCoor();
808       pnbc1 = hit1->GetTrackParam()->GetNonBendingCoor();
809       Chi2 = Chi2 + 
810         ((hbc1 - pbc1) * (hbc1 - pbc1) /
811          hit1->GetHitForRecPtr()->GetBendingReso2()) +
812         ((hnbc1 - pnbc1) * (hnbc1 - pnbc1) /
813          hit1->GetHitForRecPtr()->GetNonBendingReso2());
814     }
815   }
816   
817   delete covBending;
818   delete covNonBending;
819   delete [] msa2;
820 }
821
822 Double_t MultipleScatteringAngle2(AliMUONTrackHit *TrackHit)
823 {
824   // Returns square of multiple Coulomb scattering angle
825   // at TrackHit pointed to by "TrackHit"
826   Double_t slopeBending, slopeNonBending, radiationLength, inverseBendingMomentum2, inverseTotalMomentum2;
827   Double_t varMultipleScatteringAngle;
828   AliMUONTrack *trackBeingFitted = (AliMUONTrack*) AliMUONTrack::Fitter()->GetObjectFit();
829   AliMUONTrackParam *param = TrackHit->GetTrackParam();
830   // Better implementation in AliMUONTrack class ????
831   slopeBending = param->GetBendingSlope();
832   slopeNonBending = param->GetNonBendingSlope();
833   // thickness in radiation length for the current track,
834   // taking local angle into account
835   radiationLength =
836     trackBeingFitted->GetTrackReconstructor()->GetChamberThicknessInX0() *
837     TMath::Sqrt(1.0 +
838                 slopeBending * slopeBending + slopeNonBending * slopeNonBending);
839   inverseBendingMomentum2 = 
840     param->GetInverseBendingMomentum() * param->GetInverseBendingMomentum();
841   inverseTotalMomentum2 =
842     inverseBendingMomentum2 * (1.0 + slopeBending * slopeBending) /
843     (1.0 + slopeBending *slopeBending + slopeNonBending * slopeNonBending); 
844   varMultipleScatteringAngle = 0.0136 * (1.0 + 0.038 * TMath::Log(radiationLength));
845   // The velocity is assumed to be 1 !!!!
846   varMultipleScatteringAngle = inverseTotalMomentum2 * radiationLength *
847     varMultipleScatteringAngle * varMultipleScatteringAngle;
848   return varMultipleScatteringAngle;
849 }
850
851 //______________________________________________________________________________
852  void mnvertLocal(Double_t *a, Int_t l, Int_t, Int_t n, Int_t &ifail)
853 {
854 //*-*-*-*-*-*-*-*-*-*-*-*Inverts a symmetric matrix*-*-*-*-*-*-*-*-*-*-*-*-*
855 //*-*                    ==========================
856 //*-*        inverts a symmetric matrix.   matrix is first scaled to
857 //*-*        have all ones on the diagonal (equivalent to change of units)
858 //*-*        but no pivoting is done since matrix is positive-definite.
859 //*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
860
861   // taken from TMinuit package of Root (l>=n)
862   // fVERTs, fVERTq and fVERTpp changed to localVERTs, localVERTq and localVERTpp
863   //  Double_t localVERTs[n], localVERTq[n], localVERTpp[n];
864   Double_t * localVERTs = new Double_t[n];
865   Double_t * localVERTq = new Double_t[n];
866   Double_t * localVERTpp = new Double_t[n];
867   // fMaxint changed to localMaxint
868   Int_t localMaxint = n;
869
870     /* System generated locals */
871     Int_t aOffset;
872
873     /* Local variables */
874     Double_t si;
875     Int_t i, j, k, kp1, km1;
876
877     /* Parameter adjustments */
878     aOffset = l + 1;
879     a -= aOffset;
880
881     /* Function Body */
882     ifail = 0;
883     if (n < 1) goto L100;
884     if (n > localMaxint) goto L100;
885 //*-*-                  scale matrix by sqrt of diag elements
886     for (i = 1; i <= n; ++i) {
887         si = a[i + i*l];
888         if (si <= 0) goto L100;
889         localVERTs[i-1] = 1 / TMath::Sqrt(si);
890     }
891     for (i = 1; i <= n; ++i) {
892         for (j = 1; j <= n; ++j) {
893             a[i + j*l] = a[i + j*l]*localVERTs[i-1]*localVERTs[j-1];
894         }
895     }
896 //*-*-                                       . . . start main loop . . . .
897     for (i = 1; i <= n; ++i) {
898         k = i;
899 //*-*-                  preparation for elimination step1
900         if (a[k + k*l] != 0) localVERTq[k-1] = 1 / a[k + k*l];
901         else goto L100;
902         localVERTpp[k-1] = 1;
903         a[k + k*l] = 0;
904         kp1 = k + 1;
905         km1 = k - 1;
906         if (km1 < 0) goto L100;
907         else if (km1 == 0) goto L50;
908         else               goto L40;
909 L40:
910         for (j = 1; j <= km1; ++j) {
911             localVERTpp[j-1] = a[j + k*l];
912             localVERTq[j-1]  = a[j + k*l]*localVERTq[k-1];
913             a[j + k*l]   = 0;
914         }
915 L50:
916         if (k - n < 0) goto L51;
917         else if (k - n == 0) goto L60;
918         else                goto L100;
919 L51:
920         for (j = kp1; j <= n; ++j) {
921             localVERTpp[j-1] = a[k + j*l];
922             localVERTq[j-1]  = -a[k + j*l]*localVERTq[k-1];
923             a[k + j*l]   = 0;
924         }
925 //*-*-                  elimination proper
926 L60:
927         for (j = 1; j <= n; ++j) {
928             for (k = j; k <= n; ++k) { a[j + k*l] += localVERTpp[j-1]*localVERTq[k-1]; }
929         }
930     }
931 //*-*-                  elements of left diagonal and unscaling
932     for (j = 1; j <= n; ++j) {
933         for (k = 1; k <= j; ++k) {
934             a[k + j*l] = a[k + j*l]*localVERTs[k-1]*localVERTs[j-1];
935             a[j + k*l] = a[k + j*l];
936         }
937     }
938     delete [] localVERTs;
939     delete [] localVERTq;
940     delete [] localVERTpp;
941     return;
942 //*-*-                  failure return
943 L100:
944     delete [] localVERTs;
945     delete [] localVERTq;
946     delete [] localVERTpp;
947     ifail = 1;
948 } /* mnvertLocal */
949