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