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