Code revision:
[u/mrichter/AliRoot.git] / MUON / AliMUONTrackK.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 #include <stdlib.h> // for exit()
17
18 #include <Riostream.h>
19 #include <TClonesArray.h>
20 #include <TMatrixD.h>
21
22 #include "AliMUONTrackK.h"
23 #include "AliCallf77.h"
24 #include "AliMUON.h"
25 #include "AliMUONChamber.h"
26 #include "AliMUONEventReconstructor.h"
27 #include "AliMUONSegment.h"
28 #include "AliMUONHitForRec.h"
29 #include "AliMUONRawCluster.h"
30 #include "AliMUONTrackParam.h"
31 #include "AliRun.h"
32 //#include "AliMagF.h"
33
34 const Int_t AliMUONTrackK::fgkSize = 5;
35 const Int_t AliMUONTrackK::fgkNSigma = 4; 
36 const Int_t AliMUONTrackK::fgkTriesMax = 10000; 
37 const Double_t AliMUONTrackK::fgkEpsilon = 0.002; 
38
39 void mnvertLocalK(Double_t* a, Int_t l, Int_t m, Int_t n, Int_t& ifail);
40
41 ClassImp(AliMUONTrackK) // Class implementation in ROOT context
42
43   // A few calls in Fortran or from Fortran (extrap.F).
44 #ifndef WIN32 
45 # define extrap_onestep_helix extrap_onestep_helix_
46 # define extrap_onestep_helix3 extrap_onestep_helix3_
47 # define extrap_onestep_rungekutta extrap_onestep_rungekutta_
48 # define gufld_double gufld_double_
49 #else 
50 # define extrap_onestep_helix EXTRAP_ONESTEP_HELIX
51 # define extrap_onestep_helix3 EXTRAP_ONESTEP_HELIX3
52 # define extrap_onestep_rungekutta EXTRAP_ONESTEP_RUNGEKUTTA
53 # define gufld_double GUFLD_DOUBLE
54 #endif 
55
56 extern "C" {
57   void type_of_call extrap_onestep_helix
58   (Double_t &Charge, Double_t &StepLength, Double_t *VGeant3, Double_t *VGeant3New);
59
60   void type_of_call extrap_onestep_helix3
61   (Double_t &Field, Double_t &StepLength, Double_t *VGeant3, Double_t *VGeant3New);
62
63   void type_of_call extrap_onestep_rungekutta
64   (Double_t &Charge, Double_t &StepLength, Double_t *VGeant3, Double_t *VGeant3New);
65
66   void type_of_call gufld_double(Double_t *Position, Double_t *Field);
67     /*  void type_of_call gufld_double(Double_t *Position, Double_t *Field) {
68     // interface to "gAlice->Field()->Field" for arguments in double precision
69     Float_t x[3], b[3];
70     x[0] = Position[0]; x[1] = Position[1]; x[2] = Position[2];
71     gAlice->Field()->Field(x, b);
72     Field[0] = b[0]; Field[1] = b[1]; Field[2] = b[2];
73   }
74     */
75 }
76
77 Int_t AliMUONTrackK::fgNOfPoints = 0; 
78 AliMUON* AliMUONTrackK::fgMUON = NULL;
79 AliMUONEventReconstructor* AliMUONTrackK::fgEventReconstructor = NULL; 
80 TClonesArray* AliMUONTrackK::fgHitForRec = NULL; 
81
82   //__________________________________________________________________________
83 AliMUONTrackK::AliMUONTrackK()
84   : TObject()
85 {
86   // Default constructor
87
88   fgEventReconstructor = NULL; // pointer to event reconstructor
89   fgMUON = NULL; // pointer to Muon module
90   fgHitForRec = NULL; // pointer to points
91   fgNOfPoints = 0; // number of points
92
93   fStartSegment = NULL;
94   fTrackHitsPtr = NULL;
95   fNTrackHits = 0;
96   fTrackPar = NULL;
97   fTrackParNew = NULL;
98   fCovariance = NULL;
99   fWeight = NULL;
100   fSkipHit = NULL;
101
102   return;
103 }
104
105   //__________________________________________________________________________
106 AliMUONTrackK::AliMUONTrackK(AliMUONEventReconstructor *EventReconstructor, TClonesArray *hitForRec)
107   : TObject()
108 {
109   // Constructor
110
111   fgEventReconstructor = EventReconstructor; // pointer to event reconstructor
112   fgMUON = (AliMUON*) gAlice->GetModule("MUON"); // pointer to Muon module
113   fgHitForRec = hitForRec; // pointer to points
114   fgNOfPoints = fgHitForRec->GetEntriesFast(); // number of points
115
116   fStartSegment = NULL;
117   fTrackHitsPtr = NULL;
118   fNTrackHits = 0;
119   fChi2 = 0;
120   fTrackPar = NULL;
121   fTrackParNew = NULL;
122   fCovariance = NULL;
123   fWeight = NULL;
124   fSkipHit = NULL;
125
126   return;
127 }
128
129   //__________________________________________________________________________
130 AliMUONTrackK::AliMUONTrackK(AliMUONSegment *segment)
131   : TObject()
132 {
133   // Constructor from a segment
134   Double_t dX, dY, dZ;
135   AliMUONHitForRec *hit1, *hit2;
136   AliMUONRawCluster *clus;
137   TClonesArray *rawclusters;
138
139   fStartSegment = segment;
140   fRecover = 0;
141   // Pointers to hits from the segment
142   hit1 = segment->GetHitForRec1();
143   hit2 = segment->GetHitForRec2();
144   hit1->SetNTrackHits(hit1->GetNTrackHits()+1); // mark hit as being on track
145   hit2->SetNTrackHits(hit2->GetNTrackHits()+1); // mark hit as being on track
146   // check sorting in Z
147   if (hit1->GetZ() > hit2->GetZ()) {
148     hit1 = hit2;
149     hit2 = segment->GetHitForRec1();
150   }
151   // memory allocation for the TObjArray of pointers to reconstructed TrackHit's
152   fTrackHitsPtr = new TObjArray(10);
153   fNTrackHits = 2;
154   fChi2 = 0;
155   fBPFlag = kFALSE;
156   fTrackPar = new TMatrixD(fgkSize,1); // track parameters
157   fTrackParNew = new TMatrixD(fgkSize,1); // track parameters
158   fCovariance = new TMatrixD(fgkSize,fgkSize); // covariance matrix
159   fWeight = new TMatrixD(fgkSize,fgkSize); // weight matrix (inverse of covariance)
160
161   // Fill array of track parameters
162   if (hit1->GetChamberNumber() > 7) {
163     // last tracking station
164     (*fTrackPar)(0,0) = hit1->GetBendingCoor(); // y
165     (*fTrackPar)(1,0) = hit1->GetNonBendingCoor(); // x
166     fPosition = hit1->GetZ(); // z
167     fTrackHitsPtr->Add((TObjArray*)hit2); // add hit 2
168     fTrackHitsPtr->Add((TObjArray*)hit1); // add hit 1
169     fTrackDir = -1;
170   } else {
171     // last but one tracking station
172     (*fTrackPar)(0,0) = hit2->GetBendingCoor(); // y
173     (*fTrackPar)(1,0) = hit2->GetNonBendingCoor(); // x
174     fPosition = hit2->GetZ(); // z
175     fTrackHitsPtr->Add((TObjArray*)hit1); // add hit 1
176     fTrackHitsPtr->Add((TObjArray*)hit2); // add hit 2
177     fTrackDir = 1;
178   }
179   dZ = hit2->GetZ() - hit1->GetZ();
180   dY = hit2->GetBendingCoor() - hit1->GetBendingCoor();
181   dX = hit2->GetNonBendingCoor() - hit1->GetNonBendingCoor();
182   (*fTrackPar)(2,0) = TMath::ATan2(dY,dZ); // alpha
183   (*fTrackPar)(3,0) = TMath::ATan2(dX,dZ/TMath::Cos((*fTrackPar)(2,0))); // beta
184   (*fTrackPar)(4,0) = 1/fgEventReconstructor->GetBendingMomentumFromImpactParam(segment->GetBendingImpact()); // 1/Pt
185   (*fTrackPar)(4,0) *= TMath::Cos((*fTrackPar)(3,0)); // 1/p
186   cout << fgEventReconstructor->GetBendingMomentumFromImpactParam(segment->GetBendingImpact()) << " " << 1/(*fTrackPar)(4,0) << " ";
187   if (fgEventReconstructor->GetRecGeantHits()) { 
188     // from GEANT hits
189     cout << ((AliMUONHitForRec*)((*fTrackHitsPtr)[0]))->GetTHTrack() << "<-->" << ((AliMUONHitForRec*)((*fTrackHitsPtr)[1]))->GetTHTrack() << endl;
190   } else {
191     // from raw clusters
192     for (Int_t i=0; i<2; i++) {
193       hit1 = (AliMUONHitForRec*) ((*fTrackHitsPtr)[i]);
194       rawclusters = fgMUON->GetMUONData()->RawClusters(hit1->GetChamberNumber());
195       clus = (AliMUONRawCluster*) rawclusters->UncheckedAt(hit1->GetHitNumber());
196       cout << clus->GetTrack(1)-1;
197       if (clus->GetTrack(2) != 0) cout << " " << clus->GetTrack(2)-1;
198       if (i == 0) cout << " <--> ";
199     }
200     cout << endl;
201   }
202   // Evaluate covariance (and weight) matrix
203   EvalCovariance(dZ);
204
205   return;
206 }
207
208   //__________________________________________________________________________
209 AliMUONTrackK::~AliMUONTrackK()
210 {
211   // Destructor
212
213   if (fTrackHitsPtr) {
214     delete fTrackHitsPtr; // delete the TObjArray of pointers to TrackHit's
215     fTrackHitsPtr = NULL;
216   }
217   delete fTrackPar; delete fTrackParNew; delete fCovariance;
218   delete fWeight; 
219 }
220
221   //__________________________________________________________________________
222 AliMUONTrackK::AliMUONTrackK (const AliMUONTrackK& source)
223   : TObject(source)
224 {
225 // Protected copy constructor
226
227   Fatal("AliMUONTrackK", "Not implemented.");
228 }
229
230   //__________________________________________________________________________
231 AliMUONTrackK & AliMUONTrackK::operator=(const AliMUONTrackK& source)
232 {
233   // Assignment operator
234   // Members
235   if(&source == this) return *this;
236
237   // base class assignement
238   TObject::operator=(source);
239
240   fStartSegment = source.fStartSegment;
241   fNTrackHits = source.fNTrackHits;
242   fChi2 = source.fChi2;
243   fPosition = source.fPosition;
244   fPositionNew = source.fPositionNew;
245   fTrackDir = source.fTrackDir;
246   fBPFlag = source.fBPFlag;
247   fRecover = source.fRecover;
248   fSkipHit = source.fSkipHit;
249
250   // Pointers
251   fTrackHitsPtr = new TObjArray(*source.fTrackHitsPtr);
252   //source.fTrackHitsPtr->Dump();
253   //fTrackHitsPtr->Dump();
254   
255   fTrackPar = new TMatrixD(*source.fTrackPar); // track parameters
256   fTrackParNew = new TMatrixD(*source.fTrackParNew); // track parameters
257   fCovariance = new TMatrixD(*source.fCovariance); // covariance matrix
258   fWeight = new TMatrixD(*source.fWeight); // weight matrix (inverse of covariance)
259
260   return *this;
261 }
262
263   //__________________________________________________________________________
264 void AliMUONTrackK::EvalCovariance(Double_t dZ)
265 {
266   // Evaluate covariance (and weight) matrix for track candidate
267   Double_t sigmaB, sigmaNonB, tanA, tanB, dAdY, rad, dBdX, dBdY;
268
269   sigmaB = fgEventReconstructor->GetBendingResolution(); // bending resolution
270   sigmaNonB = fgEventReconstructor->GetNonBendingResolution(); // non-bending resolution
271
272   (*fWeight)(0,0) = sigmaB*sigmaB; // <yy>
273
274   (*fWeight)(1,1) = sigmaNonB*sigmaNonB; // <xx>
275
276   tanA = TMath::Tan((*fTrackPar)(2,0));
277   dAdY = 1/(1+tanA*tanA)/dZ;
278   (*fWeight)(2,2) = dAdY*dAdY*(*fWeight)(0,0)*2; // <aa>
279   (*fWeight)(0,2) = dAdY*(*fWeight)(0,0); // <ya>
280   (*fWeight)(2,0) = (*fWeight)(0,2);
281
282   rad = dZ/TMath::Cos((*fTrackPar)(2,0));
283   tanB = TMath::Tan((*fTrackPar)(3,0));
284   dBdX = 1/(1+tanB*tanB)/rad;
285   dBdY = 0; // neglect
286   (*fWeight)(3,3) = dBdX*dBdX*(*fWeight)(1,1)*2; // <bb>
287   (*fWeight)(1,3) = dBdX*(*fWeight)(1,1); // <xb>
288   (*fWeight)(3,1) = (*fWeight)(1,3);
289
290   //(*fWeight)(4,4) = ((*fTrackPar)(4,0)*0.2)*((*fTrackPar)(4,0)*0.2); // error 20%
291   (*fWeight)(4,4) = ((*fTrackPar)(4,0)*0.5)*((*fTrackPar)(4,0)*0.5); // error 50%
292
293   // check whether the Invert method returns flag if matrix cannot be inverted,
294   // and do not calculate the Determinant in that case !!!!
295   if (fWeight->Determinant() != 0) {
296
297     // fWeight->Invert();
298
299     Int_t ifailWeight;
300     mnvertLocalK(&((*fWeight)(0,0)), fgkSize,fgkSize,fgkSize,ifailWeight);
301   } else {
302     cout << " ***** Warning in EvalCovariance: Determinant fWeight=0:" << endl;
303   }
304   return;
305 }
306
307   //__________________________________________________________________________
308 Bool_t AliMUONTrackK::KalmanFilter(Int_t ichamBeg, Int_t ichamEnd, Bool_t Back, Double_t zDipole1, Double_t zDipole2)
309 {
310   // Follows track through detector stations 
311   Bool_t miss, success;
312   Int_t ichamb, iFB, iMin, iMax, dChamb, ichambOK, i;
313   Int_t ihit, firstIndx, lastIndx, currIndx, dChambMiss, iDindx=0;
314   Double_t zEnd, dChi2;
315   AliMUONHitForRec *hitAdd, *firstHit, *lastHit, *hit;
316   AliMUONRawCluster *clus;
317   TClonesArray *rawclusters;
318   hit = 0; clus = 0; rawclusters = 0;
319
320   miss = kTRUE;
321   success = kTRUE;
322   Int_t endOfProp = 0;
323   iFB = TMath::Sign(1,ichamEnd-ichamBeg);
324   iMin = TMath::Min(ichamEnd,ichamBeg);
325   iMax = TMath::Max(ichamEnd,ichamBeg);
326   ichamb = ichamBeg;
327   ichambOK = ichamb;
328
329   // Get indices of the 1'st and last hits on the track candidate
330   firstHit = (AliMUONHitForRec*) fTrackHitsPtr->First();
331   lastHit = (AliMUONHitForRec*) fTrackHitsPtr->Last();
332   firstIndx = fgHitForRec->IndexOf(firstHit);
333   lastIndx = fgHitForRec->IndexOf(lastHit);
334   currIndx = TMath::Abs (TMath::Max(firstIndx*iFB,lastIndx*iFB));
335   if (Back) {
336     // backpropagation
337     currIndx = 2; 
338     iDindx = 1;
339     if (fRecover != 0) {
340       // find hit with the highest Z
341       Double_t zbeg = 0;
342       for (i=0; i<fNTrackHits; i++) {
343         hitAdd = (AliMUONHitForRec*) ((*fTrackHitsPtr)[i]);
344         zEnd = hitAdd->GetZ();
345         if (zEnd > zbeg) zbeg = zEnd;
346         else {
347           currIndx = fNTrackHits - i + 2; //???
348           break;
349         }
350       } //for (Int_t i=0;
351     }
352   } else if (fRecover != 0) {
353     Back = kTRUE; // dirty trick
354     iDindx = -1;
355     if (ichamBeg == 7 || ichamBeg == 8) currIndx = fNTrackHits - 2;
356     else {
357       Double_t zbeg = ((AliMUONHitForRec*)((*fTrackHitsPtr)[0]))->GetZ();
358       for (i=1; i<fNTrackHits; i++) {
359         hitAdd = (AliMUONHitForRec*) ((*fTrackHitsPtr)[i]);
360         zEnd = hitAdd->GetZ();
361         if (zEnd < zbeg) break;
362       } //for (Int_t i=1;
363       currIndx = fNTrackHits - i; //???
364     }
365   }
366
367   while (ichamb>=iMin && ichamb<=iMax) {
368   // Find the closest hit in Z, not belonging to the current plane
369     if (Back) {
370       // backpropagation
371       hitAdd = (AliMUONHitForRec*) ((*fTrackHitsPtr)[fNTrackHits-currIndx]);
372       zEnd = hitAdd->GetZ();
373     } else {
374       zEnd = -9999;
375       for (ihit=currIndx+iFB; ihit>=0 && ihit<fgNOfPoints; ihit+=iFB) {
376         hitAdd = (AliMUONHitForRec*) ((*fgHitForRec)[ihit]);
377         //if (TMath::Abs(hitAdd->GetZ()-fPosition) > 0.1) {
378         if (TMath::Abs(hitAdd->GetZ()-fPosition) > 0.5) {
379           zEnd = hitAdd->GetZ();
380           currIndx = ihit;
381           break;
382         }
383       }
384     }
385     if (zEnd<-999 && ichamb==ichamEnd) endOfProp = 1; // end-of-propagation
386     else {
387       // Check if there is a missing chamber
388       if (zEnd<-999 || TMath::Abs(hitAdd->GetChamberNumber()-ichamb) > 1) {
389         if (!Back && zEnd>-999) currIndx -= iFB;
390         ichamb += iFB;
391         zEnd = (&(fgMUON->Chamber(ichamb)))->Z();
392         miss = kTRUE;
393       } else {
394         ichamb = hitAdd->GetChamberNumber();
395         miss = kFALSE;
396       }
397     }
398     if (ichamb<iMin || ichamb>iMax) break;
399     // Check for missing station 
400     if (!Back) {
401       dChamb = TMath::Abs(ichamb-ichambOK); 
402       if (dChamb > 1) {
403         dChambMiss = endOfProp;
404         //Check if (iFB > 0) dChambMiss++;
405         if (iFB > 0) {
406           if (TMath::Odd(ichambOK)) dChambMiss++;
407           else dChambMiss--;
408         }
409         //cout << dChamb << " " << ichambOK << " " << fgNOfPoints << endl;
410         if (TMath::Odd(ichambOK) && dChamb > 3-dChambMiss) {
411           // missing station - abandon track
412           //cout << dChamb << " " << ichambOK << " " << fgNOfPoints << " " << 1/(*fTrackPar)(4,0) << endl;
413           /*
414           for (Int_t i1=0; i1<fgNOfPoints; i1++) {
415             cout << " Hit #" << ((AliMUONHitForRec*)((*fgHitForRec)[i1]))->GetChamberNumber() << " ";
416             cout << ((AliMUONHitForRec*)((*fgHitForRec)[i1]))->GetBendingCoor() << " ";
417             cout << ((AliMUONHitForRec*)((*fgHitForRec)[i1]))->GetNonBendingCoor() << " ";
418             cout << ((AliMUONHitForRec*)((*fgHitForRec)[i1]))->GetZ() << " " << " ";
419             cout << ((AliMUONHitForRec*)((*fgHitForRec)[i1]))->GetTHTrack() << endl;
420           }
421           //cout << endl;
422           */
423           /*
424           cout << fNTrackHits << endl;
425           for (Int_t i1=0; i1<fNTrackHits; i1++) {
426             hit = (AliMUONHitForRec*) ((*fTrackHitsPtr)[i1]);
427             printf(" * %d %10.4f %10.4f %10.4f", 
428                    hit->GetChamberNumber(), hit->GetBendingCoor(), 
429                    hit->GetNonBendingCoor(), hit->GetZ());
430             if (fgEventReconstructor->GetRecGeantHits()) { 
431               // from GEANT hits
432               printf(" %3d %3d \n", hit->GetGeantSignal(), hit->GetTHTrack());
433             } else {
434               // from raw clusters
435               rawclusters = fgMUON->RawClustAddress(hit->GetChamberNumber());
436               clus = (AliMUONRawCluster*) rawclusters->UncheckedAt(hit->GetHitNumber());
437               printf("%3d", clus->fTracks[1]-1); 
438               if (clus->fTracks[2] != 0) printf("%3d \n", clus->fTracks[2]-1);
439               else printf("\n");
440             }
441           }
442           */
443           if (fNTrackHits>2 && fRecover==0 && !(ichambOK==((AliMUONHitForRec*)((*fTrackHitsPtr)[0]))->GetChamberNumber())) {
444             // try to recover track later
445             Recover();
446           } 
447           return kFALSE;
448         }
449         //Check else if (TMath::Even(ichambOK) && dChamb > 2-endOfProp) {
450         else if (TMath::Even(ichambOK) && dChamb > 2-dChambMiss) {
451           // missing station - abandon track
452           //cout << dChamb << " " << ichambOK << " " << fgNOfPoints << " " << 1/(*fTrackPar)(4,0) << endl;
453           /*
454           for (Int_t i1=0; i1<fgNOfPoints; i1++) {
455             cout << " Hit #" << ((AliMUONHitForRec*)((*fgHitForRec)[i1]))->GetChamberNumber() << " ";
456             cout << ((AliMUONHitForRec*)((*fgHitForRec)[i1]))->GetBendingCoor() << " ";
457             cout << ((AliMUONHitForRec*)((*fgHitForRec)[i1]))->GetNonBendingCoor() << " ";
458             cout << ((AliMUONHitForRec*)((*fgHitForRec)[i1]))->GetZ() << " " << " ";
459             cout << ((AliMUONHitForRec*)((*fgHitForRec)[i1]))->GetTHTrack() << endl;
460           }
461           //cout << endl;
462           */
463           /*
464           cout << fNTrackHits << endl;
465           for (Int_t i1=0; i1<fNTrackHits; i1++) {
466             hit = (AliMUONHitForRec*) ((*fTrackHitsPtr)[i1]);
467             printf(" * %d %10.4f %10.4f %10.4f", 
468                    hit->GetChamberNumber(), hit->GetBendingCoor(), 
469                    hit->GetNonBendingCoor(), hit->GetZ());
470             if (fgEventReconstructor->GetRecGeantHits()) { 
471               // from GEANT hits
472               printf(" %3d %3d \n", hit->GetGeantSignal(), hit->GetTHTrack());
473             } else {
474               // from raw clusters
475               rawclusters = fgMUON->RawClustAddress(hit->GetChamberNumber());
476               clus = (AliMUONRawCluster*) rawclusters->UncheckedAt(hit->GetHitNumber());
477               printf("%3d", clus->fTracks[1]-1); 
478               if (clus->fTracks[2] != 0) printf("%3d \n", clus->fTracks[2]-1);
479               else printf("\n");
480             }
481           }
482           */
483           if (fNTrackHits>2 && fRecover==0 && !(ichambOK==((AliMUONHitForRec*)((*fTrackHitsPtr)[0]))->GetChamberNumber())) {
484             // try to recover track later
485             Recover();
486           } 
487           return kFALSE;
488         }
489       }
490     }
491     if (endOfProp != 0) break;
492
493     // propagate to the found Z
494
495     // Check if track steps into dipole
496     if (fPosition>zDipole2 && zEnd<zDipole2) {
497       //LinearPropagation(zDipole2-zBeg); 
498       ParPropagation(zDipole2); 
499       MSThin(1); // multiple scattering in the chamber
500       WeightPropagation(zDipole2); // propagate weight matrix
501       fPosition = fPositionNew;
502       *fTrackPar = *fTrackParNew; 
503       //MagnetPropagation(zEnd); 
504       ParPropagation(zEnd); 
505       WeightPropagation(zEnd);
506       fPosition = fPositionNew;
507     } 
508     // Check if track steps out of dipole
509     else if (fPosition>zDipole1 && zEnd<zDipole1) {
510       //MagnetPropagation(zDipole1-zBeg); 
511       ParPropagation(zDipole1); 
512       MSThin(1); // multiple scattering in the chamber
513       WeightPropagation(zDipole1);
514       fPosition = fPositionNew;
515       *fTrackPar = *fTrackParNew; 
516       //LinearPropagation(zEnd-zDipole1); 
517       ParPropagation(zEnd); 
518       WeightPropagation(zEnd);
519       fPosition = fPositionNew;
520     } else {
521       ParPropagation(zEnd);
522       //MSThin(1); // multiple scattering in the chamber
523       if (TMath::Abs(zEnd-fPosition) > 5) MSThin(1); // multiple scattering in the chamber
524       WeightPropagation(zEnd);
525       fPosition = fPositionNew;
526     }
527
528     // Add measurement
529     if (fRecover != 0 && hitAdd == fSkipHit && !miss) {
530       // recovered track - remove the hit
531       miss = kTRUE;
532       ichamb = hitAdd->GetChamberNumber();
533       if (fRecover == 1) {
534         // remove the last hit
535         fTrackHitsPtr->Remove((TObjArray*)hitAdd); // remove hit
536         fNTrackHits --;
537         hitAdd->SetNTrackHits(hitAdd->GetNTrackHits()-1); // unmark hit 
538       } else {
539         // remove the hits
540         for (i=fNTrackHits-1; i>1; i--) {
541           hitAdd = (AliMUONHitForRec*)((*fTrackHitsPtr)[i]);
542           fTrackHitsPtr->Remove((TObjArray*)hitAdd); // remove hit
543           hitAdd->SetNTrackHits(hitAdd->GetNTrackHits()-1); // unmark hit 
544           fNTrackHits --;
545           if (hitAdd == fSkipHit) break;
546         } // for (i=fNTrackHits-1;
547       }
548       Back = kFALSE;
549       fRecover =0; // ????????? Dec-17-2001
550       ichambOK = ((AliMUONHitForRec*)((*fTrackHitsPtr)[fNTrackHits-1]))->GetChamberNumber();
551       currIndx = fgHitForRec->IndexOf(fSkipHit);
552     }
553
554     if (Back && !miss) {
555       // backward propagator
556       TMatrixD pointWeight(fgkSize,fgkSize);
557       TMatrixD point(fgkSize,1);
558       TMatrixD trackParTmp = point;
559       point(0,0) = hitAdd->GetBendingCoor();
560       point(1,0) = hitAdd->GetNonBendingCoor();
561       pointWeight(0,0) = 1/hitAdd->GetBendingReso2();
562       pointWeight(1,1) = 1/hitAdd->GetNonBendingReso2();
563       TryPoint(point,pointWeight,trackParTmp,dChi2);
564       *fTrackPar = trackParTmp;
565       *fWeight += pointWeight; 
566       fChi2 += dChi2; // Chi2
567       if (ichamb==ichamEnd) break; 
568       currIndx += iDindx;
569     } else {
570       // forward propagator
571       if (miss || !FindPoint(ichamb,zEnd,currIndx,iFB,hitAdd)) {
572         // missing point
573         *fTrackPar = *fTrackParNew; 
574       } else {
575         //add point
576         fTrackHitsPtr->Add((TObjArray*)hitAdd); // add hit
577         fNTrackHits ++;
578         hitAdd->SetNTrackHits(hitAdd->GetNTrackHits()+1); // mark hit as being on track
579         ichambOK = ichamb;
580         currIndx = fgHitForRec->IndexOf(hitAdd); // Check
581       }
582     }
583   } // while
584   cout << fNTrackHits << " " << fChi2 << " " << 1/(*fTrackPar)(4,0) << " " << fPosition << endl;
585   return success;
586 }
587
588   //__________________________________________________________________________
589 void AliMUONTrackK::ParPropagation(Double_t zEnd)
590 {
591   // Propagation of track parameters to zEnd
592   Int_t iFB, nTries;
593   Double_t dZ, step, distance, charge;
594   Double_t vGeant3[7], vGeant3New[7];
595
596   nTries = 0;
597   // First step using linear extrapolation
598   dZ = zEnd - fPosition;
599   iFB = (Int_t)TMath::Sign(Double_t(1.0),dZ);
600   step = dZ/TMath::Cos((*fTrackPar)(2,0))/TMath::Cos((*fTrackPar)(3,0)); // linear estimate
601   charge = iFB*TMath::Sign(Double_t(1.0),(*fTrackPar)(4,0));
602   fPositionNew = fPosition;
603   *fTrackParNew = *fTrackPar;
604   SetGeantParam(vGeant3,iFB);
605
606   // Check if overstep
607   do {
608     step = TMath::Abs(step);
609     // Propagate parameters
610     extrap_onestep_rungekutta(charge,step,vGeant3,vGeant3New);
611     distance = zEnd - vGeant3New[2];
612     step *= dZ/(vGeant3New[2]-fPositionNew);
613     nTries ++;
614   } while (distance*iFB < 0 && TMath::Abs(distance) > fgkEpsilon);
615
616   GetFromGeantParam(vGeant3New,iFB);
617
618   // Position ajustment (until within tolerance)
619   while (TMath::Abs(distance) > fgkEpsilon) {
620     dZ = zEnd - fPositionNew;
621     iFB = (Int_t)TMath::Sign(Double_t(1.0),dZ);
622     step = dZ/TMath::Cos((*fTrackParNew)(2,0))/TMath::Cos((*fTrackParNew)(3,0));
623     step = TMath::Abs(step);
624     SetGeantParam(vGeant3,iFB);
625     do {
626       // binary search
627       // Propagate parameters
628       extrap_onestep_rungekutta(charge,step,vGeant3,vGeant3New);
629       distance = zEnd - vGeant3New[2];
630       step /= 2;
631       nTries ++;
632       if (nTries > fgkTriesMax) {
633         cout << " ***** ParPropagation: too many tries " << nTries << endl;
634         exit(0);
635       }
636     } while (distance*iFB < 0);
637
638     GetFromGeantParam(vGeant3New,iFB);
639   }
640   //cout << nTries << endl;
641   return;
642 }
643 /*
644   //__________________________________________________________________________
645 void AliMUONTrackK::WeightPropagation(void)
646 {
647   // Propagation of the weight matrix
648   // W = DtWD, where D is Jacobian 
649
650   // !!! not implemented TMatrixD weight1(*fJacob,TMatrixD::kAtBA,*fWeight); // DtWD
651   TMatrixD weight1(*fWeight,TMatrixD::kMult,*fJacob); // WD
652   *fWeight = TMatrixD(*fJacob,TMatrixD::kTransposeMult,weight1); // DtWD
653   return;
654 }
655 */
656   //__________________________________________________________________________
657 void AliMUONTrackK::WeightPropagation(Double_t zEnd)
658 {
659   // Propagation of the weight matrix
660   // W = DtWD, where D is Jacobian 
661   Int_t i, j;
662   Double_t dPar;
663
664   TMatrixD jacob(fgkSize,fgkSize);
665   jacob = 0;
666
667   // Save initial and propagated parameters
668   TMatrixD trackPar0 = *fTrackPar;
669   TMatrixD trackParNew0 = *fTrackParNew;
670   Double_t savePosition = fPositionNew;
671
672   // Get covariance matrix
673   *fCovariance = *fWeight;
674   // check whether the Invert method returns flag if matrix cannot be inverted,
675   // and do not calculate the Determinant in that case !!!!
676   if (fCovariance->Determinant() != 0) {
677     //   fCovariance->Invert();
678     Int_t ifailCov;
679     mnvertLocalK(&((*fCovariance)(0,0)), fgkSize,fgkSize,fgkSize,ifailCov);
680   } else {
681     cout << " ***** Warning in WeightPropagation: Determinant fCovariance=0:" << endl;
682   }
683
684   // Loop over parameters to find change of the initial vs propagated ones
685   zEnd = fPosition;
686   fPosition = fPositionNew;
687   for (i=0; i<fgkSize; i++) {
688     dPar = TMath::Sqrt((*fCovariance)(i,i));
689     *fTrackPar = trackParNew0;
690     (*fTrackPar)(i,0) += dPar;
691     ParPropagation(zEnd);
692     for (j=0; j<fgkSize; j++) {
693       jacob(j,i) = ((*fTrackParNew)(j,0)-trackPar0(j,0))/dPar;
694     }
695   }
696
697   //jacob->Print();
698   //trackParNew0.Print();
699   //TMatrixD par1(jacob,TMatrixD::kMult,trackPar0); //
700   //par1.Print();
701   /*
702   if (jacob.Determinant() != 0) {
703     //  jacob.Invert();
704   } else {
705     cout << " ***** Warning in WeightPropagation: Determinant jacob=0:" << endl;
706   }
707   */
708   TMatrixD weight1(*fWeight,TMatrixD::kMult,jacob); // WD
709   *fWeight = TMatrixD(jacob,TMatrixD::kTransposeMult,weight1); // DtWD
710   //fWeight->Print();
711
712   // Restore initial and propagated parameters
713   *fTrackPar = trackPar0;
714   *fTrackParNew = trackParNew0;
715   fPosition = zEnd;
716   fPositionNew = savePosition;
717   return;
718 }
719
720   //__________________________________________________________________________
721 Bool_t AliMUONTrackK::FindPoint(Int_t ichamb, Double_t zEnd, Int_t currIndx, Int_t iFB, AliMUONHitForRec *&hitAdd)
722 {
723   // Picks up point within a window for the chamber No ichamb 
724   // Split the track if there are more than 1 hit
725   Int_t ihit, nRecTracks;
726   Double_t windowB, windowNonB, dChi2Tmp=0, dChi2, y, x, savePosition=0;
727   TClonesArray *trackPtr;
728   AliMUONHitForRec *hit, *hitLoop;
729   AliMUONTrackK *trackK;
730
731   Bool_t ok = kFALSE;
732   //sigmaB = fgEventReconstructor->GetBendingResolution(); // bending resolution
733   //sigmaNonB = fgEventReconstructor->GetNonBendingResolution(); // non-bending resolution
734   *fCovariance = *fWeight;
735   // check whether the Invert method returns flag if matrix cannot be inverted,
736   // and do not calculate the Determinant in that case !!!!
737   if (fCovariance->Determinant() != 0) {
738     //  fCovariance->Invert();
739
740       Int_t ifailCov;
741       mnvertLocalK(&((*fCovariance)(0,0)), fgkSize,fgkSize,fgkSize,ifailCov);
742   } else {
743     cout << " ***** Warning in FindPoint: Determinant fCovariance=0:" << endl;
744   }
745   //windowB = fgkNSigma*TMath::Sqrt((*fCovariance)(0,0)+sigmaB*sigmaB);
746   //windowNonB = fgkNSigma*TMath::Sqrt((*fCovariance)(1,1)+sigmaNonB*sigmaNonB);
747   // Loop over all hits and take hits from the chamber
748   TMatrixD pointWeight(fgkSize,fgkSize);
749   TMatrixD saveWeight = pointWeight;
750   TMatrixD pointWeightTmp = pointWeight;
751   TMatrixD point(fgkSize,1);
752   TMatrixD trackPar = point;
753   TMatrixD trackParTmp = point;
754   Int_t nHitsOK = 0;
755
756   for (ihit=currIndx; ihit>=0 && ihit<fgNOfPoints; ihit+=iFB) {
757     hit = (AliMUONHitForRec*) ((*fgHitForRec)[ihit]);
758     if (hit->GetChamberNumber() == ichamb) {
759       //if (TMath::Abs(hit->GetZ()-zEnd) < 0.1) {
760       if (TMath::Abs(hit->GetZ()-zEnd) < 0.5) {
761         if (TMath::Abs(hit->GetZ()-zEnd) > 0.1) {
762           // adjust position: for multiple hits in the chamber
763           // (mostly (only?) for GEANT hits)
764           zEnd = hit->GetZ();
765           *fTrackPar = *fTrackParNew;
766           ParPropagation(zEnd);
767           WeightPropagation(zEnd);
768           fPosition = fPositionNew;
769           *fTrackPar = *fTrackParNew;
770           // Get covariance
771           *fCovariance = *fWeight;
772           if (fCovariance->Determinant() != 0) {
773             //fCovariance->Invert();
774             Int_t ifailCov;
775             mnvertLocalK(&((*fCovariance)(0,0)), fgkSize,fgkSize,fgkSize,ifailCov);
776           } else {
777             cout << " ***** Warning in FindPoint: Determinant fCovariance=0:" << endl;
778           }
779         }
780         y = hit->GetBendingCoor();
781         x = hit->GetNonBendingCoor();
782         windowB = fgkNSigma*TMath::Sqrt((*fCovariance)(0,0)+hit->GetBendingReso2());
783         windowNonB = fgkNSigma*TMath::Sqrt((*fCovariance)(1,1)+hit->GetNonBendingReso2());
784         if (TMath::Abs((*fTrackParNew)(0,0)-y) <= windowB &&
785             TMath::Abs((*fTrackParNew)(1,0)-x) <= windowNonB) {
786           // Vector of measurements and covariance matrix
787           point.Zero();
788           point(0,0) = y;
789           point(1,0) = x;
790           pointWeight(0,0) = 1/hit->GetBendingReso2();
791           pointWeight(1,1) = 1/hit->GetNonBendingReso2();
792           TryPoint(point,pointWeight,trackPar,dChi2);
793           if (TMath::Abs(1./(trackPar)(4,0)) < fgEventReconstructor->GetMinBendingMomentum()) continue; // p < p_min - next hit
794           ok = kTRUE;
795           nHitsOK++;
796           //if (nHitsOK > -1) {
797           if (nHitsOK == 1) {
798             // Save current members
799             saveWeight = *fWeight;
800             savePosition = fPosition;
801             // temporary storage for the current track
802             dChi2Tmp = dChi2;
803             trackParTmp = trackPar;
804             pointWeightTmp = pointWeight;
805             hitAdd = hit;
806           } else {
807             // branching: create a new track
808             trackPtr = fgEventReconstructor->GetRecTracksPtr();
809             nRecTracks = fgEventReconstructor->GetNRecTracks();
810             trackK = new ((*trackPtr)[nRecTracks])
811                      AliMUONTrackK(*this); // dummy copy constructor
812             *trackK = *this;
813             fgEventReconstructor->SetNRecTracks(nRecTracks+1);
814             //cout << " ******** New track: " << ichamb << " " << hit->GetTHTrack() << " " << 1/(trackPar)(4,0) << " " << hit->GetBendingCoor() << " " << fNTrackHits << " " << nRecTracks << endl;
815             trackK->fRecover = 0;
816             *(trackK->fTrackPar) = trackPar;
817             *(trackK->fWeight) += pointWeight; 
818             trackK->fChi2 += dChi2;
819             // Mark hits as being on 2 tracks
820             for (Int_t i=0; i<fNTrackHits; i++) {
821               hitLoop = (AliMUONHitForRec*) ((*fTrackHitsPtr)[i]);
822               hitLoop->SetNTrackHits(hitLoop->GetNTrackHits()+1); 
823               /*
824               cout << " ** ";
825               cout << hitLoop->GetChamberNumber() << " ";
826               cout << hitLoop->GetBendingCoor() << " ";
827               cout << hitLoop->GetNonBendingCoor() << " ";
828               cout << hitLoop->GetZ() << " " << " ";
829               cout << hitLoop->GetGeantSignal() << " " << " ";
830               cout << hitLoop->GetTHTrack() << endl;
831               printf(" ** %d %10.4f %10.4f %10.4f %d %d \n", 
832                      hitLoop->GetChamberNumber(), hitLoop->GetBendingCoor(), 
833                      hitLoop->GetNonBendingCoor(), hitLoop->GetZ(), 
834                      hitLoop->GetGeantSignal(), hitLoop->GetTHTrack());
835               */
836             }
837             //add point
838             trackK->fTrackHitsPtr->Add((TObjArray*)hit); // add hit
839             trackK->fNTrackHits ++;
840             hit->SetNTrackHits(hit->GetNTrackHits()+1); // mark hit as being on track
841             if (ichamb == 9) {
842               // the last chamber
843               trackK->fTrackDir = -1;
844               trackK->fBPFlag = kTRUE; 
845             }
846           }
847         }
848       }
849     } else break; // different chamber
850   } // for (ihit=currIndx;
851   if (ok) {
852     *fTrackPar = trackParTmp;
853     *fWeight = saveWeight;
854     *fWeight += pointWeightTmp; 
855     fChi2 += dChi2Tmp; // Chi2
856     // Restore members
857     fPosition = savePosition;
858   }
859   return ok;
860 }
861
862   //__________________________________________________________________________
863 void AliMUONTrackK::TryPoint(TMatrixD &point, const TMatrixD &pointWeight, TMatrixD &trackParTmp, Double_t &dChi2)
864 {
865   // Adds a measurement point (modifies track parameters and computes
866   // change of Chi2)
867
868   // Solving linear system (W+U)p' = U(m-p) + (W+U)p
869   TMatrixD wu = *fWeight;
870   wu += pointWeight; // W+U
871   trackParTmp = point;
872   trackParTmp -= *fTrackParNew; // m-p
873   TMatrixD right(pointWeight,TMatrixD::kMult,trackParTmp); // U(m-p)
874   TMatrixD right1(wu,TMatrixD::kMult,*fTrackParNew); // (W+U)p
875   right += right1; // U(m-p) + (W+U)p
876
877   // check whether the Invert method returns flag if matrix cannot be inverted,
878   // and do not calculate the Determinant in that case !!!!
879   if (wu.Determinant() != 0) {
880
881     //  wu.Invert();
882      Int_t ifailWU;
883       mnvertLocalK(&((wu)(0,0)), fgkSize,fgkSize,fgkSize,ifailWU);
884   } else {
885     cout << " ***** Warning in TryPoint: Determinant wu=0:" << endl;
886   }
887   trackParTmp = TMatrixD(wu,TMatrixD::kMult,right); 
888
889   right1 = trackParTmp;
890   right1 -= point; // p'-m
891   point = trackParTmp;
892   point -= *fTrackParNew; // p'-p
893   right = TMatrixD(*fWeight,TMatrixD::kMult,point); // W(p'-p)
894   TMatrixD value(point,TMatrixD::kTransposeMult,right); // (p'-p)'W(p'-p)
895   dChi2 = value(0,0);
896   right = TMatrixD(pointWeight,TMatrixD::kMult,right1); // U(p'-m)
897   value = TMatrixD(right1,TMatrixD::kTransposeMult,right); // (p'-m)'U(p'-m)
898   dChi2 += value(0,0);
899   return;
900 }
901
902   //__________________________________________________________________________
903 void AliMUONTrackK::MSThin(Int_t sign)
904 {
905   // Adds multiple scattering in a thin layer (only angles are affected)
906   Double_t cosAlph, cosBeta, momentum, velo, path, theta0;
907
908   // check whether the Invert method returns flag if matrix cannot be inverted,
909   // and do not calculate the Determinant in that case !!!!
910   if (fWeight->Determinant() != 0) {
911     //fWeight->Invert(); // covariance
912
913     Int_t ifailWeight;
914     mnvertLocalK(&((*fWeight)(0,0)), fgkSize,fgkSize,fgkSize,ifailWeight);
915   } else {
916     cout << " ***** Warning in MSThin: Determinant fWeight=0:" << endl;
917   }
918
919   cosAlph = TMath::Cos((*fTrackParNew)(2,0));
920   cosBeta = TMath::Cos((*fTrackParNew)(3,0));
921   momentum = 1/(*fTrackParNew)(4,0); // particle momentum
922   //velo = momentum/TMath::Sqrt(momentum*momentum+muonMass*muonMass); // velocity/c for muon hypothesis
923   velo = 1; // relativistic
924   path = fgEventReconstructor->GetChamberThicknessInX0()/cosAlph/cosBeta; // path length
925   theta0 = 0.0136/velo/momentum*TMath::Sqrt(path)*(1+0.038*TMath::Log(path)); // projected scattering angle
926
927   (*fWeight)(2,2) += sign*theta0/cosBeta*theta0/cosBeta; // alpha
928   (*fWeight)(3,3) += sign*theta0*theta0; // beta
929   //fWeight->Invert(); // weight
930
931   Int_t ifailWeight;
932   mnvertLocalK(&((*fWeight)(0,0)), fgkSize,fgkSize,fgkSize,ifailWeight);
933   return;
934 }
935   //__________________________________________________________________________
936 void AliMUONTrackK::StartBack(void)
937 {
938   // Starts backpropagator
939   
940   fBPFlag = kTRUE;
941   fChi2 = 0;
942   for (Int_t i=0; i<fgkSize; i++) {
943     for (Int_t j=0; j<fgkSize; j++) {
944       if (j==i) (*fWeight)(i,i) /= 100;
945       //if (j==i) (*fWeight)(i,i) /= fNTrackHits*fNTrackHits;
946       else (*fWeight)(j,i) = 0;
947     }
948   }
949 }
950
951   //__________________________________________________________________________
952 void AliMUONTrackK::SetGeantParam(Double_t *VGeant3, Int_t iFB)
953 {
954   // Set vector of Geant3 parameters pointed to by "VGeant3"
955   // from track parameters 
956
957   VGeant3[0] = (*fTrackParNew)(1,0); // X
958   VGeant3[1] = (*fTrackParNew)(0,0); // Y
959   VGeant3[2] = fPositionNew; // Z
960   VGeant3[3] = iFB*TMath::Sin((*fTrackParNew)(3,0)); // Px/Ptot
961   VGeant3[4] = iFB*TMath::Cos((*fTrackParNew)(3,0))*TMath::Sin((*fTrackParNew)(2,0)); // Py/Ptot
962   VGeant3[5] = iFB*TMath::Sqrt(1.0-VGeant3[3]*VGeant3[3]-VGeant3[4]*VGeant3[4]); // Pz/Ptot
963   VGeant3[6] = 1/TMath::Abs((*fTrackParNew)(4,0)); // Ptot
964 }
965
966   //__________________________________________________________________________
967 void AliMUONTrackK::GetFromGeantParam(Double_t *VGeant3, Int_t iFB)
968 {
969   // Get track parameters from vector of Geant3 parameters pointed 
970   // to by "VGeant3"
971
972   fPositionNew = VGeant3[2]; // Z
973   (*fTrackParNew)(0,0) = VGeant3[1]; // Y 
974   (*fTrackParNew)(1,0) = VGeant3[0]; // X
975   (*fTrackParNew)(3,0) = TMath::ASin(iFB*VGeant3[3]); // beta
976   (*fTrackParNew)(2,0) = TMath::ASin(iFB*VGeant3[4]/TMath::Cos((*fTrackParNew)(3,0))); // alpha
977   (*fTrackParNew)(4,0) = 1/VGeant3[6]*TMath::Sign(Double_t(1.0),(*fTrackPar)(4,0)); // 1/Ptot
978 }
979
980   //__________________________________________________________________________
981 void AliMUONTrackK::SetTrackQuality(Int_t iChi2)
982 {
983   // Computes "track quality" from Chi2 (if iChi2==0) or vice versa
984
985   if (fChi2 > 250) {
986     cout << " ***** Too high Chi2: " << fChi2 << endl;
987     fChi2 = 250;
988     //   exit(0);
989   }
990   if (iChi2 == 0) fChi2 = fNTrackHits + (250.-fChi2)/251;
991   else fChi2 = 250 - (fChi2-fNTrackHits)*251;
992 }
993
994   //__________________________________________________________________________
995 Int_t AliMUONTrackK::Compare(const TObject* trackK) const
996 {
997   // "Compare" function to sort with decreasing "track quality".
998   // Returns +1 (0, -1) if quality of current track
999   // is smaller than (equal to, larger than) quality of trackK
1000
1001   if (fChi2 < ((AliMUONTrackK*)trackK)->fChi2) return(+1);
1002   else if (fChi2 == ((AliMUONTrackK*)trackK)->fChi2) return(0);
1003   else return(-1);
1004 }
1005
1006   //__________________________________________________________________________
1007 Bool_t AliMUONTrackK::KeepTrack(AliMUONTrackK* track0) const
1008 {
1009   // Check whether or not to keep current track 
1010   // (keep, if it has less than half of common hits with track0)
1011   Int_t hitsInCommon, nHits0, i, j, nTrackHits2;
1012   AliMUONHitForRec *hit0, *hit1;
1013
1014   hitsInCommon = 0;
1015   nHits0 = track0->fNTrackHits;
1016   nTrackHits2 = fNTrackHits/2;
1017
1018   for (i=0; i<nHits0; i++) {
1019     // Check if hit belongs to several tracks
1020     hit0 = (AliMUONHitForRec*) (*track0->fTrackHitsPtr)[i]; 
1021     if (hit0->GetNTrackHits() == 1) continue; 
1022     for (j=0; j<fNTrackHits; j++) {
1023       hit1 = (AliMUONHitForRec*) (*fTrackHitsPtr)[j]; 
1024       if (hit1->GetNTrackHits() == 1) continue; 
1025       if (hit0 == hit1) {
1026         hitsInCommon++;
1027         if (hitsInCommon >= nTrackHits2) return kFALSE;
1028         break;
1029       }
1030     } // for (j=0; 
1031   } // for (i=0; 
1032   return kTRUE;
1033 }
1034
1035   //__________________________________________________________________________
1036 void AliMUONTrackK::Kill(void)
1037 {
1038   // Kill track candidate
1039   Int_t i;
1040   AliMUONHitForRec *hit;
1041
1042   if (fTrackHitsPtr) {
1043     // Remove track mark from hits
1044     for (i=0; i<fNTrackHits; i++) {
1045       hit = (AliMUONHitForRec*) (*fTrackHitsPtr)[i]; 
1046       hit->SetNTrackHits(hit->GetNTrackHits()-1); 
1047     }
1048   }
1049   fgEventReconstructor->GetRecTracksPtr()->Remove(this);
1050 }
1051
1052   //__________________________________________________________________________
1053 void AliMUONTrackK::Branson(void)
1054 {
1055   // Propagates track to the vertex thru absorber using Branson correction
1056   // (makes use of the AliMUONTrackParam class)
1057  
1058   AliMUONTrackParam *trackParam = new AliMUONTrackParam();
1059   trackParam->SetBendingCoor((*fTrackPar)(0,0));
1060   trackParam->SetNonBendingCoor((*fTrackPar)(1,0));
1061   trackParam->SetBendingSlope(TMath::Tan((*fTrackPar)(2,0)));
1062   trackParam->SetNonBendingSlope(TMath::Tan((*fTrackPar)(3,0))/TMath::Cos((*fTrackPar)(2,0)));
1063   trackParam->SetInverseBendingMomentum((*fTrackPar)(4,0)/TMath::Cos((*fTrackPar)(3,0)));
1064   trackParam->SetZ(fPosition);
1065
1066   trackParam->ExtrapToVertex();
1067
1068   (*fTrackPar)(0,0) = trackParam->GetBendingCoor();
1069   (*fTrackPar)(1,0) = trackParam->GetNonBendingCoor();
1070   (*fTrackPar)(2,0) = TMath::ATan(trackParam->GetBendingSlope());
1071   (*fTrackPar)(3,0) = TMath::ATan(TMath::Cos((*fTrackPar)(2,0))*trackParam->GetNonBendingSlope());
1072   (*fTrackPar)(4,0) = TMath::Cos((*fTrackPar)(3,0))*trackParam->GetInverseBendingMomentum();
1073   fPosition = trackParam->GetZ();
1074   delete trackParam;
1075   cout << 1/(*fTrackPar)(4,0) << " " << fPosition << " " << (*fTrackPar)(0,0) << endl;
1076
1077   // Get covariance matrix
1078   *fCovariance = *fWeight;
1079   if (fCovariance->Determinant() != 0) {
1080     //    fCovariance->Invert();
1081
1082       Int_t ifailCov;
1083       mnvertLocalK(&((*fCovariance)(0,0)), fgkSize,fgkSize,fgkSize,ifailCov);
1084   } else {
1085     cout << " ***** Warning in Branson: Determinant fCovariance=0:" << endl;
1086   }
1087 }
1088
1089   //__________________________________________________________________________
1090 void AliMUONTrackK::GoToZ(Double_t zEnd)
1091 {
1092   // Propagates track to given Z
1093
1094   ParPropagation(zEnd);
1095   MSThin(1); // multiple scattering in the chamber
1096   WeightPropagation(zEnd);
1097   fPosition = fPositionNew;
1098   *fTrackPar = *fTrackParNew; 
1099 }
1100
1101   //__________________________________________________________________________
1102 void AliMUONTrackK::GoToVertex(void)
1103 {
1104   // Version 3.08
1105   // Propagates track to the vertex
1106   // All material constants are taken from AliRoot
1107
1108     static Double_t x01[5] = { 24.282,  // C
1109                                24.282,  // C
1110                                11.274,  // Concrete
1111                                 1.758,  // Fe 
1112                                 1.758}; // Fe (cm)
1113   // inner part theta < 3 degrees
1114     static Double_t x02[5] = { 30413,  // Air
1115                                24.282, // C
1116                                11.274, // Concrete
1117                                1.758,  // Fe
1118                                0.369}; // W (cm)
1119   // z positions of the materials inside the absober outer part theta > 3 degres
1120   static Double_t zPos[10] = {90, 105, 315, 443, 468};
1121   // R > 1
1122   // R < 1
1123
1124   Double_t dZ, r0Norm, x0, deltaP, dChi2, pTotal, pOld;
1125   AliMUONHitForRec *hit;
1126   AliMUONRawCluster *clus;
1127   TClonesArray *rawclusters;
1128
1129   // First step to the rear end of the absorber
1130   Double_t zRear = 503;
1131   GoToZ(zRear);
1132   Double_t tan3 = TMath::Tan(3./180*TMath::Pi());
1133
1134   // Go through absorber
1135   pOld = 1/(*fTrackPar)(4,0);
1136   Double_t r0Rear = (*fTrackPar)(0,0)*(*fTrackPar)(0,0) + 
1137                     (*fTrackPar)(1,0)*(*fTrackPar)(1,0);
1138   r0Rear = TMath::Sqrt(r0Rear)/fPosition/tan3;
1139   r0Norm = r0Rear;
1140   for (Int_t i=4; i>=0; i--) {
1141     ParPropagation(zPos[i]);
1142     WeightPropagation(zPos[i]);
1143     dZ = TMath::Abs (fPositionNew-fPosition);
1144     if (r0Norm > 1) x0 = x01[i];
1145     else x0 = x02[i];
1146     MSLine(dZ,x0); // multiple scattering in the medium (linear approximation)
1147     fPosition = fPositionNew;
1148     *fTrackPar = *fTrackParNew; 
1149     r0Norm = (*fTrackPar)(0,0)*(*fTrackPar)(0,0) + 
1150              (*fTrackPar)(1,0)*(*fTrackPar)(1,0);
1151     r0Norm = TMath::Sqrt(r0Norm)/fPosition/tan3;
1152   }
1153   // Correct momentum for energy losses
1154   pTotal = 1/TMath::Abs((*fTrackPar)(4,0));
1155   Double_t p0 = pTotal;
1156   for (Int_t j=0; j<2; j++) {
1157     /*
1158     if (r0Rear > 1) {
1159       if (p0 < 20) {
1160         deltaP = 2.164 + 0.145e-1*p0 - 0.417e-3*p0*p0;
1161       } else {
1162         deltaP = 2.275 + 0.102e-2*p0 - 0.674e-6*p0*p0;
1163       }
1164     } else {
1165       if (p0 < 20) {
1166         deltaP = 2.581 + 0.188e-1*p0 - 0.398e-3*p0*p0;
1167       } else {
1168         deltaP = 2.727 + 0.356e-2*p0 + 0.242e-5*p0*p0;
1169       }
1170     }
1171     */
1172     if (r0Rear < 1) {
1173       //W
1174       if (p0<15) {
1175         deltaP = 2.737 + 0.0494*p0 - 0.001123*p0*p0;
1176       } else {
1177         deltaP = 3.0643 + 0.01346*p0;
1178       }
1179     } else {
1180       //Pb
1181       if (p0<15) {
1182         deltaP  = 2.1380 + 0.0351*p0 - 0.000853*p0*p0;
1183       } else {
1184         deltaP = 2.407 + 0.00702*p0;
1185       }
1186     }
1187
1188     p0 = pTotal + deltaP/TMath::Cos((*fTrackPar)(2,0))/TMath::Cos((*fTrackPar)(3,0));
1189   }
1190   (*fTrackPar)(4,0) = 1/p0*TMath::Sign((Double_t)1.,(*fTrackPar)(4,0));
1191
1192   // Go to the vertex
1193   ParPropagation((Double_t)0.);
1194   WeightPropagation((Double_t)0.);
1195   fPosition = fPositionNew;
1196   //*fTrackPar = *fTrackParNew; 
1197   // Add vertex as a hit
1198   TMatrixD pointWeight(fgkSize,fgkSize);
1199   TMatrixD point(fgkSize,1);
1200   TMatrixD trackParTmp = point;
1201   point(0,0) = 0; // vertex coordinate - should be taken somewhere
1202   point(1,0) = 0; // vertex coordinate - should be taken somewhere
1203   pointWeight(0,0) = 1/1.e-3/1.e-3; // 10 um error
1204   pointWeight(1,1) = 1/1.e-3/1.e-3; // 10 um error
1205   TryPoint(point,pointWeight,trackParTmp,dChi2);
1206   *fTrackPar = trackParTmp;
1207   *fWeight += pointWeight; 
1208   fChi2 += dChi2; // Chi2
1209   cout << pOld << " " << 1/(*fTrackPar)(4,0) << " " << dChi2 << " " << fChi2 << " " << fNTrackHits << endl;
1210   for (Int_t i1=0; i1<fNTrackHits; i1++) {
1211     hit =  (AliMUONHitForRec*) ((*fTrackHitsPtr)[i1]);
1212     printf ("%4d", hit->GetChamberNumber()); 
1213     //cout << ((AliMUONHitForRec*)((*fTrackHitsPtr)[i1]))->GetChamberNumber() << " ";
1214   }
1215   cout << endl;
1216   for (Int_t i1=0; i1<fNTrackHits; i1++) {
1217     hit =  (AliMUONHitForRec*) ((*fTrackHitsPtr)[i1]);
1218     //cout << ((AliMUONHitForRec*)((*fTrackHitsPtr)[i1]))->GetHitNumber() << " ";
1219     //cout << ((AliMUONHitForRec*)((*fTrackHitsPtr)[i1]))->GetZ() << " ";
1220     printf ("%4d", fgHitForRec->IndexOf(hit)); 
1221     //cout << fgHitForRec->IndexOf(((AliMUONHitForRec*)((*fTrackHitsPtr)[i1]))) << " ";
1222   }
1223   cout << endl;
1224   if (fgEventReconstructor->GetRecGeantHits()) { 
1225       // from GEANT hits
1226     for (Int_t i1=0; i1<fNTrackHits; i1++) {
1227       hit =  (AliMUONHitForRec*) ((*fTrackHitsPtr)[i1]);
1228       cout << hit->GetTHTrack() + hit->GetGeantSignal()*10000 << " ";
1229     }
1230   } else {
1231     // from raw clusters
1232     for (Int_t i1=0; i1<fNTrackHits; i1++) {
1233       hit =  (AliMUONHitForRec*) ((*fTrackHitsPtr)[i1]);
1234       rawclusters = fgMUON->GetMUONData()->RawClusters(hit->GetChamberNumber());
1235       clus = (AliMUONRawCluster*) rawclusters->UncheckedAt(hit->GetHitNumber());
1236       printf ("%4d", clus->GetTrack(1) - 1); 
1237       //cout << clus->fTracks[1] - 1 << " ";
1238     }
1239     cout << endl;
1240     for (Int_t i1=0; i1<fNTrackHits; i1++) {
1241       hit =  (AliMUONHitForRec*) ((*fTrackHitsPtr)[i1]);
1242       rawclusters = fgMUON->GetMUONData()->RawClusters(hit->GetChamberNumber());
1243       clus = (AliMUONRawCluster*) rawclusters->UncheckedAt(hit->GetHitNumber());
1244       if (clus->GetTrack(2) != 0) printf ("%4d", clus->GetTrack(2) - 1);
1245       else printf ("%4s", "   ");
1246       //if (clus->fTracks[2] != 0) cout << clus->fTracks[2] - 1 << " ";
1247     }
1248   }
1249   cout << endl;
1250   for (Int_t i1=0; i1<fNTrackHits; i1++) {
1251     //cout << ((AliMUONHitForRec*)((*fTrackHitsPtr)[i1]))->GetHitNumber() << " ";
1252     cout << ((AliMUONHitForRec*)((*fTrackHitsPtr)[i1]))->GetZ() << " ";
1253     //cout << fgHitForRec->IndexOf(((AliMUONHitForRec*)((*fTrackHitsPtr)[i1]))) << " ";
1254   }
1255   cout << endl;
1256   cout << "---------------------------------------------------" << endl;
1257
1258   // Get covariance matrix
1259   *fCovariance = *fWeight;
1260   if (fCovariance->Determinant() != 0) {
1261     //   fCovariance->Invert();
1262
1263       Int_t ifailCov;
1264       mnvertLocalK(&((*fCovariance)(0,0)), fgkSize,fgkSize,fgkSize,ifailCov);
1265   } else {
1266     cout << " ***** Warning in GoToVertex: Determinant fCovariance=0:" << endl;
1267   }
1268 }
1269
1270   //__________________________________________________________________________
1271 void AliMUONTrackK::MSLine(Double_t dZ, Double_t x0)
1272 {
1273   // Adds multiple scattering in a thick layer for linear propagation
1274
1275   Double_t cosAlph = TMath::Cos((*fTrackPar)(2,0));
1276   Double_t tanAlph = TMath::Tan((*fTrackPar)(2,0));
1277   Double_t cosBeta = TMath::Cos((*fTrackPar)(3,0));
1278   Double_t sinBeta;
1279   sinBeta = TMath::Sin((*fTrackPar)(3,0));
1280   Double_t tanBeta = TMath::Tan((*fTrackPar)(3,0));
1281   Double_t momentum = 1/(*fTrackPar)(4,0);
1282   Double_t velo = 1; // relativistic velocity
1283   Double_t step = TMath::Abs(dZ)/cosAlph/cosBeta; // step length
1284
1285   // Projected scattering angle
1286   Double_t theta0 = 0.0136/velo/momentum/TMath::Sqrt(x0)*(1+0.038*TMath::Log(step/x0)); 
1287   Double_t theta02 = theta0*theta0;
1288   Double_t dl2 = step*step/2*theta02;
1289   Double_t dl3 = dl2*step*2/3;
1290
1291   //Derivatives
1292   Double_t dYdT = 1/cosAlph;
1293   Double_t dYdB = 0; //(*fTrackPar)(2,0)*sinBeta/cosAlph;
1294   Double_t dXdT = tanAlph*tanBeta;
1295   //Double_t dXdB = (1+(*fTrackPar)(2,0)*tanAlph*sinBeta*sinBeta)/cosBeta;
1296   Double_t dXdB = 1/cosBeta;
1297   Double_t dAdT = 1/cosBeta;
1298   Double_t dAdB = 0; //(*fTrackPar)(2,0)*tanBeta;
1299
1300   // Get covariance matrix
1301   *fCovariance = *fWeight;
1302   if (fCovariance->Determinant() != 0) {
1303     //   fCovariance->Invert();
1304
1305        Int_t ifailCov;
1306        mnvertLocalK(&((*fCovariance)(0,0)), fgkSize,fgkSize,fgkSize,ifailCov);
1307   } else {
1308     cout << " ***** Warning in MSLine: Determinant fCovariance=0:" << endl;
1309   }
1310
1311   (*fCovariance)(0,0) += dl3*(dYdT*dYdT+dYdB*dYdB); // <yy>
1312   (*fCovariance)(1,1) += dl3*(dXdT*dXdT+dXdB*dXdB); // <xx>
1313   (*fCovariance)(2,2) += theta02*step*(dAdT*dAdT+dAdB*dAdB); // <aa>
1314   (*fCovariance)(3,3) += theta02*step; // <bb>
1315
1316   (*fCovariance)(0,1) += dl3*(dYdT*dXdT+dYdB*dXdB); // <yx>
1317   (*fCovariance)(1,0) = (*fCovariance)(0,1);
1318
1319   (*fCovariance)(0,2) += dl2*(dYdT*dAdT+dYdB*dAdB); // <ya>
1320   (*fCovariance)(2,0) = (*fCovariance)(0,2);
1321
1322   (*fCovariance)(0,3) += dl2*dYdB; // <yb>
1323   (*fCovariance)(3,0) = (*fCovariance)(0,3);
1324
1325   (*fCovariance)(1,2) += dl2*(dXdT*dAdT+dXdB*dAdB); // <xa>
1326   (*fCovariance)(2,1) = (*fCovariance)(1,2);
1327
1328   (*fCovariance)(1,3) += dl2*dXdB; // <xb>
1329   (*fCovariance)(3,1) = (*fCovariance)(1,3);
1330
1331   (*fCovariance)(2,3) += theta02*step*dAdB; // <ab>
1332   (*fCovariance)(3,2) = (*fCovariance)(2,3);
1333
1334   // Get weight matrix
1335   *fWeight = *fCovariance;
1336   if (fWeight->Determinant() != 0) {
1337     //  fWeight->Invert();
1338
1339        Int_t ifailWeight;
1340        mnvertLocalK(&((*fWeight)(0,0)), fgkSize,fgkSize,fgkSize,ifailWeight);
1341   } else {
1342     cout << " ***** Warning in MSLine: Determinant fWeight=0:" << endl;
1343   }
1344 }
1345  
1346   //__________________________________________________________________________
1347 void AliMUONTrackK::Recover(void)
1348 {
1349   // Adds new failed track(s) which can be tried to be recovered
1350   Int_t nRecTracks, ichamb;
1351   TClonesArray *trackPtr;
1352   AliMUONTrackK *trackK;
1353
1354   //cout << " ******** Enter Recover " << endl;
1355   //return;
1356   trackPtr = fgEventReconstructor->GetRecTracksPtr();
1357
1358   // The last hit will be removed
1359   nRecTracks = fgEventReconstructor->GetNRecTracks();
1360
1361   // Check if the track candidate doesn't exist yet
1362   for (Int_t i=0; i<nRecTracks; i++) {
1363     trackK = (AliMUONTrackK*) ((*trackPtr)[i]);
1364     if (trackK->fNTrackHits == 2 && trackK->GetRecover() == 0) continue;
1365     if (trackK == this) continue;
1366     //if (trackK->GetRecover() != 1) continue;
1367     if (trackK->fNTrackHits >= fNTrackHits-1) {
1368       /*
1369       for (Int_t j=0; j<fNTrackHits-1; j++) {
1370         if ((*trackK->fTrackHitsPtr)[j] != ((*fTrackHitsPtr)[j])) break;
1371         return;
1372       } // for (Int_t j=0;
1373       */
1374       if ((*trackK->fTrackHitsPtr)[0] == ((*fTrackHitsPtr)[0])) return;
1375     }
1376   } // for (Int_t i=0;
1377
1378   cout << " ******** Enter Recover " << endl;
1379   trackK = new ((*trackPtr)[nRecTracks]) AliMUONTrackK(fStartSegment); 
1380   fgEventReconstructor->SetNRecTracks(nRecTracks+1);
1381   trackK->fRecover = 1;
1382   trackK->fSkipHit = (AliMUONHitForRec*) ((*fTrackHitsPtr)[fNTrackHits-1]);
1383   trackK->fNTrackHits = fNTrackHits;
1384   delete trackK->fTrackHitsPtr; // not efficient ?
1385   trackK->fTrackHitsPtr = new TObjArray(*fTrackHitsPtr);
1386   cout << nRecTracks << " " << trackK->fRecover << endl;
1387
1388   // The hit before missing chamber will be removed
1389   Int_t ichamBeg = ((AliMUONHitForRec*)((*fTrackHitsPtr)[0]))->GetChamberNumber();
1390   Int_t indxSkip = -1;
1391   if (ichamBeg == 9) {
1392     // segment in the last station
1393     // look for the missing chamber
1394     for (Int_t i=1; i<fNTrackHits; i++) {
1395       ichamb = ((AliMUONHitForRec*)((*fTrackHitsPtr)[i]))->GetChamberNumber();
1396       if (TMath::Abs(ichamBeg-ichamb)>1 && i>2) {
1397         indxSkip = i;
1398         break;
1399       }
1400       ichamBeg = ichamb;
1401     } // for (Int_t i=1;
1402   } else {
1403     // in the last but one station
1404     for (Int_t i=1; i<fNTrackHits; i++) {
1405       ichamb = ((AliMUONHitForRec*)((*fTrackHitsPtr)[i]))->GetChamberNumber();
1406       if (TMath::Abs(ichamBeg-ichamb)>1 && ichamb<4) {
1407         indxSkip = i;
1408         break;
1409       }
1410       ichamBeg = ichamb;
1411     } // for (Int_t i=1;
1412   }
1413   if (indxSkip < 0) return;
1414   
1415   // Check if the track candidate doesn't exist yet
1416   for (Int_t i=0; i<nRecTracks; i++) {
1417     trackK = (AliMUONTrackK*) ((*trackPtr)[i]);
1418     if (trackK->fNTrackHits == 2 && trackK->GetRecover() == 0) continue;
1419     if (trackK == this) continue;
1420     //if (trackK->GetRecover() != 1) continue;
1421     if (trackK->fNTrackHits >= indxSkip-1) {
1422       /*
1423       for (Int_t j=0; j<indxSkip-1; j++) {
1424         if ((*trackK->fTrackHitsPtr)[j] != ((*fTrackHitsPtr)[j])) break;
1425         return;
1426       } // for (Int_t j=0;
1427       */
1428       if ((*trackK->fTrackHitsPtr)[0] == ((*fTrackHitsPtr)[0])) return;
1429     }
1430   } // for (Int_t i=0;
1431
1432   nRecTracks = fgEventReconstructor->GetNRecTracks();
1433   trackK = new ((*trackPtr)[nRecTracks]) AliMUONTrackK(fStartSegment); 
1434   fgEventReconstructor->SetNRecTracks(nRecTracks+1);
1435   trackK->fRecover = 2;
1436   trackK->fSkipHit = (AliMUONHitForRec*) ((*fTrackHitsPtr)[indxSkip-1]);
1437   trackK->fNTrackHits = fNTrackHits;
1438   delete trackK->fTrackHitsPtr; // not efficient ?
1439   trackK->fTrackHitsPtr = new TObjArray(*fTrackHitsPtr);
1440   cout << nRecTracks << " " << trackK->fRecover << endl;
1441 }
1442
1443 //______________________________________________________________________________
1444  void mnvertLocalK(Double_t *a, Int_t l, Int_t, Int_t n, Int_t &ifail)
1445 {
1446 //*-*-*-*-*-*-*-*-*-*-*-*Inverts a symmetric matrix*-*-*-*-*-*-*-*-*-*-*-*-*
1447 //*-*                    ==========================
1448 //*-*        inverts a symmetric matrix.   matrix is first scaled to
1449 //*-*        have all ones on the diagonal (equivalent to change of units)
1450 //*-*        but no pivoting is done since matrix is positive-definite.
1451 //*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
1452
1453   // taken from TMinuit package of Root (l>=n)
1454   // fVERTs, fVERTq and fVERTpp changed to localVERTs, localVERTq and localVERTpp
1455   //  Double_t localVERTs[n], localVERTq[n], localVERTpp[n];
1456   Double_t * localVERTs = new Double_t[n];
1457   Double_t * localVERTq = new Double_t[n];
1458   Double_t * localVERTpp = new Double_t[n];
1459   // fMaxint changed to localMaxint
1460   Int_t localMaxint = n;
1461
1462     /* System generated locals */
1463     Int_t aOffset;
1464
1465     /* Local variables */
1466     Double_t si;
1467     Int_t i, j, k, kp1, km1;
1468
1469     /* Parameter adjustments */
1470     aOffset = l + 1;
1471     a -= aOffset;
1472
1473     /* Function Body */
1474     ifail = 0;
1475     if (n < 1) goto L100;
1476     if (n > localMaxint) goto L100;
1477 //*-*-                  scale matrix by sqrt of diag elements
1478     for (i = 1; i <= n; ++i) {
1479         si = a[i + i*l];
1480         if (si <= 0) goto L100;
1481         localVERTs[i-1] = 1 / TMath::Sqrt(si);
1482     }
1483     for (i = 1; i <= n; ++i) {
1484         for (j = 1; j <= n; ++j) {
1485             a[i + j*l] = a[i + j*l]*localVERTs[i-1]*localVERTs[j-1];
1486         }
1487     }
1488 //*-*-                                       . . . start main loop . . . .
1489     for (i = 1; i <= n; ++i) {
1490         k = i;
1491 //*-*-                  preparation for elimination step1
1492         if (a[k + k*l] != 0) localVERTq[k-1] = 1 / a[k + k*l];
1493         else goto L100;
1494         localVERTpp[k-1] = 1;
1495         a[k + k*l] = 0;
1496         kp1 = k + 1;
1497         km1 = k - 1;
1498         if (km1 < 0) goto L100;
1499         else if (km1 == 0) goto L50;
1500         else               goto L40;
1501 L40:
1502         for (j = 1; j <= km1; ++j) {
1503             localVERTpp[j-1] = a[j + k*l];
1504             localVERTq[j-1]  = a[j + k*l]*localVERTq[k-1];
1505             a[j + k*l]   = 0;
1506         }
1507 L50:
1508         if (k - n < 0) goto L51;
1509         else if (k - n == 0) goto L60;
1510         else                goto L100;
1511 L51:
1512         for (j = kp1; j <= n; ++j) {
1513             localVERTpp[j-1] = a[k + j*l];
1514             localVERTq[j-1]  = -a[k + j*l]*localVERTq[k-1];
1515             a[k + j*l]   = 0;
1516         }
1517 //*-*-                  elimination proper
1518 L60:
1519         for (j = 1; j <= n; ++j) {
1520             for (k = j; k <= n; ++k) { a[j + k*l] += localVERTpp[j-1]*localVERTq[k-1]; }
1521         }
1522     }
1523 //*-*-                  elements of left diagonal and unscaling
1524     for (j = 1; j <= n; ++j) {
1525         for (k = 1; k <= j; ++k) {
1526             a[k + j*l] = a[k + j*l]*localVERTs[k-1]*localVERTs[j-1];
1527             a[j + k*l] = a[k + j*l];
1528         }
1529     }
1530     delete localVERTs;
1531     delete localVERTq;
1532     delete localVERTpp;
1533     return;
1534 //*-*-                  failure return
1535 L100:
1536     delete localVERTs;
1537     delete localVERTq;
1538     delete localVERTpp;
1539     ifail = 1;
1540 } /* mnvertLocal */