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